mirror of
https://github.com/Ichinga-Samuel/aiomql.git
synced 2026-08-22 08:18:06 +00:00
v4
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Table of Contents
|
# Table of Contents
|
||||||
- [MetaTrader](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/meta_trader.md)
|
- [MetaTrader](core/meta_trader.md)
|
||||||
- [Config](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/config.md)
|
- [Config](core/config.md)
|
||||||
- [Base](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/base.md)
|
- [Base](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/base.md)
|
||||||
- [Constants](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/constants.md)
|
- [Constants](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/constants.md)
|
||||||
- [TaskQueue](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/task_queue.md)
|
- [TaskQueue](https://github.com/Ichinga-Samuel/aiomql/blob/master/docs/core/task_queue.md)
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Fractals
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
- [fractals](#fractals)
|
||||||
|
- [find_bearish_fractal](#fractals.find_bearish_fractal)
|
||||||
|
- [find_bullish_fractal](#fractals.find_bullish_fractal)
|
||||||
|
|
||||||
|
|
||||||
|
<a id="fractals.find_bearish_fractal"></a>
|
||||||
|
### find_bearish_fractal
|
||||||
|
```python
|
||||||
|
def find_bearish_fractal(candles: Candles) -> Candle | None
|
||||||
|
```
|
||||||
|
Given a candles object, find the most recent bearish fractal.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="fractals.find_bullish_fractal"></a>
|
||||||
|
### find_bullish_fractal
|
||||||
|
```python
|
||||||
|
def find_bullish_fractal(candles: Candles) -> Candle | None
|
||||||
|
```
|
||||||
|
Given a candles object, find the most recent bullish fractal.
|
||||||
Binary file not shown.
@@ -0,0 +1,58 @@
|
|||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [backtest\_account](#backtest_account)
|
||||||
|
* [BackTestAccount](#backtest_account.BackTestAccount)
|
||||||
|
* [get\_dict](#backtest_account.BackTestAccount.get_dict)
|
||||||
|
* [asdict](#backtest_account.BackTestAccount.asdict)
|
||||||
|
* [set\_attrs](#backtest_account.BackTestAccount.set_attrs)
|
||||||
|
|
||||||
|
<a id="backtest_account"></a>
|
||||||
|
|
||||||
|
# backtest\_account
|
||||||
|
|
||||||
|
<a id="backtest_account.BackTestAccount"></a>
|
||||||
|
|
||||||
|
## BackTestAccount Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class BackTestAccount()
|
||||||
|
```
|
||||||
|
|
||||||
|
Account data for backtesting
|
||||||
|
|
||||||
|
<a id="backtest_account.BackTestAccount.get_dict"></a>
|
||||||
|
|
||||||
|
#### get\_dict
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_dict(exclude: set = None, include: set = None)
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns a dictionary of the account data. Using the exclude and include arguments, you can filter the data
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `exclude` _set_ - A set of keys to exclude
|
||||||
|
- `include` _set_ - A set of keys to include
|
||||||
|
|
||||||
|
<a id="backtest_account.BackTestAccount.asdict"></a>
|
||||||
|
|
||||||
|
#### asdict
|
||||||
|
|
||||||
|
```python
|
||||||
|
def asdict()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns a dictionary of the account data
|
||||||
|
|
||||||
|
<a id="backtest_account.BackTestAccount.set_attrs"></a>
|
||||||
|
|
||||||
|
#### set\_attrs
|
||||||
|
|
||||||
|
```python
|
||||||
|
def set_attrs(**kwargs)
|
||||||
|
```
|
||||||
|
|
||||||
|
Se the attributes of the account data to the instance
|
||||||
|
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [backtest\_controller](#backtest_controller)
|
||||||
|
* [BackTestController](#backtest_controller.BackTestController)
|
||||||
|
* [backtest\_engine](#backtest_controller.BackTestController.backtest_engine)
|
||||||
|
* [add\_tasks](#backtest_controller.BackTestController.add_tasks)
|
||||||
|
* [set\_parties](#backtest_controller.BackTestController.set_parties)
|
||||||
|
* [parties](#backtest_controller.BackTestController.parties)
|
||||||
|
* [control](#backtest_controller.BackTestController.control)
|
||||||
|
* [stop\_backtesting](#backtest_controller.BackTestController.stop_backtesting)
|
||||||
|
* [wait](#backtest_controller.BackTestController.wait)
|
||||||
|
* [abort](#backtest_controller.BackTestController.abort)
|
||||||
|
|
||||||
|
<a id="backtest_controller"></a>
|
||||||
|
|
||||||
|
# backtest\_controller
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController"></a>
|
||||||
|
|
||||||
|
## BackTestController Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BackTestController()
|
||||||
|
```
|
||||||
|
|
||||||
|
The controller for the backtesting engine.
|
||||||
|
It also act's as a synchronizier for running multiple strategies (tasks) using a threading.Barrier primitive.
|
||||||
|
It handles the updating of open positions and close them when necessary.
|
||||||
|
It handles the iterator for the backtesting engine and handles it movement in time by moving it to the next time step.
|
||||||
|
|
||||||
|
**Attributes**:
|
||||||
|
|
||||||
|
- `_instance` _Self_ - The instance of the controller
|
||||||
|
- `config` _Config_ - The configuration for the backtesting engine
|
||||||
|
- `tasks` _list[Task]_ - The tasks that are being run
|
||||||
|
- `barrier` _Barrier_ - The barrier for synchronizing the tasks
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.backtest_engine"></a>
|
||||||
|
|
||||||
|
#### backtest\_engine
|
||||||
|
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def backtest_engine()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the backtest engine
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.add_tasks"></a>
|
||||||
|
|
||||||
|
#### add\_tasks
|
||||||
|
|
||||||
|
```python
|
||||||
|
def add_tasks(*tasks: Task)
|
||||||
|
```
|
||||||
|
|
||||||
|
Adds tasks to the tasks list
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.set_parties"></a>
|
||||||
|
|
||||||
|
#### set\_parties
|
||||||
|
|
||||||
|
```python
|
||||||
|
def set_parties(*, parties: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Sets the number of parties for the barrier. The barrier will wait for the number of parties to reach the barrier.
|
||||||
|
This has to be done here as it can be impossible to know the eventual number of parties to set the barrier to during initialization.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `parties` _int_ - The number of parties to set the barrier to
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.parties"></a>
|
||||||
|
|
||||||
|
#### parties
|
||||||
|
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def parties()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the number of parties for the barrier
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.control"></a>
|
||||||
|
|
||||||
|
#### control
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def control()
|
||||||
|
```
|
||||||
|
|
||||||
|
The backtest controller. It controls the backtesting engine and the tasks that are being run.
|
||||||
|
It acts as a synchronizer for the tasks and the backtesting engine.
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.stop_backtesting"></a>
|
||||||
|
|
||||||
|
#### stop\_backtesting
|
||||||
|
|
||||||
|
```python
|
||||||
|
def stop_backtesting()
|
||||||
|
```
|
||||||
|
|
||||||
|
Stop the backtester, and shutdown the executor
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.wait"></a>
|
||||||
|
|
||||||
|
#### wait
|
||||||
|
|
||||||
|
```python
|
||||||
|
def wait()
|
||||||
|
```
|
||||||
|
|
||||||
|
Called by individual tasks to indicate completion of their cycle
|
||||||
|
|
||||||
|
<a id="backtest_controller.BackTestController.abort"></a>
|
||||||
|
|
||||||
|
#### abort
|
||||||
|
|
||||||
|
```python
|
||||||
|
def abort()
|
||||||
|
```
|
||||||
|
|
||||||
|
Aborts the barrier
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,185 @@
|
|||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [get\_data](#get_data)
|
||||||
|
* [Cursor](#get_data.Cursor)
|
||||||
|
* [BackTestData](#get_data.BackTestData)
|
||||||
|
* [set\_attrs](#get_data.BackTestData.set_attrs)
|
||||||
|
* [fields](#get_data.BackTestData.fields)
|
||||||
|
* [GetData](#get_data.GetData)
|
||||||
|
* [\_\_init\_\_](#get_data.GetData.__init__)
|
||||||
|
* [pickle\_data](#get_data.GetData.pickle_data)
|
||||||
|
* [load\_data](#get_data.GetData.load_data)
|
||||||
|
* [save\_data](#get_data.GetData.save_data)
|
||||||
|
* [get\_data](#get_data.GetData.get_data)
|
||||||
|
|
||||||
|
<a id="get_data"></a>
|
||||||
|
|
||||||
|
# get\_data
|
||||||
|
|
||||||
|
<a id="get_data.Cursor"></a>
|
||||||
|
|
||||||
|
## Cursor Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Cursor(NamedTuple)
|
||||||
|
```
|
||||||
|
|
||||||
|
A cursor to iterate over the data. Marks the current position.
|
||||||
|
|
||||||
|
<a id="get_data.BackTestData"></a>
|
||||||
|
|
||||||
|
## BackTestData Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class BackTestData()
|
||||||
|
```
|
||||||
|
|
||||||
|
The data class to store the backtesting data.
|
||||||
|
|
||||||
|
**Attributes**:
|
||||||
|
|
||||||
|
- `name` _str_ - The name of the backtest data.
|
||||||
|
- `terminal` _dict_ - The terminal information.
|
||||||
|
- `version` _tuple_ - The version of the terminal.
|
||||||
|
- `account` _dict_ - The account information.
|
||||||
|
- `symbols` _dict_ - The symbols information.
|
||||||
|
- `ticks` _dict_ - The ticks data.
|
||||||
|
- `rates` _dict_ - The rates data.
|
||||||
|
- `span` _range_ - The range of the data.
|
||||||
|
- `range` _range_ - The range of the data.
|
||||||
|
- `orders` _dict_ - The orders data.
|
||||||
|
- `deals` _dict_ - The deals data.
|
||||||
|
- `positions` _dict_ - The positions data.
|
||||||
|
- `open_positions` _set_ - The open positions.
|
||||||
|
- `cursor` _Cursor_ - The cursor to iterate over the data.
|
||||||
|
- `margins` _dict_ - The margins data.
|
||||||
|
- `fully_loaded` _bool_ - A flag to indicate if the data is fully loaded
|
||||||
|
|
||||||
|
<a id="get_data.BackTestData.set_attrs"></a>
|
||||||
|
|
||||||
|
#### set\_attrs
|
||||||
|
|
||||||
|
```python
|
||||||
|
def set_attrs(**kwargs)
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the attributes of the class on the instance.
|
||||||
|
|
||||||
|
<a id="get_data.BackTestData.fields"></a>
|
||||||
|
|
||||||
|
#### fields
|
||||||
|
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def fields()
|
||||||
|
```
|
||||||
|
|
||||||
|
A list of the fields of the class.
|
||||||
|
|
||||||
|
<a id="get_data.GetData"></a>
|
||||||
|
|
||||||
|
## GetData Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class GetData()
|
||||||
|
```
|
||||||
|
|
||||||
|
A class to get the backtesting data from the MetaTrader5 terminal.
|
||||||
|
|
||||||
|
**Attributes**:
|
||||||
|
|
||||||
|
- `start` _datetime_ - The start date of the data.
|
||||||
|
- `end` _datetime_ - The end date of the data.
|
||||||
|
- `symbols` _Sequence[str]_ - The symbols to get the data for.
|
||||||
|
- `timeframes` _Sequence[TimeFrame]_ - The timeframes to get the data for.
|
||||||
|
- `name` _str_ - The name of the backtest data.
|
||||||
|
- `range` _range_ - The range of the data.
|
||||||
|
- `span` _range_ - The span of the data.
|
||||||
|
- `data` _BackTestData_ - The backtesting data.
|
||||||
|
- `mt5` _MetaTrader_ - The MetaTrader5 instance.
|
||||||
|
- `task_queue` _TaskQueue_ - The task queue to handle the requests.
|
||||||
|
|
||||||
|
<a id="get_data.GetData.__init__"></a>
|
||||||
|
|
||||||
|
#### \_\_init\_\_
|
||||||
|
|
||||||
|
```python
|
||||||
|
def __init__(*,
|
||||||
|
start: datetime,
|
||||||
|
end: datetime,
|
||||||
|
symbols: Sequence[str],
|
||||||
|
timeframes: Sequence[TimeFrame],
|
||||||
|
name: str = "")
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the backtesting data from the MetaTrader5 terminal.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `start` _datetime_ - The start date of the data.
|
||||||
|
- `end` _datetime_ - The end date of the data.
|
||||||
|
- `symbols` _Sequence[str]_ - The symbols to get the data for.
|
||||||
|
- `timeframes` _Sequence[TimeFrame]_ - The timeframes to get the data for.
|
||||||
|
- `name` _str_ - The name of the backtest data.
|
||||||
|
|
||||||
|
<a id="get_data.GetData.pickle_data"></a>
|
||||||
|
|
||||||
|
#### pickle\_data
|
||||||
|
|
||||||
|
```python
|
||||||
|
@classmethod
|
||||||
|
def pickle_data(cls, *, data: BackTestData, name: str | Path)
|
||||||
|
```
|
||||||
|
|
||||||
|
Pickle the data to a file.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `data` _BackTestData_ - The data to pickle.
|
||||||
|
- `name` _str | Path_ - The name of the file to pickle the data to.
|
||||||
|
|
||||||
|
<a id="get_data.GetData.load_data"></a>
|
||||||
|
|
||||||
|
#### load\_data
|
||||||
|
|
||||||
|
```python
|
||||||
|
@classmethod
|
||||||
|
def load_data(cls, *, name: str | Path) -> BackTestData
|
||||||
|
```
|
||||||
|
|
||||||
|
Load the data from a file.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `name` _str | Path_ - The name of the file to load the data from.
|
||||||
|
|
||||||
|
<a id="get_data.GetData.save_data"></a>
|
||||||
|
|
||||||
|
#### save\_data
|
||||||
|
|
||||||
|
```python
|
||||||
|
def save_data(*, name: str | Path = "")
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the data to a file.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `name` _str | Path_ - The name of the file to save the data to. If not provided, the name of the data is used.
|
||||||
|
|
||||||
|
<a id="get_data.GetData.get_data"></a>
|
||||||
|
|
||||||
|
#### get\_data
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def get_data(workers: int = None)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the task queue to get the data from the MetaTrader5 terminal.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `workers` _int_ - The number of workers to use in the task queue. If not provided, the default number of workers
|
||||||
|
is used.
|
||||||
|
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [trades\_manager](#trades_manager)
|
||||||
|
* [TradeManager](#trades_manager.TradeManager)
|
||||||
|
* [update](#trades_manager.TradeManager.update)
|
||||||
|
* [values](#trades_manager.TradeManager.values)
|
||||||
|
* [keys](#trades_manager.TradeManager.keys)
|
||||||
|
* [items](#trades_manager.TradeManager.items)
|
||||||
|
* [to\_dict](#trades_manager.TradeManager.to_dict)
|
||||||
|
* [PositionsManager](#trades_manager.PositionsManager)
|
||||||
|
* [\_\_init\_\_](#trades_manager.PositionsManager.__init__)
|
||||||
|
* [margin](#trades_manager.PositionsManager.margin)
|
||||||
|
* [close](#trades_manager.PositionsManager.close)
|
||||||
|
* [get\_margin](#trades_manager.PositionsManager.get_margin)
|
||||||
|
* [delete\_margin](#trades_manager.PositionsManager.delete_margin)
|
||||||
|
* [set\_margin](#trades_manager.PositionsManager.set_margin)
|
||||||
|
* [positions\_get](#trades_manager.PositionsManager.positions_get)
|
||||||
|
* [positions\_total](#trades_manager.PositionsManager.positions_total)
|
||||||
|
* [open\_positions](#trades_manager.PositionsManager.open_positions)
|
||||||
|
* [OrdersManager](#trades_manager.OrdersManager)
|
||||||
|
* [get\_orders\_range](#trades_manager.OrdersManager.get_orders_range)
|
||||||
|
* [history\_orders\_get](#trades_manager.OrdersManager.history_orders_get)
|
||||||
|
* [history\_orders\_total](#trades_manager.OrdersManager.history_orders_total)
|
||||||
|
* [DealsManager](#trades_manager.DealsManager)
|
||||||
|
* [get\_deals\_range](#trades_manager.DealsManager.get_deals_range)
|
||||||
|
* [history\_deals\_get](#trades_manager.DealsManager.history_deals_get)
|
||||||
|
* [history\_deals\_total](#trades_manager.DealsManager.history_deals_total)
|
||||||
|
|
||||||
|
<a id="trades_manager"></a>
|
||||||
|
|
||||||
|
# trades\_manager
|
||||||
|
|
||||||
|
<a id="trades_manager.TradeManager"></a>
|
||||||
|
|
||||||
|
## TradeManager Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class TradeManager(Generic[TradeData])
|
||||||
|
```
|
||||||
|
|
||||||
|
A generic class to manage trades data during a backtest. It is the parent class of the
|
||||||
|
PositionsManager, OrdersManager, and DealsManager. It implements some dict-like methods to manage the data.
|
||||||
|
It has a private attribute _data to store the data. It exposes the data through the values, keys, and items methods.
|
||||||
|
It also has a to_dict method to convert the data to a dictionary.
|
||||||
|
|
||||||
|
**Attributes**:
|
||||||
|
|
||||||
|
- `_data` _dict[int, TradeData]_ - The data to store the trades.
|
||||||
|
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
|
||||||
|
>>> manager = TradeManager()
|
||||||
|
>>> manager[123456] = TradePosition(ticket=123456, symbol="EURUSD", volume=0.1)
|
||||||
|
>>> manager.update(ticket=123456, symbol="EURUSD", volume=0.1)
|
||||||
|
>>> manager[123456]
|
||||||
|
TradePosition(ticket=123456, symbol='EURUSD', volume=0.1)
|
||||||
|
>>> manager.values()
|
||||||
|
(TradePosition(ticket=123456, symbol='EURUSD', volume=0.1),)
|
||||||
|
>>> manager.keys()
|
||||||
|
(123456,)
|
||||||
|
>>> manager.items()
|
||||||
|
((123456, TradePosition(ticket=123456, symbol='EURUSD', volume=0.1)),)
|
||||||
|
>>> manager.to_dict()
|
||||||
|
- `{123456` - {'ticket': 123456, 'symbol': 'EURUSD', 'volume': 0.1}}
|
||||||
|
>>> pos = manager.get(123456)
|
||||||
|
>>> pos
|
||||||
|
TradePosition(ticket=123456, symbol='EURUSD', volume=0.1)
|
||||||
|
>>> pos in manager
|
||||||
|
True
|
||||||
|
>>> len(manager)
|
||||||
|
1
|
||||||
|
>>> pos in manager
|
||||||
|
False
|
||||||
|
|
||||||
|
<a id="trades_manager.TradeManager.update"></a>
|
||||||
|
|
||||||
|
#### update
|
||||||
|
|
||||||
|
```python
|
||||||
|
def update(*, ticket: int, **kwargs)
|
||||||
|
```
|
||||||
|
|
||||||
|
Update the data of a trade. Given the ticket of the trade and the new data to update.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `ticket` _int_ - The ticket of the trade to update.
|
||||||
|
- `**kwargs` - The new data to update.
|
||||||
|
|
||||||
|
<a id="trades_manager.TradeManager.values"></a>
|
||||||
|
|
||||||
|
#### values
|
||||||
|
|
||||||
|
```python
|
||||||
|
def values() -> tuple[TradeData, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the values of the data.
|
||||||
|
|
||||||
|
<a id="trades_manager.TradeManager.keys"></a>
|
||||||
|
|
||||||
|
#### keys
|
||||||
|
|
||||||
|
```python
|
||||||
|
def keys() -> tuple[int, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the keys of the data.
|
||||||
|
|
||||||
|
<a id="trades_manager.TradeManager.items"></a>
|
||||||
|
|
||||||
|
#### items
|
||||||
|
|
||||||
|
```python
|
||||||
|
def items() -> tuple[tuple[int, TradeData], ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the items of the data.
|
||||||
|
|
||||||
|
<a id="trades_manager.TradeManager.to_dict"></a>
|
||||||
|
|
||||||
|
#### to\_dict
|
||||||
|
|
||||||
|
```python
|
||||||
|
def to_dict()
|
||||||
|
```
|
||||||
|
|
||||||
|
Convert the data to a dictionary.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager"></a>
|
||||||
|
|
||||||
|
## PositionsManager Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class PositionsManager(TradeManager)
|
||||||
|
```
|
||||||
|
|
||||||
|
A class to manage the open positions during a backtest. It is a subclass of TradeManager. It has an additional
|
||||||
|
attribute _open_positions to store the open positions. It also has a margins attribute to store the margins of the
|
||||||
|
open positions. It overrides some methods of the TradeManager class to manage the open positions.
|
||||||
|
|
||||||
|
**Attributes**:
|
||||||
|
|
||||||
|
- `_open_positions` _set[int]_ - The open positions.
|
||||||
|
- `margins` _dict[int, float]_ - The margins of the open positions.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.__init__"></a>
|
||||||
|
|
||||||
|
#### \_\_init\_\_
|
||||||
|
|
||||||
|
```python
|
||||||
|
def __init__(*,
|
||||||
|
data: dict = None,
|
||||||
|
open_positions: set[int] = None,
|
||||||
|
margins: dict = None)
|
||||||
|
```
|
||||||
|
|
||||||
|
Positions manager manages the open positions during a backtest. It is a subclass of TradeManager. It has an
|
||||||
|
additional attribute _open_positions to store the open positions. It also has a margins attribute to store the
|
||||||
|
margins of the open positions. It overrides some methods of the TradeManager class to manage the open positions.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `data` _dict, optional_ - The data to store the trades. This used for continuation of the backtesting, if it
|
||||||
|
was stopped with some open positions.
|
||||||
|
|
||||||
|
- `open_positions` _set, optional_ - The open positions. Defaults to None.
|
||||||
|
|
||||||
|
- `margins` _dict, optional_ - The margins of the open positions. Defaults to None.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.margin"></a>
|
||||||
|
|
||||||
|
#### margin
|
||||||
|
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def margin()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the total margin of all open positions
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.close"></a>
|
||||||
|
|
||||||
|
#### close
|
||||||
|
|
||||||
|
```python
|
||||||
|
def close(*, ticket: int) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Close a position. Given the ticket of the position to close.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `ticket` _int_ - The ticket of the position to close.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.get_margin"></a>
|
||||||
|
|
||||||
|
#### get\_margin
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_margin(*, ticket: int) -> float
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the margin of a position. Given the ticket of the position.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `ticket` _int_ - The ticket of the position.
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
- `float` - The margin of the position.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.delete_margin"></a>
|
||||||
|
|
||||||
|
#### delete\_margin
|
||||||
|
|
||||||
|
```python
|
||||||
|
def delete_margin(*, ticket: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete the margin of a position. Given the ticket of the position.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `ticket` _int_ - The ticket of the position.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.set_margin"></a>
|
||||||
|
|
||||||
|
#### set\_margin
|
||||||
|
|
||||||
|
```python
|
||||||
|
def set_margin(*, ticket: int, margin: float)
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the margin of a position. Given the ticket of the position and the margin.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `ticket` _int_ - The ticket of the position.
|
||||||
|
- `margin` _float_ - The margin of the position
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.positions_get"></a>
|
||||||
|
|
||||||
|
#### positions\_get
|
||||||
|
|
||||||
|
```python
|
||||||
|
def positions_get(*,
|
||||||
|
ticket: int = None,
|
||||||
|
symbol: str = None,
|
||||||
|
group: None = None) -> tuple[TradePosition, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Get positions. Given the ticket, symbol, or group of the positions.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `ticket` _int_ - The ticket of the position.
|
||||||
|
- `symbol` _str_ - The symbol of the position.
|
||||||
|
- `group` _str_ - The group
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
tuple[TradePosition, ...]: The positions
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.positions_total"></a>
|
||||||
|
|
||||||
|
#### positions\_total
|
||||||
|
|
||||||
|
```python
|
||||||
|
def positions_total() -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the total number of open positions.
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
- `int` - The total number of open positions.
|
||||||
|
|
||||||
|
<a id="trades_manager.PositionsManager.open_positions"></a>
|
||||||
|
|
||||||
|
#### open\_positions
|
||||||
|
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def open_positions() -> tuple[TradePosition, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the open positions.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
tuple[TradePosition, ...]: The open positions.
|
||||||
|
|
||||||
|
<a id="trades_manager.OrdersManager"></a>
|
||||||
|
|
||||||
|
## OrdersManager Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class OrdersManager(TradeManager)
|
||||||
|
```
|
||||||
|
|
||||||
|
Managers orders data during a backtest. It is a subclass of TradeManager. It manages access to the historical
|
||||||
|
orders data
|
||||||
|
|
||||||
|
<a id="trades_manager.OrdersManager.get_orders_range"></a>
|
||||||
|
|
||||||
|
#### get\_orders\_range
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_orders_range(*, date_from: float,
|
||||||
|
date_to: float) -> tuple[TradeData, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Get orders within a date range. Given the start and end date of the range.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `date_from` _float_ - The start date of the range.
|
||||||
|
- `date_to` _float_ - The end date of the range.
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
tuple[TradeData, ...]: The orders within the date range.
|
||||||
|
|
||||||
|
<a id="trades_manager.OrdersManager.history_orders_get"></a>
|
||||||
|
|
||||||
|
#### history\_orders\_get
|
||||||
|
|
||||||
|
```python
|
||||||
|
def history_orders_get(*,
|
||||||
|
date_from: float | datetime = None,
|
||||||
|
date_to: float | datetime = None,
|
||||||
|
group: str = "",
|
||||||
|
ticket: int = None,
|
||||||
|
position: int = None) -> tuple[TradeOrder, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Get historical orders. Given the start and end date of the range, the group, ticket, or position of the
|
||||||
|
orders.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `date_from` _float, datetime_ - The start date of the range.
|
||||||
|
- `date_to` _float, datetime_ - The end date of the range.
|
||||||
|
- `group` _str_ - The group of the orders.
|
||||||
|
- `ticket` _int_ - The ticket of the order.
|
||||||
|
- `position` _int_ - The position of the order.
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
tuple[TradeOrder, ...]: The historical orders.
|
||||||
|
|
||||||
|
<a id="trades_manager.OrdersManager.history_orders_total"></a>
|
||||||
|
|
||||||
|
#### history\_orders\_total
|
||||||
|
|
||||||
|
```python
|
||||||
|
def history_orders_total(*, date_from: datetime | float,
|
||||||
|
date_to: datetime | float) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the total number of historical orders. Given the start and end date of the range.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `date_from` _datetime, float_ - The start date of the range.
|
||||||
|
- `date_to` _datetime, float_ - The end date of the range.
|
||||||
|
|
||||||
|
<a id="trades_manager.DealsManager"></a>
|
||||||
|
|
||||||
|
## DealsManager Objects
|
||||||
|
|
||||||
|
```python
|
||||||
|
class DealsManager(TradeManager)
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="trades_manager.DealsManager.get_deals_range"></a>
|
||||||
|
|
||||||
|
#### get\_deals\_range
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_deals_range(*, date_from: float,
|
||||||
|
date_to: float) -> tuple[TradeData, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Get deals within a date range. Given the start and end date of the range.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `date_from` _float_ - The start date of the range.
|
||||||
|
- `date_to` _float_ - The end date of the range.
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
tuple[TradeData, ...]: The deals within the date range.
|
||||||
|
|
||||||
|
<a id="trades_manager.DealsManager.history_deals_get"></a>
|
||||||
|
|
||||||
|
#### history\_deals\_get
|
||||||
|
|
||||||
|
```python
|
||||||
|
def history_deals_get(*,
|
||||||
|
date_from: float | datetime = None,
|
||||||
|
date_to: float | datetime = None,
|
||||||
|
group: str = "",
|
||||||
|
ticket: int = None,
|
||||||
|
position: int = None) -> tuple[TradeDeal, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
History deals get. Given the start and end date of the range, the group, ticket, or position of the deals.
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `date_from` _float, datetime_ - The start date of the range.
|
||||||
|
- `date_to` _float, datetime_ - The end date of the range.
|
||||||
|
- `group` _str_ - The group of the deals.
|
||||||
|
- `ticket` _int_ - The ticket of the deal.
|
||||||
|
- `position` _int_ - The position of the deal.
|
||||||
|
|
||||||
|
<a id="trades_manager.DealsManager.history_deals_total"></a>
|
||||||
|
|
||||||
|
#### history\_deals\_total
|
||||||
|
|
||||||
|
```python
|
||||||
|
def history_deals_total(*, date_from: datetime | float,
|
||||||
|
date_to: datetime | float) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the total number of historical deals. Given the start and end date of the range
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `date_from` _datetime, float_ - The start date of the range.
|
||||||
|
- `date_to` _datetime, float_ - The end date of the range.
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
|
||||||
|
- `int` - The total number of historical deals.
|
||||||
|
|
||||||
+53
-27
@@ -1,14 +1,17 @@
|
|||||||
# Base Class
|
# Base
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [Base](#base)
|
- [Base](#base.base)
|
||||||
- [set\_attributes](#base.set_attributes)
|
- [set_attributes](#base.set_attributes)
|
||||||
- [annotations](#base.annotations)
|
- [annotations](#base.annotations)
|
||||||
- [get\_dict](#base.get_dict)
|
- [get_dict](#base.get_dict)
|
||||||
- [class\_vars](#base.class_vars)
|
- [class_vars](#base.class_vars)
|
||||||
- [dict](#base.dict)
|
- [dict](#base.dict)
|
||||||
|
|
||||||
<a id="base"></a>
|
- [_Base](#_base._base)
|
||||||
|
|
||||||
|
|
||||||
|
<a id="base.base"></a>
|
||||||
### Base
|
### Base
|
||||||
```python
|
```python
|
||||||
class Base
|
class Base
|
||||||
@@ -16,11 +19,12 @@ class Base
|
|||||||
A base class for all data model classes in the aiomql package. This class provides a set of common methods
|
A base class for all data model classes in the aiomql package. This class provides a set of common methods
|
||||||
and attributes for all data model classes.
|
and attributes for all data model classes.
|
||||||
|
|
||||||
#### Class Attributes
|
#### Attributes:
|
||||||
| Name | Type | Description | Default |
|
| Name | Type | Description |
|
||||||
|----------|--------------|-------------------------------------|---------|
|
|-----------|-------|------------------------------------------------------------------------------------------------------|
|
||||||
| `mt5` | `MetaTrader` | An instance of the MetaTrader class | |
|
| `exclude` | `set` | A set of attributes to be excluded when retrieving attributes using the *get_dict* and *dict* method |
|
||||||
| `config` | `Config` | An instance of the Config class | |
|
| `include` | `set` | A set of attributes to be included when retrieving attributes using the *get_dict* and *dict* method |
|
||||||
|
|
||||||
|
|
||||||
<a id="base.__init__"></a>
|
<a id="base.__init__"></a>
|
||||||
### __init__
|
### __init__
|
||||||
@@ -32,25 +36,28 @@ def __init__(**kwargs)
|
|||||||
|----------|-------|---------------------------------------------------|
|
|----------|-------|---------------------------------------------------|
|
||||||
| `kwargs` | `Any` | Object attributes and values as keyword arguments |
|
| `kwargs` | `Any` | Object attributes and values as keyword arguments |
|
||||||
|
|
||||||
|
|
||||||
<a id="base.set_attributes"></a>
|
<a id="base.set_attributes"></a>
|
||||||
### set_attributes
|
### set_attributes
|
||||||
```python
|
```python
|
||||||
def set_attributes(**kwargs)
|
def set_attributes(**kwargs)
|
||||||
```
|
```
|
||||||
Set keyword arguments as object attributes. Only sets attributes that have been annotated on the class body.
|
Set keyword arguments as object attributes. Only sets attributes that have been annotated on the class body.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|---------------------------------------------------|
|
|----------|-------|---------------------------------------------------|
|
||||||
| `kwargs` | `Any` | Object attributes and values as keyword arguments |
|
| `kwargs` | `Any` | Object attributes and values as keyword arguments |
|
||||||
|
|
||||||
#### Raises
|
#### Raises:
|
||||||
| Exception | Description |
|
| Exception | Description |
|
||||||
|------------------|-----------------------------------------------------------------------------------|
|
|------------------|-----------------------------------------------------------------------------------|
|
||||||
| `AttributeError` | When assigning an attribute that does not belong to the class or any parent class |
|
| `AttributeError` | When assigning an attribute that does not belong to the class or any parent class |
|
||||||
|
|
||||||
#### Notes
|
#### Notes:
|
||||||
Only sets attributes that have been annotated on the class body.
|
Only sets attributes that have been annotated on the class body.
|
||||||
|
|
||||||
|
|
||||||
<a id="base.annotations"></a>
|
<a id="base.annotations"></a>
|
||||||
### annotations
|
### annotations
|
||||||
```python
|
```python
|
||||||
@@ -59,43 +66,49 @@ Only sets attributes that have been annotated on the class body.
|
|||||||
def annotations() -> dict
|
def annotations() -> dict
|
||||||
```
|
```
|
||||||
Class annotations from all ancestor classes and the current class.
|
Class annotations from all ancestor classes and the current class.
|
||||||
#### Returns
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|-----------------------------------|
|
|------------------|-----------------------------------|
|
||||||
| `dict` | A dictionary of class annotations |
|
| `dict[str, Any]` | A dictionary of class annotations |
|
||||||
|
|
||||||
|
|
||||||
<a id="base.get_dict"></a>
|
<a id="base.get_dict"></a>
|
||||||
#### get\_dict
|
#### get_dict
|
||||||
```python
|
```python
|
||||||
def get_dict(exclude: set = None, include: set = None) -> dict
|
def get_dict(exclude: set = None, include: set = None) -> dict
|
||||||
```
|
```
|
||||||
Returns class attributes as a dict, with the ability to filter
|
Returns class attributes as a dict, with the ability to filter
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-----------|-------|------------------------------------|
|
|-----------|-------|------------------------------------|
|
||||||
| `exclude` | `set` | A set of attributes to be excluded |
|
| `exclude` | `set` | A set of attributes to be excluded |
|
||||||
| `include` | `set` | Specific attributes to be returned |
|
| `include` | `set` | Specific attributes to be returned |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------------------|
|
|--------|--------------------------------------------|
|
||||||
| `dict` | A dictionary of specified class attributes |
|
| `dict` | A dictionary of specified class attributes |
|
||||||
|
|
||||||
#### Notes
|
#### Notes:
|
||||||
You can only set either of include or exclude. If you set both, include will take precedence
|
You can only set either of include or exclude. If you set both, include will take precedence
|
||||||
|
|
||||||
|
|
||||||
<a id="base.class_vars"></a>
|
<a id="base.class_vars"></a>
|
||||||
### class\_vars
|
### class_vars
|
||||||
```python
|
```python
|
||||||
@property
|
@property
|
||||||
@cache
|
@cache
|
||||||
def class_vars()
|
def class_vars()
|
||||||
```
|
```
|
||||||
Annotated class attributes
|
Annotated class attributes
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|-------------------------------------------------------------------------------------------|
|
|--------|-------------------------------------------------------------------------------------------|
|
||||||
| `dict` | A dictionary of available class attributes in all ancestor classes and the current class. |
|
| `dict` | A dictionary of available class attributes in all ancestor classes and the current class. |
|
||||||
|
|
||||||
|
|
||||||
<a id="base.dict"></a>
|
<a id="base.dict"></a>
|
||||||
### dict
|
### dict
|
||||||
```python
|
```python
|
||||||
@@ -103,7 +116,20 @@ Annotated class attributes
|
|||||||
def dict() -> dict
|
def dict() -> dict
|
||||||
```
|
```
|
||||||
All instance and class attributes as a dictionary, except those excluded in the Meta class.
|
All instance and class attributes as a dictionary, except those excluded in the Meta class.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|-----------------------------------------------|
|
|--------|-----------------------------------------------|
|
||||||
| `dict` | A dictionary of instance and class attributes |
|
| `dict` | A dictionary of instance and class attributes |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="_base._base></a>
|
||||||
|
### _Base(Base)
|
||||||
|
Base class that provides access to the MetaTrader and Config classes as well as the MetaBackTester class for
|
||||||
|
backtesting mode.
|
||||||
|
|
||||||
|
#### Attributes:
|
||||||
|
| Name | Type | Description | Default |
|
||||||
|
|----------|--------------|-------------------------------------|---------|
|
||||||
|
| `mt5` | `MetaTrader` | An instance of the MetaTrader class | |
|
||||||
|
| `config` | `Config` | An instance of the Config class | |
|
||||||
|
|||||||
+326
-239
@@ -2,41 +2,43 @@
|
|||||||
The MetaTrader Class provides an asynchronous wrapper around the MetaTrader5 API.
|
The MetaTrader Class provides an asynchronous wrapper around the MetaTrader5 API.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [MetaTrader](#MetaTrader)
|
- [MetaTrader](#meta_trader.meta_trader)
|
||||||
- [\_\_aenter\_\_](#__aenter__)
|
- [\__aenter\__](#meta_trader.__aenter__)
|
||||||
- [\_\_aexit\_\_](#__aexit__)
|
- [\__aexit\__](#meta_trader.__aexit__)
|
||||||
- [login](#login)
|
- [login](#meta_trader.login)
|
||||||
- [initialize](#initialize)
|
- [initialize](#meta_trader.initialize)
|
||||||
- [shutdown](#shutdown)
|
- [login_sync](#meta_trader.login_sync)
|
||||||
- [version](#version)
|
- [initialize_sync](#meta_trader.initialize_sync)
|
||||||
- [account\_info](#account_info)
|
- [shutdown](#meta_trader.shutdown)
|
||||||
- [terminal\_info](#terminal_info)
|
- [version](#meta_trader.version)
|
||||||
- [last\_error](#last_error)
|
- [account_info](#meta_trader.account_info)
|
||||||
- [symbols\_total](#symbols_total)
|
- [terminal_info](#meta_trader.terminal_info)
|
||||||
- [symbols\_get](#symbols_get)
|
- [last_error](#meta_trader.last_error)
|
||||||
- [symbol\_info](#symbol_info)
|
- [symbols_total](#meta_trader.symbols_total)
|
||||||
- [symbol\_info\_tick](#symbol_info_tick)
|
- [symbols_get](#meta_trader.symbols_get)
|
||||||
- [symbol\_select](#symbol_select)
|
- [symbol_info](#meta_trader.symbol_info)
|
||||||
- [market\_book\_add](#market_book_add)
|
- [symbol_info_tick](#meta_trader.symbol_info_tick)
|
||||||
- [market\_book\_get](#market_book_get)
|
- [symbol_select](#meta_trader.symbol_select)
|
||||||
- [market\_book\_release](#market_book_release)
|
- [market_book_add](#meta_trader.market_book_add)
|
||||||
- [copy\_rates\_from](#copy_rates_from)
|
- [market_book_get](#meta_trader.market_book_get)
|
||||||
- [copy\_rates\_from\_pos](#copy_rates_from_pos)
|
- [market_book_release](#meta_trader.market_book_release)
|
||||||
- [copy\_rates\_range](#copy_rates_range)
|
- [copy_rates_from](#meta_trader.copy_rates_from)
|
||||||
- [copy\_ticks\_from](#copy_ticks_from)
|
- [copy_rates_from_pos](#meta_trader.copy_rates_from_pos)
|
||||||
- [copy\_ticks\_range](#copy_ticks_range)
|
- [copy_rates_range](#meta_trader.copy_rates_range)
|
||||||
- [orders\_total](#orders_total)
|
- [copy_ticks_from](#meta_trader.copy_ticks_from)
|
||||||
- [orders\_get](#orders_get)
|
- [copy_ticks_range](#meta_trader.copy_ticks_range)
|
||||||
- [order\_calc\_margin](#order_calc_margin)
|
- [orders_total](#meta_trader.orders_total)
|
||||||
- [order\_calc\_profit](#order_calc_profit)
|
- [orders_get](#meta_trader.orders_get)
|
||||||
- [order\_check](#order_check)
|
- [order_calc_margin](#meta_trader.order_calc_margin)
|
||||||
- [order\_send](#order_send)
|
- [order_calc_profit](#meta_trader.order_calc_profit)
|
||||||
- [positions\_total](#positions_total)
|
- [order_check](#meta_trader.order_check)
|
||||||
- [positions\_get](#positions_get)
|
- [order_send](#meta_trader.order_send)
|
||||||
- [history\_orders\_total](#history_orders_total)
|
- [positions_total](#meta_trader.positions_total)
|
||||||
- [history\_orders\_get](#history_orders_get)
|
- [positions_get](#meta_trader.positions_get)
|
||||||
- [history\_deals\_total](#history_deals_total)
|
- [history_orders_total](#meta_trader.history_orders_total)
|
||||||
- [history\_deals\_get](#history_deals_get)
|
- [history_orders_get](#meta_trader.history_orders_get)
|
||||||
|
- [history_deals_total](#meta_trader.history_deals_total)
|
||||||
|
- [history_deals_get](#meta_trader.history_deals_get)
|
||||||
|
|
||||||
<a id="meta_trader.meta_trader"></a>
|
<a id="meta_trader.meta_trader"></a>
|
||||||
### MetaTrader
|
### MetaTrader
|
||||||
@@ -51,12 +53,13 @@ It provides methods for connecting to the MetaTrader terminal and retrieving dat
|
|||||||
|-------|-------|--------------------------------------------------------|------------------------|
|
|-------|-------|--------------------------------------------------------|------------------------|
|
||||||
| error | Error | The last error encountered by the MetaTrader terminal. | Error(1, 'Successful') |
|
| error | Error | The last error encountered by the MetaTrader terminal. | Error(1, 'Successful') |
|
||||||
|
|
||||||
#### Notes
|
#### Notes:
|
||||||
All the attributes, enums and constants of the MetaTrader5 class are also available here. Although, they are more easily
|
All the attributes, enums and constants of the MetaTrader5 class are also available here. Although, they are more easily
|
||||||
accessible and used via the various enums and models defined in the module.
|
accessible and used via the various enums and models defined in the module.
|
||||||
|
|
||||||
<a id="__aenter__"></a>
|
|
||||||
#### \_\_aenter\_\_
|
<a id="meta_trader.__aenter__"></a>
|
||||||
|
### \__aenter\__
|
||||||
```python
|
```python
|
||||||
async def __aenter__() -> 'MetaTrader'
|
async def __aenter__() -> 'MetaTrader'
|
||||||
```
|
```
|
||||||
@@ -68,405 +71,478 @@ Initializes the connection to the MetaTrader terminal.
|
|||||||
|--------------|-------------------------------------|
|
|--------------|-------------------------------------|
|
||||||
| `MetaTrader` | An instance of the MetaTrader class |
|
| `MetaTrader` | An instance of the MetaTrader class |
|
||||||
|
|
||||||
<a id="__aexit__"></a>
|
|
||||||
#### \_\_aexit\_\_
|
<a id="meta_trader.__aexit__"></a>
|
||||||
|
### \__aexit\__
|
||||||
```python
|
```python
|
||||||
async def __aexit__(exc_type, exc_val, exc_tb)
|
async def __aexit__(exc_type, exc_val, exc_tb)
|
||||||
```
|
```
|
||||||
Async context manager exit point. Closes the connection to the MetaTrader terminal.
|
Async context manager exit point. Closes the connection to the MetaTrader terminal.
|
||||||
|
|
||||||
<a id="login"></a>
|
|
||||||
#### login
|
<a id="meta_trader.login"></a>
|
||||||
|
### login
|
||||||
```python
|
```python
|
||||||
async def login(login: int,
|
async def login(*, login: int, password: str, server: str, timeout: int = 60000) -> bool
|
||||||
password: str,
|
|
||||||
server: str,
|
|
||||||
timeout: int = 60000) -> bool
|
|
||||||
```
|
```
|
||||||
Connects to the MetaTrader terminal using the specified login, password and server.
|
Connects to the MetaTrader terminal using the specified login, password and server.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------------|-------|--------------------------------------------|
|
|------------|-------|--------------------------------------------|
|
||||||
| `login` | `int` | The trading account number. |
|
| `login` | `int` | The trading account number. |
|
||||||
| `password` | `str` | The trading account password. |
|
| `password` | `str` | The trading account password. |
|
||||||
| `server` | `str` | The trading server name. |
|
| `server` | `str` | The trading server name. |
|
||||||
| `timeout` | `int` | The timeout for the connection in seconds. |
|
| `timeout` | `int` | The timeout for the connection in seconds. |
|
||||||
|
|
||||||
#### Returns:
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------------|
|
|--------|--------------------------------------|
|
||||||
| `bool` | True if successful, False otherwise. |
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
<a id="initialize"></a>
|
|
||||||
#### initialize
|
<a id="meta_trader.login_sync"></a>
|
||||||
|
#### login_sync
|
||||||
```python
|
```python
|
||||||
async def initialize(path: str = "",
|
async def login_sync(*, login: int, password: str, server: str, timeout: int = 60000) -> bool
|
||||||
login: int = 0,
|
|
||||||
password: str = "",
|
|
||||||
server: str = "",
|
|
||||||
timeout: int | None = None,
|
|
||||||
portable=False) -> bool
|
|
||||||
```
|
```
|
||||||
Initializes the connection to the MetaTrader terminal. All parameters are optional.
|
A synchronous version of the login method.
|
||||||
#### Parameters
|
Connects to the MetaTrader terminal using the specified login, password and server.
|
||||||
| Name | Type | Description |
|
|
||||||
|------------|-----------------|----------------------------------------------------------|
|
#### Parameters:
|
||||||
| `path` | `str` | The path to the MetaTrader terminal executable. |
|
| Name | Type | Description |
|
||||||
| `login` | `int` | The trading account number. |
|
|------------|-------|--------------------------------------------|
|
||||||
| `password` | `str` | The trading account password. |
|
| `login` | `int` | The trading account number. |
|
||||||
| `server` | `str` | The trading server name. |
|
| `password` | `str` | The trading account password. |
|
||||||
| `timeout` | `int` or `None` | The timeout for the connection in seconds. |
|
| `server` | `str` | The trading server name. |
|
||||||
| `portable` | `bool` | If True, the terminal will be launched in portable mode. |
|
| `timeout` | `int` | The timeout for the connection in seconds. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------------|
|
|--------|--------------------------------------|
|
||||||
| `bool` | True if successful, False otherwise. |
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
<a id="shutdown"></a>
|
|
||||||
#### shutdown
|
<a id="meta_trader.initialize"></a>
|
||||||
|
### initialize
|
||||||
|
```python
|
||||||
|
async def initialize(path: str = "", login: int = 0, password: str = "", server: str = "",
|
||||||
|
timeout: int | None = None, portable=False) -> bool
|
||||||
|
```
|
||||||
|
Initializes the connection to the MetaTrader terminal. All parameters are optional.
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------------|---------------|----------------------------------------------------------|
|
||||||
|
| `path` | `str` | The path to the MetaTrader terminal executable. |
|
||||||
|
| `login` | `int` | The trading account number. |
|
||||||
|
| `password` | `str` | The trading account password. |
|
||||||
|
| `server` | `str` | The trading server name. |
|
||||||
|
| `timeout` | `int \| None` | The timeout for the connection in seconds. |
|
||||||
|
| `portable` | `bool` | If True, the terminal will be launched in portable mode. |
|
||||||
|
|
||||||
|
#### Returns:
|
||||||
|
| Type | Description |
|
||||||
|
|--------|--------------------------------------|
|
||||||
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="meta_trader.initialize_sync"></a>
|
||||||
|
### initialize_sync
|
||||||
|
```python
|
||||||
|
async def initialize_sync(path: str = "", login: int = 0, password: str = "", server: str = "",
|
||||||
|
timeout: int | None = None, portable=False) -> bool
|
||||||
|
```
|
||||||
|
Initializes the connection to the MetaTrader terminal. All parameters are optional.
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------------|---------------|----------------------------------------------------------|
|
||||||
|
| `path` | `str` | The path to the MetaTrader terminal executable. |
|
||||||
|
| `login` | `int` | The trading account number. |
|
||||||
|
| `password` | `str` | The trading account password. |
|
||||||
|
| `server` | `str` | The trading server name. |
|
||||||
|
| `timeout` | `int \| None` | The timeout for the connection in seconds. |
|
||||||
|
| `portable` | `bool` | If True, the terminal will be launched in portable mode. |
|
||||||
|
|
||||||
|
#### Returns:
|
||||||
|
| Type | Description |
|
||||||
|
|--------|--------------------------------------|
|
||||||
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="meta_trader.shutdown"></a>
|
||||||
|
### shutdown
|
||||||
```python
|
```python
|
||||||
async def shutdown() -> None
|
async def shutdown() -> None
|
||||||
```
|
```
|
||||||
Closes the connection to the MetaTrader terminal.
|
Closes the connection to the MetaTrader terminal.
|
||||||
|
|
||||||
<a id="version"></a>
|
|
||||||
#### version
|
<a id="meta_trader.version"></a>
|
||||||
|
### version
|
||||||
```python
|
```python
|
||||||
async def version() -> tuple[int, int, str] | None
|
async def version() -> tuple[int, int, str] | None
|
||||||
```
|
```
|
||||||
Returns the version of the MetaTrader terminal.
|
Returns the version of the MetaTrader terminal.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|------------------------|-----------------------------------------------------------------------------------------------|
|
|------------------------|-----------------------------------------------------------------------------------------------|
|
||||||
| `tuple[int, int, str]` | A tuple of the MetaTrader terminal version. `Terminal Version`, `Build`, `Build Release Date` |
|
| `tuple[int, int, str]` | A tuple of the MetaTrader terminal version. `Terminal Version`, `Build`, `Build Release Date` |
|
||||||
|
|
||||||
<a id="account_info"></a>
|
|
||||||
#### account\_info
|
<a id="meta_trader.account_info"></a>
|
||||||
|
### account_info
|
||||||
```python
|
```python
|
||||||
async def account_info() -> AccountInfo | None
|
async def account_info() -> AccountInfo | None
|
||||||
```
|
```
|
||||||
Returns the account information for the connected account.
|
Returns the account information for the connected account.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|---------------|--------------------------------------|
|
|---------------|--------------------------------------|
|
||||||
| `AccountInfo` | An instance of the AccountInfo class |
|
| `AccountInfo` | An instance of the AccountInfo class |
|
||||||
|
|
||||||
<a id="terminal_info"></a>
|
|
||||||
#### terminal\_info
|
<a id="meta_trader.terminal_info"></a>
|
||||||
|
### terminal_info
|
||||||
```python
|
```python
|
||||||
async def terminal_info() -> TerminalInfo | None
|
async def terminal_info() -> TerminalInfo | None
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns the terminal information for the connected terminal.
|
Returns the terminal information for the connected terminal.
|
||||||
#### Returns
|
### Returns
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|----------------|------------------------------------------------|
|
|----------------|------------------------------------------------|
|
||||||
| `TerminalInfo` | An instance of the TerminalInfo class. A tuple |
|
| `TerminalInfo` | An instance of the TerminalInfo class. A tuple |
|
||||||
|
|
||||||
<a id="last_error"></a>
|
|
||||||
#### last\_error
|
<a id="meta_trader.last_error"></a>
|
||||||
|
### last_error
|
||||||
```python
|
```python
|
||||||
async def last_error() -> tuple[int, str]
|
async def last_error() -> tuple[int, str]
|
||||||
```
|
```
|
||||||
Returns the last error code and description.
|
Returns the last error code and description.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------------------|-------------------------------------------------|
|
|-------------------|-------------------------------------------------|
|
||||||
| `tuple[int, str]` | A tuple of the last error code and description. |
|
| `tuple[int, str]` | A tuple of the last error code and description. |
|
||||||
|
|
||||||
<a id="symbols_total"></a>
|
|
||||||
#### symbols\_total
|
<a id="meta_trader.symbols_total"></a>
|
||||||
|
### symbols_total
|
||||||
```python
|
```python
|
||||||
async def symbols_total() -> int
|
async def symbols_total() -> int
|
||||||
```
|
```
|
||||||
Returns the total number of symbols.
|
Returns the total number of symbols.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------|------------------------------|
|
|-------|------------------------------|
|
||||||
| `int` | The total number of symbols. |
|
| `int` | The total number of symbols. |
|
||||||
|
|
||||||
<a id="symbols_get"></a>
|
|
||||||
#### symbols\_get
|
<a id="meta_trader.symbols_get"></a>
|
||||||
|
### symbols_get
|
||||||
```python
|
```python
|
||||||
async def symbols_get(group: str = "") -> tuple[SymbolInfo] | None
|
async def symbols_get(group: str = "") -> tuple[SymbolInfo] | None
|
||||||
```
|
```
|
||||||
Returns the symbol information for all symbols or for a specified group.
|
Returns the symbol information for all symbols or for a specified group.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|---------|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `group` | `str` | The group name. Optional named parameter. If the group is specified, the function returns only symbols meeting a specified criteria for a symbol name. |
|
| `group` | `str` | The group name. Optional named parameter. If the group is specified, the function returns only symbols meeting a specified criteria for a symbol name. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|---------------------|--------------------------------|
|
|---------------------|--------------------------------|
|
||||||
| `tuple[SymbolInfo]` | A tuple of SymbolInfo objects. |
|
| `tuple[SymbolInfo]` | A tuple of SymbolInfo objects. |
|
||||||
|
|
||||||
|
|
||||||
<a id="symbol_info"></a>
|
<a id="meta_trader.symbol_info"></a>
|
||||||
#### symbol\_info
|
### symbol_info
|
||||||
```python
|
```python
|
||||||
async def symbol_info(symbol: str) -> SymbolInfo | None
|
async def symbol_info(symbol: str) -> SymbolInfo | None
|
||||||
```
|
```
|
||||||
Returns the symbol information for the specified symbol.
|
Returns the symbol information for the specified symbol.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|------------------|
|
|----------|-------|------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
|
|
||||||
#### Returns:
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------------|--------------------------------------|
|
|--------------|--------------------------------------|
|
||||||
| `SymbolInfo` | An instance of the SymbolInfo class. |
|
| `SymbolInfo` | An instance of the SymbolInfo class. |
|
||||||
|
|
||||||
<a id="symbol_info_tick"></a>
|
|
||||||
#### symbol\_info\_tick
|
<a id="meta_trader.symbol_info_tick"></a>
|
||||||
|
### symbol_info_tick
|
||||||
```python
|
```python
|
||||||
async def symbol_info_tick(symbol: str) -> Tick | None
|
async def symbol_info_tick(symbol: str) -> Tick | None
|
||||||
```
|
```
|
||||||
Returns the latest tick for the specified symbol.
|
Returns the latest tick for the specified symbol.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|------------------|
|
|----------|-------|------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------|
|
|--------|--------------------------------|
|
||||||
| `Tick` | An instance of the Tick class. |
|
| `Tick` | An instance of the Tick class. |
|
||||||
|
|
||||||
<a id="symbol_select"></a>
|
|
||||||
#### symbol\_select
|
<a id="meta_trader.symbol_select"></a>
|
||||||
|
### symbol_select
|
||||||
```python
|
```python
|
||||||
async def symbol_select(symbol: str, enable: bool) -> bool
|
async def symbol_select(symbol: str, enable: bool) -> bool
|
||||||
```
|
```
|
||||||
Selects or unselects the specified symbol in the Market Watch window.
|
Selects or unselects the specified symbol in the Market Watch window.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|--------|--------------------------------------------------------------------------------|
|
|----------|--------|--------------------------------------------------------------------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `enable` | `bool` | If True, the symbol will be selected. If False, the symbol will be unselected. |
|
| `enable` | `bool` | If True, the symbol will be selected. If False, the symbol will be unselected. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------------|
|
|--------|--------------------------------------|
|
||||||
| `bool` | True if successful, False otherwise. |
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
<a id="market_book_add"></a>
|
|
||||||
#### market\_book\_add
|
<a id="meta_trader.market_book_add"></a>
|
||||||
|
### market_book_add
|
||||||
```python
|
```python
|
||||||
async def market_book_add(symbol: str) -> bool
|
async def market_book_add(symbol: str) -> bool
|
||||||
```
|
```
|
||||||
Adds the specified symbol to the market book.
|
Adds the specified symbol to the market book.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|------------------|
|
|----------|-------|------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------------|
|
|--------|--------------------------------------|
|
||||||
| `bool` | True if successful, False otherwise. |
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
|
|
||||||
<a id="market_book_get"></a>
|
<a id="meta_trader.market_book_get"></a>
|
||||||
#### market\_book\_get
|
### market_book_get
|
||||||
```python
|
```python
|
||||||
async def market_book_get(symbol: str) -> tuple[BookInfo] | None
|
async def market_book_get(symbol: str) -> tuple[BookInfo] | None
|
||||||
```
|
```
|
||||||
Returns the market depth for the specified symbol.
|
Returns the market depth for the specified symbol.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|------------------|
|
|----------|-------|------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------------------|------------------------------|
|
|-------------------|------------------------------|
|
||||||
| `tuple[BookInfo]` | A tuple of BookInfo objects. |
|
| `tuple[BookInfo]` | A tuple of BookInfo objects. |
|
||||||
|
|
||||||
<a id="market_book_release"></a>
|
|
||||||
#### market\_book\_release
|
<a id="meta_trader.market_book_release"></a>
|
||||||
|
### market_book_release
|
||||||
```python
|
```python
|
||||||
async def market_book_release(symbol: str) -> bool
|
async def market_book_release(symbol: str) -> bool
|
||||||
```
|
```
|
||||||
Removes the specified symbol from the market book.
|
Removes the specified symbol from the market book.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|------------------|
|
|----------|-------|------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------|--------------------------------------|
|
|--------|--------------------------------------|
|
||||||
| `bool` | True if successful, False otherwise. |
|
| `bool` | True if successful, False otherwise. |
|
||||||
|
|
||||||
<a id="copy_rates_from"></a>
|
|
||||||
#### copy\_rates\_from
|
|
||||||
|
|
||||||
|
<a id="meta_trader.copy_rates_from"></a>
|
||||||
|
### copy_rates_from
|
||||||
```python
|
```python
|
||||||
import numpy
|
async def copy_rates_from(symbol: str, timeframe: TimeFrame, date_from: datetime | int,
|
||||||
|
|
||||||
|
|
||||||
async def copy_rates_from(symbol: str,
|
|
||||||
timeframe: TimeFrame,
|
|
||||||
date_from: datetime | int,
|
|
||||||
count: int) -> numpy.ndarray | None
|
count: int) -> numpy.ndarray | None
|
||||||
```
|
```
|
||||||
Returns the OHLCV rates for the specified symbol and timeframe starting from the specified date.
|
Returns the OHLCV rates for the specified symbol and timeframe starting from the specified date.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|--------------------------------|
|
|-------------|---------------------|--------------------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `timeframe` | `TimeFrame` | The timeframe. |
|
| `timeframe` | `TimeFrame` | The timeframe. |
|
||||||
| `date_from` | `datetime` or `int` | The date to start from. |
|
| `date_from` | `datetime` or `int` | The date to start from. |
|
||||||
| `count` | `int` | The number of rates to return. |
|
| `count` | `int` | The number of rates to return. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-----------------|-------------------------------|
|
|-----------------|-------------------------------|
|
||||||
| `numpy.ndarray` | A numpy array of OHLCV rates. |
|
| `numpy.ndarray` | A numpy array of OHLCV rates. |
|
||||||
|
|
||||||
<a id="copy_rates_from_pos"></a>
|
|
||||||
#### copy\_rates\_from\_pos
|
<a id="meta_trader.copy_rates_from_pos"></a>
|
||||||
|
### copy_rates_from_pos
|
||||||
```python
|
```python
|
||||||
async def copy_rates_from_pos(symbol: str,
|
async def copy_rates_from_pos(symbol: str, timeframe: TimeFrame, start_pos: int, count: int) -> numpy.ndarray | None
|
||||||
timeframe: TimeFrame,
|
|
||||||
start_pos: int,
|
|
||||||
count: int) -> numpy.ndarray | None
|
|
||||||
```
|
```
|
||||||
Returns the OHLCV rates for the specified symbol and timeframe starting from the specified position.
|
Returns the OHLCV rates for the specified symbol and timeframe starting from the specified position.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|-------------|--------------------------------|
|
|-------------|-------------|--------------------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `timeframe` | `TimeFrame` | The timeframe. |
|
| `timeframe` | `TimeFrame` | The timeframe. |
|
||||||
| `start_pos` | `int` | The position to start from. |
|
| `start_pos` | `int` | The position to start from. |
|
||||||
| `count` | `int` | The number of rates to return. |
|
| `count` | `int` | The number of rates to return. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-----------------|-------------------------------|
|
|-----------------|-------------------------------|
|
||||||
| `numpy.ndarray` | A numpy array of OHLCV rates. |
|
| `numpy.ndarray` | A numpy array of OHLCV rates. |
|
||||||
|
|
||||||
<a id="copy_rates_range"></a>
|
|
||||||
#### copy\_rates\_range
|
<a id="meta_trader.copy_rates_range"></a>
|
||||||
|
### copy_rates_range
|
||||||
```python
|
```python
|
||||||
async def copy_rates_range(symbol: str,
|
async def copy_rates_range(symbol: str, timeframe: TimeFrame, date_from: datetime | int,
|
||||||
timeframe: TimeFrame,
|
|
||||||
date_from: datetime | int,
|
|
||||||
date_to: datetime | int) -> numpy.ndarray | None
|
date_to: datetime | int) -> numpy.ndarray | None
|
||||||
```
|
```
|
||||||
Returns the OHLCV rates for the specified symbol and timeframe between the specified dates.
|
Returns the OHLCV rates for the specified symbol and timeframe between the specified dates.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|------------------|
|
|-------------|---------------------|------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `timeframe` | `TimeFrame` | The timeframe. |
|
| `timeframe` | `TimeFrame` | The timeframe. |
|
||||||
| `date_from` | `datetime` or `int` | The start date. |
|
| `date_from` | `datetime` or `int` | The start date. |
|
||||||
| `date_to` | `datetime` or `int` | The end date. |
|
| `date_to` | `datetime` or `int` | The end date. |
|
||||||
|
|
||||||
#### Returns:
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-----------------|-------------------------------|
|
|-----------------|-------------------------------|
|
||||||
| `numpy.ndarray` | A numpy array of OHLCV rates. |
|
| `numpy.ndarray` | A numpy array of OHLCV rates. |
|
||||||
|
|
||||||
<a id="copy_ticks_from"></a>
|
|
||||||
#### copy\_ticks\_from
|
<a id="meta_trader.copy_ticks_from"></a>
|
||||||
|
### copy_ticks_from
|
||||||
```python
|
```python
|
||||||
async def copy_ticks_from(symbol: str,
|
async def copy_ticks_from(symbol: str, date_from: datetime | int, count: int, flags: CopyTicks) -> tuple[Tick] | None
|
||||||
date_from: datetime | int,
|
|
||||||
count: int,
|
|
||||||
flags: CopyTicks) -> tuple[Tick] | None
|
|
||||||
```
|
```
|
||||||
Returns the ticks for the specified symbol starting from the specified date.
|
Returns the ticks for the specified symbol starting from the specified date.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|--------------------------------|
|
|-------------|---------------------|--------------------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `date_from` | `datetime` or `int` | The date to start from. |
|
| `date_from` | `datetime` or `int` | The date to start from. |
|
||||||
| `count` | `int` | The number of ticks to return. |
|
| `count` | `int` | The number of ticks to return. |
|
||||||
| `flags` | `CopyTicks` | The CopyTicks flags. |
|
| `flags` | `CopyTicks` | The CopyTicks flags. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|---------------|--------------------------|
|
|---------------|--------------------------|
|
||||||
| `tuple[Tick]` | A tuple of Tick objects. |
|
| `tuple[Tick]` | A tuple of Tick objects. |
|
||||||
|
|
||||||
<a id="copy_ticks_range"></a>
|
|
||||||
#### copy\_ticks\_range
|
<a id="meta_trader.copy_ticks_range"></a>
|
||||||
|
### copy_ticks_range
|
||||||
```python
|
```python
|
||||||
async def copy_ticks_range(symbol: str,
|
async def copy_ticks_range(symbol: str, date_from: datetime | int, date_to: datetime | int,
|
||||||
date_from: datetime | int,
|
|
||||||
date_to: datetime | int,
|
|
||||||
flags: CopyTicks) -> tuple[Tick] | None
|
flags: CopyTicks) -> tuple[Tick] | None
|
||||||
```
|
```
|
||||||
Returns the ticks for the specified symbol between the specified dates.
|
Returns the ticks for the specified symbol between the specified dates.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|----------------------|
|
|-------------|---------------------|----------------------|
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `date_from` | `datetime` or `int` | The start date. |
|
| `date_from` | `datetime` or `int` | The start date. |
|
||||||
| `date_to` | `datetime` or `int` | The end date. |
|
| `date_to` | `datetime` or `int` | The end date. |
|
||||||
| `flags` | `CopyTicks` | The CopyTicks flags. |
|
| `flags` | `CopyTicks` | The CopyTicks flags. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|---------------|--------------------------|
|
|---------------|--------------------------|
|
||||||
| `tuple[Tick]` | A tuple of Tick objects. |
|
| `tuple[Tick]` | A tuple of Tick objects. |
|
||||||
|
|
||||||
<a id="orders_total"></a>
|
|
||||||
#### orders\_total
|
<a id="meta_trader.orders_total"></a>
|
||||||
|
### orders_total
|
||||||
```python
|
```python
|
||||||
async def orders_total() -> int
|
async def orders_total() -> int
|
||||||
```
|
```
|
||||||
Returns the total number of active orders.
|
Returns the total number of active orders.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------|------------------------------------|
|
|-------|------------------------------------|
|
||||||
| `int` | The total number of active orders. |
|
| `int` | The total number of active orders. |
|
||||||
|
|
||||||
<a id="orders_get"></a>
|
|
||||||
#### orders\_get
|
<a id="meta_trader.orders_get"></a>
|
||||||
|
### orders_get
|
||||||
```python
|
```python
|
||||||
async def orders_get(group: str = "",
|
async def orders_get(group: str = "", ticket: int = 0, symbol: str = "") -> tuple[TradeOrder, ...] | None
|
||||||
ticket: int = 0,
|
|
||||||
symbol: str = "") -> tuple[TradeOrder] | None
|
|
||||||
```
|
```
|
||||||
Get active orders with the ability to filter by symbol or ticket. There are three call options.
|
Get active orders with the ability to filter by symbol or ticket. There are three call options.
|
||||||
Call without parameters. Return active orders on all symbols
|
Call without parameters. Return active orders on all symbols
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|----------|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only active orders meeting a specified criteria for a symbol name. |
|
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only active orders meeting a specified criteria for a symbol name. |
|
||||||
| `ticket` | `int` | Order ticket (ORDER_TICKET). Optional named parameter. |
|
| `ticket` | `int` | Order ticket (ORDER_TICKET). Optional named parameter. |
|
||||||
| `symbol` | `str` | Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored. |
|
| `symbol` | `str` | Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored. |
|
||||||
#### Returns
|
|
||||||
| Type | Description |
|
|
||||||
|---------------------|------------------------------------------------------|
|
|
||||||
| `tuple[TradeOrder]` | A tuple of active trade orders as TradeOrder objects |
|
|
||||||
#### Returns
|
|
||||||
| Type | Description |
|
|
||||||
|---------------------|------------------------------------------------------|
|
|
||||||
| `tuple[TradeOrder]` | A tuple of active trade orders as TradeOrder objects |
|
|
||||||
|
|
||||||
<a id="order_calc_margin"></a>
|
#### Returns:
|
||||||
#### order\_calc\_margin
|
| Type | Description |
|
||||||
|
|--------------------------|------------------------------------------------------|
|
||||||
|
| `tuple[TradeOrder, ...]` | A tuple of active trade orders as TradeOrder objects |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="meta_trader.order_calc_margin"></a>
|
||||||
|
### order_calc_margin
|
||||||
```python
|
```python
|
||||||
async def order_calc_margin(action: OrderType,
|
async def order_calc_margin(action: OrderType, symbol: str, volume: float, price: float) -> float | None
|
||||||
symbol: str,
|
|
||||||
volume: float,
|
|
||||||
price: float) -> float | None
|
|
||||||
```
|
```
|
||||||
Calculates the margin required to open a trade.
|
Calculates the margin required to open a trade.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------------|-------------------|
|
|----------|-------------|-------------------|
|
||||||
| `action` | `OrderType` | The order type. |
|
| `action` | `OrderType` | The order type. |
|
||||||
| `symbol` | `str` | The symbol name. |
|
| `symbol` | `str` | The symbol name. |
|
||||||
| `volume` | `float` | The order volume. |
|
| `volume` | `float` | The order volume. |
|
||||||
| `price` | `float` | The order price. |
|
| `price` | `float` | The order price. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|---------|--------------------------------------|
|
|---------|--------------------------------------|
|
||||||
| `float` | The margin required to open a trade. |
|
| `float` | The margin required to open a trade. |
|
||||||
|
|
||||||
<a id="order_calc_profit"></a>
|
|
||||||
#### order\_calc\_profit
|
<a id="meta_trader.order_calc_profit"></a>
|
||||||
|
### order_calc_profit
|
||||||
```python
|
```python
|
||||||
async def order_calc_profit(action: OrderType,
|
async def order_calc_profit(action: OrderType, symbol: str, volume: float, price_open: float,
|
||||||
symbol: str,
|
|
||||||
volume: float,
|
|
||||||
price_open: float,
|
|
||||||
price_close: float) -> float | None
|
price_close: float) -> float | None
|
||||||
```
|
```
|
||||||
Calculates the profit for a closed trade.
|
Calculates the profit for a closed trade.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|---------------|-------------|------------------------|
|
|---------------|-------------|------------------------|
|
||||||
| `action` | `OrderType` | The order type. |
|
| `action` | `OrderType` | The order type. |
|
||||||
@@ -474,103 +550,112 @@ Calculates the profit for a closed trade.
|
|||||||
| `volume` | `float` | The order volume. |
|
| `volume` | `float` | The order volume. |
|
||||||
| `price_open` | `float` | The order open price. |
|
| `price_open` | `float` | The order open price. |
|
||||||
| `price_close` | `float` | The order close price. |
|
| `price_close` | `float` | The order close price. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|---------|--------------------------------|
|
|---------|--------------------------------|
|
||||||
| `float` | The profit for a closed trade. |
|
| `float` | The profit for a closed trade. |
|
||||||
|
|
||||||
<a id="order_check"></a>
|
|
||||||
#### order\_check
|
<a id="meta_trader.order_check"></a>
|
||||||
|
### order_check
|
||||||
```python
|
```python
|
||||||
async def order_check(request: dict) -> OrderCheckResult
|
async def order_check(request: dict) -> OrderCheckResult
|
||||||
```
|
```
|
||||||
Checks the specified order for validity.
|
Checks the specified order for validity.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-----------|--------|--------------------|
|
|-----------|--------|--------------------|
|
||||||
| `request` | `dict` | The order request. |
|
| `request` | `dict` | The order request. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------------------|--------------------------------------------|
|
|--------------------|--------------------------------------------|
|
||||||
| `OrderCheckResult` | An instance of the OrderCheckResult class. |
|
| `OrderCheckResult` | An instance of the OrderCheckResult class. |
|
||||||
|
|
||||||
<a id="order_send"></a>
|
|
||||||
#### order\_send
|
<a id="meta_trader.order_send"></a>
|
||||||
|
### order_send
|
||||||
```python
|
```python
|
||||||
async def order_send(request: dict) -> OrderSendResult
|
async def order_send(request: dict) -> OrderSendResult
|
||||||
```
|
```
|
||||||
Sends the specified order request to the MetaTrader terminal.
|
Sends the specified order request to the MetaTrader terminal.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-----------|--------|--------------------|
|
|-----------|--------|--------------------|
|
||||||
| `request` | `dict` | The order request. |
|
| `request` | `dict` | The order request. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------------------|-------------------------------------------|
|
|-------------------|-------------------------------------------|
|
||||||
| `OrderSendResult` | An instance of the OrderSendResult class. |
|
| `OrderSendResult` | An instance of the OrderSendResult class. |
|
||||||
|
|
||||||
<a id="positions_total"></a>
|
|
||||||
#### positions\_total
|
<a id="meta_trader.positions_total"></a>
|
||||||
|
### positions_total
|
||||||
```python
|
```python
|
||||||
async def positions_total() -> int
|
async def positions_total() -> int
|
||||||
```
|
```
|
||||||
Returns the total number of open positions.
|
Returns the total number of open positions.
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------|-------------------------------------|
|
|-------|-------------------------------------|
|
||||||
| `int` | The total number of open positions. |
|
| `int` | The total number of open positions. |
|
||||||
|
|
||||||
|
|
||||||
<a id="positions_get"></a>
|
<a id="meta_trader.positions_get"></a>
|
||||||
#### positions\_get
|
### positions_get
|
||||||
```python
|
```python
|
||||||
async def positions_get(group: str = "",
|
async def positions_get(group: str = "", ticket: int = 0, symbol: str = "") -> tuple[TradePosition, ...] | None
|
||||||
ticket: int = 0,
|
|
||||||
symbol: str = "") -> tuple[TradePosition] | None
|
|
||||||
```
|
```
|
||||||
Returns the open positions with the ability to filter by symbol or ticket. There are three call options.
|
Returns the open positions with the ability to filter by symbol or ticket. There are three call options.
|
||||||
Call without parameters. Return open positions on all symbols
|
Call without parameters. Return open positions on all symbols
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|-------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|----------|-------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only open positions meeting a specified criteria for a symbol name. |
|
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only open positions meeting a specified criteria for a symbol name. |
|
||||||
| `ticket` | `int` | Position ticket (POSITION_TICKET). Optional named parameter. |
|
| `ticket` | `int` | Position ticket (POSITION_TICKET). Optional named parameter. |
|
||||||
| `symbol` | `str` | Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored. |
|
| `symbol` | `str` | Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored. |
|
||||||
#### Returns
|
|
||||||
| Type | Description |
|
|
||||||
|------------------------|----------------------------------------------------------|
|
|
||||||
| `tuple[TradePosition]` | A tuple of open trade positions as TradePosition objects |
|
|
||||||
|
|
||||||
<a id="history_orders_total"></a>
|
#### Returns:
|
||||||
#### history\_orders\_total
|
| Type | Description |
|
||||||
|
|-----------------------------|----------------------------------------------------------|
|
||||||
|
| `tuple[TradePosition, ...]` | A tuple of open trade positions as TradePosition objects |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="meta_trader.history_orders_total"></a>
|
||||||
|
### history_orders_total
|
||||||
```python
|
```python
|
||||||
async def history_orders_total(date_from: datetime | int,
|
async def history_orders_total(date_from: datetime | int, date_to: datetime | int) -> int
|
||||||
date_to: datetime | int) -> int
|
|
||||||
```
|
```
|
||||||
Returns the total number of closed orders for the specified period.
|
Returns the total number of closed orders for the specified period.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|-----------------|
|
|-------------|---------------------|-----------------|
|
||||||
| `date_from` | `datetime` or `int` | The start date. |
|
| `date_from` | `datetime` or `int` | The start date. |
|
||||||
| `date_to` | `datetime` or `int` | The end date. |
|
| `date_to` | `datetime` or `int` | The end date. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------|-------------------------------------------------------------|
|
|-------|-------------------------------------------------------------|
|
||||||
| `int` | The total number of closed orders for the specified period. |
|
| `int` | The total number of closed orders for the specified period. |
|
||||||
|
|
||||||
|
|
||||||
<a id="history_orders_get"></a>
|
<a id="meta_trader.history_orders_get"></a>
|
||||||
#### history\_orders\_get
|
### history_orders_get
|
||||||
```python
|
```python
|
||||||
async def history_orders_get(date_from: datetime | int = None,
|
async def history_orders_get(date_from: datetime | int = None, date_to: datetime | int = None, group: str = "",
|
||||||
date_to: datetime | int = None,
|
ticket: int = 0, position: int = 0) -> tuple[TradeOrder, ...] | None
|
||||||
group: str = "",
|
|
||||||
ticket: int = 0,
|
|
||||||
position: int = 0) -> tuple[TradeOrder] | None
|
|
||||||
```
|
```
|
||||||
Returns the closed orders for the specified period with the ability to filter by symbol or ticket. There are three call options.
|
Returns the closed orders for the specified period with the ability to filter by symbol or ticket. There are three call options.
|
||||||
Call without parameters. Return closed orders on all symbols
|
Call without parameters. Return closed orders on all symbols
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `date_from` | `datetime` or `int` | The start date. Optional named parameter. |
|
| `date_from` | `datetime` or `int` | The start date. Optional named parameter. |
|
||||||
@@ -578,40 +663,41 @@ Call without parameters. Return closed orders on all symbols
|
|||||||
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only closed orders meeting a specified criteria for a symbol name. |
|
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only closed orders meeting a specified criteria for a symbol name. |
|
||||||
| `ticket` | `int` | Order ticket (ORDER_TICKET). Optional named parameter. |
|
| `ticket` | `int` | Order ticket (ORDER_TICKET). Optional named parameter. |
|
||||||
| `position` | `int` | Position ticket (POSITION_TICKET). Optional named parameter. |
|
| `position` | `int` | Position ticket (POSITION_TICKET). Optional named parameter. |
|
||||||
#### Returns
|
|
||||||
| Type | Description |
|
|
||||||
|---------------------|------------------------------------------------------|
|
|
||||||
| `tuple[TradeOrder]` | A tuple of closed trade orders as TradeOrder objects |
|
|
||||||
|
|
||||||
<a id="history_deals_total"></a>
|
#### Returns:
|
||||||
#### history\_deals\_total
|
| Type | Description |
|
||||||
|
|--------------------------|------------------------------------------------------|
|
||||||
|
| `tuple[TradeOrder, ...]` | A tuple of closed trade orders as TradeOrder objects |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="meta_trader.history_deals_total"></a>
|
||||||
|
### history_deals_total
|
||||||
```python
|
```python
|
||||||
async def history_deals_total(date_from: datetime | int,
|
async def history_deals_total(date_from: datetime | int, date_to: datetime | int) -> int
|
||||||
date_to: datetime | int) -> int
|
|
||||||
```
|
```
|
||||||
Returns the total number of closed deals for the specified period.
|
Returns the total number of closed deals for the specified period.
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|-----------------|
|
|-------------|---------------------|-----------------|
|
||||||
| `date_from` | `datetime` or `int` | The start date. |
|
| `date_from` | `datetime` or `int` | The start date. |
|
||||||
| `date_to` | `datetime` or `int` | The end date. |
|
| `date_to` | `datetime` or `int` | The end date. |
|
||||||
#### Returns
|
|
||||||
|
#### Returns:
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|-------|------------------------------------------------------------|
|
|-------|------------------------------------------------------------|
|
||||||
| `int` | The total number of closed deals for the specified period. |
|
| `int` | The total number of closed deals for the specified period. |
|
||||||
|
|
||||||
<a id="history_deals_get"></a>
|
<a id="meta_trader.history_deals_get"></a>
|
||||||
#### history\_deals\_get
|
### history_deals_get
|
||||||
```python
|
```python
|
||||||
async def history_deals_get(date_from: datetime | int = None,
|
async def history_deals_get(date_from: datetime | int = None, date_to: datetime | int = None, group: str = "",
|
||||||
date_to: datetime | int = None,
|
ticket: int = 0,position: int = 0) -> tuple[TradeDeal, ...] | None
|
||||||
group: str = "",
|
|
||||||
ticket: int = 0,
|
|
||||||
position: int = 0) -> tuple[TradeDeal] | None
|
|
||||||
```
|
```
|
||||||
Returns the closed deals for the specified period with the ability to filter by symbol or ticket. There are three call options.
|
Returns the closed deals for the specified period with the ability to filter by symbol or ticket. There are three call options.
|
||||||
Call without parameters. Return closed deals on all symbols
|
Call without parameters. Return closed deals on all symbols
|
||||||
#### Parameters
|
|
||||||
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|-------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `date_from` | `datetime` or `int` | The start date. Optional named parameter. |
|
| `date_from` | `datetime` or `int` | The start date. Optional named parameter. |
|
||||||
@@ -619,7 +705,8 @@ Call without parameters. Return closed deals on all symbols
|
|||||||
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only closed deals meeting a specified criteria for a symbol name. |
|
| `group` | `str` | The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only closed deals meeting a specified criteria for a symbol name. |
|
||||||
| `ticket` | `int` | Order ticket (ORDER_TICKET). Optional named parameter. |
|
| `ticket` | `int` | Order ticket (ORDER_TICKET). Optional named parameter. |
|
||||||
| `position` | `int` | Position ticket (POSITION_TICKET). Optional named parameter. |
|
| `position` | `int` | Position ticket (POSITION_TICKET). Optional named parameter. |
|
||||||
#### Returns
|
|
||||||
| Type | Description |
|
#### Returns:
|
||||||
|--------------------|----------------------------------------------------|
|
| Type | Description |
|
||||||
| `tuple[TradeDeal]` | A tuple of closed trade deals as TradeDeal objects |
|
|-------------------------|----------------------------------------------------|
|
||||||
|
| `tuple[TradeDeal, ...]` | A tuple of closed trade deals as TradeDeal objects |
|
||||||
|
|||||||
+122
-32
@@ -1,69 +1,126 @@
|
|||||||
# TaskQueue and QueueItem
|
# TaskQueue and QueueItem
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [QueueItem](#queue_item)
|
- [QueueItem](#queue_item.queue_item)
|
||||||
- [run](#run)
|
- [\__init\__](#queue_item.__init__)
|
||||||
|
- [run](#queue_item.run)
|
||||||
|
|
||||||
- [TaskQueue](#task_queue)
|
- [TaskQueue](#task_queue.task_queue)
|
||||||
- [TaskQueue.add](#task_queue.add)
|
- [\__init\__](#task_queue.__init__)
|
||||||
- [TaskQueue.add_task](#task_queue.add_task)
|
- [add](#task_queue.add)
|
||||||
- [TaskQueue.worker](#task_queue.worker)
|
- [add_task](#task_queue.add_task)
|
||||||
- [TaskQueue.start](#task_queue.start)
|
- [worker](#task_queue.worker)
|
||||||
|
- [run](#task_queue.run)
|
||||||
|
- [stop_queue](#task_queue.stop_queue)
|
||||||
|
- [clean_up](#task_queue.clean_up)
|
||||||
|
- [cancel](#task_queue.cancel)
|
||||||
|
|
||||||
|
|
||||||
<a id="queue_item"></a>
|
<a id="queue_item.queue_item"></a>
|
||||||
### QueueItem
|
### QueueItem
|
||||||
```python
|
```python
|
||||||
class QueueItem:
|
class QueueItem
|
||||||
def __init__(self, task: Callable | Awaitable, *args, **kwargs):
|
|
||||||
```
|
```
|
||||||
A task to be executed by the `TaskQueue`. The task can be a callable or an awaitable. The task is wrapped as a
|
A task to be executed by the `TaskQueue`. The task can be any coroutine callable. The task is wrapped as a
|
||||||
`QueueItem` object, which is then added to the `TaskQueue` for execution. The arguments and keyword arguments are
|
`QueueItem` object, which is then added to the `TaskQueue` for execution. The arguments and keyword arguments are
|
||||||
passed to the task when it is executed. All parameters are created as attributes of the `QueueItem` object.
|
passed to the task when it is executed.
|
||||||
|
|
||||||
|
#### Attributes:
|
||||||
|
| Name | Type | Description |
|
||||||
|
|-----------------|---------------------------|-----------------------------------------------------------------------|
|
||||||
|
| `task_item` | `Callable` \| `Coroutine` | A coroutine function to be executed by the `TaskQueue` |
|
||||||
|
| `args` | `tuple[Any, ...]` | Positional arguments to be passed to the task_item |
|
||||||
|
| `kwargs` | `dict[str, Any]` | Keyword arguments to be passed to the task_item |
|
||||||
|
| `must_complete` | `bool` | If True, the item must be completed even if the queue is stopped. |
|
||||||
|
| `time` | `float` | The time the item was added to the queue. For sorting priority queues |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="queue_item.__init__"></a>
|
||||||
|
### \__init\__
|
||||||
|
```python
|
||||||
|
def __init__(self, task: Callable | Coroutine, *args, **kwargs):
|
||||||
|
```
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|----------|---------------------------|-------------------------------------------------------------------|
|
|----------|---------------------------|-------------------------------------------------------------------|
|
||||||
| `task` | `Callable` \| `Awaitable` | A callable or awaitable task to be executed by the `TaskQueue` |
|
| `task` | `Callable` \| `Coroutine` | A coroutine to be executed by the `TaskQueue` |
|
||||||
| `args` | `Any` | Positional arguments to be passed to the task when it is executed |
|
| `args` | `Any` | Positional arguments to be passed to the task when it is executed |
|
||||||
| `kwargs` | `Any` | Keyword arguments to be passed to the task when it is executed |
|
| `kwargs` | `Any` | Keyword arguments to be passed to the task when it is executed |
|
||||||
|
|
||||||
<a id="run"></a>
|
|
||||||
|
<a id="queue.run"></a>
|
||||||
### run
|
### run
|
||||||
```python
|
```python
|
||||||
def run(self) -> Any
|
def run(self)
|
||||||
```
|
```
|
||||||
Run the task. If the task is a coroutine, it is awaited. If the task is a callable, it is called.
|
Run the task. If the task is a coroutine, it is awaited. If the task is a callable, it is called.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="task_queue.task_queue"></a>
|
||||||
### TaskQueue
|
### TaskQueue
|
||||||
```python
|
```python
|
||||||
class TaskQueue:
|
class TaskQueue
|
||||||
def __init__(self):
|
|
||||||
```
|
```
|
||||||
|
A perpetual task queue that processes `QueueItem` objects. The `TaskQueue` runs indefinitely, processing `QueueItem`
|
||||||
|
objects as they are added to the queue. The `TaskQueue` is a wrapper around an `asyncio.Queue` that can be passed in as
|
||||||
|
an argument or defaults to an `asyncio.PriorityQueue`. It is added to the bot executor of the `Bot` class on a
|
||||||
|
separate thread.
|
||||||
|
|
||||||
#### Attributes:
|
#### Attributes:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|---------------|-----------------|---------------------------------------------------------------------------------|
|
|------------------|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `queue` | `asyncio.Queue` | An asyncio.Queue queue of `QueueItem` objects to be executed by the `TaskQueue` |
|
| `queue` | `asyncio.Queue` | An `asyncio.Queue` queue of `QueueItem` objects to be executed by the `TaskQueue`. If not provided during instantiation, an `asyncio.PriorityQueue` is used |
|
||||||
|
| `stop` | `bool` | A flag to stop the task_queue instance. |
|
||||||
|
| `workers` | `int` | The number of workers to process the queue items. Defaults to 10. |
|
||||||
|
| `timeout` | `int` | The maximum time to wait for the queue to complete. Default is None. If timeout is provided the queue is joined using `asyncio.wait_for` with the timeout |
|
||||||
|
| `on_exit` | `Literal["cancel", "complete_priority"]` | The action to take when the queue is stopped. If "cancel" the queue is cancelled and the remaining items are not processed. If "complete_priority" the queue is completed with the priority items. Default is "cancel" |
|
||||||
|
| `mode` | `Literal["finite", "infinite"]` | The mode of the queue. If `finite` the queue will stop when all tasks are completed. If `infinite` the queue will continue to run until stopped. |
|
||||||
|
| `worker_timeout` | `int` | The time to wait for a task to be added to the queue before stopping the worker or adding a dummy sleep task to the queue. |
|
||||||
|
| `tasks` | `List[Task]` | A list of the worker tasks running concurrently, including the main task that joins the queue. |
|
||||||
|
| `priority_tasks` | `set[QueueItem]` | A set to store the `QueueItems` that must complete before the queue stops |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="task_queue.__init__"></a>
|
||||||
|
### \__init\__
|
||||||
|
```python
|
||||||
|
def __init__(self, queue: asyncio.Queue = None, workers: int = 10, timeout: int = None, size: int = None,
|
||||||
|
on_exit: Literal["cancel", "complete_priority"] = "cancel",
|
||||||
|
mode: Literal["finite", "infinite"] = "infinite", worker_timeout: int = 60)
|
||||||
|
```
|
||||||
|
Create a new `TaskQueue` instance.
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
| Name | Type | Description | Default |
|
||||||
|
|------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|---------------------|
|
||||||
|
| `queue` | `asyncio.Queue` | An `asyncio.Queue` queue instance | None |
|
||||||
|
| `workers` | `int` | The number of workers to process the queue items. | 10 |
|
||||||
|
| `timeout` | `int` | The maximum time to wait for the queue to complete. | None |
|
||||||
|
| `size` | `int` | The maximum size of the queue. | None |
|
||||||
|
| `on_exit` | `Literal["cancel", "complete_priority"]` | The action to take when the queue is stopped. | "complete_priority" |
|
||||||
|
| `mode` | `Literal["finite", "infinite"]` | The mode of the queue. | "infinite" |
|
||||||
|
| `worker_timeout` | `int` | The time to wait for a task to be added to the queue before stopping the worker or adding a dummy sleep task to the queue. | 60 |
|
||||||
|
|
||||||
|
|
||||||
<a id="task_queue.add"></a>
|
<a id="task_queue.add"></a>
|
||||||
### add
|
### add
|
||||||
```python
|
```python
|
||||||
def add(self, item: QueueItem, *args, **kwargs) -> None
|
def add(*, item: QueueItem, priority: int = 3, must_complete_false: bool = False) -> None
|
||||||
```
|
```
|
||||||
Add a `QueueItem` to the `TaskQueue` queue.
|
Add a `QueueItem` to the `TaskQueue` queue.
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|--------|-------------|----------------------------------------|
|
|-----------------------|-------------|----------------------------------------------------------------------------------------|
|
||||||
| `item` | `QueueItem` | A `QueueItem` to be added to the queue |
|
| `item` | `QueueItem` | A `QueueItem` to be added to the queue |
|
||||||
|
| `priority` | `int` | The priority of the item. The lower the number, the higher the priority. Default is 3. |
|
||||||
|
| `must_complete_false` | `bool` | If True, the item must be completed even if the queue is stopped. Default is False. |
|
||||||
|
|
||||||
|
|
||||||
<a id="task_queue.add_task"></a>
|
<a id="task_queue.add_task"></a>
|
||||||
### add_task
|
### add_task
|
||||||
```python
|
```python
|
||||||
def add_task(self, task: Callable | Awaitable, *args, **kwargs) -> None
|
def add_task(self, task: Callable | Awaitable, *args, **kwargs)
|
||||||
```
|
```
|
||||||
Create a QueueItem from the task and add it to the `TaskQueue` queue. The task can be a callable or an awaitable.
|
Create a QueueItem from the task and add it to the `TaskQueue` queue. The task can be a callable or an awaitable.
|
||||||
The arguments and keyword arguments are passed to the QueueItem.
|
The arguments and keyword arguments are passed to the QueueItem.
|
||||||
@@ -78,14 +135,47 @@ The arguments and keyword arguments are passed to the QueueItem.
|
|||||||
<a id="task_queue.worker"></a>
|
<a id="task_queue.worker"></a>
|
||||||
### worker
|
### worker
|
||||||
```python
|
```python
|
||||||
async def worker(self) -> None
|
async def worker()
|
||||||
```
|
```
|
||||||
A worker that processes the `QueueItem` objects in the `TaskQueue` queue. The worker runs indefinitely, processing
|
A worker that processes the `QueueItem` objects in the `TaskQueue` queue.
|
||||||
`QueueItem` objects as they are added to the queue.
|
|
||||||
|
|
||||||
<a id="task_queue.start"></a>
|
|
||||||
### start
|
<a id="task_queue.run"></a>
|
||||||
|
### run
|
||||||
```python
|
```python
|
||||||
def start(self) -> None
|
async def run(timeout: int = None)
|
||||||
```
|
```
|
||||||
Start the worker that processes the `QueueItem` objects in the `TaskQueue` queue.
|
Start the `TaskQueue` instance. If a timeout is provided, the queue is joined using `asyncio.wait_for` with the timeout.
|
||||||
|
This is the main entry point for the `TaskQueue` instance. It is added to the bot executor of the `Bot` class on a
|
||||||
|
separate thread.
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
| Name | Type | Description |
|
||||||
|
|-----------|-------|----------------------------------------------------------------------|
|
||||||
|
| `timeout` | `int` | The maximum time to wait for the queue to complete. Default is None. |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="task_queue.stop_queue"></a>
|
||||||
|
### stop_queue
|
||||||
|
```python
|
||||||
|
def stop_queue()
|
||||||
|
```
|
||||||
|
Stop the `TaskQueue` instance. This sets the `stop` attribute to True, changes the `on_exit` attribute to "cancel",
|
||||||
|
and cancels the queue.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="task_queue.clean_up"></a>
|
||||||
|
### clean_up
|
||||||
|
```python
|
||||||
|
async def clean_up()
|
||||||
|
```
|
||||||
|
Clean up the `TaskQueue` instance. This is called when the queue is stopped. It cancels the queue and processes the
|
||||||
|
remaining priority items based on the `on_exit` attribute.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="task_queue.cancel"></a>
|
||||||
|
### cancel
|
||||||
|
```python
|
||||||
|
def cancel()
|
||||||
|
```
|
||||||
|
Cancel all remaining tasks.
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "aiomql"
|
name = "aiomql"
|
||||||
version = "3.23"
|
version = "4.0.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
@@ -16,7 +16,7 @@ classifiers = [
|
|||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
]
|
]
|
||||||
keywords = ['MetaTrader5', 'Asynchronous', 'Algorithmic Trading', 'Trading Bot']
|
keywords = ['MetaTrader5', 'Asynchronous', 'Algorithmic Trading', 'Trading Bot']
|
||||||
dependencies = ["MetaTrader5>=5.0.37", "pandas>=1.5.0", "pandas-ta>=0.3.14b0", "matplotlib>=3.8.4", "mplfinance>=0.12.10b0"]
|
dependencies = ["MetaTrader5>=5.0.37", "pandas>=1.5.0", "pandas-ta>=0.3.14b0"]
|
||||||
authors = [{name = "Ichinga Samuel", email = "ichingasamuel@gmail.com"}]
|
authors = [{name = "Ichinga Samuel", email = "ichingasamuel@gmail.com"}]
|
||||||
description = "Asynchronous MetaTrader5 library and Algorithmic Trading Framework"
|
description = "Asynchronous MetaTrader5 library and Algorithmic Trading Framework"
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ from ...lib.candle import Candle, Candles
|
|||||||
|
|
||||||
|
|
||||||
def find_bearish_fractal(candles: Candles) -> Candle | None:
|
def find_bearish_fractal(candles: Candles) -> Candle | None:
|
||||||
|
"""Given a candles object, find the most recent bearish fractal."""
|
||||||
for i in range(len(candles) - 3, 1, -1):
|
for i in range(len(candles) - 3, 1, -1):
|
||||||
if candles[i].high > max(candles[i - 1].high, candles[i + 1].high, candles[i - 2].high, candles[i + 2].high):
|
if candles[i].high > max(candles[i - 1].high, candles[i + 1].high, candles[i - 2].high, candles[i + 2].high):
|
||||||
return candles[i]
|
return candles[i]
|
||||||
|
|
||||||
|
|
||||||
def find_bullish_fractal(candles: Candles) -> Candle | None:
|
def find_bullish_fractal(candles: Candles) -> Candle | None:
|
||||||
|
"""Given a candles object, find the most recent bullish fractal."""
|
||||||
for i in range(len(candles) - 3, 1, -1):
|
for i in range(len(candles) - 3, 1, -1):
|
||||||
if candles[i].low < min(candles[i - 1].low, candles[i + 1].low, candles[i - 2].low, candles[i + 2].low):
|
if candles[i].low < min(candles[i - 1].low, candles[i + 1].low, candles[i - 2].low, candles[i + 2].low):
|
||||||
return candles[i]
|
return candles[i]
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ from .trades_manager import PositionsManager, OrdersManager, DealsManager
|
|||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
class BackTestEngine:
|
class BackTestEngine:
|
||||||
mt5: MetaTrader
|
mt5: MetaTrader
|
||||||
span: range
|
span: range
|
||||||
@@ -77,43 +78,51 @@ class BackTestEngine:
|
|||||||
account_info: dict = None,
|
account_info: dict = None,
|
||||||
):
|
):
|
||||||
"""The BackTestEngine class is used to simulate trading strategies on historical data.
|
"""The BackTestEngine class is used to simulate trading strategies on historical data.
|
||||||
It can accept already saved data or create new data for backtesting on the fly. Ideally only one instance of this class should be created per session.
|
It can accept already saved data or create new data for backtesting on the fly. Ideally only one instance of
|
||||||
By default it is automatically assigned to the global config instance during instantiation,
|
this class should be created per session. By default it is automatically assigned to the global config instance
|
||||||
replacing any existing backtest engine instance. But this is a configurable behaviour.
|
during instantiation, replacing any existing backtest engine instance. But this is a configurable behaviour.
|
||||||
The start and end time can still be specified even when test data is provided. In that case it will be used to set the range of the backtest.
|
The start and end time can still be specified even when test data is provided. In that case it will be used
|
||||||
|
to set the range of the backtest.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data (BackTestData, optional): The data to use for backtesting. Defaults to None.
|
data (BackTestData, optional): The data to use for backtesting. Defaults to None.
|
||||||
|
|
||||||
speed (int, optional): The speed of the backtest. Defaults to 60 seconds.
|
speed (int, optional): The speed of the backtest. Defaults to 60 seconds.
|
||||||
|
|
||||||
start (float | datetime, optional): The start time of the backtest. Defaults to 0. If a float is passed, it is assumed to be a timestamp.
|
start (float | datetime, optional): The start time of the backtest. Defaults to 0. If a float is passed,
|
||||||
|
it is assumed to be a timestamp.
|
||||||
|
|
||||||
end (float | datetime, optional): The end time of the backtest. Defaults to 0. If a float is passed, it is assumed to be a timestamp.
|
end (float | datetime, optional): The end time of the backtest. Defaults to 0. If a float is passed,
|
||||||
|
it is assumed to be a timestamp.
|
||||||
|
|
||||||
restart (bool, optional): Whether to restart the backtest from the beginning. Defaults to True. This is useful when resuming a backtest
|
restart (bool, optional): Whether to restart the backtest from the beginning. Defaults to True.
|
||||||
using a saved BackTestData instance.
|
This is useful when resuming a backtest using a saved BackTestData instance.
|
||||||
|
|
||||||
use_terminal (bool, optional): Whether to use the terminal for backtesting. Defaults to None. If None, it uses the global config setting.
|
use_terminal (bool, optional): Whether to use the terminal for backtesting. Defaults to None. If None,
|
||||||
If use terminal is true, the backtest engine will use the terminal to get price data, compute margins, profit and check order viability.
|
it uses the global config setting. If use terminal is true, the backtest engine will use the terminal to
|
||||||
If false, it will use the data provided in the BackTestData instance and default algorithm for the calculations
|
get price data, compute margins, profit and check order viability. If false, it will use the data
|
||||||
|
provided in the BackTestData instance and default algorithm for the calculations
|
||||||
|
|
||||||
name (str, optional): The name of the backtest. Defaults to "". If not provided, it is generated from the start and end times.
|
name (str, optional): The name of the backtest. Defaults to "". If not provided,
|
||||||
|
it is generated from the start and end times.
|
||||||
|
|
||||||
stop_time (float | datetime, optional): The time to stop the backtest. Defaults to None. If a float is passed, it is assumed to be a timestamp.
|
stop_time (float | datetime, optional): The time to stop the backtest. Defaults to None.
|
||||||
If not given it is asummed to be the end of the backtest range.
|
If a float is passed, it is assumed to be a timestamp. If not given it is assumed to be the end of the backtest range.
|
||||||
|
|
||||||
close_open_positions_on_exit (bool, optional): Whether to close all open positions when the backtest is stopped. Defaults to True.
|
close_open_positions_on_exit (bool, optional): Whether to close all open positions when the backtest
|
||||||
|
is stopped. Defaults to True.
|
||||||
|
|
||||||
preload (bool, optional): Whether to preload the ticks for the backtest. Defaults to True.
|
preload (bool, optional): Whether to preload the ticks for the backtest. Defaults to True.
|
||||||
|
|
||||||
assign_to_config (bool, optional): Whether to assign the backtest engine to the global config instance. Defaults to True.
|
assign_to_config (bool, optional): Whether to assign the backtest engine to the global config instance.
|
||||||
|
Defaults to True.
|
||||||
|
|
||||||
account_info (dict, optional): A dictionary of account information to use for the backtest. Defaults to None. Use this to set
|
account_info (dict, optional): A dictionary of account information to use for the backtest. Defaults to None. Use this to set
|
||||||
the account information for the backtest.
|
the account information for the backtest.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_data (BackTestData): The data used for backtesting. This is the data that is saved to disk when the backtest is stopped.
|
_data (BackTestData): The data used for backtesting. This is the data that is saved to disk when the
|
||||||
|
backtest is stopped.
|
||||||
|
|
||||||
mt5 (MetaTrader): The MetaTrader instance for the backtest engine.
|
mt5 (MetaTrader): The MetaTrader instance for the backtest engine.
|
||||||
|
|
||||||
@@ -174,14 +183,22 @@ class BackTestEngine:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__class__.__name__}()"
|
return f"{self.__class__.__name__}()"
|
||||||
|
|
||||||
def setup_test_range(self, *, start: float | datetime = None, end: float | datetime = None, speed: int = 60, restart: bool = True):
|
def setup_test_range(self, *, start: float | datetime = None, end: float | datetime = None, speed:
|
||||||
"""Setup the test range for the backtest engine. This is used to set the range of the backtest and the speed at which it runs.
|
int = 60, restart: bool = True):
|
||||||
|
"""Setup the test range for the backtest engine. This is used to set the range of the backtest and the speed
|
||||||
|
at which it runs.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start (float | datetime, optional): The start time of the backtest. Defaults to None. If a float is passed, it is assumed to be a timestamp.
|
start (float | datetime, optional): The start time of the backtest. Defaults to None. If a float is passed,
|
||||||
end (float | datetime, optional): The end time of the backtest. Defaults to None. If a float is passed, it is assumed to be a timestamp.
|
it is assumed to be a timestamp.
|
||||||
|
|
||||||
|
end (float | datetime, optional): The end time of the backtest. Defaults to None. If a float is passed,
|
||||||
|
it is assumed to be a timestamp.
|
||||||
|
|
||||||
speed (int, optional): The speed of the backtest. Defaults to 60.
|
speed (int, optional): The speed of the backtest. Defaults to 60.
|
||||||
restart (bool, optional): Whether to restart the backtest. Defaults to True. This is useful when resuming a backtest using a saved BackTestData.
|
|
||||||
|
restart (bool, optional): Whether to restart the backtest. Defaults to True.
|
||||||
|
This is useful when resuming a backtest using a saved BackTestData.
|
||||||
"""
|
"""
|
||||||
if self._data.span and self._data.range:
|
if self._data.span and self._data.range:
|
||||||
start = start or self._data.span[0]
|
start = start or self._data.span[0]
|
||||||
@@ -206,6 +223,13 @@ class BackTestEngine:
|
|||||||
self.cursor = Cursor(index=self.range.start, time=self.span.start)
|
self.cursor = Cursor(index=self.range.start, time=self.span.start)
|
||||||
|
|
||||||
def setup_data(self, *, restart: bool = True):
|
def setup_data(self, *, restart: bool = True):
|
||||||
|
"""Sets up the data for the backtest engine. This includes the orders, positions, deals and account
|
||||||
|
information. This data is handled by specialized classes such as the BackTestAccount and the TradeManager
|
||||||
|
classes.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
restart (bool, optional): Whether to restart the data. Defaults to True.
|
||||||
|
"""
|
||||||
if restart is True:
|
if restart is True:
|
||||||
self.orders = OrdersManager()
|
self.orders = OrdersManager()
|
||||||
self.positions = PositionsManager()
|
self.positions = PositionsManager()
|
||||||
@@ -231,19 +255,26 @@ class BackTestEngine:
|
|||||||
self._account = BackTestAccount(**self._data.account)
|
self._account = BackTestAccount(**self._data.account)
|
||||||
|
|
||||||
def next(self) -> Cursor:
|
def next(self) -> Cursor:
|
||||||
|
"""Move the cursor to the next time step in the backtest range."""
|
||||||
return next(self)
|
return next(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
|
"""The BackTestData instance used for the backtest. If not provided, a new instance is created,
|
||||||
|
and the data is made persistent when the backtest is stopped."""
|
||||||
return self._data
|
return self._data
|
||||||
|
|
||||||
def reset(self, clear_data: bool = False):
|
def reset(self, clear_data: bool = False):
|
||||||
|
"""Reset the backtest engine. This is useful when restarting the backtest from the beginning."""
|
||||||
self.iter = zip(self.range, self.span)
|
self.iter = zip(self.range, self.span)
|
||||||
self.cursor = Cursor(index=self.range.start, time=self.span.start)
|
self.cursor = Cursor(index=self.range.start, time=self.span.start)
|
||||||
if clear_data:
|
if clear_data:
|
||||||
self.setup_data(restart=True)
|
self.setup_data(restart=True)
|
||||||
|
|
||||||
def go_to(self, *, time: datetime | float):
|
def go_to(self, *, time: datetime | float):
|
||||||
|
"""Move the cursor to a specific time in the backtest range. You can pass a datetime object or a timestamp.
|
||||||
|
You can't go back in time or beyond the limits of the range.
|
||||||
|
"""
|
||||||
time = time.astimezone(tz=UTC) if isinstance(time, datetime) else datetime.fromtimestamp(time, tz=UTC)
|
time = time.astimezone(tz=UTC) if isinstance(time, datetime) else datetime.fromtimestamp(time, tz=UTC)
|
||||||
time = int(time.timestamp())
|
time = int(time.timestamp())
|
||||||
steps = time - self.cursor.time
|
steps = time - self.cursor.time
|
||||||
@@ -255,6 +286,7 @@ class BackTestEngine:
|
|||||||
raise ValueError("Can't go back in time or beyond the limits of the range")
|
raise ValueError("Can't go back in time or beyond the limits of the range")
|
||||||
|
|
||||||
def fast_forward(self, *, steps: int):
|
def fast_forward(self, *, steps: int):
|
||||||
|
"""Fast-forward the backtester by the given steps."""
|
||||||
for _ in range(steps):
|
for _ in range(steps):
|
||||||
self.next()
|
self.next()
|
||||||
|
|
||||||
@@ -263,6 +295,7 @@ class BackTestEngine:
|
|||||||
return [(c, t) for c, t in zip(df.columns, df.dtypes)]
|
return [(c, t) for c, t in zip(df.columns, df.dtypes)]
|
||||||
|
|
||||||
async def tracker(self):
|
async def tracker(self):
|
||||||
|
"""The tracker monitors and updates open positions on every iteration. It is called by the controller."""
|
||||||
try:
|
try:
|
||||||
pos_tasks = [self.check_position(ticket=ticket) for ticket in self.positions._open_positions]
|
pos_tasks = [self.check_position(ticket=ticket) for ticket in self.positions._open_positions]
|
||||||
await asyncio.gather(*pos_tasks)
|
await asyncio.gather(*pos_tasks)
|
||||||
@@ -274,6 +307,7 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def save_result_to_json(self):
|
def save_result_to_json(self):
|
||||||
|
"""Saves the result to a json file at the end of testing."""
|
||||||
data = self._account.get_dict(include={"balance", "profit", "equity", "margin", "margin_free", "margin_level"})
|
data = self._account.get_dict(include={"balance", "profit", "equity", "margin", "margin_free", "margin_level"})
|
||||||
wins = [position for ticket in self.positions if (position := self.positions.get(ticket)).profit > 0]
|
wins = [position for ticket in self.positions if (position := self.positions.get(ticket)).profit > 0]
|
||||||
losses = [position for ticket in self.positions if (position := self.positions.get(ticket)).profit <= 0]
|
losses = [position for ticket in self.positions if (position := self.positions.get(ticket)).profit <= 0]
|
||||||
@@ -303,6 +337,7 @@ class BackTestEngine:
|
|||||||
json.dump(data, file, indent=4)
|
json.dump(data, file, indent=4)
|
||||||
|
|
||||||
async def close_all_open(self):
|
async def close_all_open(self):
|
||||||
|
"""Closes all open position at the end of testing"""
|
||||||
tasks = [self.check_position(ticket=position.ticket) for position in self.positions.open_positions]
|
tasks = [self.check_position(ticket=position.ticket) for position in self.positions.open_positions]
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
for position in self.positions.open_positions:
|
for position in self.positions.open_positions:
|
||||||
@@ -310,6 +345,8 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def wrap_up(self):
|
async def wrap_up(self):
|
||||||
|
"""Wraps up the backtest. This is called at the end of testing to save the results and close all open
|
||||||
|
positions."""
|
||||||
if self.close_open_positions_on_exit:
|
if self.close_open_positions_on_exit:
|
||||||
await self.close_all_open()
|
await self.close_all_open()
|
||||||
self.save_result_to_json()
|
self.save_result_to_json()
|
||||||
@@ -329,7 +366,11 @@ class BackTestEngine:
|
|||||||
GetData.pickle_data(data=self._data, name=path)
|
GetData.pickle_data(data=self._data, name=path)
|
||||||
|
|
||||||
async def preload_ticks(self, *, symbol: str):
|
async def preload_ticks(self, *, symbol: str):
|
||||||
"""Pull a month data on ticks from the terminal. Starting from the current time"""
|
"""Pull a month data on ticks from the terminal. Starting from the current time.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to preload ticks for.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
start = self.cursor.time
|
start = self.cursor.time
|
||||||
end = start + (30 * 24 * 60 * 60)
|
end = start + (30 * 24 * 60 * 60)
|
||||||
@@ -348,6 +389,13 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@async_cache
|
@async_cache
|
||||||
async def get_price_tick(self, *, symbol: str, time: int) -> Tick | None:
|
async def get_price_tick(self, *, symbol: str, time: int) -> Tick | None:
|
||||||
|
"""Get the price tick for a symbol at a given time. If the preload option is set to True,
|
||||||
|
it will use the preloaded ticks when available.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get the price tick for.
|
||||||
|
time (int): The time to get the price tick.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if self.use_terminal and self.preload:
|
if self.use_terminal and self.preload:
|
||||||
if (ticks := self.preloaded_ticks.get(symbol)) is not None and time in ticks.index:
|
if (ticks := self.preloaded_ticks.get(symbol)) is not None and time in ticks.index:
|
||||||
@@ -420,6 +468,7 @@ class BackTestEngine:
|
|||||||
...
|
...
|
||||||
|
|
||||||
def check_account(self):
|
def check_account(self):
|
||||||
|
"""Checks an account status. This method is called at each iteration to check if the account has burned out."""
|
||||||
account = self._account
|
account = self._account
|
||||||
level = account.margin_level if account.margin_so_mode == AccountStopOutMode.PERCENT else account.margin_so_call
|
level = account.margin_level if account.margin_so_mode == AccountStopOutMode.PERCENT else account.margin_so_call
|
||||||
if level < account.margin_so_call and level != 0 and account.equity < 0:
|
if level < account.margin_so_call and level != 0 and account.equity < 0:
|
||||||
@@ -428,7 +477,8 @@ class BackTestEngine:
|
|||||||
|
|
||||||
async def check_position(self, *, ticket: int):
|
async def check_position(self, *, ticket: int):
|
||||||
"""
|
"""
|
||||||
Update the profit of an open position based on the current price of the symbol.
|
Update the profit of an open position based on the current price of the symbol. It is called by the
|
||||||
|
tracker to update the profit of open positions.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ticket (int): Position ticket
|
ticket (int): Position ticket
|
||||||
@@ -445,6 +495,7 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
async def close_position_manually(self, *, ticket: int):
|
async def close_position_manually(self, *, ticket: int):
|
||||||
|
"""Close a position manually without. Usually at the end of testing."""
|
||||||
res = await self.close_position(ticket=ticket)
|
res = await self.close_position(ticket=ticket)
|
||||||
if not res:
|
if not res:
|
||||||
return
|
return
|
||||||
@@ -524,9 +575,9 @@ class BackTestEngine:
|
|||||||
Modify the stop loss and take profit levels of an open position.
|
Modify the stop loss and take profit levels of an open position.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ticket: Position ticket
|
ticket (int): Position ticket
|
||||||
sl: stop loss level
|
sl (int): stop loss level
|
||||||
tp: Take profit level
|
tp (int): Take profit level
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if the stops are modified successfully, False otherwise
|
bool: True if the stops are modified successfully, False otherwise
|
||||||
@@ -535,6 +586,14 @@ class BackTestEngine:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def update_account(self, *, profit: float = None, margin: float = 0, gain: float = 0):
|
def update_account(self, *, profit: float = None, margin: float = 0, gain: float = 0):
|
||||||
|
"""
|
||||||
|
Update the account. This method is protected by thread lock.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
profit (float): The current profit of one or more open positions. Can be positive or negative.
|
||||||
|
margin (float): The margin set aside for a trade. It is released when the trade is closed.
|
||||||
|
gain (gain): The gain realized when the trade is closed.
|
||||||
|
"""
|
||||||
self.account_lock.acquire()
|
self.account_lock.acquire()
|
||||||
try:
|
try:
|
||||||
self._account.balance += round(gain, self._account.currency_digits)
|
self._account.balance += round(gain, self._account.currency_digits)
|
||||||
@@ -561,14 +620,21 @@ class BackTestEngine:
|
|||||||
self.account_lock.release()
|
self.account_lock.release()
|
||||||
|
|
||||||
def deposit(self, *, amount: float):
|
def deposit(self, *, amount: float):
|
||||||
|
"""Make deposit to the trading account"""
|
||||||
self.update_account(gain=amount)
|
self.update_account(gain=amount)
|
||||||
|
|
||||||
def withdraw(self, *, amount: float):
|
def withdraw(self, *, amount: float):
|
||||||
|
"""Make a withdrawal from the trading account. You can not withdraw more than what you have"""
|
||||||
assert amount <= self._account.balance, "Insufficient funds"
|
assert amount <= self._account.balance, "Insufficient funds"
|
||||||
self.update_account(gain=-amount)
|
self.update_account(gain=-amount)
|
||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def setup_account(self, **kwargs):
|
async def setup_account(self, **kwargs):
|
||||||
|
"""Setup the trading account before the begining of a backtesting session.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
(**kwargs, Any): Attributes for the backetest account object can be set here.
|
||||||
|
"""
|
||||||
kwargs = {**self.account_info, **kwargs}
|
kwargs = {**self.account_info, **kwargs}
|
||||||
default = {
|
default = {
|
||||||
"profit": self._account.profit,
|
"profit": self._account.profit,
|
||||||
@@ -589,6 +655,7 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def setup_account_sync(self, **kwargs):
|
def setup_account_sync(self, **kwargs):
|
||||||
|
"""Set up the backtesting account in sync mode"""
|
||||||
kwargs = {**self.account_info, **kwargs}
|
kwargs = {**self.account_info, **kwargs}
|
||||||
default = {
|
default = {
|
||||||
"profit": self._account.profit,
|
"profit": self._account.profit,
|
||||||
@@ -609,6 +676,16 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def prices(self) -> dict[str, DataFrame]:
|
def prices(self) -> dict[str, DataFrame]:
|
||||||
|
"""Get the prices for instruments used in the backtesting. This class is called when the use_terminal option
|
||||||
|
is set to False and trading data is provided in the data attribute. It makes sure that there is a price for each
|
||||||
|
symbol for every second covered in the backtesting range, by reindexing the price ticks using the backtesting
|
||||||
|
time span and filling up missing data using the nearest method.
|
||||||
|
This method returns a dictionaries of dataframe containing the prices for each symbol.
|
||||||
|
It's cached and there computed only once per backtesting session.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, DataFrame]: A dictionary mapping dataframe of prices to symbols.
|
||||||
|
"""
|
||||||
prices = {}
|
prices = {}
|
||||||
for symbol in self._data.ticks.keys():
|
for symbol in self._data.ticks.keys():
|
||||||
res = self._data.ticks[symbol]
|
res = self._data.ticks[symbol]
|
||||||
@@ -621,6 +698,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def ticks(self) -> dict[str, DataFrame]:
|
def ticks(self) -> dict[str, DataFrame]:
|
||||||
|
"""Similar to prices above, but returns prices exactly as they are without reindexing and filling up.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, DataFrame]: A dictionary mapping symbols to dataframes of ticks.
|
||||||
|
"""
|
||||||
ticks = {}
|
ticks = {}
|
||||||
for symbol in self._data.ticks.keys():
|
for symbol in self._data.ticks.keys():
|
||||||
res = self._data.ticks[symbol]
|
res = self._data.ticks[symbol]
|
||||||
@@ -630,6 +712,12 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def rates(self) -> dict[str, dict[int, DataFrame]]:
|
def rates(self) -> dict[str, dict[int, DataFrame]]:
|
||||||
|
"""This property is useful when backtesting with the use_terminal option set to false. It returns a nested dict
|
||||||
|
that maps symbols to a dict mapping timeframes to rates. The timeframes are mapped using their integer values.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, dict[int, DataFrame]]: A dictionary containing the symbol rates.
|
||||||
|
"""
|
||||||
rates = {}
|
rates = {}
|
||||||
for symbol in self._data.rates.keys():
|
for symbol in self._data.rates.keys():
|
||||||
for timeframe in self._data.rates[symbol].keys():
|
for timeframe in self._data.rates[symbol].keys():
|
||||||
@@ -640,6 +728,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def symbols(self) -> dict[str, SymbolInfo]:
|
def symbols(self) -> dict[str, SymbolInfo]:
|
||||||
|
"""A dictionary of symbols and SymbolInfo object. Used when use_terminal is set to false.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, SymbolInfo]
|
||||||
|
"""
|
||||||
symbols = {}
|
symbols = {}
|
||||||
for symbol, info in self._data.symbols.items():
|
for symbol, info in self._data.symbols.items():
|
||||||
symbols[symbol] = SymbolInfo((info.get(key) for key in SymbolInfo.__match_args__))
|
symbols[symbol] = SymbolInfo((info.get(key) for key in SymbolInfo.__match_args__))
|
||||||
@@ -647,6 +740,20 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def order_send(self, *, request: dict, use_terminal=False) -> OrderSendResult:
|
async def order_send(self, *, request: dict, use_terminal=False) -> OrderSendResult:
|
||||||
|
"""Simulates the sending of an order to the broker. An OrderSendResult is object is created at the end of this
|
||||||
|
operation as would be created if it was done in live trading. When an order is successful a positions object is
|
||||||
|
created, an order and deal object is created as well. When use_terminal is set to true the margin and profit
|
||||||
|
are calculated by sending to the broker. This increases accuracy but slows down the backtester. Check order is
|
||||||
|
called to make sure the order is valid and would go through if it was a live trade.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (dict): The order request as a dict.
|
||||||
|
use_terminal (bool): A flag to override the use_terminal attribute. If true, the terminal will
|
||||||
|
be used even if the use_terminal attribute is True.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OrderSendResult: An object containing the result of the order send operation.
|
||||||
|
"""
|
||||||
use_terminal = self.use_terminal or use_terminal
|
use_terminal = self.use_terminal or use_terminal
|
||||||
osr = {
|
osr = {
|
||||||
"retcode": 10013,
|
"retcode": 10013,
|
||||||
@@ -814,6 +921,16 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def order_check(self, *, request: dict, use_terminal: bool = False) -> OrderCheckResult:
|
async def order_check(self, *, request: dict, use_terminal: bool = False) -> OrderCheckResult:
|
||||||
|
"""Checks the order before placing it. If use_terminal, the order is checked with the broker, but the entire result
|
||||||
|
is not used. Details such as balance, profit, equity, margin, and margin level are calculated by the backtester.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (dict): The order request as a dict.
|
||||||
|
use_terminal (bool): A flag to override the use_terminal attribute. If true, the terminal will used.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OrderCheckResult: The result of the order check.
|
||||||
|
"""
|
||||||
use_terminal = self.use_terminal or use_terminal
|
use_terminal = self.use_terminal or use_terminal
|
||||||
ocr = {
|
ocr = {
|
||||||
"retcode": 10013,
|
"retcode": 10013,
|
||||||
@@ -892,6 +1009,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_terminal_info(self) -> TerminalInfo:
|
async def get_terminal_info(self) -> TerminalInfo:
|
||||||
|
"""Get the terminal information
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TerminalInfo: The terminal information
|
||||||
|
"""
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
res = await self.mt5.terminal_info()
|
res = await self.mt5.terminal_info()
|
||||||
return res
|
return res
|
||||||
@@ -899,6 +1021,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_version(self) -> tuple[int, int, str]:
|
async def get_version(self) -> tuple[int, int, str]:
|
||||||
|
"""Get the version of the terminal.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[int, int, str]: The version of the terminal
|
||||||
|
"""
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
res = await self.mt5.version()
|
res = await self.mt5.version()
|
||||||
return res
|
return res
|
||||||
@@ -906,6 +1033,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_symbols_total(self) -> int:
|
async def get_symbols_total(self) -> int:
|
||||||
|
"""Get the total number of symbols available in the terminal.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The total number of symbols available.
|
||||||
|
"""
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
syms = await self.mt5.symbols_total()
|
syms = await self.mt5.symbols_total()
|
||||||
return syms
|
return syms
|
||||||
@@ -913,6 +1045,14 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_symbols(self, *, group: str = "") -> tuple[SymbolInfo, ...]:
|
async def get_symbols(self, *, group: str = "") -> tuple[SymbolInfo, ...]:
|
||||||
|
"""Get the symbols available in the terminal. Filter by group if provided.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
group (str): The group to filter by (default is "")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[SymbolInfo, ...]: A tuple of symbol information
|
||||||
|
"""
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
syms = await self.mt5.symbols_get(group=group)
|
syms = await self.mt5.symbols_get(group=group)
|
||||||
return syms
|
return syms
|
||||||
@@ -920,10 +1060,23 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_account_info(self) -> AccountInfo:
|
def get_account_info(self) -> AccountInfo:
|
||||||
|
"""Get the account information
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AccountInfo: The account information
|
||||||
|
"""
|
||||||
return AccountInfo(self._account.asdict().values())
|
return AccountInfo(self._account.asdict().values())
|
||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_symbol_info_tick(self, *, symbol: str) -> Tick | None:
|
async def get_symbol_info_tick(self, *, symbol: str) -> Tick:
|
||||||
|
"""Get the price tick for a symbol at the current time
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tick: The price tick
|
||||||
|
"""
|
||||||
tick = await self.get_price_tick(symbol=symbol, time=self.cursor.time)
|
tick = await self.get_price_tick(symbol=symbol, time=self.cursor.time)
|
||||||
return tick
|
return tick
|
||||||
|
|
||||||
@@ -937,6 +1090,14 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_symbol_info(self, *, symbol: str) -> SymbolInfo:
|
async def get_symbol_info(self, *, symbol: str) -> SymbolInfo:
|
||||||
|
"""Get the symbol information
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get information for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SymbolInfo: The symbol information
|
||||||
|
"""
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
info = await self._symbol_info(symbol=symbol)
|
info = await self._symbol_info(symbol=symbol)
|
||||||
else:
|
else:
|
||||||
@@ -957,6 +1118,17 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_rates_from(self, *, symbol: str, timeframe: TimeFrame, date_from: datetime | float, count: int) -> np.ndarray:
|
async def get_rates_from(self, *, symbol: str, timeframe: TimeFrame, date_from: datetime | float, count: int) -> np.ndarray:
|
||||||
|
"""Get rates from a specific date to the current date. Used by the backtester to get rates for a symbol
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get rates for
|
||||||
|
timeframe (TimeFrame): The timeframe of the rates
|
||||||
|
date_from (datetime | float): The date from which to get the rates
|
||||||
|
count (int): The number of rates to get
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
np.ndarray: An array of rates
|
||||||
|
"""
|
||||||
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
rates = await self.mt5.copy_rates_from(symbol, timeframe, date_from, count)
|
rates = await self.mt5.copy_rates_from(symbol, timeframe, date_from, count)
|
||||||
@@ -970,6 +1142,17 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_rates_from_pos(self, *, symbol: str, timeframe: TimeFrame, start_pos: int, count: int) -> np.ndarray:
|
async def get_rates_from_pos(self, *, symbol: str, timeframe: TimeFrame, start_pos: int, count: int) -> np.ndarray:
|
||||||
|
"""Get a number of rates counting from a specific position. With position zero being the current time.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get rates for
|
||||||
|
timeframe (TimeFrame): The timeframe of the rates
|
||||||
|
start_pos (int): The position to start from
|
||||||
|
count (int): The number of rates to get
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
np.ndarray: An array of rates
|
||||||
|
"""
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
current_time = self.cursor.time if start_pos == 0 else self.cursor.time - start_pos * timeframe.seconds
|
current_time = self.cursor.time if start_pos == 0 else self.cursor.time - start_pos * timeframe.seconds
|
||||||
current_time = round_up(current_time, timeframe.seconds)
|
current_time = round_up(current_time, timeframe.seconds)
|
||||||
@@ -988,7 +1171,19 @@ class BackTestEngine:
|
|||||||
return np.fromiter((tuple(i) for i in rates.iloc), dtype=self.get_dtype(df=rates))
|
return np.fromiter((tuple(i) for i in rates.iloc), dtype=self.get_dtype(df=rates))
|
||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_rates_range(self, *, symbol: str, timeframe: TimeFrame, date_from: datetime | float, date_to: datetime | float) -> np.ndarray:
|
async def get_rates_range(self, *, symbol: str, timeframe: TimeFrame, date_from: datetime | float,
|
||||||
|
date_to: datetime | float) -> np.ndarray:
|
||||||
|
"""Get rates within a specific date range. Used by the backtester to get rates for a symbol
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get rates for
|
||||||
|
timeframe (TimeFrame): The timeframe of the rates
|
||||||
|
date_from (datetime | float): The date from which to get the rates
|
||||||
|
date_to (datetime | float): The date to which to get the rates
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
np.ndarray: An array of rates
|
||||||
|
"""
|
||||||
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
||||||
date_to = date_to.astimezone(tz=UTC) if isinstance(date_to, datetime) else datetime.fromtimestamp(date_to, tz=UTC)
|
date_to = date_to.astimezone(tz=UTC) if isinstance(date_to, datetime) else datetime.fromtimestamp(date_to, tz=UTC)
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
@@ -1002,7 +1197,18 @@ class BackTestEngine:
|
|||||||
return np.fromiter((tuple(i) for i in rates.iloc), dtype=self.get_dtype(df=rates))
|
return np.fromiter((tuple(i) for i in rates.iloc), dtype=self.get_dtype(df=rates))
|
||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def get_ticks_from(self, *, symbol: str, date_from: datetime | float, count: int, flags: CopyTicks = CopyTicks.ALL) -> np.ndarray:
|
async def get_ticks_from(self, *, symbol: str, date_from: datetime | float, count: int,
|
||||||
|
flags: CopyTicks = CopyTicks.ALL) -> np.ndarray:
|
||||||
|
"""Get a specified number of ticks counting from a specific date.
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get ticks for
|
||||||
|
date_from (datetime | float): The date from which to get the ticks
|
||||||
|
count (int): The number of ticks to get
|
||||||
|
flags (CopyTicks): The flags to use when getting the ticks
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
np.ndarray: An array of ticks
|
||||||
|
"""
|
||||||
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
ticks = await self.mt5.copy_ticks_from(symbol, date_from, count, flags)
|
ticks = await self.mt5.copy_ticks_from(symbol, date_from, count, flags)
|
||||||
@@ -1017,6 +1223,17 @@ class BackTestEngine:
|
|||||||
async def get_ticks_range(
|
async def get_ticks_range(
|
||||||
self, *, symbol: str, date_from: datetime | float, date_to: datetime | float, flags: CopyTicks = CopyTicks.ALL
|
self, *, symbol: str, date_from: datetime | float, date_to: datetime | float, flags: CopyTicks = CopyTicks.ALL
|
||||||
) -> np.ndarray:
|
) -> np.ndarray:
|
||||||
|
"""Get ticks within a specific date range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol (str): The symbol to get ticks for
|
||||||
|
date_from (datetime | float): The date from which to get the ticks
|
||||||
|
date_to (datetime | float): The date to which to get the ticks
|
||||||
|
flags (CopyTicks): The flags to use when getting the ticks
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
np.ndarray: An array of ticks
|
||||||
|
"""
|
||||||
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
date_from = date_from.astimezone(tz=UTC) if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from, tz=UTC)
|
||||||
date_to = date_to.astimezone(tz=UTC) if isinstance(date_to, datetime) else datetime.fromtimestamp(date_to, tz=UTC)
|
date_to = date_to.astimezone(tz=UTC) if isinstance(date_to, datetime) else datetime.fromtimestamp(date_to, tz=UTC)
|
||||||
if self.use_terminal:
|
if self.use_terminal:
|
||||||
@@ -1031,8 +1248,21 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def order_calc_margin(
|
async def order_calc_margin(
|
||||||
self, *, action: Literal[OrderType.BUY, OrderType.SELL], symbol: str, volume: float, price: float, use_terminal: bool = None
|
self, *, action: Literal[OrderType.BUY, OrderType.SELL], symbol: str, volume: float,
|
||||||
):
|
price: float, use_terminal: bool = None):
|
||||||
|
"""Calculate the margin required for a trade.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
action (Literal[OrderType.BUY, OrderType.SELL]): Type of order
|
||||||
|
symbol (str): Symbol name
|
||||||
|
volume (float): Volume of the trade
|
||||||
|
price (float): The price at which the trade is opened
|
||||||
|
use_terminal (bool): A flag to override the use_terminal attribute. If true, the terminal will be used
|
||||||
|
even if the use_terminal attribute is True.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: The margin required for the trade
|
||||||
|
"""
|
||||||
use_terminal = use_terminal if use_terminal is not None else self.use_terminal
|
use_terminal = use_terminal if use_terminal is not None else self.use_terminal
|
||||||
if use_terminal:
|
if use_terminal:
|
||||||
return await self.mt5.order_calc_margin(action, symbol, volume, price)
|
return await self.mt5.order_calc_margin(action, symbol, volume, price)
|
||||||
@@ -1045,8 +1275,23 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
async def order_calc_profit(
|
async def order_calc_profit(
|
||||||
self, *, action: Literal[OrderType.BUY, OrderType.SELL], symbol: str, volume: float, price_open: float, price_close: float, use_terminal=None
|
self, *, action: Literal[OrderType.BUY, OrderType.SELL], symbol: str, volume: float,
|
||||||
):
|
price_open: float, price_close: float, use_terminal=None):
|
||||||
|
"""
|
||||||
|
Calculate the profit for a trade.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
action (Literal[OrderType.BUY, OrderType.SELL]): Type of order
|
||||||
|
symbol (str): Symbol name
|
||||||
|
volume (float): Volume of the trade
|
||||||
|
price_open (float): The price at which the trade is opened
|
||||||
|
price_close (float): The price at which the trade is closed
|
||||||
|
use_terminal (bool): A flag to override the use_terminal attribute. If true, the terminal will be used
|
||||||
|
even if the use_terminal attribute is True.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: The profit of the trade
|
||||||
|
"""
|
||||||
use_terminal = use_terminal if use_terminal is not None else self.use_terminal
|
use_terminal = use_terminal if use_terminal is not None else self.use_terminal
|
||||||
|
|
||||||
if use_terminal:
|
if use_terminal:
|
||||||
@@ -1060,8 +1305,7 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_orders_total(self) -> int:
|
def get_orders_total(self) -> int:
|
||||||
"""
|
"""Get the total number of pending orders.
|
||||||
Get the total number of pending orders.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: Total number of pending orders
|
int: Total number of pending orders
|
||||||
@@ -1070,8 +1314,7 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_orders(self, *, symbol: str = "", group: str = "", ticket: int = None) -> tuple[TradeOrder, ...]:
|
def get_orders(self, *, symbol: str = "", group: str = "", ticket: int = None) -> tuple[TradeOrder, ...]:
|
||||||
"""
|
"""Get pending orders from the terminal history. This has to do with pending orders, which this backtester
|
||||||
Get pending orders from the terminal history. This has to do with pending orders, which this backtester
|
|
||||||
doesn't support yet.
|
doesn't support yet.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -1080,7 +1323,7 @@ class BackTestEngine:
|
|||||||
ticket: Order ticket
|
ticket: Order ticket
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple[TradeOrder]
|
tuple[TradeOrder, ...]: Pending orders
|
||||||
"""
|
"""
|
||||||
if symbol and group and ticket:
|
if symbol and group and ticket:
|
||||||
return tuple()
|
return tuple()
|
||||||
@@ -1088,8 +1331,7 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_positions_total(self) -> int:
|
def get_positions_total(self) -> int:
|
||||||
"""
|
"""Get the total number of open positions.
|
||||||
Get the total number of open positions.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: Total number of open positions
|
int: Total number of open positions
|
||||||
@@ -1098,23 +1340,21 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_positions(self, *, symbol: str = None, group: str = None, ticket: int = None) -> tuple[TradePosition, ...]:
|
def get_positions(self, *, symbol: str = None, group: str = None, ticket: int = None) -> tuple[TradePosition, ...]:
|
||||||
"""
|
"""Get open positions from the terminal history.
|
||||||
Get open positions from the terminal history.
|
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
symbol: The symbol name
|
symbol: The symbol name
|
||||||
group: Group argument to filter by
|
group: Group argument to filter by
|
||||||
ticket: Position ticket
|
ticket: Position ticket
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple[TradePosition]: Open positions
|
tuple[TradePosition, ...]: Open positions
|
||||||
"""
|
"""
|
||||||
return self.positions.positions_get(ticket=ticket, symbol=symbol, group=group)
|
return self.positions.positions_get(ticket=ticket, symbol=symbol, group=group)
|
||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_history_orders_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
def get_history_orders_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
||||||
"""
|
"""Get the total number of orders in the terminal history.
|
||||||
Get the total number of orders in the terminal history.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
date_from: The start date of the history
|
date_from: The start date of the history
|
||||||
@@ -1128,12 +1368,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_history_orders(
|
def get_history_orders(
|
||||||
self, *, date_from: datetime | float = None, date_to: datetime | float = None, group: str = "", ticket: int = None, position: int = None
|
self, *, date_from: datetime | float = None, date_to: datetime | float = None, group: str = "",
|
||||||
) -> tuple[TradeOrder, ...]:
|
ticket: int = None, position: int = None) -> tuple[TradeOrder, ...]:
|
||||||
"""
|
"""Get orders from the terminal history.
|
||||||
Get orders from the terminal history.
|
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
date_from: Date from which to start the history
|
date_from: Date from which to start the history
|
||||||
date_to: Date to which to end the history
|
date_to: Date to which to end the history
|
||||||
group: group keyword to filter by
|
group: group keyword to filter by
|
||||||
@@ -1141,14 +1380,14 @@ class BackTestEngine:
|
|||||||
position: position id to filter by
|
position: position id to filter by
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple[TradeOrder]: Orders in the history
|
tuple[TradeOrder, ...]: Orders in the history
|
||||||
"""
|
"""
|
||||||
return self.orders.history_orders_get(date_from=date_from, date_to=date_to, group=group, ticket=ticket, position=position)
|
return self.orders.history_orders_get(date_from=date_from, date_to=date_to, group=group,
|
||||||
|
ticket=ticket, position=position)
|
||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_history_deals_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
def get_history_deals_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
||||||
"""
|
"""Get the total number of deals in the terminal history.
|
||||||
Get the total number of deals in the terminal history.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
date_from: Date from which to start the history
|
date_from: Date from which to start the history
|
||||||
@@ -1161,12 +1400,11 @@ class BackTestEngine:
|
|||||||
|
|
||||||
@error_handler_sync
|
@error_handler_sync
|
||||||
def get_history_deals(
|
def get_history_deals(
|
||||||
self, *, date_from: datetime | float = None, date_to: datetime | float = None, group: str = None, position: int = None, ticket: int = None
|
self, *, date_from: datetime | float = None, date_to: datetime | float = None, group: str = None,
|
||||||
) -> tuple[TradeDeal, ...]:
|
position: int = None, ticket: int = None) -> tuple[TradeDeal, ...]:
|
||||||
"""
|
"""Get deals from the terminal history.
|
||||||
Get deals from the terminal history.
|
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
date_from: Date from which to start the history
|
date_from: Date from which to start the history
|
||||||
date_to: Date to which to end the history
|
date_to: Date to which to end the history
|
||||||
group: group keyword to filter by
|
group: group keyword to filter by
|
||||||
@@ -1176,4 +1414,5 @@ class BackTestEngine:
|
|||||||
Returns:
|
Returns:
|
||||||
tuple[TradeDeal, ...]: Deals in the history
|
tuple[TradeDeal, ...]: Deals in the history
|
||||||
"""
|
"""
|
||||||
return self.deals.history_deals_get(date_from=date_from, date_to=date_to, group=group, position=position, ticket=ticket)
|
return self.deals.history_deals_get(date_from=date_from, date_to=date_to, group=group,
|
||||||
|
position=position, ticket=ticket)
|
||||||
|
|||||||
@@ -18,12 +18,33 @@ logger = getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class Cursor(NamedTuple):
|
class Cursor(NamedTuple):
|
||||||
|
"""A cursor to iterate over the data. Marks the current position."""
|
||||||
index: int
|
index: int
|
||||||
time: int
|
time: int
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class BackTestData:
|
class BackTestData:
|
||||||
|
"""The data class to store the backtesting data.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
name (str): The name of the backtest data.
|
||||||
|
terminal (dict): The terminal information.
|
||||||
|
version (tuple): The version of the terminal.
|
||||||
|
account (dict): The account information.
|
||||||
|
symbols (dict): The symbols information.
|
||||||
|
ticks (dict): The ticks data.
|
||||||
|
rates (dict): The rates data.
|
||||||
|
span (range): The range of the data.
|
||||||
|
range (range): The range of the data.
|
||||||
|
orders (dict): The orders data.
|
||||||
|
deals (dict): The deals data.
|
||||||
|
positions (dict): The positions data.
|
||||||
|
open_positions (set): The open positions.
|
||||||
|
cursor (Cursor): The cursor to iterate over the data.
|
||||||
|
margins (dict): The margins data.
|
||||||
|
fully_loaded (bool): A flag to indicate if the data is fully loaded
|
||||||
|
"""
|
||||||
name: str = ""
|
name: str = ""
|
||||||
terminal: dict[str, [str | int | bool | float]] = field(default_factory=dict)
|
terminal: dict[str, [str | int | bool | float]] = field(default_factory=dict)
|
||||||
version: tuple[int, int, str] = (0, 0, "")
|
version: tuple[int, int, str] = (0, 0, "")
|
||||||
@@ -48,18 +69,44 @@ class BackTestData:
|
|||||||
return f"{self.__class__.__name__}({self.name})"
|
return f"{self.__class__.__name__}({self.name})"
|
||||||
|
|
||||||
def set_attrs(self, **kwargs):
|
def set_attrs(self, **kwargs):
|
||||||
|
"""Set the attributes of the class on the instance."""
|
||||||
[setattr(self, k, v) for k, v in kwargs.items() if k in self.fields]
|
[setattr(self, k, v) for k, v in kwargs.items() if k in self.fields]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fields(self):
|
def fields(self):
|
||||||
|
"""A list of the fields of the class."""
|
||||||
return [f.name for f in fields(self)]
|
return [f.name for f in fields(self)]
|
||||||
|
|
||||||
|
|
||||||
class GetData:
|
class GetData:
|
||||||
|
"""A class to get the backtesting data from the MetaTrader5 terminal.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
start (datetime): The start date of the data.
|
||||||
|
end (datetime): The end date of the data.
|
||||||
|
symbols (Sequence[str]): The symbols to get the data for.
|
||||||
|
timeframes (Sequence[TimeFrame]): The timeframes to get the data for.
|
||||||
|
name (str): The name of the backtest data.
|
||||||
|
range (range): The range of the data.
|
||||||
|
span (range): The span of the data.
|
||||||
|
data (BackTestData): The backtesting data.
|
||||||
|
mt5 (MetaTrader): The MetaTrader5 instance.
|
||||||
|
task_queue (TaskQueue): The task queue to handle the requests.
|
||||||
|
"""
|
||||||
data: BackTestData
|
data: BackTestData
|
||||||
|
|
||||||
def __init__(self, *, start: datetime, end: datetime, symbols: Sequence[str], timeframes: Sequence[TimeFrame], name: str = ""):
|
def __init__(self, *, start: datetime, end: datetime, symbols: Sequence[str],
|
||||||
""""""
|
timeframes: Sequence[TimeFrame], name: str = ""):
|
||||||
|
"""
|
||||||
|
Get the backtesting data from the MetaTrader5 terminal.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
start (datetime): The start date of the data.
|
||||||
|
end (datetime): The end date of the data.
|
||||||
|
symbols (Sequence[str]): The symbols to get the data for.
|
||||||
|
timeframes (Sequence[TimeFrame]): The timeframes to get the data for.
|
||||||
|
name (str): The name of the backtest data.
|
||||||
|
"""
|
||||||
self.config = Config()
|
self.config = Config()
|
||||||
self.start = start.astimezone(tz=UTC)
|
self.start = start.astimezone(tz=UTC)
|
||||||
self.end = end.astimezone(tz=UTC)
|
self.end = end.astimezone(tz=UTC)
|
||||||
@@ -76,7 +123,12 @@ class GetData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def pickle_data(cls, *, data: BackTestData, name: str | Path):
|
def pickle_data(cls, *, data: BackTestData, name: str | Path):
|
||||||
""""""
|
"""Pickle the data to a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (BackTestData): The data to pickle.
|
||||||
|
name (str | Path): The name of the file to pickle the data to.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
with open(name, "wb") as fo:
|
with open(name, "wb") as fo:
|
||||||
pickle.dump(data, fo, protocol=pickle.HIGHEST_PROTOCOL)
|
pickle.dump(data, fo, protocol=pickle.HIGHEST_PROTOCOL)
|
||||||
@@ -85,7 +137,11 @@ class GetData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_data(cls, *, name: str | Path) -> BackTestData:
|
def load_data(cls, *, name: str | Path) -> BackTestData:
|
||||||
""""""
|
"""Load the data from a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str | Path): The name of the file to load the data from.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
with open(name, "rb") as fo:
|
with open(name, "rb") as fo:
|
||||||
data = pickle.load(fo)
|
data = pickle.load(fo)
|
||||||
@@ -94,13 +150,23 @@ class GetData:
|
|||||||
logger.error(f"Error: {err}")
|
logger.error(f"Error: {err}")
|
||||||
|
|
||||||
def save_data(self, *, name: str | Path = ""):
|
def save_data(self, *, name: str | Path = ""):
|
||||||
|
"""Save the data to a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str | Path): The name of the file to save the data to. If not provided, the name of the data is used.
|
||||||
|
"""
|
||||||
name = name or (self.name + ".pkl" if not self.name.endswith(".pkl") else self.name)
|
name = name or (self.name + ".pkl" if not self.name.endswith(".pkl") else self.name)
|
||||||
name = Path(self.config.backtest_dir) / name if not isinstance(name, Path) else name
|
name = Path(self.config.backtest_dir) / name if not isinstance(name, Path) else name
|
||||||
with open(name, "wb") as fo:
|
with open(name, "wb") as fo:
|
||||||
pickle.dump(self.data, fo, protocol=pickle.HIGHEST_PROTOCOL)
|
pickle.dump(self.data, fo, protocol=pickle.HIGHEST_PROTOCOL)
|
||||||
|
|
||||||
async def get_data(self, workers: int = None):
|
async def get_data(self, workers: int = None):
|
||||||
""""""
|
"""Use the task queue to get the data from the MetaTrader5 terminal.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
workers (int): The number of workers to use in the task queue. If not provided, the default number of workers
|
||||||
|
is used.
|
||||||
|
"""
|
||||||
if workers:
|
if workers:
|
||||||
self.task_queue.workers = workers
|
self.task_queue.workers = workers
|
||||||
|
|
||||||
@@ -124,7 +190,6 @@ class GetData:
|
|||||||
self.data = BackTestData(name=self.name, span=self.span, range=self.range, fully_loaded=False)
|
self.data = BackTestData(name=self.name, span=self.span, range=self.range, fully_loaded=False)
|
||||||
|
|
||||||
async def get_terminal_info(self):
|
async def get_terminal_info(self):
|
||||||
""""""
|
|
||||||
terminal = await self.mt5.terminal_info()
|
terminal = await self.mt5.terminal_info()
|
||||||
if terminal is None:
|
if terminal is None:
|
||||||
self.data.fully_loaded = False
|
self.data.fully_loaded = False
|
||||||
@@ -133,7 +198,6 @@ class GetData:
|
|||||||
self.data.set_attrs(terminal=terminal)
|
self.data.set_attrs(terminal=terminal)
|
||||||
|
|
||||||
async def get_version(self):
|
async def get_version(self):
|
||||||
""""""
|
|
||||||
version = await self.mt5.version()
|
version = await self.mt5.version()
|
||||||
if version is None:
|
if version is None:
|
||||||
self.data.fully_loaded = False
|
self.data.fully_loaded = False
|
||||||
@@ -142,7 +206,6 @@ class GetData:
|
|||||||
|
|
||||||
@backoff_decorator
|
@backoff_decorator
|
||||||
async def get_account_info(self):
|
async def get_account_info(self):
|
||||||
""""""
|
|
||||||
res = await self.mt5.account_info()
|
res = await self.mt5.account_info()
|
||||||
if res is None:
|
if res is None:
|
||||||
self.data.fully_loaded = False
|
self.data.fully_loaded = False
|
||||||
@@ -151,15 +214,14 @@ class GetData:
|
|||||||
self.data.set_attrs(account=res)
|
self.data.set_attrs(account=res)
|
||||||
|
|
||||||
async def get_symbols_info(self):
|
async def get_symbols_info(self):
|
||||||
""""""
|
[self.task_queue.add(item=QueueItem(self.get_symbol_info, symbol=symbol)) for symbol in self.symbols
|
||||||
[self.task_queue.add(item=QueueItem(self.get_symbol_info, symbol=symbol)) for symbol in self.symbols if self.data.symbols.get(symbol) is None]
|
if self.data.symbols.get(symbol) is None]
|
||||||
|
|
||||||
async def get_symbols_ticks(self):
|
async def get_symbols_ticks(self):
|
||||||
""""""
|
[self.task_queue.add(item=QueueItem(self.get_symbol_ticks, symbol=symbol)) for symbol in self.symbols if
|
||||||
[self.task_queue.add(item=QueueItem(self.get_symbol_ticks, symbol=symbol)) for symbol in self.symbols if self.data.ticks.get(symbol) is None]
|
self.data.ticks.get(symbol) is None]
|
||||||
|
|
||||||
async def get_symbols_rates(self):
|
async def get_symbols_rates(self):
|
||||||
""""""
|
|
||||||
[
|
[
|
||||||
self.task_queue.add(item=QueueItem(self.get_symbol_rates, symbol=symbol, timeframe=timeframe), priority=4)
|
self.task_queue.add(item=QueueItem(self.get_symbol_rates, symbol=symbol, timeframe=timeframe), priority=4)
|
||||||
for symbol in self.symbols
|
for symbol in self.symbols
|
||||||
@@ -169,7 +231,6 @@ class GetData:
|
|||||||
|
|
||||||
@backoff_decorator
|
@backoff_decorator
|
||||||
async def get_symbol_info(self, *, symbol: str):
|
async def get_symbol_info(self, *, symbol: str):
|
||||||
""""""
|
|
||||||
res = await self.mt5.symbol_info(symbol)
|
res = await self.mt5.symbol_info(symbol)
|
||||||
if res is None:
|
if res is None:
|
||||||
self.data.fully_loaded = False
|
self.data.fully_loaded = False
|
||||||
@@ -178,7 +239,6 @@ class GetData:
|
|||||||
|
|
||||||
@backoff_decorator
|
@backoff_decorator
|
||||||
async def get_symbol_ticks(self, *, symbol: str):
|
async def get_symbol_ticks(self, *, symbol: str):
|
||||||
""""""
|
|
||||||
res = await self.mt5.copy_ticks_range(symbol, self.start, self.end, MetaTrader5.COPY_TICKS_ALL)
|
res = await self.mt5.copy_ticks_range(symbol, self.start, self.end, MetaTrader5.COPY_TICKS_ALL)
|
||||||
if res is None:
|
if res is None:
|
||||||
self.data.fully_loaded = False
|
self.data.fully_loaded = False
|
||||||
@@ -187,7 +247,6 @@ class GetData:
|
|||||||
|
|
||||||
@backoff_decorator
|
@backoff_decorator
|
||||||
async def get_symbol_rates(self, *, symbol: str, timeframe: TimeFrame):
|
async def get_symbol_rates(self, *, symbol: str, timeframe: TimeFrame):
|
||||||
""""""
|
|
||||||
res = await self.mt5.copy_rates_range(symbol, timeframe, self.start, self.end)
|
res = await self.mt5.copy_rates_range(symbol, timeframe, self.start, self.end)
|
||||||
if res is None:
|
if res is None:
|
||||||
self.data.fully_loaded = False
|
self.data.fully_loaded = False
|
||||||
|
|||||||
@@ -10,6 +10,38 @@ TradeData = TypeVar("TradeData", bound=TradePosition | TradeOrder | TradeDeal)
|
|||||||
|
|
||||||
|
|
||||||
class TradeManager(Generic[TradeData]):
|
class TradeManager(Generic[TradeData]):
|
||||||
|
"""A generic class to manage trades data during a backtest. It is the parent class of the
|
||||||
|
PositionsManager, OrdersManager, and DealsManager. It implements some dict-like methods to manage the data.
|
||||||
|
It has a private attribute _data to store the data. It exposes the data through the values, keys, and items methods.
|
||||||
|
It also has a to_dict method to convert the data to a dictionary.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
_data (dict[int, TradeData]): The data to store the trades.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> manager = TradeManager()
|
||||||
|
>>> manager[123456] = TradePosition(ticket=123456, symbol="EURUSD", volume=0.1)
|
||||||
|
>>> manager.update(ticket=123456, symbol="EURUSD", volume=0.1)
|
||||||
|
>>> manager[123456]
|
||||||
|
TradePosition(ticket=123456, symbol='EURUSD', volume=0.1)
|
||||||
|
>>> manager.values()
|
||||||
|
(TradePosition(ticket=123456, symbol='EURUSD', volume=0.1),)
|
||||||
|
>>> manager.keys()
|
||||||
|
(123456,)
|
||||||
|
>>> manager.items()
|
||||||
|
((123456, TradePosition(ticket=123456, symbol='EURUSD', volume=0.1)),)
|
||||||
|
>>> manager.to_dict()
|
||||||
|
{123456: {'ticket': 123456, 'symbol': 'EURUSD', 'volume': 0.1}}
|
||||||
|
>>> pos = manager.get(123456)
|
||||||
|
>>> pos
|
||||||
|
TradePosition(ticket=123456, symbol='EURUSD', volume=0.1)
|
||||||
|
>>> pos in manager
|
||||||
|
True
|
||||||
|
>>> len(manager)
|
||||||
|
1
|
||||||
|
>>> pos in manager
|
||||||
|
False
|
||||||
|
"""
|
||||||
_data: dict[int, TradeData]
|
_data: dict[int, TradeData]
|
||||||
|
|
||||||
def __init__(self, *, data: dict = None):
|
def __init__(self, *, data: dict = None):
|
||||||
@@ -37,6 +69,12 @@ class TradeManager(Generic[TradeData]):
|
|||||||
return self._data.get(key, default)
|
return self._data.get(key, default)
|
||||||
|
|
||||||
def update(self, *, ticket: int, **kwargs):
|
def update(self, *, ticket: int, **kwargs):
|
||||||
|
"""Update the data of a trade. Given the ticket of the trade and the new data to update.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticket (int): The ticket of the trade to update.
|
||||||
|
**kwargs: The new data to update.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
res = self[ticket]
|
res = self[ticket]
|
||||||
klass = type(res)
|
klass = type(res)
|
||||||
@@ -49,24 +87,48 @@ class TradeManager(Generic[TradeData]):
|
|||||||
logger.error(f"Update Operation Failed: Could Not Find Ticket")
|
logger.error(f"Update Operation Failed: Could Not Find Ticket")
|
||||||
|
|
||||||
def values(self) -> tuple[TradeData, ...]:
|
def values(self) -> tuple[TradeData, ...]:
|
||||||
|
"""Returns the values of the data."""
|
||||||
return tuple(value for value in self._data.values())
|
return tuple(value for value in self._data.values())
|
||||||
|
|
||||||
def keys(self) -> tuple[int, ...]:
|
def keys(self) -> tuple[int, ...]:
|
||||||
|
"""Returns the keys of the data."""
|
||||||
return tuple(key for key in self._data.keys())
|
return tuple(key for key in self._data.keys())
|
||||||
|
|
||||||
def items(self) -> tuple[tuple[int, TradeData], ...]:
|
def items(self) -> tuple[tuple[int, TradeData], ...]:
|
||||||
|
"""Returns the items of the data."""
|
||||||
return tuple((key, value) for key, value in self._data.items())
|
return tuple((key, value) for key, value in self._data.items())
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
|
"""Convert the data to a dictionary."""
|
||||||
return {key: value._asdict() for key, value in self._data.items()}
|
return {key: value._asdict() for key, value in self._data.items()}
|
||||||
|
|
||||||
|
|
||||||
class PositionsManager(TradeManager):
|
class PositionsManager(TradeManager):
|
||||||
|
"""A class to manage the open positions during a backtest. It is a subclass of TradeManager. It has an additional
|
||||||
|
attribute _open_positions to store the open positions. It also has a margins attribute to store the margins of the
|
||||||
|
open positions. It overrides some methods of the TradeManager class to manage the open positions.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
_open_positions (set[int]): The open positions.
|
||||||
|
margins (dict[int, float]): The margins of the open positions.
|
||||||
|
"""
|
||||||
_data: dict[int, TradePosition]
|
_data: dict[int, TradePosition]
|
||||||
_open_positions: set[int]
|
_open_positions: set[int]
|
||||||
margins: dict[int, float]
|
margins: dict[int, float]
|
||||||
|
|
||||||
def __init__(self, *, data: dict = None, open_positions: set = None, margins: dict = None):
|
def __init__(self, *, data: dict = None, open_positions: set[int] = None, margins: dict = None):
|
||||||
|
"""Positions manager manages the open positions during a backtest. It is a subclass of TradeManager. It has an
|
||||||
|
additional attribute _open_positions to store the open positions. It also has a margins attribute to store the
|
||||||
|
margins of the open positions. It overrides some methods of the TradeManager class to manage the open positions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (dict, optional): The data to store the trades. This used for continuation of the backtesting, if it
|
||||||
|
was stopped with some open positions.
|
||||||
|
|
||||||
|
open_positions (set, optional): The open positions. Defaults to None.
|
||||||
|
|
||||||
|
margins (dict, optional): The margins of the open positions. Defaults to None.
|
||||||
|
"""
|
||||||
super().__init__(data=data)
|
super().__init__(data=data)
|
||||||
self._open_positions = open_positions or {trade.ticket for trade in self._data.values()}
|
self._open_positions = open_positions or {trade.ticket for trade in self._data.values()}
|
||||||
self.margins: dict[int, float] = margins or dict()
|
self.margins: dict[int, float] = margins or dict()
|
||||||
@@ -96,20 +158,54 @@ class PositionsManager(TradeManager):
|
|||||||
return sum(self.margins.values())
|
return sum(self.margins.values())
|
||||||
|
|
||||||
def close(self, *, ticket: int) -> bool:
|
def close(self, *, ticket: int) -> bool:
|
||||||
|
"""Close a position. Given the ticket of the position to close.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticket (int): The ticket of the position to close.
|
||||||
|
"""
|
||||||
is_open = ticket in self._open_positions
|
is_open = ticket in self._open_positions
|
||||||
self._open_positions.discard(ticket)
|
self._open_positions.discard(ticket)
|
||||||
return is_open
|
return is_open
|
||||||
|
|
||||||
def get_margin(self, *, ticket: int) -> float:
|
def get_margin(self, *, ticket: int) -> float:
|
||||||
|
"""Get the margin of a position. Given the ticket of the position.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticket (int): The ticket of the position.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: The margin of the position.
|
||||||
|
"""
|
||||||
return self.margins.get(ticket, 0.0)
|
return self.margins.get(ticket, 0.0)
|
||||||
|
|
||||||
def delete_margin(self, *, ticket: int):
|
def delete_margin(self, *, ticket: int):
|
||||||
|
"""Delete the margin of a position. Given the ticket of the position.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticket (int): The ticket of the position.
|
||||||
|
"""
|
||||||
return self.margins.pop(ticket, 0)
|
return self.margins.pop(ticket, 0)
|
||||||
|
|
||||||
def set_margin(self, *, ticket: int, margin: float):
|
def set_margin(self, *, ticket: int, margin: float):
|
||||||
|
"""Set the margin of a position. Given the ticket of the position and the margin.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticket (int): The ticket of the position.
|
||||||
|
margin (float): The margin of the position
|
||||||
|
"""
|
||||||
self.margins[ticket] = margin
|
self.margins[ticket] = margin
|
||||||
|
|
||||||
def positions_get(self, *, ticket: int = None, symbol: str = None, group: None = None) -> tuple[TradePosition, ...]:
|
def positions_get(self, *, ticket: int = None, symbol: str = None, group: None = None) -> tuple[TradePosition, ...]:
|
||||||
|
"""Get positions. Given the ticket, symbol, or group of the positions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticket (int): The ticket of the position.
|
||||||
|
symbol (str): The symbol of the position.
|
||||||
|
group (str): The group
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[TradePosition, ...]: The positions
|
||||||
|
"""
|
||||||
if ticket:
|
if ticket:
|
||||||
return tuple(position for position in self.open_positions if position.ticket == ticket)
|
return tuple(position for position in self.open_positions if position.ticket == ticket)
|
||||||
|
|
||||||
@@ -125,24 +221,58 @@ class PositionsManager(TradeManager):
|
|||||||
return tuple()
|
return tuple()
|
||||||
|
|
||||||
def positions_total(self) -> int:
|
def positions_total(self) -> int:
|
||||||
|
"""Get the total number of open positions.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The total number of open positions.
|
||||||
|
"""
|
||||||
return len(self._open_positions)
|
return len(self._open_positions)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def open_positions(self) -> tuple[TradePosition, ...]:
|
def open_positions(self) -> tuple[TradePosition, ...]:
|
||||||
|
"""Returns the open positions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tuple[TradePosition, ...]: The open positions.
|
||||||
|
"""
|
||||||
return tuple(position for position in self.values() if position.ticket in self._open_positions)
|
return tuple(position for position in self.values() if position.ticket in self._open_positions)
|
||||||
|
|
||||||
|
|
||||||
class OrdersManager(TradeManager):
|
class OrdersManager(TradeManager):
|
||||||
|
"""Managers orders data during a backtest. It is a subclass of TradeManager. It manages access to the historical
|
||||||
|
orders data
|
||||||
|
"""
|
||||||
_data = dict[int, TradeOrder]
|
_data = dict[int, TradeOrder]
|
||||||
|
|
||||||
def get_orders_range(self, *, date_from: float, date_to: float) -> tuple[TradeData, ...]:
|
def get_orders_range(self, *, date_from: float, date_to: float) -> tuple[TradeData, ...]:
|
||||||
|
"""Get orders within a date range. Given the start and end date of the range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_from (float): The start date of the range.
|
||||||
|
date_to (float): The end date of the range.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[TradeData, ...]: The orders within the date range.
|
||||||
|
"""
|
||||||
start = date_from.timestamp() if isinstance(date_from, datetime) else date_from
|
start = date_from.timestamp() if isinstance(date_from, datetime) else date_from
|
||||||
end = date_to.timestamp() if isinstance(date_to, datetime) else date_to
|
end = date_to.timestamp() if isinstance(date_to, datetime) else date_to
|
||||||
return tuple(order for order in self.values() if start <= order.time_setup <= end)
|
return tuple(order for order in self.values() if start <= order.time_setup <= end)
|
||||||
|
|
||||||
def history_orders_get(
|
def history_orders_get(self, *, date_from: float | datetime = None, date_to: float | datetime = None,
|
||||||
self, *, date_from: float | datetime = None, date_to: float | datetime = None, group: str = "", ticket: int = None, position: int = None
|
group: str = "", ticket: int = None, position: int = None) -> tuple[TradeOrder, ...]:
|
||||||
) -> tuple[TradeOrder, ...]:
|
"""Get historical orders. Given the start and end date of the range, the group, ticket, or position of the
|
||||||
|
orders.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_from (float, datetime): The start date of the range.
|
||||||
|
date_to (float, datetime): The end date of the range.
|
||||||
|
group (str): The group of the orders.
|
||||||
|
ticket (int): The ticket of the order.
|
||||||
|
position (int): The position of the order.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[TradeOrder, ...]: The historical orders.
|
||||||
|
"""
|
||||||
if date_from and date_to:
|
if date_from and date_to:
|
||||||
orders = self.get_orders_range(date_from=date_from, date_to=date_to)
|
orders = self.get_orders_range(date_from=date_from, date_to=date_to)
|
||||||
if group:
|
if group:
|
||||||
@@ -158,6 +288,12 @@ class OrdersManager(TradeManager):
|
|||||||
return ()
|
return ()
|
||||||
|
|
||||||
def history_orders_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
def history_orders_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
||||||
|
"""Get the total number of historical orders. Given the start and end date of the range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_from (datetime, float): The start date of the range.
|
||||||
|
date_to (datetime, float): The end date of the range.
|
||||||
|
"""
|
||||||
return len(self.get_orders_range(date_from=date_from, date_to=date_to))
|
return len(self.get_orders_range(date_from=date_from, date_to=date_to))
|
||||||
|
|
||||||
|
|
||||||
@@ -165,13 +301,30 @@ class DealsManager(TradeManager):
|
|||||||
_data = dict[int, TradeDeal]
|
_data = dict[int, TradeDeal]
|
||||||
|
|
||||||
def get_deals_range(self, *, date_from: float, date_to: float) -> tuple[TradeData, ...]:
|
def get_deals_range(self, *, date_from: float, date_to: float) -> tuple[TradeData, ...]:
|
||||||
|
"""Get deals within a date range. Given the start and end date of the range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_from (float): The start date of the range.
|
||||||
|
date_to (float): The end date of the range.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[TradeData, ...]: The deals within the date range.
|
||||||
|
"""
|
||||||
start = date_from.timestamp() if isinstance(date_from, datetime) else date_from
|
start = date_from.timestamp() if isinstance(date_from, datetime) else date_from
|
||||||
end = date_to.timestamp() if isinstance(date_to, datetime) else date_to
|
end = date_to.timestamp() if isinstance(date_to, datetime) else date_to
|
||||||
return tuple(deal for deal in self.values() if start <= deal.time <= end)
|
return tuple(deal for deal in self.values() if start <= deal.time <= end)
|
||||||
|
|
||||||
def history_deals_get(
|
def history_deals_get(self, *, date_from: float | datetime = None, date_to: float | datetime = None,
|
||||||
self, *, date_from: float | datetime = None, date_to: float | datetime = None, group: str = "", ticket: int = None, position: int = None
|
group: str = "", ticket: int = None, position: int = None) -> tuple[TradeDeal, ...]:
|
||||||
) -> tuple[TradeDeal, ...]:
|
"""History deals get. Given the start and end date of the range, the group, ticket, or position of the deals.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_from (float, datetime): The start date of the range.
|
||||||
|
date_to (float, datetime): The end date of the range.
|
||||||
|
group (str): The group of the deals.
|
||||||
|
ticket (int): The ticket of the deal.
|
||||||
|
position (int): The position of the deal.
|
||||||
|
"""
|
||||||
if date_from and date_to:
|
if date_from and date_to:
|
||||||
deals = self.get_deals_range(date_from=date_from, date_to=date_to)
|
deals = self.get_deals_range(date_from=date_from, date_to=date_to)
|
||||||
if group:
|
if group:
|
||||||
@@ -187,4 +340,13 @@ class DealsManager(TradeManager):
|
|||||||
return ()
|
return ()
|
||||||
|
|
||||||
def history_deals_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
def history_deals_total(self, *, date_from: datetime | float, date_to: datetime | float) -> int:
|
||||||
|
"""Get the total number of historical deals. Given the start and end date of the range
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_from (datetime, float): The start date of the range.
|
||||||
|
date_to (datetime, float): The end date of the range.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The total number of historical deals.
|
||||||
|
"""
|
||||||
return len(self.get_deals_range(date_from=date_from, date_to=date_to))
|
return len(self.get_deals_range(date_from=date_from, date_to=date_to))
|
||||||
|
|||||||
+16
-7
@@ -12,10 +12,16 @@ logger = getLogger(__name__)
|
|||||||
class Base:
|
class Base:
|
||||||
"""A base class for all data structure classes in the aiomql package. This class provides a set of common methods
|
"""A base class for all data structure classes in the aiomql package. This class provides a set of common methods
|
||||||
and attributes for handling data.
|
and attributes for handling data.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
exclude (set[str]): A set of attributes to be excluded when retrieving attributes
|
||||||
|
using the get_dict and dict method.
|
||||||
|
include (set [str]): A set of attributes to be included when retrieving attributes
|
||||||
|
using the get_dict and dict method.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
exclude: set
|
exclude: set[str]
|
||||||
include: set
|
include: set[str]
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
@@ -74,12 +80,12 @@ class Base:
|
|||||||
annots |= getattr(base, "__annotations__", {})
|
annots |= getattr(base, "__annotations__", {})
|
||||||
return annots
|
return annots
|
||||||
|
|
||||||
def get_dict(self, exclude: set = None, include: set = None) -> dict:
|
def get_dict(self, exclude: set[str] = None, include: set[str] = None) -> dict:
|
||||||
"""Returns class attributes as a dict, with the ability to filter
|
"""Returns class attributes as a dict, with the ability to filter out specific attributes
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
exclude: A set of attributes to be excluded
|
exclude (set[str]): A set of attributes to be excluded
|
||||||
include: Specific attributes to be returned
|
include (set[str]): Specific attributes to be returned
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary of specified class attributes
|
dict: A dictionary of specified class attributes
|
||||||
@@ -120,6 +126,9 @@ class Base:
|
|||||||
|
|
||||||
|
|
||||||
class _Base(Base):
|
class _Base(Base):
|
||||||
|
"""Base class that provides access to the MetaTrader and Config classes as well as the MetaBackTester class for
|
||||||
|
backtesting mode.
|
||||||
|
"""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.config = Config()
|
self.config = Config()
|
||||||
self.mt5 = MetaTrader() if self.config.mode != "backtest" else MetaBackTester()
|
self.mt5 = MetaTrader() if self.config.mode != "backtest" else MetaBackTester()
|
||||||
|
|||||||
+29
-24
@@ -1,4 +1,3 @@
|
|||||||
import inspect
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterator, Literal, TypeVar, Self
|
from typing import Iterator, Literal, TypeVar, Self
|
||||||
@@ -12,28 +11,32 @@ Bot = TypeVar("Bot")
|
|||||||
BackTestEngine = TypeVar("BackTestEngine")
|
BackTestEngine = TypeVar("BackTestEngine")
|
||||||
|
|
||||||
|
|
||||||
def func():
|
|
||||||
stack = inspect.stack()
|
|
||||||
calling_context = next(context for context in stack if context.filename != __file__)
|
|
||||||
print(calling_context.filename)
|
|
||||||
return calling_context.filename
|
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
"""A class for handling configuration settings for the aiomql package.
|
"""A class for handling configuration settings for the aiomql package.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
record_trades (bool): Whether to keep record of trades or not.
|
login (int): The account login number
|
||||||
trade_record_mode: How to save trade, json or csv. Defaults to json
|
trade_record_mode (Literal["csv", "json"]): The mode for recording trades
|
||||||
filename (str): Name of the config file
|
password (str): The account password
|
||||||
records_dir (str): Path to the directory where trade records are saved
|
server (str): The account server
|
||||||
login (int): Trading account number
|
path (str | Path): The path to the terminal
|
||||||
password (str): Trading account password
|
timeout (int): The timeout argument for the terminal
|
||||||
server (str): Broker server
|
filename (str): The filename of the config file
|
||||||
path (str): Path to terminal file
|
state (dict): The
|
||||||
timeout (int): Timeout for terminal connection
|
root (Path): The root directory of the project
|
||||||
state (dict): A global state dictionary for storing data across the framework
|
record_trades (bool): To record trades or not. Default is True
|
||||||
root (Path): Root directory of the project
|
records_dir (Path): The directory to store trade records, relative to the root directory
|
||||||
|
records_dir_name (str): The name of the trade records directory
|
||||||
|
backtest_dir (Path): The directory to store backtest results, relative to the root directory
|
||||||
|
backtest_dir_name (str): The name of the backtest directory
|
||||||
|
task_queue (TaskQueue): The TaskQueue object for handling background tasks
|
||||||
|
_backtest_engine (BackTestEngine): The backtest engine object
|
||||||
|
bot (Bot): The bot object
|
||||||
|
_instance (Self): The instance of the Config class
|
||||||
|
mode (Literal["backtest", "live"]): The trading mode, either backtest or live, default is live
|
||||||
|
use_terminal_for_backtesting (bool): Use the terminal for backtesting, default is True
|
||||||
|
shutdown (bool): A signal to shut down the terminal, default is False
|
||||||
|
force_shutdown (bool): A signal to force shut down the terminal, default is False
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
By default, the config class looks for a file named aiomql.json.
|
By default, the config class looks for a file named aiomql.json.
|
||||||
@@ -41,7 +44,6 @@ class Config:
|
|||||||
or the load_config method.
|
or the load_config method.
|
||||||
By passing reload=True to the load_config method, you can reload and search again for the config file.
|
By passing reload=True to the load_config method, you can reload and search again for the config file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
login: int
|
login: int
|
||||||
trade_record_mode: Literal["csv", "json"]
|
trade_record_mode: Literal["csv", "json"]
|
||||||
password: str
|
password: str
|
||||||
@@ -93,6 +95,7 @@ class Config:
|
|||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
"""Initialize the Config object. The root directory can be set here or in the load_config method."""
|
||||||
root = kwargs.pop("root", None)
|
root = kwargs.pop("root", None)
|
||||||
if root is not None:
|
if root is not None:
|
||||||
self.load_config(root=root, **kwargs)
|
self.load_config(root=root, **kwargs)
|
||||||
@@ -101,16 +104,18 @@ class Config:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def backtest_engine(self):
|
def backtest_engine(self):
|
||||||
|
"""Returns the backtest engine object"""
|
||||||
return self._backtest_engine
|
return self._backtest_engine
|
||||||
|
|
||||||
@backtest_engine.setter
|
@backtest_engine.setter
|
||||||
def backtest_engine(self, value: BackTestEngine):
|
def backtest_engine(self, value: BackTestEngine):
|
||||||
|
"""Set the backtest engine object"""
|
||||||
self._backtest_engine = value
|
self._backtest_engine = value
|
||||||
|
|
||||||
def set_attributes(self, **kwargs):
|
def set_attributes(self, **kwargs):
|
||||||
"""Set keyword arguments as object attributes, The root folder attribute can't be set here.
|
"""Set keyword arguments as object attributes, The root folder attribute can't be set here.
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
**kwargs: Object attributes and values as keyword arguments
|
**kwargs: Object attributes and values as keyword arguments
|
||||||
"""
|
"""
|
||||||
if kwargs.pop("root", None) is not None:
|
if kwargs.pop("root", None) is not None:
|
||||||
@@ -146,11 +151,11 @@ class Config:
|
|||||||
def load_config(self, *, file: str | Path = None, filename: str = None, root: str | Path = None, **kwargs) -> Self:
|
def load_config(self, *, file: str | Path = None, filename: str = None, root: str | Path = None, **kwargs) -> Self:
|
||||||
"""Load configuration settings from a file.
|
"""Load configuration settings from a file.
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
file (str | Path): The absolute path to the config file.
|
file (str | Path): The absolute path to the config file.
|
||||||
filename (str): The name of the file to load if file path is not specified. If not provided aiomql.json is used
|
filename (str): The name of the file to load if file path is not specified. If not provided aiomql.json is used
|
||||||
root (str): The root directory of the project.
|
root (str): The root directory of the project.
|
||||||
kwargs: Additional keyword arguments to set as object attributes.
|
**kwargs: Additional keyword arguments to be set on the config object.
|
||||||
"""
|
"""
|
||||||
if root is not None:
|
if root is not None:
|
||||||
root = Path(root).resolve()
|
root = Path(root).resolve()
|
||||||
@@ -197,6 +202,6 @@ class Config:
|
|||||||
"""Returns Account login details as found in the config object if available
|
"""Returns Account login details as found in the config object if available
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary of login details
|
dict[str, int | str]: A dictionary of login details
|
||||||
"""
|
"""
|
||||||
return {"login": self.login, "password": self.password, "server": self.server}
|
return {"login": self.login, "password": self.password, "server": self.server}
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ BackTestEngine = TypeVar("BackTestEngine")
|
|||||||
|
|
||||||
|
|
||||||
class MetaBackTester(MetaTrader):
|
class MetaBackTester(MetaTrader):
|
||||||
"""A class for testing trading strategies in the MetaTrader 5 terminal. A subclass of MetaTrader."""
|
"""A class for testing trading strategies in the MetaTrader 5 terminal. A subclass of MetaTrader.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
backtest_engine (BackTestEngine): The backtesting engine to use for testing trading strategies.
|
||||||
|
"""
|
||||||
|
|
||||||
backtest_engine: BackTestEngine
|
backtest_engine: BackTestEngine
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from typing import Literal
|
from typing import Literal, Self
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -23,7 +23,7 @@ class MetaTrader(MetaCore):
|
|||||||
self.config = Config()
|
self.config = Config()
|
||||||
self.error: Error = Error(1)
|
self.error: Error = Error(1)
|
||||||
|
|
||||||
async def __aenter__(self) -> "MetaTrader":
|
async def __aenter__(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Async context manager entry point.
|
Async context manager entry point.
|
||||||
Initializes the connection to the MetaTrader terminal.
|
Initializes the connection to the MetaTrader terminal.
|
||||||
|
|||||||
@@ -26,25 +26,40 @@ class QueueItem:
|
|||||||
try:
|
try:
|
||||||
if asyncio.iscoroutinefunction(self.task_item):
|
if asyncio.iscoroutinefunction(self.task_item):
|
||||||
await self.task_item(*self.args, **self.kwargs)
|
await self.task_item(*self.args, **self.kwargs)
|
||||||
|
|
||||||
else:
|
|
||||||
self.task_item(*self.args, **self.kwargs)
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Error {err} occurred in {self.task_item.__name__} with args {self.args} and kwargs {self.kwargs}")
|
logger.error(f"Error {err} occurred in {self.task_item.__name__} with args {self.args} and kwargs"
|
||||||
|
f" {self.kwargs}")
|
||||||
|
|
||||||
|
|
||||||
class TaskQueue:
|
class TaskQueue:
|
||||||
def __init__(
|
"""TaskQueue is a class that allows you to queue tasks and run them concurrently with a specified number of workers.
|
||||||
self,
|
|
||||||
size: int = 0,
|
Attributes:
|
||||||
workers: int = 10,
|
- `workers` (int): The number of workers to run concurrently. Default is 10.
|
||||||
timeout: int = None,
|
|
||||||
queue: asyncio.Queue = None,
|
- `timeout` (int): The maximum time to wait for the queue to complete. Default is None. If timeout is provided
|
||||||
on_exit: Literal["cancel", "complete_priority"] = "complete_priority",
|
the queue is joined using `asyncio.wait_for` with the timeout.
|
||||||
mode: Literal["finite", "infinite"] = "infinite",
|
|
||||||
worker_timeout: int = 60,
|
- `queue` (asyncio.Queue): The queue to store the tasks. Default is `asyncio.PriorityQueue` with no size limit.
|
||||||
):
|
|
||||||
|
- `on_exit` (Literal["cancel", "complete_priority"]): The action to take when the queue is stopped.
|
||||||
|
|
||||||
|
- `mode` (Literal["finite", "infinite"]): The mode of the queue. If `finite` the queue will stop when all tasks
|
||||||
|
are completed. If `infinite` the queue will continue to run until stopped.
|
||||||
|
|
||||||
|
- `worker_timeout` (int): The time to wait for a task to be added to the queue before stopping the worker or
|
||||||
|
adding a dummy sleep task to the queue.
|
||||||
|
|
||||||
|
- `stop` (bool): A flag to stop the queue instance.
|
||||||
|
|
||||||
|
- `tasks` (list): A list of the worker tasks running concurrently, including the main task that joins the queue.
|
||||||
|
|
||||||
|
- `priority_tasks` (set): A set to store the QueueItems that must complete before the queue stops.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, size: int = 0, workers: int = 10, timeout: int = None, queue: asyncio.Queue = None,
|
||||||
|
on_exit: Literal["cancel", "complete_priority"] = "complete_priority",
|
||||||
|
mode: Literal["finite", "infinite"] = "infinite", worker_timeout: int = 60):
|
||||||
self.queue = queue or asyncio.PriorityQueue(maxsize=size)
|
self.queue = queue or asyncio.PriorityQueue(maxsize=size)
|
||||||
self.workers = workers
|
self.workers = workers
|
||||||
self.tasks = []
|
self.tasks = []
|
||||||
@@ -55,7 +70,14 @@ class TaskQueue:
|
|||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.worker_timeout = worker_timeout
|
self.worker_timeout = worker_timeout
|
||||||
|
|
||||||
def add(self, *, item: QueueItem, priority=3, must_complete=False):
|
def add(self, *, item: QueueItem, priority: int = 3, must_complete: bool = False):
|
||||||
|
"""Add a task to the queue.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item (QueueItem): The task to add to the queue.
|
||||||
|
priority (int): The priority of the task. Default is 3.
|
||||||
|
must_complete (bool): A flag to indicate if the task must complete before the queue stops. Default is False.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if self.stop:
|
if self.stop:
|
||||||
return
|
return
|
||||||
@@ -67,6 +89,9 @@ class TaskQueue:
|
|||||||
except asyncio.QueueFull:
|
except asyncio.QueueFull:
|
||||||
logger.error("Queue is full")
|
logger.error("Queue is full")
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
logger.error("%s: Error occurred in %s.add", err, self.__class__.__name__)
|
||||||
|
|
||||||
async def worker(self):
|
async def worker(self):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -98,7 +123,7 @@ class TaskQueue:
|
|||||||
await asyncio.sleep(self.worker_timeout)
|
await asyncio.sleep(self.worker_timeout)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error("%s: Error occurred in worker", err)
|
logger.error("%s: Error occurred in %s worker", err, self.__class__.__name__)
|
||||||
|
|
||||||
async def run(self, timeout: int = 0):
|
async def run(self, timeout: int = 0):
|
||||||
start = time.perf_counter()
|
start = time.perf_counter()
|
||||||
@@ -145,7 +170,7 @@ class TaskQueue:
|
|||||||
...
|
...
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"%s: Error occurred in %s.clean_up", err, self.__class__.__name__)
|
logger.error("%s: Error occurred in %s.clean_up", err, self.__class__.__name__)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.cancel()
|
self.cancel()
|
||||||
|
|||||||
@@ -194,10 +194,10 @@ class Candles:
|
|||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data.index)
|
return len(self._data.index)
|
||||||
|
|
||||||
def __contains__(self, item: Self):
|
def __contains__(self, item: Candle):
|
||||||
return item.time == self[item.Index].time
|
return item.time == self[item.Index].time
|
||||||
|
|
||||||
def __getitem__(self, index) -> Self | Self | Series:
|
def __getitem__(self, index: slice | int | str) -> Self | Series | Candle:
|
||||||
if isinstance(index, slice):
|
if isinstance(index, slice):
|
||||||
cls = self.__class__
|
cls = self.__class__
|
||||||
data = self._data.iloc[index]
|
data = self._data.iloc[index]
|
||||||
|
|||||||
Reference in New Issue
Block a user