This commit is contained in:
Ichinga Samuel
2023-10-16 15:36:31 +01:00
parent 027f9fd8de
commit e285610fe5
22 changed files with 849 additions and 817 deletions
+2
View File
@@ -16,6 +16,7 @@ pip install aiomql
- Record and keep track of trades and strategies in csv files.
- Utility classes for using the MetaTrader 5 Library
- Sample Pre-Built strategies
- Trade sessions for managing trading sessions
## Simple Usage as an asynchronous MetaTrader5 Libray
```python
@@ -60,6 +61,7 @@ bot.add_strategy(ft_eur_usd)
bot.execute()
```
## API Documentation
<a id="aiomql"></a>
# aiomql
+14 -30
View File
@@ -5,14 +5,13 @@ class Account(AccountInfo)
```
Singleton class for managing a trading account. A subclass of [AccountInfo](#accountinfo). All AccountInfo attributes are available in this class.
**Attributes**
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**connected**|**bool**|Status of connection to MetaTrader 5 Terminal|False|
|symbols|set[SymbolInfo]|A set of available symbols for the financial market.|set()|
**Notes**\
### Notes
Other Account properties are defined in the AccountInfo class.
### refresh
@@ -28,73 +27,58 @@ def account_info() -> dict
```
Get account login, server and password details. If the login attribute of the account instance returns
a falsy value, the config instance is used to get the account details.
**Returns**
#### Returns:
|Type|Description|
|---|---|
|**dict**|A dict of login, server and password details|
**Notes**\
#### Note:
This method will only look for config details in the config instance if the login attribute of the account Instance returns a falsy value
#### __aenter__
### __aenter__
```python
async def __aenter__() -> 'Account'
```
Connect to a trading account and return the account instance.
Async context manager for the Account class.
**Returns**
#### Returns:
|Type|Description|
|---|---|
|**Account**|An instance of the Account class|
**Raises**
#### Raises:
|Exception|Description|
|---|---|
|**LoginError**|If login fails|
#### sign_in
### sign_in
```python
async def sign_in() -> bool
```
Connect to a trading account.
**Returns**
#### Returns:
|Type|Description|
|---|---|
|**bool**|True if login was successful else False|
#### has_symbol
### has_symbol
```python
def has_symbol(symbol: str | Type[SymbolInfo])
```
Checks to see if a symbol is available for a trading account\
**Parameters**
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**symbol**|**str** or **SymbolInfo**|A symbol name or SymbolInfo instance|
**Returns**
#### Returns:
|Type|Description|
|---|---|
|**bool**|True if symbol is available else False|
#### symbols_get
### symbols_get
```python
async def symbols_get() -> set[SymbolInfo]
```
Get all financial instruments from the MetaTrader 5 terminal available for the current account.
**Returns**
#### Returns:
|Type|Description|
|---|---|
|**set[SymbolInfo]**|A set of SymbolInfo instances|
+32 -34
View File
@@ -4,104 +4,102 @@
class Bot()
```
The bot class. Create a bot instance to run your strategies.
**Attributes**
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**account**|**Account**|Account Object.|None|
|**executor**|**ThreadPoolExecutor**|The default thread executor.|None|
|**symbols**|**set[Symbols]**|A set of symbols for the trading session|set()|
### initialize
```python
async def initialize()
```
Prepares the bot by signing in to the trading account and initializing the symbols for the trading session.
*Raises*
#### Raises:
|Exception|Description|
|---|---|
|**SystemExit**|If sign in was not successful|
SystemExit if sign in was not successful
#### execute
### execute
```python
def execute()
```
Execute the bot.
#### start
Execute the bot. This method calls start internally. To enable you run your bot outside of an async function.
### start
```python
async def start()
```
Starts the bot by calling the initialize method and running the strategies in the executor.
#### add_strategy
### add_coroutine
```python
def add_coroutine(coro: Coroutine, **kwargs)
```
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**coro**|**Coroutine**|A coroutine to run in the executor|
### add_function
```python
def add_coroutine(func: Callable, **kwargs)
```
#### Arguments:
| Name | Type | Description |
|----------|--------------|-----------------------------------|
| **func** | **Callable** | A function to run in the executor |
### add_strategy
```python
def add_strategy(strategy: Strategy)
```
Add a strategy to the executor. An added strategy will only run if it's symbol was successfully initialized.
**Parameters**
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**strategy**|**Strategy**|A Strategy instance to run on bot|
#### add_strategies
### add_strategies
```python
def add_strategies(strategies: Iterable[Strategy])
```
Add multiple strategies at the same time
**Parameters**
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**strategies**|**Iterable[Strategy]**|An iterable of Strategy instances|
#### add_strategy_all
### add_strategy_all
```python
def add_strategy_all(*, strategy: Type[Strategy], params: dict | None = None)
```
Use this to run a single strategy on all available instruments in the market using the default parameters
i.e one set of parameters for all trading symbols
**Parameters**
#### Arguments
|Name|Type|Description|
|---|---|---|
|**strategy**|**Type[Strategy]**|A Strategy class|
|**params**|**dict** or **None**|A dictionary of parameters for the strategy|
#### init_symbols
### init_symbols
```python
async def init_symbols()
```
Initialize the symbols for the current trading session. This method is called internally by the bot.
#### init_symbol
### init_symbol
```python
async def init_symbol(symbol: Symbol) -> Symbol
```
Initialize a symbol before the beginning of a trading session.
Removes it from the list of symbols if it was not successfully initialized or not available
for the account.
**Parameters**
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**symbol**|**Symbol**|A Symbol instance|
*returns*
#### Returns:
|Type|Description|
|---|---|
|**Symbol**|A Symbol instance|
+12 -39
View File
@@ -1,16 +1,12 @@
## <a id="candle"></a> Candle
Candle and Candles classes for handling bars from the MetaTrader 5 terminal.
```python
class Candle
```
A class representing bars from the MetaTrader 5 terminal as a customized class analogous to Japanese Candlesticks.
You can subclass this class for added customization.
**Attributes**
### Attributes
|Name|Type|Description|
|---|---|---|
|**time**|**int**|Period start time|
@@ -28,9 +24,7 @@ You can subclass this class for added customization.
def __init__(**kwargs)
```
Create a Candle object from keyword arguments. Kwargs are set as instance attributes.
**Parameters**
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**kwargs**|**Any**|Candle attributes and values as keyword arguments.|
@@ -47,22 +41,17 @@ Set keyword arguments as instance attributes
def mid() -> float
```
The median of open and close
**returns**
#### Returns:
|Type|Description|
|---|---|
|**float**|The median of open and close|
### is_bullish
```python
def is_bullish() -> bool
```
A simple check to see if the candle is bullish.
**returns**
#### Returns:
|Type|Description|
|---|---|
|**bool**|True or False|
@@ -72,23 +61,17 @@ A simple check to see if the candle is bullish.
def is_bearish() -> bool
```
A simple check to see if the candle is bearish.
**returns**
#### Returns:
|Type|Description|
|---|---|
|bool|True or False|
## <a id="candles"></a> Candles
## <a id="candles"></a> Candles
```python
class Candles(Generic[_Candle])
```
An iterable container class of Candle objects in chronological order. A wrapper around Pandas DataFrame object.
**Attributes**
### Attributes:
|Name|Type|Description|
|---|---|---|
|**data**|**DataFrame**|A pandas DataFrame of all candles in the object.|
@@ -108,7 +91,6 @@ An iterable container class of Candle objects in chronological order. A wrapper
**Notes**: When subclassing this class make sure to Candle attribute is set to your desired candle class.
#### \_\_init\_\_
```python
def __init__(*,
data: DataFrame | _Candles | Iterable,
@@ -116,26 +98,21 @@ def __init__(*,
candle_class: Type[_Candle] = None)
```
A container class of Candle objects in chronological order.
**Arguments**:
#### Arguments:
|Name|Type|Description|Default|
|---|---|---|---|
|**data**|**DataFrame** or **Candles** or **Iterable**|A pandas dataframe, a Candles object or any suitable iterable|
|**flip**|**bool**|Reverse the chronological order of the candles to the oldest first.|False|
|**candle_class**|**Type[Candle]**|A subclass of Candle to use as the candle class.|Candle|
#### ta
```python
@property
def ta()
```
Access to the pandas_ta library for performing technical analysis on the underlying data attribute. Use this as you would use the pandas_ta library.
**returns**:
#### Returns:
|Type|Description|
|---|---|
|**pandas_ta**|The pandas_ta library|
@@ -148,8 +125,7 @@ def ta_lib()
Access to the ta library for performing technical analysis. Not dependent on the underlying data attribute. Use this for
functions that require pandas Series as input.
**returns**:
#### Returns:
|Type|Description|
|---|---|
|ta|The ta library|
@@ -166,16 +142,13 @@ A pandas DataFrame of all candles in the object.
def rename(inplace=True, **kwargs) -> _Candles | None
```
Rename columns of the candles class.
**Arguments**:
#### Arguments:
| Name | Type |Description|Default|
|---------|----------|---|---|
| inplace | **bool** |Rename the columns inplace or return a new instance of the class with the renamed columns|True|
| **kwargs** | **str** |The new names of the columns||
**returns**:
#### Returns:
|Type|Description|
|---|---|
|**Candles**|A new instance of the class with the renamed columns if inplace is False.|
-1
View File
@@ -20,7 +20,6 @@
```python
class Base()
```
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.
For the data model classes attributes are annotated on the class body and are set as object attributes when the
+21 -37
View File
@@ -1,93 +1,77 @@
## <a id="executor"></a> Executor
```python
class Executor
```
Executor class for running multiple strategies on multiple symbols concurrently.
**Attributes**:
### Attributes:
| Name | Type | Description | Default |
|----------------|---------------------|------------------------------------------------|----|
| **executor** |**ThreadPoolExecutor** | The default thread executor. |None|
| **workers** |**list** | List of strategies. |[]|
| **coroutines** |**dict** | Dictionary of coroutines and keyword arguments | {} |
| **functions** |**dict** | Dictionary of functions and keyword arguments | {} |
|Name| Type | Description | Default |
|---|---------------------|------------------------------------------------|----|
|**executor**|**ThreadPoolExecutor** | The default thread executor. |None|
|**workers**|**list** | List of strategies. |[]|
|**coros**|**dict** | Dictionary of coroutines and keyword arguments | {} |
|**funcs**|**dict** | Dictionary of functions and keyword arguments | {} |
#### add\_workers
### add\_workers
```python
def add_workers(strategies: Sequence[type(Strategy)])
```
Add multiple strategies at once
*Arguments*:
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**strategies**|**Sequence[type(Strategy)]**|A sequence of strategies.|
#### remove\_workers
### remove\_workers
```python
def remove_workers(*symbols: Sequence[Symbol])
```
Removes any worker running on a symbol not successfully initialized.
*Arguments*:
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**symbols**|**Sequence[Symbol]**|A sequence of symbols.|
#### add\_worker
### add\_worker
```python
def add_worker(strategy: type(Strategy))
```
Add a strategy instance to the list of workers
*Arguments*:
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**strategy**|**type(Strategy)**|A strategy instance.|
#### run
### run
```python
@staticmethod
def run(func: Callable|Coroutine, kwargs: dict)
```
Wrap the input coroutine function with 'asyncio.run' so that it can be executed in a threadpool executor.
*Arguments*
#### Arguments:
| Name | Type |Description|
|------------|------------|---|
| **func** | **Callable |Coroutine**|A coroutine function.|
| **kwargs** | **Dict** |Keyword arguments to pass to the function.|
#### trade
### trade
```python
def trade(strategy: Strategy)
```
Wrap the input coroutine function trade method of each strategy with 'asyncio.run'.
*Arguments*:
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**strategy**|**Strategy**|A strategy instance.|
#### execute
### execute
```python
async def execute(workers: int = 0)
```
Run the strategies with a threadpool executor.
*Arguments*:
#### Arguments:
|Name|Type|Description|
|---|---|---|
|**workers**|**int**|Number of workers to use in executor pool. Defaults to zero which uses all workers.|
**Notes**: No matter the number specified, the executor will always use a minimum of 5 workers.
#### Notes:
No matter the number specified, the executor will always use a minimum of 5 workers.
+24 -44
View File
@@ -6,71 +6,60 @@ class Order(TradeRequest)
```
Trade order related functions and properties. Subclass of [TradeRequest](#traderequest).
#### \_\_init\_\_
### \_\_init\_\_
```python
def __init__(**kwargs)
```
Initialize the order object with keyword arguments, symbol must be provided.
Provides default values for action, type_time and type_filling if not provided.
*Arguments*:
|Name|Type|Description|Default|
|---|---|---|---|
|**kwargs**|**kwargs**|Keyword arguments must match the attributes of TradeRequest as well as the attributes of Order class as specified in the annotations in the class definition.|None|
*Default Arguments*:
|Name|Type|Description|Default|
|---|---|---|---|
|**action**|**TradeAction**|Trade action|TradeAction.DEAL|
|**type_time**|**OrderTime**|Order time|OrderTime.DAY|
|**type_filling**|**OrderFilling**|Order filling|OrderFilling.FOK|
*Raises*:
#### Arguments:
|Name| Type | Description | Default |
|---|-------------------------|--------------|-------------------|
|**symbol**| **str** \| **Symbol** | Symbol name. Required keyword argument | |
|**action**| **TradeAction** | Trade action | TradeAction.DEAL |
|**type_time**| **OrderTime** | Order time | OrderTime.DAY |
|**type_filling**| **OrderFilling** | Order filling | OrderFilling.FOK |
#### Raises:
|Exception|Description|
|---|---|
|**SymbolError**|If symbol is not provided|
#### <a id=order.Order.orders_total> orders_total
### <a id=order.Order.orders_total> orders_total
```python
async def orders_total()
```
Get the number of active orders.
*returns*:
#### Returns:
|Type|Description|
|---|---|
|**int**|total number of active orders|
#### orders
### orders
```python
async def orders() -> tuple[TradeOrder]
```
Get the list of active orders for the current symbol.
*Returns*:
#### Returns:
|Type|Description|
|---|---|
|**tuple[TradeOrder]**|A Tuple of active trade orders as TradeOrder objects|
#### check
### check
```python
async def check() -> OrderCheckResult
```
Check funds sufficiency for performing a required trading operation and the possibility to execute it at
*returns*:
#### Returns::
|Type|Description|
|---|---|
|**OrderCheckResult**|An OrderCheckResult object|
*raises*:
#### Raises:
|Exception|Description|
|---|---|
@@ -84,51 +73,42 @@ async def send() -> OrderSendResult
```
Send a request to perform a trading operation from the terminal to the trade server.
*returns*:
#### Returns:
|Type|Description|
|---|---|
|**OrderSendResult**|An OrderSendResult object|
*raises*:
#### Raises:
|Exception|Description|
|---|---|
|**OrderError**|If not successful|
#### <a id="order.Order.calc_margin"></a> calc_margin
### calc_margin
```python
async def calc_margin() -> float
```
Return the required margin in the account currency to perform a specified trading operation.
*returns*:
#### Returns:
|Type|Description|
|---|---|
|**float**|Returns float value if successful|
*raises*:
#### Raises:
|Exception|Description|
|---|---|
|**OrderError**|If not successful|
#### <a id="order.Order.calc_profit"></a> calc_profit
### calc_profit
```python
async def calc_profit() -> float
```
Return profit in the account currency for a specified trading operation.
*returns*:
#### Returns:
|Type|Description|
|---|---|
|**float**|Returns float value if successful|
*raises*:
#### Raises:
|Exception|Description|
|---|---|
|**OrderError**|If not successful|
+169
View File
@@ -0,0 +1,169 @@
## <a id="sessions"></a> Sessions and Session
Sessions allow you to run code at specific times of the day.
```python
class Session()
```
A session is a time period between two datetime.time objects specified in utc.
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**start**|**datetime.time**|The start time of the session.|None|
|**end**|**datetime.time**|The end time of the session.|None|
|**on_start**|**str**|The action to take when the session starts. Default is None.|None|
|**on_end**|**str**|The action to take when the session ends. Default is None.|None|
|**custom_start**|**Callable**|A custom function to call when the session starts. Default is None.|None|
|**custom_end**|**Callable**|A custom function to call when the session ends. Default is None.|None|
### Methods:
|Name|Description|
|---|---|
|**begin**|Call the action specified in on_start or custom_start.|
|**close**|Call the action specified in on_end or custom_end.|
|**action**|Used by begin and close to call the action specified.|
|**delta**|Get the timedelta of a datetime.time object.|
|**until**|Get the seconds until the session starts from the current time.|
### \_\_init\_\_
```python
def __init__(*,
start: int | time,
end: int | time,
on_start: Literal['close_all', 'close_win', 'close_loss',
'custom_start'] = None,
on_end: Literal['close_all', 'close_win', 'close_loss',
'custom_end'] = None,
custom_start: Callable = None,
custom_end: Callable = None)
```
Create a session.
#### Arguments:
|Name| Type | Description | Default |
|---|-------------------------|--------------|-------------------|
|**start**| **int** \| **datetime.time** | The start time of the session in UTC. | None |
|**end**| **int** \| **datetime.time** | The end time of the session in UTC. | None |
|**on_start**| **Literal['close_all', 'close_win', 'close_loss', 'custom_start']** | The action to take when the session starts. Default is None. | None |
|**on_end**| **Literal['close_all', 'close_win', 'close_loss', 'custom_end']** | The action to take when the session ends. Default is None. | None |
|**custom_start**| **Callable** | A custom function to call when the session starts. Default is None. | None |
|**custom_end**| **Callable** | A custom function to call when the session ends. Default is None. | None |
### begin
```python
async def begin()
```
Call the action specified in on_start or custom_start.
### close
```python
async def close()
```
Call the action specified in on_end or custom_end.
### action
```python
async def action(action)
```
Used by begin and close to call the action specified.
#### Arguments:
|Name| Type | Description | Default |
|---|-------------------------|--------------|-------------------|
|**action**| **Literal['close_all', 'close_win', 'close_loss', 'custom_start', 'custom_end']** | The action to take. | None |
### delta
```python
@staticmethod
def delta(obj: time)
```
Get the timedelta of a datetime.time object.
#### Arguments:
|Name| Type | Description | Default |
|---|-------------------------|--------------|-------------------|
|**obj**| **datetime.time** | A datetime.time object. | None |
#### Returns:
|Type|Description|
|---|---|
|**timedelta**|A timedelta object.|
### until
```python
def until()
```
Get the seconds until the session starts from the current time.
#### Returns:
|Type|Description|
|---|---|
|**int**|The seconds until the session starts.|
## Sessions
```python
class Sessions()
```
Sessions allow you to run code at specific times of the day. It is a collection of Session objects.
Sessions are sorted by start time. The sessions object is an asynchronous context manager.
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**sessions**|**list[Session]**|A list of Session objects.|[]|
|**current_session**|**Session**|The current session.|None|
### Methods:
|Name|Description|
|---|---|
|**add**|Add a Session object to the sessions list.|
|**remove**|Remove a Session object from the sessions list.|
|**find**|Find a session that contains a datetime.time object.|
|**find_next**|Find the next session that contains a datetime.time object.|
|**check**|Check if the current session has started and if not, wait until it starts.|
#### \_\_init\_\_
```python
def __init__(*sessions)
```
Create a Sessions object.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**sessions**| **tuple[Session]** | A tuple of Session objects. | None |
### find
```python
def find(obj: time) -> Session | None
```
Find a session that contains a datetime.time object.
#### Arguments:
|Name| Type | Description | Default |
|---|-------------------------|--------------|-------------------|
|**obj**| **datetime.time** | A datetime.time object. | None |
#### Returns:
|Type|Description|
|---|---|
|**Session**|A Session object or None if not found.|
### find\_next
```python
def find_next(obj: time) -> Session
```
Find the next session that contains a datetime.time object.
#### Arguments:
|Name| Type | Description | Default |
|---|-------------------------|--------------|-------------------|
|**obj**| **datetime.time** | A datetime.time object. | None |
#### Returns:
|Type|Description|
|---|---|
|**Session**|A Session object.|
### check
```python
async def check()
```
Check if the current session has started and if not, wait until it starts.
+27 -52
View File
@@ -1,77 +1,52 @@
<a id="aiomql.strategy"></a>
# aiomql.strategy
## <a id="strategy"></a> Strategy
The base class for creating strategies.
<a id="aiomql.strategy.Strategy"></a>
## Strategy Objects
```python
class Strategy(ABC)
```
The base class for creating strategies.
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**name**|**str**|A name for the strategy.|None|
|**account**|**Account**|Account instance.|None|
|**mt5**|**MetaTrader**|MetaTrader instance.|None|
|**config**|**Config**|Config instance.|None|
|**symbol**|**Symbol**|The Financial Instrument as a Symbol Object|None|
|**parameters**|**Dict**|A dictionary of parameters for the strategy.|None|
**Attributes**:
- `symbol` _Symbol_ - The Financial Instrument as a Symbol Object
- `parameters` _Dict_ - A dictionary of parameters for the strategy.
Class Attributes:
- `name` _str_ - A name for the strategy.
- `account` _Account_ - Account instance.
- `mt5` _MetaTrader_ - MetaTrader instance.
- `config` _Config_ - Config instance.
**Notes**:
Define the name of a strategy as a class attribute. If not provided, the class name will be used as the name.
<a id="aiomql.strategy.Strategy.__init__"></a>
#### \_\_init\_\_
### Notes:
Define the name of a strategy as a class attribute. If not provided, the class name will be used as the name.
### \_\_init\_\_
```python
def __init__(*, symbol: Symbol, params: dict = None)
def __init__(*, symbol: Symbol, params: dict = None, sessions: Sessions)
```
Initiate the parameters dict and add name and symbol fields. Use class name as strategy name if name is not provided.
### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**symbol**| **Symbol** | The Financial instrument | None |
|**params**| **Dict** | Trading strategy parameters | None |
|**sessions**| **Sessions** | Trading sessions | None |
Initiate the parameters dict and add name and symbol fields.
Use class name as strategy name if name is not provided
**Arguments**:
- `symbol` _Symbol_ - The Financial instrument
- `params` _Dict_ - Trading strategy parameters
<a id="aiomql.strategy.Strategy.sleep"></a>
#### sleep
### sleep
```python
@staticmethod
async def sleep(secs: float)
```
Sleep for the needed amount of seconds in between requests to the terminal.
computes the accurate amount of time needed to sleep ensuring that the next request is made at the start of
a new bar and making cooperative multitasking possible.
**Arguments**:
- `secs` _float_ - The time in seconds. Usually the timeframe you are trading on.
<a id="aiomql.strategy.Strategy.trade"></a>
#### trade
### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**secs**| **float** | The time in seconds. Usually the timeframe you are trading on. | None |
### trade
```python
@abstractmethod
async def trade()
```
Place trades using this method. This is the main method of the strategy.
It will be called by the strategy runner.
+190 -263
View File
@@ -1,383 +1,310 @@
<a id="aiomql.symbol"></a>
# aiomql.symbol
## <a id="symbol"></a> Symbol
Symbol class for handling a financial instrument.
<a id="aiomql.symbol.Symbol"></a>
## Symbol Objects
```python
class Symbol(SymbolInfo)
```
Main class for handling a financial instrument. A subclass of SymbolInfo and Base it has attributes and methods
for working with a financial instrument.
**Attributes**:
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**name**|**str**|The name of the symbol.|None|
|**mt5**|**MetaTrader**|MetaTrader instance.|None|
|**config**|**Config**|Config instance.|None|
|**account**|**Account**|Account instance.|None|
|**tick**|**Tick**|The current price tick of the symbol.|None|
- `tick` _Tick_ - Price tick object for instrument
- `account` - An instance of the current trading account
### Methods:
|Name|Description|
|---|---|
|**pip**|Returns the pip value of the symbol. This is ten times the point value for forex symbols.|
|**info_tick**|Get the current price tick of a financial instrument.|
|**symbol_select**|Select a symbol in the MarketWatch window or remove a symbol from the window.|
|**info**|Get data on the specified financial instrument and update the symbol object properties.|
|**init**|Initialized the symbol by pulling properties from the terminal.|
|**book_add**|Subscribes the MetaTrader 5 terminal to the Market Depth change events for a specified symbol.|
|**book_get**|Returns a tuple of BookInfo featuring Market Depth entries for the specified symbol.|
|**book_release**|Cancels subscription of the MetaTrader 5 terminal to the Market Depth change events for a specified symbol.|
|**compute_volume**|Computes the volume of a trade based on the amount and the number of pips to target.|
|**currency_conversion**|Convert from one currency to the other.|
|**copy_rates_from**|Get bars from the MetaTrader 5 terminal starting from the specified date.|
|**copy_rates_from_pos**|Get bars from the MetaTrader 5 terminal starting from the specified index.|
|**copy_rates_range**|Get bars in the specified date range from the MetaTrader 5 terminal.|
|**copy_ticks_from**|Get ticks from the MetaTrader 5 terminal starting from the specified date.|
|**copy_ticks_range**|Get ticks for the specified date range from the MetaTrader 5 terminal.|
**Notes**:
Full properties are on the SymbolInfo Object.
Make sure Symbol is always initialized with a name argument
### Notes:
Full properties are on the SymbolInfo Object.
Make sure Symbol is always initialized with a name argument
<a id="aiomql.symbol.Symbol.pip"></a>
#### pip
### pip
```python
@property
def pip()
```
Returns the pip value of the symbol. This is ten times the point value for forex symbols.
**Returns**:
- `float` - The pip value of the symbol.
<a id="aiomql.symbol.Symbol.info_tick"></a>
#### info\_tick
## Returns:
|Type|Description|
|---|---|
|**float**|The pip value of the symbol.|
### info\_tick
```python
async def info_tick(*, name: str = "") -> Tick
```
Get the current price tick of a financial instrument.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**name**| **str** | The name of the symbol. | None |
**Arguments**:
- `name` - if name is supplied get price tick of that financial instrument
#### Returns:
|Type|Description|
|---|---|
|**Tick**|Return a Tick Object|
**Returns**:
- `Tick` - Return a Tick Object
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.symbol_select"></a>
#### symbol\_select
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
### symbol\_select
```python
async def symbol_select(*, enable: bool = True) -> bool
```
Select a symbol in the MarketWatch window or remove a symbol from the window.
Update the select property
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**enable**| **bool** | Switch. Optional unnamed parameter. If 'false', a symbol should be removed from the MarketWatch window. | None |
**Arguments**:
- `enable` _bool_ - Switch. Optional unnamed parameter. If 'false', a symbol should be removed from
the MarketWatch window.
**Returns**:
- `bool` - True if successful, otherwise False.
<a id="aiomql.symbol.Symbol.info"></a>
#### info
#### Returns:
|Type|Description|
|---|---|
|**bool**|True if successful, otherwise False.|
### info
```python
async def info() -> SymbolInfo
```
Get data on the specified financial instrument and update the symbol object properties
**Returns**:
#### Returns:
|Type|Description|
|---|---|
|**SymbolInfo**|SymbolInfo if successful|
- `(SymbolInfo)` - SymbolInfo if successful
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.init"></a>
#### init
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
### init
```python
async def init() -> bool
```
Initialized the symbol by pulling properties from the terminal
#### Returns:
|Type|Description|
|---|---|
|**bool**|Returns True if symbol info was successful initialized|
**Returns**:
- `bool` - Returns True if symbol info was successful initialized
<a id="aiomql.symbol.Symbol.book_add"></a>
#### book\_add
### book\_add
```python
async def book_add() -> bool
```
Subscribes the MetaTrader 5 terminal to the Market Depth change events for a specified symbol.
If the symbol is not in the list of instruments for the market, This method will return False
#### Returns:
|Type|Description|
|---|---|
**Returns**:
- `bool` - True if successful, otherwise False.
<a id="aiomql.symbol.Symbol.book_get"></a>
#### book\_get
### book\_get
```python
async def book_get() -> tuple[BookInfo]
```
Returns a tuple of BookInfo featuring Market Depth entries for the specified symbol.
#### Returns:
|Type|Description|
|---|---|
|**tuple[BookInfo]**|Returns the Market Depth contents as a tuples of BookInfo Objects|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
**Returns**:
- `tuple[BookInfo]` - Returns the Market Depth contents as a tuples of BookInfo Objects
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.book_release"></a>
#### book\_release
### book\_release
```python
async def book_release() -> bool
```
Cancels subscription of the MetaTrader 5 terminal to the Market Depth change events for a specified symbol.
**Returns**:
- `bool` - True if successful, otherwise False.
<a id="aiomql.symbol.Symbol.compute_volume"></a>
#### Returns:
|Type|Description|
|---|---|
|**bool**|True if successful, otherwise False.|
#### compute\_volume
```python
async def compute_volume(*,
amount: float,
pips: float,
use_minimum: bool = True) -> float
```
Computes the volume of a trade based on the amount and the number of pips to target.
This is a dummy method that returns the minimum volume of the symbol. It is meant to be overridden by a subclass
Checkout Forex Symbol implementation in srciomql\lib\ForexSymbol.py
Checkout Forex Symbol implementation in [ForexSymbol](#forexsymbol)
**Arguments**:
- `amount` _float_ - Amount to risk in the trade
- `pips` _float_ - Number of pips to target
**Arguments**:
- `use_minimum` _bool_ - If True, the minimum volume is returned if the computed volume is less than the minimum volume.
**Returns**:
- `float` - Returns the volume of the trade
<a id="aiomql.symbol.Symbol.currency_conversion"></a>
#### currency\_conversion
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**amount**| **float** | Amount to risk in the trade | None |
|**pips**| **float** | Number of pips to target | None |
|**use_minimum**| **bool** | If True, the minimum volume is returned if the computed volume is less than the minimum volume. | True |
#### Returns:
|Type|Description|
|---|---|
|**float**|Returns the volume of the trade|
### currency\_conversion
```python
async def currency_conversion(*, amount: float, base: str,
quote: str) -> float
```
Convert from one currency to the other.
#### Arguments:
**Arguments**:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**amount**| **float** | Amount to convert given in terms of the quote currency | None |
|**base**| **str** | The base currency of the pair | None |
|**quote**| **str** | The quote currency of the pair | None |
- `amount` - amount to convert given in terms of the quote currency
- `base` - The base currency of the pair
- `quote` - The quote currency of the pair
#### Returns:
|Type|Description|
|---|---|
|**float**|Amount in terms of the base currency or None if it failed to convert|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If conversion is impossible|
**Returns**:
- `float` - Amount in terms of the base currency or None if it failed to convert
**Raises**:
- `ValueError` - If conversion is impossible
<a id="aiomql.symbol.Symbol.copy_rates_from"></a>
#### copy\_rates\_from
### copy\_rates\_from
```python
async def copy_rates_from(*,
timeframe: TimeFrame,
date_from: datetime | int,
count: int = 500) -> Candles
```
Get bars from the MetaTrader 5 terminal starting from the specified date.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**timeframe**| **TimeFrame** | Timeframe the bars are requested for. Set by a value from the TimeFrame enumeration. | Required unnamed parameter |
|**date_from**| **datetime, int** | Date of opening of the first bar from the requested sample. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. | Required unnamed parameter |
|**count**| **int** | Number of bars to receive. | Required unnamed parameter |
#### Returns:
|Type|Description|
|---|---|
|**Candles**|Returns a Candles object as a collection of rates ordered chronologically|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
**Arguments**:
- `timeframe` _TimeFrame_ - Timeframe the bars are requested for. Set by a value from the TimeFrame enumeration. Required unnamed parameter.
- `date_from` _datetime | int_ - Date of opening of the first bar from the requested sample. Set by the 'datetime' object or as a number
of seconds elapsed since 1970.01.01. Required unnamed parameter.
- `count` _int_ - Number of bars to receive. Required unnamed parameter.
**Returns**:
- `Candles` - Returns a Candles object as a collection of rates ordered chronologically
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.copy_rates_from_pos"></a>
#### copy\_rates\_from\_pos
### copy\_rates\_from\_pos
```python
async def copy_rates_from_pos(*,
timeframe: TimeFrame,
count: int = 500,
start_position: int = 0) -> Candles
```
Get bars from the MetaTrader 5 terminal starting from the specified index.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**timeframe**| **TimeFrame** | TimeFrame value from TimeFrame Enum. Required keyword only parameter | Required keyword only parameter |
|**count**| **int** | Number of bars to return. Keyword argument defaults to 500 | 500 |
|**start_position**| **int** | Initial index of the bar the data are requested from. The numbering of bars goes from present to past. Thus, the zero bar means the current one. Keyword argument defaults to 0. | 0 |
#### Returns:
|Type|Description|
|---|---|
|**Candles**|Returns a Candles object as a collection of rates ordered chronologically.|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
**Arguments**:
- `timeframe` _TimeFrame_ - TimeFrame value from TimeFrame Enum. Required keyword only parameter
- `count` _int_ - Number of bars to return. Keyword argument defaults to 500
- `start_position` _int_ - Initial index of the bar the data are requested from. The numbering of bars goes from
present to past. Thus, the zero bar means the current one. Keyword argument defaults to 0.
**Returns**:
- `Candles` - Returns a Candles object as a collection of rates ordered chronologically.
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.copy_rates_range"></a>
#### copy\_rates\_range
### copy\_rates\_range
```python
async def copy_rates_range(*, timeframe: TimeFrame, date_from: datetime | int,
date_to: datetime | int) -> Candles
```
Get bars in the specified date range from the MetaTrader 5 terminal.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**timeframe**| **TimeFrame** | Timeframe for the bars using the TimeFrame enumeration. Required unnamed parameter. | Required unnamed parameter |
|date_from|datetime, int|Date the bars are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Bars with the open time >= date_from are returned. Required unnamed parameter.|Required unnamed parameter|
|date_to|datetime, int|Date, up to which the bars are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Bars with the open time <= date_to are returned. Required unnamed parameter.|Required unnamed parameter|
#### Returns:
|Type|Description|
|---|---|
|**Candles**|Returns a Candles object as a collection of rates ordered chronologically.|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
**Arguments**:
- `timeframe` _TimeFrame_ - Timeframe for the bars using the TimeFrame enumeration. Required unnamed parameter.
- `date_from` _datetime | int_ - Date the bars are requested from. Set by the 'datetime' object or as a number of seconds
elapsed since 1970.01.01. Bars with the open time >= date_from are returned. Required unnamed parameter.
- `date_to` _datetime | int_ - Date, up to which the bars are requested. Set by the 'datetime' object or as a number of
seconds elapsed since 1970.01.01. Bars with the open time <= date_to are returned. Required unnamed parameter.
**Returns**:
- `Candles` - Returns a Candles object as a collection of rates ordered chronologically.
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.copy_ticks_from"></a>
#### copy\_ticks\_from
### copy\_ticks\_from
```python
async def copy_ticks_from(*,
date_from: datetime | int,
count: int = 100,
flags: CopyTicks = CopyTicks.ALL) -> Ticks
```
Get ticks from the MetaTrader 5 terminal starting from the specified date.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**date_from**| **datetime, int** | Date the ticks are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. | Required unnamed parameter |
|**count**| **int** | Number of requested ticks. Defaults to 100 | Required unnamed parameter |
|**flags**| **CopyTicks** | A flag to define the type of the requested ticks from CopyTicks enum. INFO is the default | Required unnamed parameter |
#### Returns:
|Type|Description|
|---|---|
|**Ticks**|Returns a Ticks object as a collection of ticks ordered chronologically.|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
Args: date_from (datetime | int): Date the ticks are requested from. Set by the 'datetime' object or as a
number of seconds elapsed since 1970.01.01.
count (int): Number of requested ticks. Defaults to 100
flags (CopyTicks): A flag to define the type of the requested ticks from CopyTicks enum. INFO is the default
**Returns**:
- `Candles` - Returns a Candles object as a collection of ticks ordered chronologically.
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned
<a id="aiomql.symbol.Symbol.copy_ticks_range"></a>
#### copy\_ticks\_range
### copy\_ticks\_range
```python
async def copy_ticks_range(*,
date_from: datetime | int,
date_to: datetime | int,
flags: CopyTicks = CopyTicks.ALL) -> Ticks
```
Get ticks for the specified date range from the MetaTrader 5 terminal.
**Arguments**:
- `date_from` - Date the bars are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Bars with
the open time >= date_from are returned. Required unnamed parameter.
- `date_to` - Date, up to which the bars are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Bars
with the open time <= date_to are returned. Required unnamed parameter.
flags (CopyTicks):
**Returns**:
- `Candles` - Returns a Candles object as a collection of ticks ordered chronologically.
**Raises**:
- `ValueError` - If request was unsuccessful and None was returned.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**date_from**| **datetime, int** | Date the ticks are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. | Required unnamed parameter |
|**date_to**| **datetime, int** | Date, up to which the ticks are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. | Required unnamed parameter |
|**flags**| **CopyTicks** | A flag to define the type of the requested ticks from CopyTicks enum. INFO is the default | Required unnamed parameter |
#### Returns:
|Type|Description|
|---|---|
|**Ticks**|Returns a Ticks object as a collection of ticks ordered chronologically.|
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If request was unsuccessful and None was returned|
+33 -50
View File
@@ -1,88 +1,71 @@
<a id="aiomql.terminal"></a>
# aiomql.terminal
## <a id="terminal"></a> Terminal
Terminal related functions and properties
<a id="aiomql.terminal.Terminal"></a>
## Terminal Objects
```python
class Terminal(TerminalInfo)
```
Terminal Class. Get information about the MetaTrader 5 terminal. The class is a subclass of the TerminalInfo
class. It inherits all the attributes and methods of the TerminalInfo class and adds some useful methods.
### Attributes:
|Name| Type | Description | Default |
|---|---------------------|------------------------------------------------|----|
|**initialized**|**bool** | check if initial request has been sent to the terminal to get terminal info. | False |
|**mt5**|**MetaTrader** | MetaTrader instance | None |
|**config**|**Config** | Config instance | None |
**Notes**:
Other attributes are defined in the TerminalInfo Class
<a id="aiomql.terminal.Terminal.initialize"></a>
#### initialize
### Notes:
Other attributes are defined in the TerminalInfo Class
### initialize
```python
async def initialize() -> bool
```
Establish a connection with the MetaTrader 5 terminal. There are three call options. Call without parameters.
The terminal for connection is found automatically. Call specifying the path to the MetaTrader 5 terminal we
want to connect to. word path as a keyword argument Call specifying the trading account path and parameters
i.e login, password, server, as keyword arguments, path can be omitted.
#### Returns:
|Type|Description|
|---|---|
|**bool**|True if successful else False|
**Returns**:
- `bool` - True if successful else False
<a id="aiomql.terminal.Terminal.version"></a>
#### version
### version
```python
async def version()
```
Get the MetaTrader 5 terminal version. This method returns the terminal version, build and release date as
a tuple of three values
**Returns**:
#### Returns:
|Type|Description|
|---|---|
|**Version**|version of tuple as Version object|
- `Version` - version of tuple as Version object
**Raises**:
- `ValueError` - If the terminal version cannot be obtained
<a id="aiomql.terminal.Terminal.info"></a>
#### info
#### Raises:
|Exception|Description|
|---|---|
|**ValueError**|If the terminal version cannot be obtained|
### info
```python
async def info()
```
Get the connected MetaTrader 5 client terminal status and settings. gets terminal info in the form of a
named tuple structure (namedtuple). Return None in case of an error. The info on the error can be
obtained using last_error().
**Returns**:
- `Terminal` - Terminal status and settings as a terminal object.
<a id="aiomql.terminal.Terminal.symbols_total"></a>
#### symbols\_total
#### Returns:
|Type|Description|
|---|---|
|**TerminalInfo**|Terminal status and settings as a terminal object.|
### symbols\_total
```python
async def symbols_total() -> int
```
Get the number of all financial instruments in the MetaTrader 5 terminal.
**Returns**:
- `int` - Total number of available symbols
#### Returns:
|Type|Description|
|---|---|
|**int**|Total number of available symbols|
+52 -96
View File
@@ -1,141 +1,97 @@
<a id="aiomql.ticks"></a>
# aiomql.ticks
## <a id="ticks"></a> ticks
Module for working with price ticks.
<a id="aiomql.ticks.Tick"></a>
## Tick Objects
```python
class Tick()
```
Price Tick of a Financial Instrument.
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**symbol**|**Symbol**|The Financial Instrument as a Symbol Object|None|
|**time**|**datetime**|Time of the last prices update for the symbol|None|
|**bid**|**float**|Current Bid price|None|
|**ask**|**float**|Current Ask price|None|
|**last**|**float**|Price of the last deal (Last)|None|
|**volume**|**float**|Volume for the current Last price|None|
|**time_msc**|**int**|Time of the last prices update for the symbol in milliseconds|None|
|**flags**|**TickFlag**|Tick flags|None|
|**volume_real**|**float**|Volume for the current Last price|None|
|**Index**|**int**|Custom attribute representing the position of the tick in a sequence.|None|
**Attributes**:
- `time` _int_ - Time of the last prices update for the symbol
- `bid` _float_ - Current Bid price
- `ask` _float_ - Current Ask price
- `last` _float_ - Price of the last deal (Last)
- `volume` _float_ - Volume for the current Last price
- `time_msc` _int_ - Time of the last prices update for the symbol in milliseconds
- `flags` _TickFlag_ - Tick flags
- `volume_real` _float_ - Volume for the current Last price
- `Index` _int_ - Custom attribute representing the position of the tick in a sequence.
<a id="aiomql.ticks.Tick.set_attributes"></a>
#### set\_attributes
### set\_attributes
```python
def set_attributes(**kwargs)
```
Set attributes from keyword arguments
<a id="aiomql.ticks.Ticks"></a>
## Ticks Objects
## Ticks
```python
class Ticks()
```
Container data class for price ticks. Arrange in chronological order.
Supports iteration, slicing and assignment
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**data**|**DataFrame**|DataFrame of price ticks arranged in chronological order.|None|
**Arguments**:
- `data` _DataFrame | tuple[tuple]_ - Dataframe of price ticks or a tuple of tuples
**Arguments**:
- `flip` _bool_ - If flip is True reverse data chronological order.
**Attributes**:
- `data` - Dataframe Object holding the ticks
<a id="aiomql.ticks.Ticks.__init__"></a>
#### \_\_init\_\_
### \_\_init\_\_
```python
def __init__(*, data: DataFrame | Iterable, flip=False)
```
Initialize the Ticks class. Creates a DataFrame of price ticks from the data argument.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**data**| **DataFrame** \| **Iterable** | Dataframe of price ticks or any iterable object that can be converted to a pandas DataFrame | None |
|**flip**| **bool** | If flip is True reverse data chronological order. | False |
**Arguments**:
- `data` _DataFrame | Iterable_ - Dataframe of price ticks or any iterable object that can be converted to a
pandas DataFrame
- `flip` _bool_ - If flip is True reverse data chronological order.
<a id="aiomql.ticks.Ticks.ta"></a>
#### ta
### ta
```python
@property
def ta()
```
Access to the pandas_ta library for performing technical analysis on the underlying data attribute.
#### Returns:
|Name|Type|Description|
|---|---|---|
|**pandas_ta**|**pandas_ta**|The pandas_ta library|
**Returns**:
- `pandas_ta` - The pandas_ta library
<a id="aiomql.ticks.Ticks.ta_lib"></a>
#### ta\_lib
### ta\_lib
```python
@property
def ta_lib()
```
Access to the ta library for performing technical analysis. Not dependent on the underlying data attribute.
#### Returns:
|Name|Type|Description|
|---|---|---|
|**ta**|**ta**|The ta library|
**Returns**:
- `ta` - The ta library
<a id="aiomql.ticks.Ticks.data"></a>
#### data
### data
```python
@property
def data() -> DataFrame
```
DataFrame of price ticks arranged in chronological order.
#### Returns:
|Name|Type|Description|
|---|---|---|
|**data**|**DataFrame**|DataFrame of price ticks arranged in chronological order.|
<a id="aiomql.ticks.Ticks.rename"></a>
#### rename
### rename
```python
def rename(inplace=True, **kwargs) -> _Ticks | None
```
Rename columns of the candle class.
**Arguments**:
- `inplace` _bool_ - Rename the columns inplace or return a new instance of the class with the renamed columns
- `**kwargs` - The new names of the columns
**Returns**:
- `Ticks` - A new instance of the class with the renamed columns if inplace is False.
- `None` - If inplace is True
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**inplace**| **bool** | Rename the columns inplace or return a new instance of the class with the renamed columns | True |
|**kwargs**| | The new names of the columns | |
#### Returns:
|Type|Description|
|---|---|
|**Ticks**|A new instance of the class with the renamed columns if inplace is False.|
|**None**|If inplace is True|
+38 -63
View File
@@ -1,90 +1,65 @@
<a id="aiomql.trader"></a>
# aiomql.trader
## <a id="trader"></a> Trader
Trader class module. Handles the creation of an order and the placing of trades
<a id="aiomql.trader.Trader"></a>
## Trader Objects
```python
class Trader()
```
Base class for creating a Trader object. Handles the creation of an order and the placing of trades
### Attributes:
|Name|Type|Description|Default|
|---|---|---|---|
|**name**|**str**|A name for the strategy.|None|
|**account**|**Account**|Account instance.|None|
|**mt5**|**MetaTrader**|MetaTrader instance.|None|
|**config**|**Config**|Config instance.|None|
|**symbol**|**Symbol**|The Financial Instrument as a Symbol Object|None|
|**parameters**|**Dict**|A dictionary of parameters for the strategy.|None|
**Attributes**:
- `symbol` _Symbol_ - Financial instrument class Symbol class or any subclass of it.
- `ram` _RAM_ - RAM instance
- `order` _Order_ - Trade order
Class Attributes:
- `name` _str_ - A name for the strategy.
- `account` _Account_ - Account instance.
- `mt5` _MetaTrader_ - MetaTrader instance.
- `config` _Config_ - Config instance.
<a id="aiomql.trader.Trader.__init__"></a>
#### \_\_init\_\_
### \_\_init\_\_
```python
def __init__(*, symbol: Symbol, ram: RAM = None)
```
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**symbol**| **Symbol** | The Financial instrument | None |
|**ram**| **RAM** | Risk Assessment and Management instance | None |
Initializes the order object and RAM instance
**Arguments**:
- `symbol` _Symbol_ - Financial instrument
- `ram` _RAM_ - Risk Assessment and Management instance
<a id="aiomql.trader.Trader.create_order"></a>
#### create\_order
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**symbol**| **Symbol** | The Financial instrument | None |
|**ram**| **RAM** | Risk Assessment and Management instance | None |
### create\_order
```python
async def create_order(*, order_type: OrderType, **kwargs)
```
Complete the order object with the required values. Creates a simple order.
Uses the ram instance to set the volume.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**order_type**| **OrderType** | Type of order | None |
|**kwargs**| | keyword arguments as required for the specific trader | |
**Arguments**:
- `order_type` _OrderType_ - Type of order
- `kwargs` - keyword arguments as required for the specific trader
<a id="aiomql.trader.Trader.set_order_limits"></a>
#### set\_order\_limits
### set\_order\_limits
```python
async def set_order_limits(pips: float)
```
Sets the stop loss and take profit for the order.
This method uses pips as defined for forex instruments.
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**pips**| **float** | Target pips | None |
**Arguments**:
- `pips` - Target pips
<a id="aiomql.trader.Trader.place_trade"></a>
#### place\_trade
### place\_trade
```python
async def place_trade(order_type: OrderType, params: dict = None, **kwargs)
```
Places a trade based on the order_type.
**Arguments**:
- `order_type` _OrderType_ - Type of order
- `params` - parameters to be saved with the trade
- `kwargs` - keyword arguments as required for the specific trader
#### Arguments:
|Name| Type | Description | Default |
|---|--------------------|-----------------------------|-------------------|
|**order_type**| **OrderType** | Type of order | None |
|**params**| **dict** | parameters to be saved with the trade | None |
|**kwargs**| | keyword arguments as required for the specific trader | |
+11 -24
View File
@@ -1,7 +1,9 @@
import asyncio
import logging
from aiomql.lib import FingerTrap
from aiomql import Bot, Account, ForexSymbol, Records, RAM, DealTrader
from aiomql import Bot, Account, ForexSymbol
logging.basicConfig(level=logging.INFO)
def build_bot():
@@ -11,29 +13,14 @@ def build_bot():
# Prebuilt strategy from the library.
# Disclaimer: These strategy is only for demonstration purposes.
ram = RAM(amount=50)
st1 = FingerTrap(symbol=ForexSymbol(name='Volatility 10 (1s) Index'))
# st1 = FingerTrap(symbol=ForexSymbol(name='Volatility 50 (1s) Index'))
# st.trader.ram = ram
st1.trader.ram = ram
# st1 = FingerTrap(symbol=ForexSymbol(name='GBPUSD'), params={'trend_candles_count': 500})
# st3 = FingerTrap(symbol=ForexSymbol(name='AUDUSD'))
# st4 = FingerTrap(symbol=ForexSymbol(name='USDCAD'))
# st5 = FingerTrap(symbol=ForexSymbol(name='USDJPY'))
# st6 = FingerTrap(symbol=ForexSymbol(name='EURGBP'))
# bot.add_strategies([st, st1, st3, st4, st5, st6])
# bot.add_strategy(st)
bot.add_strategy(st1)
params = {'trend_candles_count': 500}
st1 = FingerTrap(symbol=ForexSymbol(name='GBPUSD'), params=params)
st3 = FingerTrap(symbol=ForexSymbol(name='AUDUSD'), params=params)
st4 = FingerTrap(symbol=ForexSymbol(name='USDCAD'), params=params)
st5 = FingerTrap(symbol=ForexSymbol(name='USDJPY'), params=params)
st6 = FingerTrap(symbol=ForexSymbol(name='EURGBP'), params=params)
bot.add_strategies([st1, st3, st4, st5, st6])
bot.execute()
build_bot()
async def main():
async with Account():
res = Records()
await res.update_records()
# asyncio.run(main())
-17
View File
@@ -1,17 +0,0 @@
from aiomql import ForexSymbol, Order, Trader, Account
import asyncio
async def main():
async with Account():
les = ForexSymbol(name='Volatility 50 (1s) Index')
# t = ForexSymbol(name='EURUSD')
await les.init()
# await t.init()
await les.info_tick()
# await t.info_tick()
vol = await les.compute_volume(amount=50, pips=10)
print(les.tick.ask, les.tick.bid, les.volume_min, vol, les.point, les.digits, les.volume_max)
print(les.tick.ask + les.point*100)
asyncio.run(main())
+21 -6
View File
@@ -1,14 +1,14 @@
import asyncio
from typing import Type, Iterable, TypeVar
from typing import Type, Iterable, TypeVar, Callable, Coroutine
import logging
from .executor import Executor
from .account import Account
from .symbol import Symbol as _Symbol
from .strategy import Strategy as _Strategy
# from
logger = logging.getLogger(__name__)
Strategy = TypeVar('Strategy', bound=_Strategy)
Symbol = TypeVar('Symbol', bound=_Symbol)
@@ -41,11 +41,26 @@ class Bot:
await self.init_symbols()
self.executor.remove_workers()
def add_func(self, func, kwargs):
self.executor.add_func(func, kwargs)
def add_function(self, func: Callable, **kwargs: dict):
"""Add a function to the executor.
def add_coro(self, coro, **kwargs):
self.executor.add_coro(coro, kwargs)
Args:
func (Callable): A function to be executed
**kwargs (dict): Keyword arguments for the function
"""
self.executor.add_function(func, kwargs)
def add_coroutine(self, coro: Coroutine, **kwargs):
"""Add a coroutine to the executor.
Args:
coro (Coroutine): A coroutine to be executed
**kwargs (dict): keyword arguments for the coroutine
Returns:
"""
self.executor.add_coroutine(coro, kwargs)
def execute(self):
"""Execute the bot.
+1 -1
View File
@@ -1,7 +1,7 @@
"""Candle and Candles classes for handling bars from the MetaTrader 5 terminal."""
from typing import Type, TypeVar, Generic, Iterable
from logging import getLogger
from logging import getLogger
import reprlib
from pandas import DataFrame, Series
+12 -13
View File
@@ -11,23 +11,23 @@ class Executor:
Attributes:
executor (ThreadPoolExecutor): The executor object.
workers (list): List of strategies.
coros (dict[Coroutine, dict]): A dictionary of coroutines to run in the executor
funcs (dict[Callable, dict]): A dictionary of functions to run in the executor
coroutines (dict[Coroutine, dict]): A dictionary of coroutines to run in the executor
functions (dict[Callable, dict]): A dictionary of functions to run in the executor
"""
def __init__(self, bot=None):
self.executor = ThreadPoolExecutor
self.workers: list[type(Strategy)] = []
self.coros: dict[Coroutine|Callable: dict] = {}
self.funcs: dict[Callable: dict] = {}
self.coroutines: dict[Coroutine | Callable: dict] = {}
self.functions: dict[Callable: dict] = {}
self.bot = bot
def add_func(self, func, kwargs):
self.funcs[func] = kwargs | {'bot': self.bot}
def add_function(self, func: Callable, kwargs: dict):
self.functions[func] = kwargs | {'bot': self.bot}
def add_coro(self, coro, kwargs):
self.coros[coro] = kwargs | {'bot': self.bot}
def add_coroutine(self, coro: Coroutine, kwargs: dict):
self.coroutines[coro] = kwargs | {'bot': self.bot}
def add_workers(self, strategies: Sequence[type(Strategy)]):
"""Add multiple strategies at once
@@ -38,8 +38,7 @@ class Executor:
self.workers.extend(strategies)
def remove_workers(self):
"""Removes any worker running on a symbol not successfully initialized.
"""
"""Removes any worker running on a symbol not successfully initialized."""
self.workers = [worker for worker in self.workers if worker.symbol in self.bot.symbols]
def add_worker(self, strategy: type(Strategy)):
@@ -78,10 +77,10 @@ class Executor:
Notes:
No matter the number specified, the executor will always use a minimum of 5 workers.
"""
workers = workers or sum([len(self.workers), len(self.funcs), len(self.coros)])
workers = workers or sum([len(self.workers), len(self.functions), len(self.coroutines)])
workers = max(workers, 5)
loop = asyncio.get_running_loop()
with self.executor(max_workers=workers) as executor:
[loop.run_in_executor(executor, self.trade, worker) for worker in self.workers]
[loop.run_in_executor(executor, self.run, coro, kwargs) for coro, kwargs in self.coros.items()]
[loop.run_in_executor(executor, func, kwargs) for func, kwargs in self.funcs.items()]
[loop.run_in_executor(executor, self.run, coro, kwargs) for coro, kwargs in self.coroutines.items()]
[loop.run_in_executor(executor, func, kwargs) for func, kwargs in self.functions.items()]
+19 -11
View File
@@ -7,6 +7,7 @@ from .order import Order
logger = getLogger(__name__)
class Positions:
"""Get Open Positions.
@@ -18,7 +19,7 @@ class Positions:
mt5 (MetaTrader): MetaTrader instance.
"""
mt5: MetaTrader = MetaTrader()
def __init__(self, *, symbol: str = "", group: str = "", ticket: int = 0):
"""Get Open Positions.
@@ -61,22 +62,29 @@ class Positions:
return []
return [TradePosition(**pos._asdict()) for pos in positions]
async def close(self, *, ticket: int, symbol: str, price: float, volume: float, order_type: OrderType):
"""Close an open position for the trading account."""
order = Order(action=TradeAction.DEAL, price=price, position=ticket, symbol=symbol, volume=volume,
type=order_type.opposite)
return await order.send()
async def close_all(self, symbol: str = '', group: str = '') -> int:
"""Close all open positions for the trading account.
Keyword Args:
symbol (str): Financial instrument name.
group (str): The filter for specifying a group of symbols.
Returns:
int: Return number of positions closed.
"""
orders = [Order(action=TradeAction.DEAL, price=pos.price_current, position=pos.ticket,
type=OrderType(pos.type).opposite,
**pos.get_dict(include={'symbol', 'volume'})) for pos in
(await self.positions_get(symbol=symbol, group=group))]
symbol = symbol or self.symbol
group = group or self.group
positions = [pos for pos in await self.positions_get(symbol=symbol, group=group)]
orders = [self.close(price=pos.price_current, ticket=pos.ticket, order_type=pos.type, volume=pos.volume,
symbol=pos.symbol) for pos in positions]
results = await asyncio.gather(*[order.send() for order in orders], return_exceptions=True)
results = await asyncio.gather(*[order for order in orders], return_exceptions=True)
amount_closed = len([res for res in results if res.retcode == 10009])
pos = await self.positions_total()
if pos > 0:
logger.warning(f'Failed to close {pos} positions')
else:
logger.info('All positions closed')
return amount_closed
+15 -21
View File
@@ -11,28 +11,24 @@ class RAM:
pips: float
volume: float
def __init__(self, **kwargs):
"""Risk Assessment and Management. All provided keyword arguments are set as attributes.
def __init__(self, *, risk_to_reward: float = 1, risk: float = 0.01, amount: float = 0, pips: float = 0, volume=0):
"""Initialize Risk Assessment and Management with the provided keyword arguments.
Args:
kwargs (Dict): Keyword arguments.
Defaults:
risk_to_reward (float): Risk to reward ratio 1
Keyword Args:
risk_to_reward (float): Risk to reward ratio. Defaults to 1
risk (float): Percentage of account balance to risk per trade 0.01 # 1%
amount (float): Amount to risk per trade in terms of account currency 0
pips (float): Target pips 0
pips (float): Target pips to risk
volume (float): Volume to trade 0
"""
self.risk_to_reward = kwargs.pop('risk_to_reward', 1)
self.risk = kwargs.pop('risk', 0.01)
self.amount = kwargs.pop('amount', 0)
self.pips = kwargs.pop('pips', 0)
self.volume = kwargs.pop('volume', 0)
[setattr(self, key, value) for key, value in kwargs.items()]
self.risk_to_reward = risk_to_reward
self.risk = risk
self.amount = amount
self.pips = pips
self.volume = volume
async def get_amount(self, risk: float = 0) -> float:
"""Calculate the amount to risk per trade as a percentage of free margin.
"""Calculate the amount to risk per trade as a percentage of equity.
Keyword Args:
risk (float): Percentage of account balance to risk per trade. Defaults to zero.
@@ -42,16 +38,15 @@ class RAM:
"""
await self.account.refresh()
risk = risk or self.risk
return self.account.margin_free * risk
return self.account.equity * risk
async def get_volume(self, *, symbol: Symbol, pips: float = 0, amount: float = 0) -> float:
"""Calculate the volume to trade. if pips is not provided, the pips attribute is used.
If the amount attribute or amount argument is zero, the amount is calculated using the get_amount method based on the risk.
Args:
symbol (Symbol): Financial instrument
If the amount attribute or amount argument is zero, the amount is calculated using the get_amount method based
on the risk.
Keyword Args:
symbol (Symbol): Financial instrument
pips (float): Target pips. Defaults to zero.
amount (float): Amount to risk per trade. Defaults to zero.
@@ -61,4 +56,3 @@ class RAM:
pips = pips or self.pips
amount = amount or self.amount or await self.get_amount()
return await symbol.compute_volume(amount=amount, pips=pips)
+154 -13
View File
@@ -1,41 +1,174 @@
"""Sessions allow you to run code at specific times of the day."""
import asyncio
from datetime import time, timedelta, datetime
from asyncio import sleep
from asyncio import sleep, iscoroutinefunction
from typing import Literal, Callable
from logging import getLogger
from .positions import Positions
logger = getLogger(__name__)
class Session:
"""A session is a time period between two datetime.time objects specified in utc.
def __init__(self, start: int | time, end: int | time):
Attributes:
start (datetime.time): The start time of the session.
end (datetime.time): The end time of the session.
on_start (str): The action to take when the session starts. Default is None.
on_end (str): The action to take when the session ends. Default is None.
custom_start (Callable): A custom function to call when the session starts. Default is None.
custom_end (Callable): A custom function to call when the session ends. Default is None.
Methods:
begin: Call the action specified in on_start or custom_start.
close: Call the action specified in on_end or custom_end.
action: Used by begin and close to call the action specified.
delta: Get the timedelta of a datetime.time object.
until: Get the seconds until the session starts from the current time.
"""
def __init__(self, *, start: int | time, end: int | time,
on_start: Literal['close_all', 'close_win', 'close_loss', 'custom_start'] = None,
on_end: Literal['close_all', 'close_win', 'close_loss', 'custom_end'] = None,
custom_start: Callable = None, custom_end: Callable = None):
"""Create a session.
Keyword Args:
start (int | datetime.time): The start time of the session in UTC.
end (int | datetime.time): The end time of the session in UTC.
on_start (Literal['close_all', 'close_win', 'close_loss', 'custom_start']): The action to take when the
session starts. Default is None.
on_end (Literal['close_all', 'close_win', 'close_loss', 'custom_end']): The action to take when the session
ends. Default is None.
custom_start (Callable): A custom function to call when the session starts. Default is None.
custom_end (Callable): A custom function to call when the session ends. Default is None.
"""
self.start = start if isinstance(start, time) else time(hour=start)
self.end = end if isinstance(end, time) else time(hour=end)
self.__from = self.delta(self.start)
self.__to = self.delta(self.end)
self.on_start = on_start
self.on_end = on_end
self.custom_start = custom_start
self.custom_end = custom_end
def __contains__(self, item: time):
return self.start <= item < self.end
def delta(self, obj):
def __repr__(self):
return f'{self.start}<-{len(self)}->{self.end}'
async def begin(self):
"""Call the action specified in on_start or custom_start."""
await self.action(self.on_start)
async def close(self):
"""Call the action specified in on_end or custom_end."""
await self.action(self.on_end)
async def action(self, action):
"""Used by begin and close to call the action specified.
Args:
action (Literal['close_all', 'close_win', 'close_loss', 'custom_start', 'custom_end']): The action to take.
"""
try:
position = Positions()
positions = await position.positions_get()
match action:
case 'close_all':
await asyncio.gather(*(position.close(price=pos.price_current, ticket=pos.ticket,
order_type=pos.type, volume=pos.volume,
symbol=pos.symbol) for pos in positions),
return_exceptions=True)
case 'close_win':
await asyncio.gather(
*(position.close(price=pos.price_current, ticket=pos.ticket, order_type=pos.type,
volume=pos.volume, symbol=pos.symbol) for pos in positions if pos.profit > 0),
return_exceptions=True)
case 'close_loss':
await asyncio.gather(
*(position.close(price=pos.price_current, ticket=pos.ticket, order_type=pos.type,
volume=pos.volume, symbol=pos.symbol) for pos in positions if
pos.profit < 0), return_exceptions=True)
case 'custom_end':
if iscoroutinefunction(self.custom_end):
await self.custom_end()
self.custom_end()
case 'custom_start':
if iscoroutinefunction(self.custom_start):
await self.custom_start()
self.custom_start()
case _:
pass
except Exception as exe:
logger.warning(f'Failed to call action {action} due to {exe}')
@staticmethod
def delta(obj: time):
"""Get the timedelta of a datetime.time object.
Args:
obj (datetime.time): A datetime.time object.
"""
return timedelta(hours=obj.hour, minutes=obj.minute, seconds=obj.second, microseconds=obj.microsecond)
def __len__(self):
return (self.__to - self.__from).seconds
def until(self):
now = lambda: datetime.utcnow().time()
return (self.__from - self.delta(now())).seconds
"""Get the seconds until the session starts from the current time."""
return (self.__from - self.delta(datetime.utcnow().time())).seconds
class Sessions:
"""Sessions allow you to run code at specific times of the day. It is a collection of Session objects.
Sessions are sorted by start time. The sessions object is an asynchronous context manager.
Attributes:
sessions (list[Session]): A list of Session objects.
current_session (Session): The current session.
Methods:
find: Find a session that contains a datetime.time object.
find_next: Find the next session that contains a datetime.time object.
check: Check if the current session has started and if not, wait until it starts.
"""
def __init__(self, *sessions: Session):
self.sessions = list(sessions)
self.sessions.sort(key=lambda x: x.start)
self.current_session = sessions[0]
def find(self, obj):
def find(self, obj: time) -> Session | None:
"""Find a session that contains a datetime.time object.
Args:
obj (datetime.time): A datetime.time object.
Returns:
Session | None: A Session object or None if not found.
"""
for session in self.sessions:
if obj in session:
return session
return None
def find_next(self, obj):
def find_next(self, obj: time) -> Session:
"""Find the next session that contains a datetime.time object.
Args:
obj (datetime.time): A datetime.time object.
Returns:
Session: A Session object.
"""
for session in self.sessions:
if obj < session.start:
return session
@@ -45,16 +178,24 @@ class Sessions:
return True if self.find(item) is not None else False
async def __aenter__(self):
await self.check()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
pass
await self.current_session.close()
async def check(self):
"""Check if the current session has started and if not, wait until it starts."""
now = datetime.utcnow().time()
if now in self:
if now in self.current_session:
return
next_session = self.find_next(now)
secs = next_session.until()
print(f'sleeping for {secs} seconds')
await sleep(secs)
await self.current_session.close()
current_session = self.find(now)
if current_session is None:
current_session = self.find_next(now)
secs = current_session.until() + 10
print(f'sleeping for {secs} seconds until next session')
await sleep(secs)
self.current_session = current_session
await self.current_session.begin()
+2 -2
View File
@@ -35,7 +35,7 @@ class Strategy(ABC):
mt5: MetaTrader()
config = Config()
def __init__(self, *, symbol: Symbol, params: dict = None, session: Session):
def __init__(self, *, symbol: Symbol, params: dict = None, sessions: Sessions = None):
"""Initiate the parameters dict and add name and symbol fields.
Use class name as strategy name if name is not provided
@@ -47,7 +47,7 @@ class Strategy(ABC):
self.parameters = params.copy() if isinstance(params, dict) else {}
self.parameters['symbol'] = symbol.name
self.parameters['name'] = self.name or self.__class__.__name__
self.session = session or Sessions(Session(8, 13))
self.sessions = sessions or Sessions(Session(start=0, end=23))
def __repr__(self):
return f"{self.name}({self.symbol!r})"