mirror of
https://github.com/Ichinga-Samuel/aiomql.git
synced 2026-08-06 00:37:45 +00:00
add docs
This commit is contained in:
+73
@@ -0,0 +1,73 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
venv/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
#Ipython Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# Ide environment
|
||||
*.idea/
|
||||
|
||||
.pypirc
|
||||
|
||||
.vscode/
|
||||
|
||||
# config file
|
||||
aiomql.json
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Ichinga Samuel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
## <a id="account"></a> Account
|
||||
|
||||
```python
|
||||
class Account(AccountInfo)
|
||||
```
|
||||
Singleton class for managing a trading account. A subclass of [AccountInfo](#accountinfo). All AccountInfo attributes are available in this class.
|
||||
|
||||
**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**\
|
||||
Other Account properties are defined in the AccountInfo class.
|
||||
|
||||
### refresh
|
||||
```python
|
||||
async def refresh()
|
||||
```
|
||||
Refreshes the account instance with the latest data from the MetaTrader 5 terminal
|
||||
|
||||
### account_info
|
||||
```python
|
||||
@property
|
||||
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**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**dict**|A dict of login, server and password details|
|
||||
|
||||
**Notes**\
|
||||
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__
|
||||
```python
|
||||
async def __aenter__() -> 'Account'
|
||||
```
|
||||
Connect to a trading account and return the account instance.
|
||||
Async context manager for the Account class.
|
||||
|
||||
**Returns**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**Account**|An instance of the Account class|
|
||||
|
||||
**Raises**
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**LoginError**|If login fails|
|
||||
|
||||
#### sign_in
|
||||
```python
|
||||
async def sign_in() -> bool
|
||||
```
|
||||
Connect to a trading account.
|
||||
|
||||
**Returns**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**bool**|True if login was successful else False|
|
||||
|
||||
#### has_symbol
|
||||
|
||||
```python
|
||||
def has_symbol(symbol: str | Type[SymbolInfo])
|
||||
```
|
||||
Checks to see if a symbol is available for a trading account\
|
||||
**Parameters**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**symbol**|**str** or **SymbolInfo**|A symbol name or SymbolInfo instance|
|
||||
|
||||
**Returns**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**bool**|True if symbol is available else False|
|
||||
|
||||
#### symbols_get
|
||||
```python
|
||||
async def symbols_get() -> set[SymbolInfo]
|
||||
```
|
||||
Get all financial instruments from the MetaTrader 5 terminal available for the current account.
|
||||
|
||||
**Returns**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**set[SymbolInfo]**|A set of SymbolInfo instances|
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
## <a id="bot_builder"></a> Bot Builder
|
||||
|
||||
```python
|
||||
class Bot()
|
||||
```
|
||||
The bot class. Create a bot instance to run your strategies.
|
||||
|
||||
**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*
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**SystemExit**|If sign in was not successful|
|
||||
|
||||
SystemExit if sign in was not successful
|
||||
|
||||
#### execute
|
||||
```python
|
||||
def execute()
|
||||
```
|
||||
Execute the bot.
|
||||
|
||||
#### start
|
||||
```python
|
||||
async def start()
|
||||
```
|
||||
Starts the bot by calling the initialize method and running the strategies 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**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**strategy**|**Strategy**|A Strategy instance to run on bot|
|
||||
|
||||
#### add_strategies
|
||||
```python
|
||||
def add_strategies(strategies: Iterable[Strategy])
|
||||
```
|
||||
Add multiple strategies at the same time
|
||||
|
||||
**Parameters**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**strategies**|**Iterable[Strategy]**|An iterable of Strategy instances|
|
||||
|
||||
#### 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**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**strategy**|**Type[Strategy]**|A Strategy class|
|
||||
|**params**|**dict** or **None**|A dictionary of parameters for the strategy|
|
||||
|
||||
#### 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
|
||||
```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**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**symbol**|**Symbol**|A Symbol instance|
|
||||
|
||||
|
||||
*returns*
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**Symbol**|A Symbol instance|
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
## <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**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**time**|**int**|Period start time|
|
||||
|**open**|**int**|Open price|
|
||||
|**high**|**float**|The highest price of the period|
|
||||
|**low**|**float**|The lowest price of the period|
|
||||
|**close**|**float**|Close price|
|
||||
|**tick_volume**|**float**|Tick volume|
|
||||
|**real_volume**|**float**|Trade volume|
|
||||
|**spread**|**float**|Spread|
|
||||
|**Index**|**int**|Custom attribute representing the position of the candle in a sequence.|
|
||||
|
||||
### \_\_init\_\_
|
||||
```python
|
||||
def __init__(**kwargs)
|
||||
```
|
||||
Create a Candle object from keyword arguments. Kwargs are set as instance attributes.
|
||||
|
||||
**Parameters**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**kwargs**|**Any**|Candle attributes and values as keyword arguments.|
|
||||
|
||||
### set\_attributes
|
||||
```python
|
||||
def set_attributes(**kwargs)
|
||||
```
|
||||
Set keyword arguments as instance attributes
|
||||
|
||||
### mid
|
||||
```python
|
||||
@property
|
||||
def mid() -> float
|
||||
```
|
||||
The median of open and close
|
||||
|
||||
**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**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**bool**|True or False|
|
||||
|
||||
### is_bearish
|
||||
```python
|
||||
def is_bearish() -> bool
|
||||
```
|
||||
A simple check to see if the candle is bearish.
|
||||
|
||||
**returns**
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|bool|True or False|
|
||||
|
||||
|
||||
## <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**
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**data**|**DataFrame**|A pandas DataFrame of all candles in the object.|
|
||||
|**Index**|**Series['int']**|A pandas Series of the indexes of all candles in the object|
|
||||
|**time**|**Series['int']**|A pandas Series of the time of all candles in the object|
|
||||
|**open**|**Series[float]**|A pandas Series of the opening price of all candles in the object|
|
||||
|**high**|**Series[float]**|A pandas Series of the high price of all candles in the object|
|
||||
|**low**|**Series[float]**|A pandas Series of the low price of all candles in the object|
|
||||
|**close**|**Series[float]**|A pandas Series of the closing price of all candles in the object|
|
||||
|**tick_volume**|**Series[float]**|A pandas Series of the tick volume of all candles in the object|
|
||||
|**real_volume**|**Series[float]**|A pandas Series of the real volume of all candles in the object|
|
||||
|**spread**|**Series[float]**|A pandas Series of the spread of all candles in the object|
|
||||
|**timeframe**|**TimeFrame**|The timeframe of the candles in the object|
|
||||
|**Candle**|**Type[Candle]**|The Candle class for representing the candles in the object.|
|
||||
|**data**|**DataFrame**|A pandas DataFrame of all candles in the object.|
|
||||
|
||||
**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,
|
||||
flip=False,
|
||||
candle_class: Type[_Candle] = None)
|
||||
```
|
||||
A container class of Candle objects in chronological order.
|
||||
|
||||
**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**:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**pandas_ta**|The pandas_ta library|
|
||||
|
||||
#### ta\_lib
|
||||
```python
|
||||
@property
|
||||
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**:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|ta|The ta library|
|
||||
|
||||
#### data
|
||||
```python
|
||||
@property
|
||||
def data() -> DataFrame
|
||||
```
|
||||
A pandas DataFrame of all candles in the object.
|
||||
|
||||
#### rename
|
||||
```python
|
||||
def rename(inplace=True, **kwargs) -> _Candles | None
|
||||
```
|
||||
Rename columns of the candles class.
|
||||
|
||||
**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**:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**Candles**|A new instance of the class with the renamed columns if inplace is False.|
|
||||
@@ -0,0 +1,164 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.base](#aiomql.core.base)
|
||||
* [Base](#aiomql.core.base.Base)
|
||||
* [set\_attributes](#aiomql.core.base.Base.set_attributes)
|
||||
* [annotations](#aiomql.core.base.Base.annotations)
|
||||
* [get\_dict](#aiomql.core.base.Base.get_dict)
|
||||
* [class\_vars](#aiomql.core.base.Base.class_vars)
|
||||
* [dict](#aiomql.core.base.Base.dict)
|
||||
* [Meta](#aiomql.core.base.Base.Meta)
|
||||
|
||||
<a id="aiomql.core.base"></a>
|
||||
|
||||
# aiomql.core.base
|
||||
|
||||
<a id="aiomql.core.base.Base"></a>
|
||||
|
||||
## Base Objects
|
||||
|
||||
```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
|
||||
class is instantiated.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `**kwargs` - Object attributes and values as keyword arguments. Only added if they are annotated on the class body.
|
||||
|
||||
Class Attributes:
|
||||
- `mt5` _MetaTrader_ - An instance of the MetaTrader class
|
||||
- `config` _Config_ - An instance of the Config class
|
||||
- `Meta` _Type[Meta]_ - The Meta class for configuration of the data model class
|
||||
|
||||
<a id="aiomql.core.base.Base.set_attributes"></a>
|
||||
|
||||
#### set\_attributes
|
||||
|
||||
```python
|
||||
def set_attributes(**kwargs)
|
||||
```
|
||||
|
||||
Set keyword arguments as object attributes
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `**kwargs` - Object attributes and values as keyword arguments
|
||||
|
||||
|
||||
**Raises**:
|
||||
|
||||
- `AttributeError` - When assigning an attribute that does not belong to the class or any parent class
|
||||
|
||||
|
||||
**Notes**:
|
||||
|
||||
Only sets attributes that have been annotated on the class body.
|
||||
|
||||
<a id="aiomql.core.base.Base.annotations"></a>
|
||||
|
||||
#### annotations
|
||||
|
||||
```python
|
||||
@property
|
||||
@cache
|
||||
def annotations() -> dict
|
||||
```
|
||||
|
||||
Class annotations from all ancestor classes and the current class.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `dict` - A dictionary of class annotations
|
||||
|
||||
<a id="aiomql.core.base.Base.get_dict"></a>
|
||||
|
||||
#### get\_dict
|
||||
|
||||
```python
|
||||
def get_dict(exclude: set = None, include: set = None) -> dict
|
||||
```
|
||||
|
||||
Returns class attributes as a dict, with the ability to filter
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `exclude` - A set of attributes to be excluded
|
||||
- `include` - Specific attributes to be returned
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `dict` - A dictionary of specified class attributes
|
||||
|
||||
|
||||
**Notes**:
|
||||
|
||||
You can only set either of include or exclude. If you set both, include will take precedence
|
||||
|
||||
<a id="aiomql.core.base.Base.class_vars"></a>
|
||||
|
||||
#### class\_vars
|
||||
|
||||
```python
|
||||
@property
|
||||
@cache
|
||||
def class_vars()
|
||||
```
|
||||
|
||||
Annotated class attributes
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `dict` - A dictionary of available class attributes in all ancestor classes and the current class.
|
||||
|
||||
<a id="aiomql.core.base.Base.dict"></a>
|
||||
|
||||
#### dict
|
||||
|
||||
```python
|
||||
@property
|
||||
def dict() -> dict
|
||||
```
|
||||
|
||||
All instance and class attributes as a dictionary, except those excluded in the Meta class.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `dict` - A dictionary of instance and class attributes
|
||||
|
||||
<a id="aiomql.core.base.Base.Meta"></a>
|
||||
|
||||
## Meta Objects
|
||||
|
||||
```python
|
||||
class Meta()
|
||||
```
|
||||
|
||||
A class for defining class attributes to be excluded or included in the dict property
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `exclude` _set_ - A set of attributes to be excluded
|
||||
- `include` _set_ - Specific attributes to be returned. Include supercedes exclude.
|
||||
|
||||
<a id="aiomql.core.base.Base.Meta.filter"></a>
|
||||
|
||||
#### filter
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
@property
|
||||
def filter(cls) -> set
|
||||
```
|
||||
|
||||
Combine the exclude and include attributes to return a set of attributes to be excluded.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `set` - A set of attributes to be excluded
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.config](#aiomql.core.config)
|
||||
* [Config](#aiomql.core.config.Config)
|
||||
* [account\_info](#aiomql.core.config.Config.account_info)
|
||||
|
||||
<a id="aiomql.core.config"></a>
|
||||
|
||||
# aiomql.core.config
|
||||
|
||||
<a id="aiomql.core.config.Config"></a>
|
||||
|
||||
## Config Objects
|
||||
|
||||
```python
|
||||
class Config()
|
||||
```
|
||||
|
||||
A class for handling configuration settings for the aiomql package.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `**kwargs` - Configuration settings as keyword arguments.
|
||||
Variables set this way supersede those set in the config file.
|
||||
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `record_trades` _bool_ - Whether to keep record of trades or not.
|
||||
- `filename` _str_ - Name of the config file
|
||||
- `records_dir` _str_ - Path to the directory where trade records are saved
|
||||
- `win_percentage` _float_ - Percentage of achieved target profit in a trade to be considered a win
|
||||
- `login` _int_ - Trading account number
|
||||
- `password` _str_ - Trading account password
|
||||
- `server` _str_ - Broker server
|
||||
- `path` _str_ - Path to terminal file
|
||||
- `timeout` _int_ - Timeout for terminal connection
|
||||
|
||||
|
||||
**Notes**:
|
||||
|
||||
By default, the config class looks for a file named aiomql.json.
|
||||
You can change this by passing the filename keyword argument to the constructor.
|
||||
By passing reload=True to the load_config method, you can reload and search again for the config file.
|
||||
|
||||
<a id="aiomql.core.config.Config.account_info"></a>
|
||||
|
||||
#### account\_info
|
||||
|
||||
```python
|
||||
def account_info() -> dict['login', 'password', 'server']
|
||||
```
|
||||
|
||||
Returns Account login details as found in the config object if available
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `dict` - A dictionary of login details
|
||||
|
||||
@@ -0,0 +1,736 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.constants](#aiomql.core.constants)
|
||||
* [TradeAction](#aiomql.core.constants.TradeAction)
|
||||
* [OrderFilling](#aiomql.core.constants.OrderFilling)
|
||||
* [OrderTime](#aiomql.core.constants.OrderTime)
|
||||
* [OrderType](#aiomql.core.constants.OrderType)
|
||||
* [opposite](#aiomql.core.constants.OrderType.opposite)
|
||||
* [BookType](#aiomql.core.constants.BookType)
|
||||
* [TimeFrame](#aiomql.core.constants.TimeFrame)
|
||||
* [time](#aiomql.core.constants.TimeFrame.time)
|
||||
* [CopyTicks](#aiomql.core.constants.CopyTicks)
|
||||
* [PositionType](#aiomql.core.constants.PositionType)
|
||||
* [PositionReason](#aiomql.core.constants.PositionReason)
|
||||
* [DealType](#aiomql.core.constants.DealType)
|
||||
* [DealEntry](#aiomql.core.constants.DealEntry)
|
||||
* [DealReason](#aiomql.core.constants.DealReason)
|
||||
* [OrderReason](#aiomql.core.constants.OrderReason)
|
||||
* [SymbolChartMode](#aiomql.core.constants.SymbolChartMode)
|
||||
* [SymbolCalcMode](#aiomql.core.constants.SymbolCalcMode)
|
||||
* [SymbolTradeMode](#aiomql.core.constants.SymbolTradeMode)
|
||||
* [SymbolTradeExecution](#aiomql.core.constants.SymbolTradeExecution)
|
||||
* [SymbolSwapMode](#aiomql.core.constants.SymbolSwapMode)
|
||||
* [DayOfWeek](#aiomql.core.constants.DayOfWeek)
|
||||
* [SymbolOrderGTCMode](#aiomql.core.constants.SymbolOrderGTCMode)
|
||||
* [SymbolOptionRight](#aiomql.core.constants.SymbolOptionRight)
|
||||
* [SymbolOptionMode](#aiomql.core.constants.SymbolOptionMode)
|
||||
* [AccountTradeMode](#aiomql.core.constants.AccountTradeMode)
|
||||
* [TickFlag](#aiomql.core.constants.TickFlag)
|
||||
* [TradeRetcode](#aiomql.core.constants.TradeRetcode)
|
||||
* [AccountStopOutMode](#aiomql.core.constants.AccountStopOutMode)
|
||||
* [AccountMarginMode](#aiomql.core.constants.AccountMarginMode)
|
||||
|
||||
<a id="aiomql.core.constants"></a>
|
||||
|
||||
# aiomql.core.constants
|
||||
|
||||
<a id="aiomql.core.constants.TradeAction"></a>
|
||||
|
||||
## TradeAction Objects
|
||||
|
||||
```python
|
||||
class TradeAction(Repr, IntEnum)
|
||||
```
|
||||
|
||||
TRADE_REQUEST_ACTION Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `DEAL` _int_ - Delete the pending order placed previously Place a trade order for an immediate execution with the
|
||||
specified parameters (market order).
|
||||
- `PENDING` _int_ - Delete the pending order placed previously
|
||||
- `SLTP` _int_ - Modify Stop Loss and Take Profit values of an opened position
|
||||
- `MODIFY` _int_ - Modify the parameters of the order placed previously
|
||||
- `REMOVE` _int_ - Delete the pending order placed previously
|
||||
- `CLOSE_BY` _int_ - Close a position by an opposite one
|
||||
|
||||
<a id="aiomql.core.constants.OrderFilling"></a>
|
||||
|
||||
## OrderFilling Objects
|
||||
|
||||
```python
|
||||
class OrderFilling(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ORDER_TYPE_FILLING Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `FOK` _int_ - This execution policy means that an order can be executed only in the specified volume.
|
||||
If the necessary amount of a financial instrument is currently unavailable in the market, the order will
|
||||
not be executed. The desired volume can be made up of several available offers.
|
||||
|
||||
- `IOC` _int_ - An agreement to execute a deal at the maximum volume available in the market within the volume
|
||||
specified in the order. If the request cannot be filled completely, an order with the available volume will
|
||||
be executed, and the remaining volume will be canceled.
|
||||
|
||||
- `RETURN` _int_ - This policy is used only for market (ORDER_TYPE_BUY and ORDER_TYPE_SELL), limit and stop limit
|
||||
orders (ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT,ORDER_TYPE_BUY_STOP_LIMIT and
|
||||
ORDER_TYPE_SELL_STOP_LIMIT) and only for the symbols with Market or Exchange execution modes. If filled
|
||||
partially, a market or limit order with the remaining volume is not canceled, and is processed further.
|
||||
During activation of the ORDER_TYPE_BUY_STOP_LIMIT and ORDER_TYPE_SELL_STOP_LIMIT orders, an appropriate
|
||||
limit order ORDER_TYPE_BUY_LIMIT/ORDER_TYPE_SELL_LIMIT with the ORDER_FILLING_RETURN type is created.
|
||||
|
||||
<a id="aiomql.core.constants.OrderTime"></a>
|
||||
|
||||
## OrderTime Objects
|
||||
|
||||
```python
|
||||
class OrderTime(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ORDER_TIME Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `GTC` _int_ - Good till cancel order
|
||||
- `DAY` _int_ - Good till current trade day order
|
||||
- `SPECIFIED` _int_ - The order is active until the specified date
|
||||
- `SPECIFIED_DAY` _int_ - The order is active until 23:59:59 of the specified day. If this time appears to be out of
|
||||
a trading session, the expiration is processed at the nearest trading time.
|
||||
|
||||
<a id="aiomql.core.constants.OrderType"></a>
|
||||
|
||||
## OrderType Objects
|
||||
|
||||
```python
|
||||
class OrderType(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ORDER_TYPE Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `BUY` _int_ - Market buy order
|
||||
- `SELL` _int_ - Market sell order
|
||||
- `BUY_LIMIT` _int_ - Buy Limit pending order
|
||||
- `SELL_LIMIT` _int_ - Sell Limit pending order
|
||||
- `BUY_STOP` _int_ - Buy Stop pending order
|
||||
- `SELL_STOP` _int_ - Sell Stop pending order
|
||||
- `BUY_STOP_LIMIT` _int_ - Upon reaching the order price, Buy Limit pending order is placed at StopLimit price
|
||||
- `SELL_STOP_LIMIT` _int_ - Upon reaching the order price, Sell Limit pending order is placed at StopLimit price
|
||||
- `CLOSE_BY` _int_ - Order for closing a position by an opposite one
|
||||
|
||||
Properties:
|
||||
- `opposite` _int_ - Gets the opposite of an order type
|
||||
|
||||
<a id="aiomql.core.constants.OrderType.opposite"></a>
|
||||
|
||||
#### opposite
|
||||
|
||||
```python
|
||||
@property
|
||||
def opposite()
|
||||
```
|
||||
|
||||
Gets the opposite of an order type for closing an open position
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `int` - integer value of opposite order type
|
||||
|
||||
<a id="aiomql.core.constants.BookType"></a>
|
||||
|
||||
## BookType Objects
|
||||
|
||||
```python
|
||||
class BookType(Repr, IntEnum)
|
||||
```
|
||||
|
||||
BOOK_TYPE Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `SELL` _int_ - Sell order (Offer)
|
||||
- `BUY` _int_ - Buy order (Bid)
|
||||
- `SELL_MARKET` _int_ - Sell order by Market
|
||||
- `BUY_MARKET` _int_ - Buy order by Market
|
||||
|
||||
<a id="aiomql.core.constants.TimeFrame"></a>
|
||||
|
||||
## TimeFrame Objects
|
||||
|
||||
```python
|
||||
class TimeFrame(Repr, IntEnum)
|
||||
```
|
||||
|
||||
TIMEFRAME Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `M1` _int_ - One Minute
|
||||
- `M2` _int_ - Two Minutes
|
||||
- `M3` _int_ - Three Minutes
|
||||
- `M4` _int_ - Four Minutes
|
||||
- `M5` _int_ - Five Minutes
|
||||
- `M6` _int_ - Six Minutes
|
||||
- `M10` _int_ - Ten Minutes
|
||||
- `M15` _int_ - Fifteen Minutes
|
||||
- `M20` _int_ - Twenty Minutes
|
||||
- `M30` _int_ - Thirty Minutes
|
||||
- `H1` _int_ - One Hour
|
||||
- `H2` _int_ - Two Hours
|
||||
- `H3` _int_ - Three Hours
|
||||
- `H4` _int_ - Four Hours
|
||||
- `H6` _int_ - Six Hours
|
||||
- `H8` _int_ - Eight Hours
|
||||
- `D1` _int_ - One Day
|
||||
- `W1` _int_ - One Week
|
||||
- `MN1` _int_ - One Month
|
||||
|
||||
Properties:
|
||||
- `time` - return the value of the timeframe object in seconds. Used as a property
|
||||
|
||||
|
||||
**Methods**:
|
||||
|
||||
- `get` - get a timeframe object from a time value in seconds
|
||||
|
||||
<a id="aiomql.core.constants.TimeFrame.time"></a>
|
||||
|
||||
#### time
|
||||
|
||||
```python
|
||||
@property
|
||||
def time()
|
||||
```
|
||||
|
||||
The number of seconds in a TIMEFRAME
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `int` - The number of seconds in a TIMEFRAME
|
||||
|
||||
|
||||
**Examples**:
|
||||
|
||||
>>> t = TimeFrame.H1
|
||||
>>> print(t.time)
|
||||
3600
|
||||
|
||||
<a id="aiomql.core.constants.CopyTicks"></a>
|
||||
|
||||
## CopyTicks Objects
|
||||
|
||||
```python
|
||||
class CopyTicks(Repr, IntEnum)
|
||||
```
|
||||
|
||||
COPY_TICKS Enum. This defines the types of ticks that can be requested using the copy_ticks_from() and
|
||||
copy_ticks_range() functions.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `ALL` _int_ - All ticks
|
||||
- `INFO` _int_ - Ticks containing Bid and/or Ask price changes
|
||||
- `TRADE` _int_ - Ticks containing Last and/or Volume price changes
|
||||
|
||||
<a id="aiomql.core.constants.PositionType"></a>
|
||||
|
||||
## PositionType Objects
|
||||
|
||||
```python
|
||||
class PositionType(Repr, IntEnum)
|
||||
```
|
||||
|
||||
POSITION_TYPE Enum. Direction of an open position (buy or sell)
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `BUY` _int_ - Buy
|
||||
- `SELL` _int_ - Sell
|
||||
|
||||
<a id="aiomql.core.constants.PositionReason"></a>
|
||||
|
||||
## PositionReason Objects
|
||||
|
||||
```python
|
||||
class PositionReason(Repr, IntEnum)
|
||||
```
|
||||
|
||||
POSITION_REASON Enum. The reason for opening a position is contained in the POSITION_REASON Enum
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `CLIENT` _int_ - The position was opened as a result of activation of an order placed from a desktop terminal
|
||||
- `MOBILE` _int_ - The position was opened as a result of activation of an order placed from a mobile application
|
||||
- `WEB` _int_ - The position was opened as a result of activation of an order placed from the web platform
|
||||
- `EXPERT` _int_ - The position was opened as a result of activation of an order placed from an MQL5 program,
|
||||
i.e. an Expert Advisor or a script
|
||||
|
||||
<a id="aiomql.core.constants.DealType"></a>
|
||||
|
||||
## DealType Objects
|
||||
|
||||
```python
|
||||
class DealType(Repr, IntEnum)
|
||||
```
|
||||
|
||||
DEAL_TYPE enum. Each deal is characterized by a type, allowed values are enumerated in this enum
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `BUY` _int_ - Buy
|
||||
- `SELL` _int_ - Sell
|
||||
- `BALANCE` _int_ - Balance
|
||||
- `CREDIT` _int_ - Credit
|
||||
- `CHARGE` _int_ - Additional Charge
|
||||
- `CORRECTION` _int_ - Correction
|
||||
- `BONUS` _int_ - Bonus
|
||||
- `COMMISSION` _int_ - Additional Commission
|
||||
- `COMMISSION_DAILY` _int_ - Daily Commission
|
||||
- `COMMISSION_MONTHLY` _int_ - Monthly Commission
|
||||
- `COMMISSION_AGENT_DAILY` _int_ - Daily Agent Commission
|
||||
- `COMMISSION_AGENT_MONTHLY` _int_ - Monthly Agent Commission
|
||||
- `INTEREST` _int_ - Interest Rate
|
||||
- `DEAL_DIVIDEND` _int_ - Dividend Operations
|
||||
- `DEAL_DIVIDEND_FRANKED` _int_ - Franked (non-taxable) dividend operations
|
||||
- `DEAL_TAX` _int_ - Tax Charges
|
||||
|
||||
- `BUY_CANCELED` _int_ - Canceled buy deal. There can be a situation when a previously executed buy deal is canceled.
|
||||
In this case, the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED,
|
||||
and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated
|
||||
balance operation
|
||||
|
||||
- `SELL_CANCELED` _int_ - Canceled sell deal. There can be a situation when a previously executed sell deal is
|
||||
canceled. In this case, the type of the previously executed deal (DEAL_TYPE_SELL) is changed to
|
||||
DEAL_TYPE_SELL_CANCELED, and its profit/loss is zeroized. Previously obtained profit/loss is
|
||||
charged/withdrawn using a separated balance operation.
|
||||
|
||||
<a id="aiomql.core.constants.DealEntry"></a>
|
||||
|
||||
## DealEntry Objects
|
||||
|
||||
```python
|
||||
class DealEntry(Repr, IntEnum)
|
||||
```
|
||||
|
||||
DEAL_ENTRY Enum. Deals differ not only in their types set in DEAL_TYPE enum, but also in the way they change
|
||||
positions. This can be a simple position opening, or accumulation of a previously opened position (market entering),
|
||||
position closing by an opposite deal of a corresponding volume (market exiting), or position reversing, if the
|
||||
opposite-direction deal covers the volume of the previously opened position.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `IN` _int_ - Entry In
|
||||
- `OUT` _int_ - Entry Out
|
||||
- `INOUT` _int_ - Reverse
|
||||
- `OUT_BY` _int_ - Close a position by an opposite one
|
||||
|
||||
<a id="aiomql.core.constants.DealReason"></a>
|
||||
|
||||
## DealReason Objects
|
||||
|
||||
```python
|
||||
class DealReason(Repr, IntEnum)
|
||||
```
|
||||
|
||||
DEAL_REASON Enum. The reason for deal execution is contained in the DEAL_REASON property. A deal can be executed
|
||||
as a result of triggering of an order placed from a mobile application or an MQL5 program, as well as as a result
|
||||
of the StopOut event, variation margin calculation, etc.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `CLIENT` _int_ - The deal was executed as a result of activation of an order placed from a desktop terminal
|
||||
- `MOBILE` _int_ - The deal was executed as a result of activation of an order placed from a desktop terminal
|
||||
- `WEB` _int_ - The deal was executed as a result of activation of an order placed from the web platform
|
||||
- `EXPERT` _int_ - The deal was executed as a result of activation of an order placed from an MQL5 program, i.e.
|
||||
an Expert Advisor or a script
|
||||
- `SL` _int_ - The deal was executed as a result of Stop Loss activation
|
||||
- `TP` _int_ - The deal was executed as a result of Take Profit activation
|
||||
- `SO` _int_ - The deal was executed as a result of the Stop Out event
|
||||
- `ROLLOVER` _int_ - The deal was executed due to a rollover
|
||||
- `VMARGIN` _int_ - The deal was executed after charging the variation margin
|
||||
- `SPLIT` _int_ - The deal was executed after the split (price reduction) of an instrument, which had an open
|
||||
position during split announcement
|
||||
|
||||
<a id="aiomql.core.constants.OrderReason"></a>
|
||||
|
||||
## OrderReason Objects
|
||||
|
||||
```python
|
||||
class OrderReason(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ORDER_REASON Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `CLIENT` _int_ - The order was placed from a desktop terminal
|
||||
- `MOBILE` _int_ - The order was placed from a mobile application
|
||||
- `WEB` _int_ - The order was placed from a web platform
|
||||
- `EXPERT` _int_ - The order was placed from an MQL5-program, i.e. by an Expert Advisor or a script
|
||||
- `SL` _int_ - The order was placed as a result of Stop Loss activation
|
||||
- `TP` _int_ - The order was placed as a result of Take Profit activation
|
||||
- `SO` _int_ - The order was placed as a result of the Stop Out event
|
||||
|
||||
<a id="aiomql.core.constants.SymbolChartMode"></a>
|
||||
|
||||
## SymbolChartMode Objects
|
||||
|
||||
```python
|
||||
class SymbolChartMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_CHART_MODE Enum. A symbol price chart can be based on Bid or Last prices. The price selected for symbol
|
||||
charts also affects the generation and display of bars in the terminal.
|
||||
Possible values of the SYMBOL_CHART_MODE property are described in this enum
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `BID` _int_ - Bars are based on Bid prices
|
||||
- `LAST` _int_ - Bars are based on last prices
|
||||
|
||||
<a id="aiomql.core.constants.SymbolCalcMode"></a>
|
||||
|
||||
## SymbolCalcMode Objects
|
||||
|
||||
```python
|
||||
class SymbolCalcMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_CALC_MODE Enum. The SYMBOL_CALC_MODE enumeration is used for obtaining information about how the margin
|
||||
requirements for a symbol are calculated.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `FOREX` _int_ - Forex mode - calculation of profit and margin for Forex
|
||||
- `FOREX_NO_LEVERAGE` _int_ - Forex No Leverage mode – calculation of profit and margin for Forex symbols without
|
||||
taking into account the leverage
|
||||
- `FUTURES` _int_ - Futures mode - calculation of margin and profit for futures
|
||||
- `CFD` _int_ - CFD mode - calculation of margin and profit for CFD
|
||||
- `CFDINDEX` _int_ - CFD index mode - calculation of margin and profit for CFD by indexes
|
||||
- `CFDLEVERAGE` _int_ - CFD Leverage mode - calculation of margin and profit for CFD at leverage trading
|
||||
- `EXCH_STOCKS` _int_ - Calculation of margin and profit for trading securities on a stock exchange
|
||||
- `EXCH_FUTURES` _int_ - Calculation of margin and profit for trading futures contracts on a stock exchange
|
||||
- `EXCH_OPTIONS` _int_ - value is 34
|
||||
- `EXCH_OPTIONS_MARGIN` _int_ - value is 36
|
||||
- `EXCH_BONDS` _int_ - Exchange Bonds mode – calculation of margin and profit for trading bonds on a stock exchange
|
||||
- `STOCKS_MOEX` _int_ - Exchange MOEX Stocks mode –calculation of margin and profit for trading securities on MOEX
|
||||
- `EXCH_BONDS_MOEX` _int_ - Exchange MOEX Bonds mode – calculation of margin and profit for trading bonds on MOEX
|
||||
|
||||
- `SERV_COLLATERAL` _int_ - Collateral mode - a symbol is used as a non-tradable asset on a trading account.
|
||||
The market value of an open position is calculated based on the volume, current market price, contract size
|
||||
and liquidity ratio. The value is included into Assets, which are added to Equity. Open positions of such
|
||||
symbols increase the Free Margin amount and are used as additional margin (collateral) for open positions
|
||||
|
||||
<a id="aiomql.core.constants.SymbolTradeMode"></a>
|
||||
|
||||
## SymbolTradeMode Objects
|
||||
|
||||
```python
|
||||
class SymbolTradeMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_TRADE_MODE Enum. There are several symbol trading modes. Information about trading modes of a certain
|
||||
symbol is reflected in the values this enumeration
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `DISABLED` _int_ - Trade is disabled for the symbol
|
||||
- `LONGONLY` _int_ - Allowed only long positions
|
||||
- `SHORTONLY` _int_ - Allowed only short positions
|
||||
- `CLOSEONLY` _int_ - Allowed only position close operations
|
||||
- `FULL` _int_ - No trade restrictions
|
||||
|
||||
<a id="aiomql.core.constants.SymbolTradeExecution"></a>
|
||||
|
||||
## SymbolTradeExecution Objects
|
||||
|
||||
```python
|
||||
class SymbolTradeExecution(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_TRADE_EXECUTION Enum. The modes, or execution policies, define the rules for cases when the price has
|
||||
changed or the requested volume cannot be completely fulfilled at the moment.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `REQUEST` _int_ - Executing a market order at the price previously received from the broker. Prices for a certain
|
||||
market order are requested from the broker before the order is sent. Upon receiving the prices, order
|
||||
execution at the given price can be either confirmed or rejected.
|
||||
|
||||
- `INSTANT` _int_ - Executing a market order at the specified price immediately. When sending a trade request to be
|
||||
executed, the platform automatically adds the current prices to the order.
|
||||
- If the broker accepts the price, the order is executed.
|
||||
- If the broker does not accept the requested price, a "Requote" is sent — the broker returns prices,
|
||||
at which this order can be executed.
|
||||
|
||||
- `MARKET` _int_ - A broker makes a decision about the order execution price without any additional discussion with the trader.
|
||||
Sending the order in such a mode means advance consent to its execution at this price.
|
||||
|
||||
- `EXCHANGE` _int_ - Trade operations are executed at the prices of the current market offers.
|
||||
|
||||
<a id="aiomql.core.constants.SymbolSwapMode"></a>
|
||||
|
||||
## SymbolSwapMode Objects
|
||||
|
||||
```python
|
||||
class SymbolSwapMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_SWAP_MODE Enum. Methods of swap calculation at position transfer are specified in enumeration
|
||||
ENUM_SYMBOL_SWAP_MODE. The method of swap calculation determines the units of measure of the SYMBOL_SWAP_LONG and
|
||||
SYMBOL_SWAP_SHORT parameters. For example, if swaps are charged in the client deposit currency, then the values of
|
||||
those parameters are specified as an amount of money in the client deposit currency.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `DISABLED` _int_ - Swaps disabled (no swaps)
|
||||
- `POINTS` _int_ - Swaps are charged in points
|
||||
- `CURRENCY_SYMBOL` _int_ - Swaps are charged in money in base currency of the symbol
|
||||
- `CURRENCY_MARGIN` _int_ - Swaps are charged in money in margin currency of the symbol
|
||||
- `CURRENCY_DEPOSIT` _int_ - Swaps are charged in money, in client deposit currency
|
||||
|
||||
- `INTEREST_CURRENT` _int_ - Swaps are charged as the specified annual interest from the instrument price at
|
||||
calculation of swap (standard bank year is 360 days)
|
||||
|
||||
- `INTEREST_OPEN` _int_ - Swaps are charged as the specified annual interest from the open price of position
|
||||
(standard bank year is 360 days)
|
||||
|
||||
- `REOPEN_CURRENT` _int_ - Swaps are charged by reopening positions. At the end of a trading day the position is
|
||||
closed. Next day it is reopened by the close price +/- specified number of points
|
||||
(parameters SYMBOL_SWAP_LONG and SYMBOL_SWAP_SHORT)
|
||||
|
||||
- `REOPEN_BID` _int_ - Swaps are charged by reopening positions. At the end of a trading day the position is closed.
|
||||
Next day it is reopened by the current Bid price +/- specified number of
|
||||
points (parameters SYMBOL_SWAP_LONG and SYMBOL_SWAP_SHORT)
|
||||
|
||||
<a id="aiomql.core.constants.DayOfWeek"></a>
|
||||
|
||||
## DayOfWeek Objects
|
||||
|
||||
```python
|
||||
class DayOfWeek(Repr, IntEnum)
|
||||
```
|
||||
|
||||
DAY_OF_WEEK Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `SUNDAY` _int_ - Sunday
|
||||
- `MONDAY` _int_ - Monday
|
||||
- `TUESDAY` _int_ - Tuesday
|
||||
- `WEDNESDAY` _int_ - Wednesday
|
||||
- `THURSDAY` _int_ - Thursday
|
||||
- `FRIDAY` _int_ - Friday
|
||||
- `SATURDAY` _int_ - Saturday
|
||||
|
||||
<a id="aiomql.core.constants.SymbolOrderGTCMode"></a>
|
||||
|
||||
## SymbolOrderGTCMode Objects
|
||||
|
||||
```python
|
||||
class SymbolOrderGTCMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_ORDER_GTC_MODE Enum. If the SYMBOL_EXPIRATION_MODE property is set to SYMBOL_EXPIRATION_GTC
|
||||
(good till canceled), the expiration of pending orders, as well as of
|
||||
Stop Loss/Take Profit orders should be additionally set using the ENUM_SYMBOL_ORDER_GTC_MODE enumeration.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `GTC` _int_ - Pending orders and Stop Loss/Take Profit levels are valid for an unlimited period
|
||||
until theirConstants, Enumerations and explicit cancellation
|
||||
|
||||
- `DAILY` _int_ - Orders are valid during one trading day. At the end of the day, all Stop Loss and
|
||||
Take Profit levels, as well as pending orders are deleted.
|
||||
|
||||
- `DAILY_NO_STOPS` _int_ - When a trade day changes, only pending orders are deleted,
|
||||
while Stop Loss and Take Profit levels are preserved
|
||||
|
||||
<a id="aiomql.core.constants.SymbolOptionRight"></a>
|
||||
|
||||
## SymbolOptionRight Objects
|
||||
|
||||
```python
|
||||
class SymbolOptionRight(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_OPTION_RIGHT Enum. An option is a contract, which gives the right, but not the obligation,
|
||||
to buy or sell an underlying asset (goods, stocks, futures, etc.) at a specified price on or before a specific date.
|
||||
The following enumerations describe option properties, including the option type and the right arising from it.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `CALL` _int_ - A call option gives you the right to buy an asset at a specified price.
|
||||
- `PUT` _int_ - A put option gives you the right to sell an asset at a specified price.
|
||||
|
||||
<a id="aiomql.core.constants.SymbolOptionMode"></a>
|
||||
|
||||
## SymbolOptionMode Objects
|
||||
|
||||
```python
|
||||
class SymbolOptionMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
SYMBOL_OPTION_MODE Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `EUROPEAN` _int_ - European option may only be exercised on a specified date (expiration, execution date, delivery date)
|
||||
- `AMERICAN` _int_ - American option may be exercised on any trading day or before expiry. The period within which
|
||||
a buyer can exercise the option is specified for it.
|
||||
|
||||
<a id="aiomql.core.constants.AccountTradeMode"></a>
|
||||
|
||||
## AccountTradeMode Objects
|
||||
|
||||
```python
|
||||
class AccountTradeMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ACCOUNT_TRADE_MODE Enum. There are several types of accounts that can be opened on a trade server.
|
||||
The type of account on which an MQL5 program is running can be found out using
|
||||
the ENUM_ACCOUNT_TRADE_MODE enumeration.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `DEMO` - Demo account
|
||||
- `CONTEST` - Contest account
|
||||
- `REAL` - Real Account
|
||||
|
||||
<a id="aiomql.core.constants.TickFlag"></a>
|
||||
|
||||
## TickFlag Objects
|
||||
|
||||
```python
|
||||
class TickFlag(Repr, IntFlag)
|
||||
```
|
||||
|
||||
TICK_FLAG Enum. TICK_FLAG defines possible flags for ticks. These flags are used to describe ticks obtained by the
|
||||
copy_ticks_from() and copy_ticks_range() functions.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `BID` _int_ - Bid price changed
|
||||
- `ASK` _int_ - Ask price changed
|
||||
- `LAST` _int_ - Last price changed
|
||||
- `VOLUME` _int_ - Volume changed
|
||||
- `BUY` _int_ - last Buy price changed
|
||||
- `SELL` _int_ - last Sell price changed
|
||||
|
||||
<a id="aiomql.core.constants.TradeRetcode"></a>
|
||||
|
||||
## TradeRetcode Objects
|
||||
|
||||
```python
|
||||
class TradeRetcode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
TRADE_RETCODE Enum. Return codes for order send/check operations
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `REQUOTE` _int_ - Requote
|
||||
- `REJECT` _int_ - Request rejected
|
||||
- `CANCEL` _int_ - Request canceled by trader
|
||||
- `PLACED` _int_ - Order placed
|
||||
- `DONE` _int_ - Request completed
|
||||
- `DONE_PARTIAL` _int_ - Only part of the request was completed
|
||||
- `ERROR` _int_ - Request processing error
|
||||
- `TIMEOUT` _int_ - Request canceled by timeout
|
||||
- `INVALID` _int_ - Invalid request
|
||||
- `INVALID_VOLUME` _int_ - Invalid volume in the request
|
||||
- `INVALID_PRICE` _int_ - Invalid price in the request
|
||||
- `INVALID_STOPS` _int_ - Invalid stops in the request
|
||||
- `TRADE_DISABLED` _int_ - Trade is disabled
|
||||
- `MARKET_CLOSED` _int_ - Market is closed
|
||||
- `NO_MONEY` _int_ - There is not enough money to complete the request
|
||||
- `PRICE_CHANGED` _int_ - Prices changed
|
||||
- `PRICE_OFF` _int_ - There are no quotes to process the request
|
||||
- `INVALID_EXPIRATION` _int_ - Invalid order expiration date in the request
|
||||
- `ORDER_CHANGED` _int_ - Order state changed
|
||||
- `TOO_MANY_REQUESTS` _int_ - Too frequent requests
|
||||
- `NO_CHANGES` _int_ - No changes in request
|
||||
- `SERVER_DISABLES_AT` _int_ - Autotrading disabled by server
|
||||
- `CLIENT_DISABLES_AT` _int_ - Autotrading disabled by client terminal
|
||||
- `LOCKED` _int_ - Request locked for processing
|
||||
- `FROZEN` _int_ - Order or position frozen
|
||||
- `INVALID_FILL` _int_ - Invalid order filling type
|
||||
- `CONNECTION` _int_ - No connection with the trade server
|
||||
- `ONLY_REAL` _int_ - Operation is allowed only for live accounts
|
||||
- `LIMIT_ORDERS` _int_ - The number of pending orders has reached the limit
|
||||
- `LIMIT_VOLUME` _int_ - The volume of orders and positions for the symbol has reached the limit
|
||||
- `INVALID_ORDER` _int_ - Incorrect or prohibited order type
|
||||
- `POSITION_CLOSED` _int_ - Position with the specified POSITION_IDENTIFIER has already been closed
|
||||
- `INVALID_CLOSE_VOLUME` _int_ - A close volume exceeds the current position volume
|
||||
|
||||
- `CLOSE_ORDER_EXIST` _int_ - A close order already exists for a specified position. This may happen when working in
|
||||
the hedging system:
|
||||
· when attempting to close a position with an opposite one, while close orders for the position already exist
|
||||
· when attempting to fully or partially close a position if the total volume of the already present close
|
||||
orders and the newly placed one exceeds the current position volume
|
||||
|
||||
- `LIMIT_POSITIONS` _int_ - The number of open positions simultaneously present on an account can be limited by the
|
||||
server settings.After a limit is reached, the server returns the TRADE_RETCODE_LIMIT_POSITIONS error when
|
||||
attempting to place an order. The limitation operates differently depending on the position accounting type:
|
||||
· Netting — number of open positions is considered. When a limit is reached, the platform does not let
|
||||
placing new orders whose execution may increase the number of open positions. In fact, the platform
|
||||
allows placing orders only for the symbols that already have open positions.
|
||||
The current pending orders are not considered since their execution may lead to changes in the current
|
||||
positions but it cannot increase their number.
|
||||
|
||||
· Hedging — pending orders are considered together with open positions, since a pending order activation
|
||||
always leads to opening a new position. When a limit is reached, the platform does not allow placing
|
||||
both new market orders for opening positions and pending orders.
|
||||
|
||||
- `REJECT_CANCEL` _int_ - The pending order activation request is rejected, the order is canceled.
|
||||
- `LONG_ONLY` _int_ - The request is rejected, because the "Only long positions are allowed" rule is set for the
|
||||
symbol (POSITION_TYPE_BUY)
|
||||
- `SHORT_ONLY` _int_ - The request is rejected, because the "Only short positions are allowed" rule is set for the
|
||||
symbol (POSITION_TYPE_SELL)
|
||||
- `CLOSE_ONLY` _int_ - The request is rejected, because the "Only position closing is allowed" rule is set for the
|
||||
symbol
|
||||
- `FIFO_CLOSE` _int_ - The request is rejected, because "Position closing is allowed only by FIFO rule" flag is set
|
||||
for the trading account (ACCOUNT_FIFO_CLOSE=true)
|
||||
|
||||
<a id="aiomql.core.constants.AccountStopOutMode"></a>
|
||||
|
||||
## AccountStopOutMode Objects
|
||||
|
||||
```python
|
||||
class AccountStopOutMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ACCOUNT_STOPOUT_MODE Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `PERCENT` _int_ - Account stop out mode in percents
|
||||
- `MONEY` _int_ - Account stop out mode in money
|
||||
|
||||
<a id="aiomql.core.constants.AccountMarginMode"></a>
|
||||
|
||||
## AccountMarginMode Objects
|
||||
|
||||
```python
|
||||
class AccountMarginMode(Repr, IntEnum)
|
||||
```
|
||||
|
||||
ACCOUNT_MARGIN_MODE Enum.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `RETAIL_NETTING` _int_ - Used for the OTC markets to interpret positions in the "netting"
|
||||
mode (only one position can exist for one symbol). The margin is calculated based on the symbol
|
||||
type (SYMBOL_TRADE_CALC_MODE).
|
||||
|
||||
- `EXCHANGE` _int_ - Used for the exchange markets. Margin is calculated based on the discounts specified in
|
||||
symbol settings. Discounts are set by the broker, but not less than the values set by the exchange.
|
||||
|
||||
- `HEDGING` _int_ - Used for the exchange markets where individual positions are possible
|
||||
(hedging, multiple positions can exist for one symbol). The margin is calculated based on the symbol
|
||||
type (SYMBOL_TRADE_CALC_MODE) taking into account the hedged margin (SYMBOL_MARGIN_HEDGED).
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.errors](#aiomql.core.errors)
|
||||
* [Error](#aiomql.core.errors.Error)
|
||||
|
||||
<a id="aiomql.core.errors"></a>
|
||||
|
||||
# aiomql.core.errors
|
||||
|
||||
<a id="aiomql.core.errors.Error"></a>
|
||||
|
||||
## Error Objects
|
||||
|
||||
```python
|
||||
class Error()
|
||||
```
|
||||
|
||||
Error class for handling errors from MetaTrader 5.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.exceptions](#aiomql.core.exceptions)
|
||||
* [LoginError](#aiomql.core.exceptions.LoginError)
|
||||
* [VolumeError](#aiomql.core.exceptions.VolumeError)
|
||||
* [SymbolError](#aiomql.core.exceptions.SymbolError)
|
||||
* [OrderError](#aiomql.core.exceptions.OrderError)
|
||||
|
||||
<a id="aiomql.core.exceptions"></a>
|
||||
|
||||
# aiomql.core.exceptions
|
||||
|
||||
Exceptions for the aiomql package.
|
||||
|
||||
<a id="aiomql.core.exceptions.LoginError"></a>
|
||||
|
||||
## LoginError Objects
|
||||
|
||||
```python
|
||||
class LoginError(Exception)
|
||||
```
|
||||
|
||||
Raised when an error occurs when logging in.
|
||||
|
||||
<a id="aiomql.core.exceptions.VolumeError"></a>
|
||||
|
||||
## VolumeError Objects
|
||||
|
||||
```python
|
||||
class VolumeError(Exception)
|
||||
```
|
||||
|
||||
Raised when a volume is not valid or out of range for a symbol.
|
||||
|
||||
<a id="aiomql.core.exceptions.SymbolError"></a>
|
||||
|
||||
## SymbolError Objects
|
||||
|
||||
```python
|
||||
class SymbolError(Exception)
|
||||
```
|
||||
|
||||
Raised when a symbol is not provided where required or not available in the Market Watch.
|
||||
|
||||
<a id="aiomql.core.exceptions.OrderError"></a>
|
||||
|
||||
## OrderError Objects
|
||||
|
||||
```python
|
||||
class OrderError(Exception)
|
||||
```
|
||||
|
||||
Raised when an error occurs when working with the order class.
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.meta\_trader](#aiomql.core.meta_trader)
|
||||
* [MetaTrader](#aiomql.core.meta_trader.MetaTrader)
|
||||
* [\_\_aenter\_\_](#aiomql.core.meta_trader.MetaTrader.__aenter__)
|
||||
* [\_\_aexit\_\_](#aiomql.core.meta_trader.MetaTrader.__aexit__)
|
||||
* [login](#aiomql.core.meta_trader.MetaTrader.login)
|
||||
* [initialize](#aiomql.core.meta_trader.MetaTrader.initialize)
|
||||
* [shutdown](#aiomql.core.meta_trader.MetaTrader.shutdown)
|
||||
* [version](#aiomql.core.meta_trader.MetaTrader.version)
|
||||
* [account\_info](#aiomql.core.meta_trader.MetaTrader.account_info)
|
||||
* [orders\_get](#aiomql.core.meta_trader.MetaTrader.orders_get)
|
||||
|
||||
<a id="aiomql.core.meta_trader"></a>
|
||||
|
||||
# aiomql.core.meta\_trader
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader"></a>
|
||||
|
||||
## MetaTrader Objects
|
||||
|
||||
```python
|
||||
class MetaTrader(metaclass=BaseMeta)
|
||||
```
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.__aenter__"></a>
|
||||
|
||||
#### \_\_aenter\_\_
|
||||
|
||||
```python
|
||||
async def __aenter__() -> 'MetaTrader'
|
||||
```
|
||||
|
||||
Async context manager entry point.
|
||||
Initializes the connection to the MetaTrader terminal.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `MetaTrader` - An instance of the MetaTrader class.
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.__aexit__"></a>
|
||||
|
||||
#### \_\_aexit\_\_
|
||||
|
||||
```python
|
||||
async def __aexit__(exc_type, exc_val, exc_tb)
|
||||
```
|
||||
|
||||
Async context manager exit point. Closes the connection to the MetaTrader terminal.
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.login"></a>
|
||||
|
||||
#### login
|
||||
|
||||
```python
|
||||
async def login(login: int,
|
||||
password: str,
|
||||
server: str,
|
||||
timeout: int = 60000) -> bool
|
||||
```
|
||||
|
||||
Connects to the MetaTrader terminal using the specified login, password and server.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `login` _int_ - The trading account number.
|
||||
- `password` _str_ - The trading account password.
|
||||
- `server` _str_ - The trading server name.
|
||||
- `timeout` _int_ - The timeout for the connection in seconds.
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `bool` - True if successful, False otherwise.
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.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.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `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_ - The timeout for the connection in seconds.
|
||||
- `portable` _bool_ - If True, the terminal will be launched in portable mode.
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `bool` - True if successful, False otherwise.
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.shutdown"></a>
|
||||
|
||||
#### shutdown
|
||||
|
||||
```python
|
||||
async def shutdown() -> None
|
||||
```
|
||||
|
||||
Closes the connection to the MetaTrader terminal.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `None` - None
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.version"></a>
|
||||
|
||||
#### version
|
||||
|
||||
```python
|
||||
async def version() -> tuple[int, int, str] | None
|
||||
```
|
||||
|
||||
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.account_info"></a>
|
||||
|
||||
#### account\_info
|
||||
|
||||
```python
|
||||
async def account_info() -> AccountInfo | None
|
||||
```
|
||||
|
||||
|
||||
|
||||
<a id="aiomql.core.meta_trader.MetaTrader.orders_get"></a>
|
||||
|
||||
#### orders\_get
|
||||
|
||||
```python
|
||||
async def orders_get(group: str = "",
|
||||
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.
|
||||
Call without parameters. Return active orders on all symbols
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `symbol` _str_ - Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored.
|
||||
|
||||
- `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.
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `list[TradeOrder]` - A list of active trade orders as TradeOrder objects
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
# Table of Contents
|
||||
|
||||
* [aiomql.core.models](#aiomql.core.models)
|
||||
* [AccountInfo](#aiomql.core.models.AccountInfo)
|
||||
* [TerminalInfo](#aiomql.core.models.TerminalInfo)
|
||||
* [SymbolInfo](#aiomql.core.models.SymbolInfo)
|
||||
* [BookInfo](#aiomql.core.models.BookInfo)
|
||||
* [TradeOrder](#aiomql.core.models.TradeOrder)
|
||||
* [TradeRequest](#aiomql.core.models.TradeRequest)
|
||||
* [OrderCheckResult](#aiomql.core.models.OrderCheckResult)
|
||||
* [OrderSendResult](#aiomql.core.models.OrderSendResult)
|
||||
* [TradePosition](#aiomql.core.models.TradePosition)
|
||||
* [TradeDeal](#aiomql.core.models.TradeDeal)
|
||||
|
||||
<a id="aiomql.core.models"></a>
|
||||
|
||||
# aiomql.core.models
|
||||
|
||||
<a id="aiomql.core.models.AccountInfo"></a>
|
||||
|
||||
## AccountInfo Objects
|
||||
|
||||
```python
|
||||
class AccountInfo(Base)
|
||||
```
|
||||
|
||||
Account Information Class.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `login` - int
|
||||
- `password` - str
|
||||
- `server` - str
|
||||
- `trade_mode` - AccountTradeMode
|
||||
- `balance` - float
|
||||
- `leverage` - float
|
||||
- `profit` - float
|
||||
- `point` - float
|
||||
- `amount` - float = 0
|
||||
- `equity` - float
|
||||
- `credit` - float
|
||||
- `margin` - float
|
||||
- `margin_level` - float
|
||||
- `margin_free` - float
|
||||
- `margin_mode` - AccountMarginMode
|
||||
- `margin_so_mode` - AccountStopoutMode
|
||||
- `margin_so_call` - float
|
||||
- `margin_so_so` - float
|
||||
- `margin_initial` - float
|
||||
- `margin_maintenance` - float
|
||||
- `fifo_close` - bool
|
||||
- `limit_orders` - float
|
||||
- `currency` - str = "USD"
|
||||
- `trade_allowed` - bool = True
|
||||
- `trade_expert` - bool = True
|
||||
- `currency_digits` - int
|
||||
- `assets` - float
|
||||
- `liabilities` - float
|
||||
- `commission_blocked` - float
|
||||
- `name` - str
|
||||
- `company` - str
|
||||
|
||||
<a id="aiomql.core.models.TerminalInfo"></a>
|
||||
|
||||
## TerminalInfo Objects
|
||||
|
||||
```python
|
||||
class TerminalInfo(Base)
|
||||
```
|
||||
|
||||
Terminal information class. Holds information about the terminal.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `community_account` - bool
|
||||
- `community_connection` - bool
|
||||
- `connected` - bool
|
||||
- `dlls_allowed` - bool
|
||||
- `trade_allowed` - bool
|
||||
- `tradeapi_disabled` - bool
|
||||
- `email_enabled` - bool
|
||||
- `ftp_enabled` - bool
|
||||
- `notifications_enabled` - bool
|
||||
- `mqid` - bool
|
||||
- `build` - int
|
||||
- `maxbars` - int
|
||||
- `codepage` - int
|
||||
- `ping_last` - int
|
||||
- `community_balance` - float
|
||||
- `retransmission` - float
|
||||
- `company` - str
|
||||
- `name` - str
|
||||
- `language` - str
|
||||
- `path` - str
|
||||
- `data_path` - str
|
||||
- `commondata_path` - str
|
||||
|
||||
<a id="aiomql.core.models.SymbolInfo"></a>
|
||||
|
||||
## SymbolInfo Objects
|
||||
|
||||
```python
|
||||
class SymbolInfo(Base)
|
||||
```
|
||||
|
||||
Symbol Information Class. Symbols are financial instruments available for trading in the MetaTrader 5 terminal.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `name` - str
|
||||
- `custom` - bool
|
||||
- `chart_mode` - SymbolChartMode
|
||||
- `select` - bool
|
||||
- `visible` - bool
|
||||
- `session_deals` - int
|
||||
- `session_buy_orders` - int
|
||||
- `session_sell_orders` - int
|
||||
- `volume` - float
|
||||
- `volumehigh` - float
|
||||
- `volumelow` - float
|
||||
- `time` - int
|
||||
- `digits` - int
|
||||
- `spread` - float
|
||||
- `spread_float` - bool
|
||||
- `ticks_bookdepth` - int
|
||||
- `trade_calc_mode` - SymbolCalcMode
|
||||
- `trade_mode` - SymbolTradeMode
|
||||
- `start_time` - int
|
||||
- `expiration_time` - int
|
||||
- `trade_stops_level` - int
|
||||
- `trade_freeze_level` - int
|
||||
- `trade_exemode` - SymbolTradeExecution
|
||||
- `swap_mode` - SymbolSwapMode
|
||||
- `swap_rollover3days` - DayOfWeek
|
||||
- `margin_hedged_use_leg` - bool
|
||||
- `expiration_mode` - int
|
||||
- `filling_mode` - int
|
||||
- `order_mode` - int
|
||||
- `order_gtc_mode` - SymbolOrderGTCMode
|
||||
- `option_mode` - SymbolOptionMode
|
||||
- `option_right` - SymbolOptionRight
|
||||
- `bid` - float
|
||||
- `bidhigh` - float
|
||||
- `bidlow` - float
|
||||
- `ask` - float
|
||||
- `askhigh` - float
|
||||
- `asklow` - float
|
||||
- `last` - float
|
||||
- `lasthigh` - float
|
||||
- `lastlow` - float
|
||||
- `volume_real` - float
|
||||
- `volumehigh_real` - float
|
||||
- `volumelow_real` - float
|
||||
- `option_strike` - float
|
||||
- `point` - float
|
||||
- `trade_tick_value` - float
|
||||
- `trade_tick_value_profit` - float
|
||||
- `trade_tick_value_loss` - float
|
||||
- `trade_tick_size` - float
|
||||
- `trade_contract_size` - float
|
||||
- `trade_accrued_interest` - float
|
||||
- `trade_face_value` - float
|
||||
- `trade_liquidity_rate` - float
|
||||
- `volume_min` - float
|
||||
- `volume_max` - float
|
||||
- `volume_step` - float
|
||||
- `volume_limit` - float
|
||||
- `swap_long` - float
|
||||
- `swap_short` - float
|
||||
- `margin_initial` - float
|
||||
- `margin_maintenance` - float
|
||||
- `session_volume` - float
|
||||
- `session_turnover` - float
|
||||
- `session_interest` - float
|
||||
- `session_buy_orders_volume` - float
|
||||
- `session_sell_orders_volume` - float
|
||||
- `session_open` - float
|
||||
- `session_close` - float
|
||||
- `session_aw` - float
|
||||
- `session_price_settlement` - float
|
||||
- `session_price_limit_min` - float
|
||||
- `session_price_limit_max` - float
|
||||
- `margin_hedged` - float
|
||||
- `price_change` - float
|
||||
- `price_volatility` - float
|
||||
- `price_theoretical` - float
|
||||
- `price_greeks_delta` - float
|
||||
- `price_greeks_theta` - float
|
||||
- `price_greeks_gamma` - float
|
||||
- `price_greeks_vega` - float
|
||||
- `price_greeks_rho` - float
|
||||
- `price_greeks_omega` - float
|
||||
- `price_sensitivity` - float
|
||||
- `basis` - str
|
||||
- `category` - str
|
||||
- `currency_base` - str
|
||||
- `currency_profit` - str
|
||||
- `currency_margin` - Any
|
||||
- `bank` - str
|
||||
- `description` - str
|
||||
- `exchange` - str
|
||||
- `formula` - Any
|
||||
- `isin` - Any
|
||||
- `name` - str
|
||||
- `page` - str
|
||||
- `path` - str
|
||||
|
||||
<a id="aiomql.core.models.BookInfo"></a>
|
||||
|
||||
## BookInfo Objects
|
||||
|
||||
```python
|
||||
class BookInfo(Base)
|
||||
```
|
||||
|
||||
Book Information Class.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `type` - BookType
|
||||
- `price` - float
|
||||
- `volume` - float
|
||||
- `volume_dbl` - float
|
||||
|
||||
<a id="aiomql.core.models.TradeOrder"></a>
|
||||
|
||||
## TradeOrder Objects
|
||||
|
||||
```python
|
||||
class TradeOrder(Base)
|
||||
```
|
||||
|
||||
Trade Order Class.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `ticket` - int
|
||||
- `time_setup` - int
|
||||
- `time_setup_msc` - int
|
||||
- `time_expiration` - int
|
||||
- `time_done` - int
|
||||
- `time_done_msc` - int
|
||||
- `type` - OrderType
|
||||
- `type_time` - OrderTime
|
||||
- `type_filling` - OrderFilling
|
||||
- `state` - int
|
||||
- `magic` - int
|
||||
- `position_id` - int
|
||||
- `position_by_id` - int
|
||||
- `reason` - OrderReason
|
||||
- `volume_current` - float
|
||||
- `volume_initial` - float
|
||||
- `price_open` - float
|
||||
- `sl` - float
|
||||
- `tp` - float
|
||||
- `price_current` - float
|
||||
- `price_stoplimit` - float
|
||||
- `symbol` - str
|
||||
- `comment` - str
|
||||
- `external_id` - str
|
||||
|
||||
<a id="aiomql.core.models.TradeRequest"></a>
|
||||
|
||||
## TradeRequest Objects
|
||||
|
||||
```python
|
||||
class TradeRequest(Base)
|
||||
```
|
||||
|
||||
Trade Request Class.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `action` - TradeAction
|
||||
- `type` - OrderType
|
||||
- `order` - int
|
||||
- `symbol` - str
|
||||
- `volume` - float
|
||||
- `sl` - float
|
||||
- `tp` - float
|
||||
- `price` - float
|
||||
- `deviation` - float
|
||||
- `stop_limit` - float
|
||||
- `type_time` - OrderTime
|
||||
- `type_filling` - OrderFilling
|
||||
- `expiration` - int
|
||||
- `position` - int
|
||||
- `position_by` - int
|
||||
- `comment` - str
|
||||
- `magic` - int
|
||||
- `deviation` - int
|
||||
- `comment` - str
|
||||
|
||||
<a id="aiomql.core.models.OrderCheckResult"></a>
|
||||
|
||||
## OrderCheckResult Objects
|
||||
|
||||
```python
|
||||
class OrderCheckResult(Base)
|
||||
```
|
||||
|
||||
Order Check Result
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `retcode` - int
|
||||
- `balance` - float
|
||||
- `equity` - float
|
||||
- `profit` - float
|
||||
- `margin` - float
|
||||
- `margin_free` - float
|
||||
- `margin_level` - float
|
||||
- `comment` - str
|
||||
- `request` - TradeRequest
|
||||
|
||||
<a id="aiomql.core.models.OrderSendResult"></a>
|
||||
|
||||
## OrderSendResult Objects
|
||||
|
||||
```python
|
||||
class OrderSendResult(Base)
|
||||
```
|
||||
|
||||
Order Send Result
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `retcode` - int
|
||||
- `deal` - int
|
||||
- `order` - int
|
||||
- `volume` - float
|
||||
- `price` - float
|
||||
- `bid` - float
|
||||
- `ask` - float
|
||||
- `comment` - str
|
||||
- `request` - TradeRequest
|
||||
- `request_id` - int
|
||||
- `retcode_external` - int
|
||||
- `profit` - float
|
||||
|
||||
<a id="aiomql.core.models.TradePosition"></a>
|
||||
|
||||
## TradePosition Objects
|
||||
|
||||
```python
|
||||
class TradePosition(Base)
|
||||
```
|
||||
|
||||
Trade Position
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `ticket` - int
|
||||
- `time` - int
|
||||
- `time_msc` - int
|
||||
- `time_update` - int
|
||||
- `time_update_msc` - int
|
||||
- `type` - OrderType
|
||||
- `magic` - float
|
||||
- `identifier` - int
|
||||
- `reason` - PositionReason
|
||||
- `volume` - float
|
||||
- `price_open` - float
|
||||
- `sl` - float
|
||||
- `tp` - float
|
||||
- `price_current` - float
|
||||
- `swap` - float
|
||||
- `profit` - float
|
||||
- `symbol` - str
|
||||
- `comment` - str
|
||||
- `external_id` - str
|
||||
|
||||
<a id="aiomql.core.models.TradeDeal"></a>
|
||||
|
||||
## TradeDeal Objects
|
||||
|
||||
```python
|
||||
class TradeDeal(Base)
|
||||
```
|
||||
|
||||
Trade Deal
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `ticket` - int
|
||||
- `order` - int
|
||||
- `time` - int
|
||||
- `time_msc` - int
|
||||
- `type` - DealType
|
||||
- `entry` - DealEntry
|
||||
- `magic` - int
|
||||
- `position_id` - int
|
||||
- `reason` - DealReason
|
||||
- `volume` - float
|
||||
- `price` - float
|
||||
- `commission` - float
|
||||
- `swap` - float
|
||||
- `profit` - float
|
||||
- `fee` - float
|
||||
- `sl` - float
|
||||
- `tp` - float
|
||||
- `symbol` - str
|
||||
- `comment` - str
|
||||
- `external_id` - str
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
## <a id="executor"></a> Executor
|
||||
|
||||
|
||||
```python
|
||||
class Executor
|
||||
```
|
||||
Executor class for running multiple strategies on multiple symbols concurrently.
|
||||
**Attributes**:
|
||||
|
||||
|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
|
||||
```python
|
||||
def add_workers(strategies: Sequence[type(Strategy)])
|
||||
```
|
||||
Add multiple strategies at once
|
||||
|
||||
*Arguments*:
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**strategies**|**Sequence[type(Strategy)]**|A sequence of strategies.|
|
||||
|
||||
#### remove\_workers
|
||||
```python
|
||||
def remove_workers(*symbols: Sequence[Symbol])
|
||||
```
|
||||
Removes any worker running on a symbol not successfully initialized.
|
||||
|
||||
*Arguments*:
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**symbols**|**Sequence[Symbol]**|A sequence of symbols.|
|
||||
|
||||
#### add\_worker
|
||||
```python
|
||||
def add_worker(strategy: type(Strategy))
|
||||
```
|
||||
Add a strategy instance to the list of workers
|
||||
|
||||
*Arguments*:
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**strategy**|**type(Strategy)**|A strategy instance.|
|
||||
|
||||
|
||||
#### 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*
|
||||
|
||||
| Name | Type |Description|
|
||||
|------------|------------|---|
|
||||
| **func** | **Callable |Coroutine**|A coroutine function.|
|
||||
| **kwargs** | **Dict** |Keyword arguments to pass to the function.|
|
||||
|
||||
#### trade
|
||||
```python
|
||||
def trade(strategy: Strategy)
|
||||
```
|
||||
Wrap the input coroutine function trade method of each strategy with 'asyncio.run'.
|
||||
|
||||
*Arguments*:
|
||||
|
||||
|Name|Type|Description|
|
||||
|---|---|---|
|
||||
|**strategy**|**Strategy**|A strategy instance.|
|
||||
|
||||
#### execute
|
||||
```python
|
||||
async def execute(workers: int = 0)
|
||||
```
|
||||
Run the strategies with a threadpool executor.
|
||||
|
||||
*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.
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
## <a id="aiomhistory"></a> History
|
||||
|
||||
|
||||
```python
|
||||
class History
|
||||
```
|
||||
The history class handles completed trade deals and trade orders in the trading history of an account.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|------------------------------------------------|----|
|
||||
|**deals**|**list[TradeDeal]** | Iterable of trade deals | [] |
|
||||
|**orders**|**list[TradeOrder]** | Iterable of trade orders | [] |
|
||||
|**total_deals**|**int** | Total number of deals | 0 |
|
||||
|**total_orders**|**int** | Total number orders | 0 |
|
||||
|**group**|**str** | Filter for selecting history by symbols. | "" |
|
||||
|**ticket**|**int** | Filter for selecting history by ticket number | 0 |
|
||||
|**position**|**int** | Filter for selecting history deals by position | 0 |
|
||||
|**initialized**|**bool** | check if initial request has been sent to the terminal to get history. | False |
|
||||
|**mt5**|**MetaTrader** | MetaTrader instance | None |
|
||||
|**config**|**Config** | Config instance | None |
|
||||
|
||||
|
||||
#### \_\_init\_\_
|
||||
```python
|
||||
def __init__(*,
|
||||
date_from: datetime | float = 0,
|
||||
date_to: datetime | float = 0,
|
||||
group: str = "",
|
||||
ticket: int = 0,
|
||||
position: int = 0)
|
||||
```
|
||||
*Arguments*:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|------------------------------------------------|----|
|
||||
|**date_from**|**datetime, float** | Date the deals are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Defaults to twenty-four hours from the current time in 'utc' | 0 |
|
||||
|**date_to**|**datetime, float** | Date up to which the deals are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Defaults to the current time in "utc" | 0 |
|
||||
|**group**|**str** | Filter for selecting history by symbols. | "" |
|
||||
|**ticket**|**int** | Filter for selecting history by ticket number | 0 |
|
||||
|**position**|**int** | Filter for selecting history deals by position | 0 |
|
||||
|
||||
#### init
|
||||
```python
|
||||
async def init(deals=True, orders=True) -> bool
|
||||
```
|
||||
Get history deals and orders
|
||||
|
||||
*Arguments*:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|------------------------------------------------|----|
|
||||
|**deals**|**bool** | If true get history deals during initial request to terminal | True |
|
||||
|**orders**|**bool** | If true get history orders during initial request to terminal | True |
|
||||
|
||||
*returns*:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|------------------------------------------------|----|
|
||||
|**bool**|**bool** | True if all requests were successful else False | False |
|
||||
- `bool` - True if all requests were successful else False
|
||||
|
||||
#### get_deals
|
||||
```python
|
||||
async def get_deals() -> list[TradeDeal]
|
||||
```
|
||||
Get deals from trading history using the parameters set in the constructor.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|------------------------------------------------|----|
|
||||
|**deals**|**list[TradeDeal]** | A list of trade deals | [] |
|
||||
|
||||
#### deals_total
|
||||
```python
|
||||
async def deals_total() -> int
|
||||
```
|
||||
Get total number of deals within the specified period in the constructor.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|------------------------------------------------|----|
|
||||
|**total_deals**|**int** | Total number of deals | 0 |
|
||||
|
||||
#### get_orders
|
||||
```python
|
||||
async def get_orders() -> list[TradeOrder]
|
||||
```
|
||||
Get orders from trading history using the parameters set in the constructor.
|
||||
*returns*:
|
||||
|
||||
|Name|Type|Description|Default|
|
||||
|---|---|---|---|
|
||||
|**orders**|**list[TradeOrder]**|A list of trade orders|[]|
|
||||
|
||||
#### orders_total
|
||||
```python
|
||||
async def orders_total() -> int
|
||||
```
|
||||
Get total number of orders within the specified period in the constructor.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Name| Type | Description | Default |
|
||||
|---|---------------------|--------------------|----|
|
||||
|**total_orders**|**int** | Total number orders| 0 |
|
||||
|
||||
+3842
File diff suppressed because it is too large
Load Diff
+135
@@ -0,0 +1,135 @@
|
||||
## <a id="order"></a> Order
|
||||
|
||||
|
||||
```python
|
||||
class Order(TradeRequest)
|
||||
```
|
||||
Trade order related functions and properties. Subclass of [TradeRequest](#traderequest).
|
||||
|
||||
#### \_\_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*:
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**SymbolError**|If symbol is not provided|
|
||||
|
||||
#### <a id=order.Order.orders_total> orders_total
|
||||
```python
|
||||
async def orders_total()
|
||||
```
|
||||
Get the number of active orders.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**int**|total number of active orders|
|
||||
|
||||
#### orders
|
||||
```python
|
||||
async def orders() -> tuple[TradeOrder]
|
||||
```
|
||||
Get the list of active orders for the current symbol.
|
||||
|
||||
*Returns*:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**tuple[TradeOrder]**|A Tuple of active trade orders as TradeOrder objects|
|
||||
|
||||
#### check
|
||||
```python
|
||||
async def check() -> OrderCheckResult
|
||||
```
|
||||
Check funds sufficiency for performing a required trading operation and the possibility to execute it at
|
||||
|
||||
*returns*:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**OrderCheckResult**|An OrderCheckResult object|
|
||||
|
||||
*raises*:
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**OrderError**|If not successful|
|
||||
- `OrderError` - If not successful
|
||||
|
||||
#### <a id="order.Order.send"></a> send
|
||||
|
||||
```python
|
||||
async def send() -> OrderSendResult
|
||||
```
|
||||
Send a request to perform a trading operation from the terminal to the trade server.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**OrderSendResult**|An OrderSendResult object|
|
||||
|
||||
*raises*:
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**OrderError**|If not successful|
|
||||
|
||||
#### <a id="order.Order.calc_margin"></a> calc_margin
|
||||
```python
|
||||
async def calc_margin() -> float
|
||||
```
|
||||
Return the required margin in the account currency to perform a specified trading operation.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**float**|Returns float value if successful|
|
||||
|
||||
*raises*:
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**OrderError**|If not successful|
|
||||
|
||||
|
||||
#### <a id="order.Order.calc_profit"></a> calc_profit
|
||||
```python
|
||||
async def calc_profit() -> float
|
||||
```
|
||||
Return profit in the account currency for a specified trading operation.
|
||||
|
||||
*returns*:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**float**|Returns float value if successful|
|
||||
|
||||
*raises*:
|
||||
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**OrderError**|If not successful|
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
## <a id="positions"></a> Positions
|
||||
|
||||
```python
|
||||
class Positions
|
||||
```
|
||||
Get and handle Open positions.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
|Name|Type|Description|Default|
|
||||
|---|---|---|---|
|
||||
|**symbol**|**str**|Financial instrument name.|""|
|
||||
|**group**|**str**|The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only positions meeting a specified criteria for a symbol name.|""|
|
||||
|**ticket**|**int**|Position ticket.|0|
|
||||
|**mt5**|**MetaTrader**|MetaTrader instance.|None|
|
||||
|
||||
- `symbol` _str_ - Financial instrument name.
|
||||
- `group` _str_ - The filter for arranging a group of necessary symbols. Optional named parameter.
|
||||
If the group is specified, the function returns only positions meeting a specified criteria for a symbol name.
|
||||
- `ticket` _int_ - Position ticket.
|
||||
- `mt5` _MetaTrader_ - MetaTrader instance.
|
||||
|
||||
<a id="positions.Positions.__init__"></a> #### \_\_init\_\_
|
||||
|
||||
```python
|
||||
def __init__(*, symbol: str = "", group: str = "", ticket: int = 0)
|
||||
```
|
||||
Get Open Positions.
|
||||
|
||||
|Name|Type|Description|Default|
|
||||
|---|---|---|---|
|
||||
|**symbol**|**str**|Financial instrument name.|""|
|
||||
|**group**|**str**|The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only positions meeting a specified criteria for a symbol name.|""|
|
||||
|**ticket**|**int**|Position ticket.|0|
|
||||
|
||||
#### <a id="positions.Positions.positions_total"></a> positions_total
|
||||
```python
|
||||
async def positions_total() -> int
|
||||
```
|
||||
Get the number of open positions.
|
||||
|
||||
**Returns**:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**int**|Return total number of open positions|
|
||||
|
||||
#### <a id="positions.Positions.positions_get"></a> positions_get
|
||||
|
||||
```python
|
||||
async def positions_get()
|
||||
```
|
||||
Get open positions with the ability to filter by symbol or ticket.
|
||||
|
||||
**Returns**:
|
||||
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
|**list[TradePosition]**|A list of open trade positions|
|
||||
|
||||
|
||||
|
||||
|
||||
#### <a id="aiomql.positions.Positions.close_all"></a> close_all
|
||||
```python
|
||||
async def close_all() -> int
|
||||
```
|
||||
Close all open positions for the trading account.
|
||||
|
||||
**Returns**:
|
||||
- `int` - Return number of positions closed.
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<a id="aiomql.ram"></a>
|
||||
|
||||
# aiomql.ram
|
||||
|
||||
Risk Assessment and Management
|
||||
|
||||
<a id="aiomql.ram.RAM"></a>
|
||||
|
||||
## RAM Objects
|
||||
|
||||
```python
|
||||
class RAM()
|
||||
```
|
||||
|
||||
<a id="aiomql.ram.RAM.__init__"></a>
|
||||
|
||||
#### \_\_init\_\_
|
||||
|
||||
```python
|
||||
def __init__(**kwargs)
|
||||
```
|
||||
|
||||
Risk Assessment and Management. All provided keyword arguments are set as attributes.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `kwargs` _Dict_ - Keyword arguments.
|
||||
|
||||
Defaults:
|
||||
- `risk_to_reward` _float_ - Risk to reward ratio 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
|
||||
- `volume` _float_ - Volume to trade 0
|
||||
|
||||
<a id="aiomql.ram.RAM.get_amount"></a>
|
||||
|
||||
#### get\_amount
|
||||
|
||||
```python
|
||||
async def get_amount(risk: float = 0) -> float
|
||||
```
|
||||
|
||||
Calculate the amount to risk per trade as a percentage of free margin.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `risk` _float_ - Percentage of account balance to risk per trade. Defaults to zero.
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `float` - Amount to risk per trade
|
||||
|
||||
<a id="aiomql.ram.RAM.get_volume"></a>
|
||||
|
||||
#### get\_volume
|
||||
|
||||
```python
|
||||
async def get_volume(*,
|
||||
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.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `symbol` _Symbol_ - Financial instrument
|
||||
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `pips` _float_ - Target pips. Defaults to zero.
|
||||
- `amount` _float_ - Amount to risk per trade. Defaults to zero.
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `float` - Volume to trade
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
<a id="aiomql.records"></a>
|
||||
|
||||
# aiomql.records
|
||||
|
||||
This module contains the Records class, which is used to read and update trade records from csv files.
|
||||
|
||||
<a id="aiomql.records.Records"></a>
|
||||
|
||||
## Records Objects
|
||||
|
||||
```python
|
||||
class Records()
|
||||
```
|
||||
|
||||
This utility class read trade records from csv files, and update them based on their closing positions.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `config` - Config object
|
||||
- `records_dir(Path)` - Path to directory containing record of placed trades, If not given takes the default
|
||||
from the config
|
||||
|
||||
<a id="aiomql.records.Records.__init__"></a>
|
||||
|
||||
#### \_\_init\_\_
|
||||
|
||||
```python
|
||||
def __init__(records_dir: Path = '')
|
||||
```
|
||||
|
||||
Initialize the Records class.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `records_dir` _Path_ - Path to directory containing record of placed trades.
|
||||
|
||||
<a id="aiomql.records.Records.get_records"></a>
|
||||
|
||||
#### get\_records
|
||||
|
||||
```python
|
||||
async def get_records()
|
||||
```
|
||||
|
||||
Get trade records from records_dir folder
|
||||
|
||||
**Yields**:
|
||||
|
||||
- `files` - Trade record files
|
||||
|
||||
<a id="aiomql.records.Records.read_update"></a>
|
||||
|
||||
#### read\_update
|
||||
|
||||
```python
|
||||
async def read_update(file: Path)
|
||||
```
|
||||
|
||||
Read and update trade records
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `file` - Trade record file
|
||||
|
||||
<a id="aiomql.records.Records.update_rows"></a>
|
||||
|
||||
#### update\_rows
|
||||
|
||||
```python
|
||||
async def update_rows(rows: list[dict]) -> list[dict]
|
||||
```
|
||||
|
||||
Update the rows of entered trades in the csv file with the actual profit.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `rows` - A list of dictionaries from the dictionary writer object of the csv file.
|
||||
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `list[dict]` - A list of dictionaries with the actual profit and win status.
|
||||
|
||||
<a id="aiomql.records.Records.update_records"></a>
|
||||
|
||||
#### update\_records
|
||||
|
||||
```python
|
||||
async def update_records()
|
||||
```
|
||||
|
||||
Update trade records in the records_dir folder.
|
||||
|
||||
<a id="aiomql.records.Records.update_record"></a>
|
||||
|
||||
#### update\_record
|
||||
|
||||
```python
|
||||
async def update_record(file: Path | str)
|
||||
```
|
||||
|
||||
Update a single trade record file.
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<a id="aiomql.result"></a>
|
||||
|
||||
# aiomql.result
|
||||
|
||||
<a id="aiomql.result.Result"></a>
|
||||
|
||||
## Result Objects
|
||||
|
||||
```python
|
||||
class Result()
|
||||
```
|
||||
|
||||
A base class for handling trade results and strategy parameters for record keeping and reference purpose.
|
||||
The data property must be implemented in the subclass
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `config` _Config_ - The configuration object
|
||||
- `name` - Any desired name for the result file object
|
||||
|
||||
<a id="aiomql.result.Result.__init__"></a>
|
||||
|
||||
#### \_\_init\_\_
|
||||
|
||||
```python
|
||||
def __init__(result: OrderSendResult, parameters: dict = None, name: str = '')
|
||||
```
|
||||
|
||||
Prepare result data
|
||||
|
||||
**Arguments**:
|
||||
|
||||
result:
|
||||
parameters:
|
||||
name:
|
||||
|
||||
<a id="aiomql.result.Result.to_csv"></a>
|
||||
|
||||
#### to\_csv
|
||||
|
||||
```python
|
||||
async def to_csv()
|
||||
```
|
||||
|
||||
Record trade results and associated parameters as a csv file
|
||||
|
||||
<a id="aiomql.result.Result.save_csv"></a>
|
||||
|
||||
#### save\_csv
|
||||
|
||||
```python
|
||||
async def save_csv()
|
||||
```
|
||||
|
||||
Save trade results and associated parameters as a csv file in a separate thread
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<a id="aiomql.strategy"></a>
|
||||
|
||||
# aiomql.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**:
|
||||
|
||||
- `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\_\_
|
||||
|
||||
```python
|
||||
def __init__(*, symbol: Symbol, params: dict = 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
|
||||
|
||||
```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
|
||||
|
||||
```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.
|
||||
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
<a id="aiomql.symbol"></a>
|
||||
|
||||
# aiomql.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**:
|
||||
|
||||
- `tick` _Tick_ - Price tick object for instrument
|
||||
- `account` - An instance of the current trading account
|
||||
|
||||
|
||||
**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
|
||||
|
||||
```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
|
||||
|
||||
```python
|
||||
async def info_tick(*, name: str = "") -> Tick
|
||||
```
|
||||
|
||||
Get the current price tick of a financial instrument.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `name` - if name is supplied get price tick of that financial instrument
|
||||
|
||||
|
||||
**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
|
||||
|
||||
```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**:
|
||||
|
||||
- `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
|
||||
|
||||
```python
|
||||
async def info() -> SymbolInfo
|
||||
```
|
||||
|
||||
Get data on the specified financial instrument and update the symbol object properties
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `(SymbolInfo)` - SymbolInfo if successful
|
||||
|
||||
|
||||
**Raises**:
|
||||
|
||||
- `ValueError` - If request was unsuccessful and None was returned
|
||||
|
||||
<a id="aiomql.symbol.Symbol.init"></a>
|
||||
|
||||
#### init
|
||||
|
||||
```python
|
||||
async def init() -> bool
|
||||
```
|
||||
|
||||
Initialized the symbol by pulling properties from the terminal
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `bool` - Returns True if symbol info was successful initialized
|
||||
|
||||
<a id="aiomql.symbol.Symbol.book_add"></a>
|
||||
|
||||
#### 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**:
|
||||
|
||||
- `bool` - True if successful, otherwise – False.
|
||||
|
||||
<a id="aiomql.symbol.Symbol.book_get"></a>
|
||||
|
||||
#### book\_get
|
||||
|
||||
```python
|
||||
async def book_get() -> tuple[BookInfo]
|
||||
```
|
||||
|
||||
Returns a tuple of BookInfo featuring Market Depth entries for the specified symbol.
|
||||
|
||||
**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
|
||||
|
||||
```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>
|
||||
|
||||
#### 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
|
||||
|
||||
**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
|
||||
|
||||
```python
|
||||
async def currency_conversion(*, amount: float, base: str,
|
||||
quote: str) -> float
|
||||
```
|
||||
|
||||
Convert from one currency to the other.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `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**:
|
||||
|
||||
- `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
|
||||
|
||||
```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**:
|
||||
|
||||
- `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
|
||||
|
||||
```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**:
|
||||
|
||||
- `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
|
||||
|
||||
```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**:
|
||||
|
||||
- `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
|
||||
|
||||
```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.
|
||||
|
||||
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
|
||||
|
||||
```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.
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<a id="aiomql.terminal"></a>
|
||||
|
||||
# aiomql.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.
|
||||
|
||||
**Notes**:
|
||||
|
||||
Other attributes are defined in the TerminalInfo Class
|
||||
|
||||
<a id="aiomql.terminal.Terminal.initialize"></a>
|
||||
|
||||
#### 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**:
|
||||
|
||||
- `bool` - True if successful else False
|
||||
|
||||
<a id="aiomql.terminal.Terminal.version"></a>
|
||||
|
||||
#### 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**:
|
||||
|
||||
- `Version` - version of tuple as Version object
|
||||
|
||||
|
||||
**Raises**:
|
||||
|
||||
- `ValueError` - If the terminal version cannot be obtained
|
||||
|
||||
<a id="aiomql.terminal.Terminal.info"></a>
|
||||
|
||||
#### 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
|
||||
|
||||
```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
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
<a id="aiomql.ticks"></a>
|
||||
|
||||
# aiomql.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**:
|
||||
|
||||
- `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
|
||||
|
||||
```python
|
||||
def set_attributes(**kwargs)
|
||||
```
|
||||
|
||||
Set attributes from keyword arguments
|
||||
|
||||
<a id="aiomql.ticks.Ticks"></a>
|
||||
|
||||
## Ticks Objects
|
||||
|
||||
```python
|
||||
class Ticks()
|
||||
```
|
||||
|
||||
Container data class for price ticks. Arrange in chronological order.
|
||||
Supports iteration, slicing and assignment
|
||||
|
||||
**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\_\_
|
||||
|
||||
```python
|
||||
def __init__(*, data: DataFrame | Iterable, flip=False)
|
||||
```
|
||||
|
||||
Initialize the Ticks class. Creates a DataFrame of price ticks from the data argument.
|
||||
|
||||
**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
|
||||
|
||||
```python
|
||||
@property
|
||||
def ta()
|
||||
```
|
||||
|
||||
Access to the pandas_ta library for performing technical analysis on the underlying data attribute.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `pandas_ta` - The pandas_ta library
|
||||
|
||||
<a id="aiomql.ticks.Ticks.ta_lib"></a>
|
||||
|
||||
#### ta\_lib
|
||||
|
||||
```python
|
||||
@property
|
||||
def ta_lib()
|
||||
```
|
||||
|
||||
Access to the ta library for performing technical analysis. Not dependent on the underlying data attribute.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `ta` - The ta library
|
||||
|
||||
<a id="aiomql.ticks.Ticks.data"></a>
|
||||
|
||||
#### data
|
||||
|
||||
```python
|
||||
@property
|
||||
def data() -> DataFrame
|
||||
```
|
||||
|
||||
DataFrame of price ticks arranged in chronological order.
|
||||
|
||||
<a id="aiomql.ticks.Ticks.rename"></a>
|
||||
|
||||
#### 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
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<a id="aiomql.trader"></a>
|
||||
|
||||
# aiomql.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**:
|
||||
|
||||
- `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\_\_
|
||||
|
||||
```python
|
||||
def __init__(*, symbol: Symbol, ram: RAM = 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
|
||||
|
||||
```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**:
|
||||
|
||||
- `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
|
||||
|
||||
```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**:
|
||||
|
||||
- `pips` - Target pips
|
||||
|
||||
<a id="aiomql.trader.Trader.place_trade"></a>
|
||||
|
||||
#### 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
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import asyncio
|
||||
|
||||
from aiomql.lib import FingerTrap
|
||||
from aiomql import Bot, Account, ForexSymbol, Records, RAM, DealTrader
|
||||
|
||||
|
||||
def build_bot():
|
||||
# Either initialize an account here with your login details here or set them in the aiomql.json file.
|
||||
# acc = Account(login=1111111111, password='*******', server='Deriv-Demo')
|
||||
bot = 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)
|
||||
bot.execute()
|
||||
|
||||
|
||||
build_bot()
|
||||
|
||||
async def main():
|
||||
async with Account():
|
||||
res = Records()
|
||||
await res.update_records()
|
||||
|
||||
# asyncio.run(main())
|
||||
@@ -0,0 +1,44 @@
|
||||
import asyncio
|
||||
from aiomql import Symbol, TimeFrame, Account
|
||||
|
||||
|
||||
async def main():
|
||||
async with Account():
|
||||
# create a symbol
|
||||
sym = Symbol(name="AUDUSD")
|
||||
|
||||
# Get EURUSD price bars for the past 48 hours
|
||||
candles = await sym.copy_rates_from_pos(timeframe=TimeFrame.H1, count=48, start_position=0)
|
||||
print(len(candles)) # 48
|
||||
|
||||
# get the latest candle by accessing the last one.
|
||||
last = candles[-1] # A Candle object
|
||||
print(type(last))
|
||||
print(last.time)
|
||||
|
||||
# get the last five hours
|
||||
last_five = candles[-5:] # A Candles object.
|
||||
print(type(last_five))
|
||||
print(last_five)
|
||||
|
||||
close = candles['close'] # close price of all the candles as a pandas series
|
||||
print(type(close))
|
||||
print(close)
|
||||
|
||||
# compute ema using pandas ta
|
||||
candles.ta.ema(length=34, append=True, fillna=0)
|
||||
# rename the column to ema
|
||||
candles.rename(EMA_34='ema')
|
||||
|
||||
# use talib to compute crossover. This returns a series object that is not part of the candles object.
|
||||
closeXema = candles.ta_lib.cross(candles.close, candles.ema)
|
||||
# add to the candles
|
||||
candles['closeXema'] = closeXema
|
||||
print(candles)
|
||||
|
||||
# iterate over the first 5 candles
|
||||
for candle in candles[:5]:
|
||||
print(candle.open, candle.Index)
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,37 @@
|
||||
import asyncio
|
||||
|
||||
from aiomql import Account, OrderType, TradeAction, Order, ForexSymbol
|
||||
|
||||
|
||||
async def main():
|
||||
async with Account():
|
||||
|
||||
# create a symbol
|
||||
sym = ForexSymbol(name="EURUSD")
|
||||
|
||||
# Confirm the symbol is available for this account and initialize with default values.
|
||||
res = await sym.init()
|
||||
|
||||
# I want to place a market buy order, risk only 2usd, and target 10 pips in this trade.
|
||||
# The ForexSymbol object has a compute_volume method that can be used to compute the volume
|
||||
# given a target pips and amount.
|
||||
volume = await sym.compute_volume(amount=2, pips=10)
|
||||
|
||||
# a risk to reward ratio of 1:2
|
||||
# get the price tick of the symbol
|
||||
tick = await sym.info_tick()
|
||||
sl = tick.ask - (10 * sym.pip)
|
||||
tp = tick.ask + (20 * sym.pip)
|
||||
# create order
|
||||
order = Order(symbol=sym.name, type=OrderType.BUY, volume=volume, action=TradeAction.DEAL,
|
||||
price=tick.ask, sl=sl, tp=tp)
|
||||
# check order. returns an OrderCheckResult object
|
||||
chk = await order.check()
|
||||
print(chk)
|
||||
|
||||
# send order returns an OrderSendResult object
|
||||
res = await order.send()
|
||||
print(res)
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,59 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from aiomql import ForexSymbol, Account, Positions, History, Trader, OrderType, RAM
|
||||
|
||||
|
||||
async def main():
|
||||
# Account details are in the aiomql.json file
|
||||
async with Account():
|
||||
|
||||
# get start time using local timezone
|
||||
tz = datetime.now().astimezone().tzinfo
|
||||
start = datetime.now(tz=tz)
|
||||
|
||||
# create two symbols and initialize them
|
||||
sym1 = ForexSymbol(name="EURUSD")
|
||||
sym2 = ForexSymbol(name="GBPUSD")
|
||||
await sym1.init()
|
||||
await sym2.init()
|
||||
|
||||
# Risk Assets Management instance
|
||||
# fix the amount to be risked at 2 USD. USD is the account currency.
|
||||
ram = RAM(amount=2)
|
||||
|
||||
# Create two traders instance
|
||||
trd = Trader(symbol=sym1, ram=ram)
|
||||
trd2 = Trader(symbol=sym2, ram=ram)
|
||||
|
||||
# Place Trades
|
||||
await trd.place_trade(order_type=OrderType.SELL)
|
||||
await trd2.place_trade(order_type=OrderType.BUY)
|
||||
|
||||
# Create a Positions object
|
||||
pos = Positions(group='*USD*')
|
||||
|
||||
# get the number of open positions
|
||||
total = await pos.positions_total()
|
||||
print(f'{total} Open positions') # 2
|
||||
|
||||
# close all open positions
|
||||
await pos.close_all()
|
||||
end = datetime.now(tz=tz)
|
||||
|
||||
# get the number of open positions
|
||||
total = await pos.positions_total()
|
||||
print(f'{total} Open positions') # 0
|
||||
|
||||
# get historical trades
|
||||
his = History(date_from=start, date_to=end)
|
||||
|
||||
# get the number of deals
|
||||
total_deals = await his.deals_total()
|
||||
print(f'{total_deals} Deals')
|
||||
|
||||
# get the number of order
|
||||
orders = await his.orders_total()
|
||||
print(f'{orders} orders')
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,37 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from aiomql import ForexSymbol, Symbol, TimeFrame, Account
|
||||
|
||||
async def main():
|
||||
async with Account():
|
||||
sym = ForexSymbol(name="EURUSD")
|
||||
res = await sym.init()
|
||||
if not res:
|
||||
print('Symbol not available')
|
||||
return
|
||||
|
||||
# get the last 1000 rates.
|
||||
# data is returned as a Candles object
|
||||
candles = await sym.copy_rates_from_pos(timeframe=TimeFrame.H1, count=1000, start_position=0)
|
||||
print(len(candles)) # 1000
|
||||
|
||||
# get candles of the last 24 hours
|
||||
today = datetime.now()
|
||||
yesterday = today.replace(day=today.day - 1)
|
||||
rates = await sym.copy_rates_range(timeframe=TimeFrame.H1, date_from=yesterday, date_to=today)
|
||||
print(len(rates)) # 24
|
||||
|
||||
# get price ticks for the last 24 hours
|
||||
# data is returned as a Ticks object
|
||||
ticks = await sym.copy_ticks_range(date_from=yesterday, date_to=today)
|
||||
print(len(ticks)) # ??
|
||||
|
||||
# get the current price tick
|
||||
tick = await sym.info_tick()
|
||||
# ask and bid price
|
||||
ask, bid = tick.ask, tick.bid
|
||||
print(ask, bid)
|
||||
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,17 @@
|
||||
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())
|
||||
@@ -0,0 +1,25 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
"setuptools>=42",
|
||||
"wheel"
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "aiomql"
|
||||
version = "3.0.4"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
keywords = ['MetaTrader5', 'Asynchronous', 'Algorithmic Trading', 'Trading Bot']
|
||||
dependencies = ["MetaTrader5>=5.0.37", "pandas>=1.5.0", "pandas-ta>=0.3.14b0"]
|
||||
authors = [{name = "Ichinga Samuel", email = "ichingasamuel@gmail.com"}]
|
||||
description = "Asynchronous MetaTrader5 library and Bot Building Framework"
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://github.com/Ichinga-Samuel/aiomql"
|
||||
"Bug Tracker" = "https://github.com/Ichinga-Samuel/aiomql/issues"
|
||||
@@ -0,0 +1,47 @@
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import asyncio
|
||||
import random
|
||||
import time
|
||||
|
||||
se = set()
|
||||
def fun(arg):
|
||||
while True:
|
||||
time.sleep(10)
|
||||
print('sleep')
|
||||
# print('sleeping')
|
||||
# await asyncio.sleep(random.randint(1, 10))
|
||||
# print('wake up')
|
||||
|
||||
|
||||
def nuf():
|
||||
while True:
|
||||
# time.sleep(5)
|
||||
print('awake')
|
||||
|
||||
|
||||
def main(f):
|
||||
asyncio.run(f())
|
||||
|
||||
|
||||
async def run():
|
||||
# loop = asyncio.get_running_loop()
|
||||
with ThreadPoolExecutor(max_workers=10) as exe:
|
||||
exe.submit(fun, 10)
|
||||
exe.submit(nuf)
|
||||
# r.cancel()
|
||||
# print(r.done())
|
||||
# return r.result()
|
||||
|
||||
|
||||
|
||||
asyncio.run(run())
|
||||
|
||||
# ars = (1, 3, 4)
|
||||
#
|
||||
# def check(f, args):
|
||||
# print(*args)
|
||||
#
|
||||
#
|
||||
# b = {check: (3, ars)}
|
||||
|
||||
# [k(v[0], v[1]) for k,v in b.items()]
|
||||
@@ -0,0 +1,23 @@
|
||||
from .account import Account
|
||||
from .ram import RAM
|
||||
from .symbol import Symbol
|
||||
from .strategy import Strategy
|
||||
from .bot_builder import Bot
|
||||
from .result import Result
|
||||
from .records import Records
|
||||
from .candle import Candle, Candles
|
||||
from .positions import Positions
|
||||
from .executor import Executor
|
||||
from .order import Order
|
||||
from .ticks import Tick, Ticks
|
||||
from .history import History
|
||||
from .trader import Trader
|
||||
from .terminal import Terminal
|
||||
from .sessions import Session, Sessions
|
||||
|
||||
from .core.config import Config
|
||||
from .core.constants import *
|
||||
from .core.meta_trader import MetaTrader
|
||||
from .core.models import *
|
||||
from .core.exceptions import *
|
||||
from .lib import *
|
||||
@@ -0,0 +1,109 @@
|
||||
from logging import getLogger
|
||||
from typing import Type
|
||||
|
||||
from .core.models import AccountInfo, SymbolInfo
|
||||
from .core.exceptions import LoginError
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Account(AccountInfo):
|
||||
"""A class for managing a trading account. A singleton class.
|
||||
A subclass of AccountInfo. All AccountInfo attributes are available in this class.
|
||||
|
||||
Attributes:
|
||||
connected (bool): Status of connection to MetaTrader 5 Terminal
|
||||
symbols (set[SymbolInfo]): A set of available symbols for the financial market.
|
||||
|
||||
Notes:
|
||||
Other Account properties are defined in the AccountInfo class.
|
||||
"""
|
||||
connected: bool
|
||||
symbols = set()
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not hasattr(cls, '_instance'):
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
async def refresh(self):
|
||||
"""
|
||||
Refreshes the account instance with the latest account details from the MetaTrader 5 terminal
|
||||
"""
|
||||
account_info = await self.mt5.account_info()
|
||||
acc = account_info._asdict()
|
||||
self.set_attributes(**acc)
|
||||
|
||||
@property
|
||||
def account_info(self) -> 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:
|
||||
dict: A dict of login, server and password details
|
||||
|
||||
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
|
||||
"""
|
||||
acc_info = self.get_dict(include={'login', 'server', 'password'})
|
||||
return acc_info if acc_info['login'] else self.config.account_info()
|
||||
|
||||
async def __aenter__(self) -> 'Account':
|
||||
"""Connect to a trading account and return the account instance.
|
||||
Async context manager for the Account class.
|
||||
|
||||
Returns:
|
||||
Account: An instance of the Account class
|
||||
|
||||
Raises:
|
||||
LoginError: If login fails
|
||||
"""
|
||||
res = await self.sign_in()
|
||||
if not res:
|
||||
raise LoginError('Login failed')
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
await self.mt5.shutdown()
|
||||
self.connected = False
|
||||
|
||||
async def sign_in(self) -> bool:
|
||||
"""Connect to a trading account.
|
||||
|
||||
Returns:
|
||||
bool: True if login was successful else False
|
||||
"""
|
||||
await self.mt5.initialize(**self.account_info)
|
||||
self.connected = await self.mt5.login(**self.account_info)
|
||||
if self.connected:
|
||||
await self.refresh()
|
||||
self.symbols = await self.symbols_get()
|
||||
return self.connected
|
||||
await self.mt5.shutdown()
|
||||
return False
|
||||
|
||||
def has_symbol(self, symbol: str | Type[SymbolInfo]):
|
||||
"""Checks to see if a symbol is available for a trading account
|
||||
|
||||
Args:
|
||||
symbol (str | SymbolInfo):
|
||||
|
||||
Returns:
|
||||
bool: True if symbol is present otherwise False
|
||||
"""
|
||||
try:
|
||||
symbol = SymbolInfo(name=str(symbol)) if not isinstance(symbol, SymbolInfo) else symbol
|
||||
return symbol in self.symbols
|
||||
except Exception as err:
|
||||
logger.warning(f'Error: {err}; {symbol} not available in this market')
|
||||
return False
|
||||
|
||||
async def symbols_get(self) -> set[SymbolInfo]:
|
||||
"""Get all financial instruments from the MetaTrader 5 terminal available for the current account.
|
||||
|
||||
Returns:
|
||||
set[Symbol]: A set of available symbols.
|
||||
"""
|
||||
syms = await self.mt5.symbols_get()
|
||||
return {SymbolInfo(name=sym.name) for sym in syms}
|
||||
@@ -0,0 +1,116 @@
|
||||
import asyncio
|
||||
from typing import Type, Iterable, TypeVar
|
||||
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)
|
||||
|
||||
|
||||
class Bot:
|
||||
"""The bot class. Create a bot instance to run your strategies.
|
||||
|
||||
Attributes:
|
||||
account (Account): Account Object.
|
||||
executor: The default thread executor.
|
||||
symbols (set[Symbols]): A set of symbols for the trading session
|
||||
"""
|
||||
account: Account = Account()
|
||||
|
||||
def __init__(self):
|
||||
self.symbols = set()
|
||||
self.executor = Executor(bot=self)
|
||||
|
||||
async def initialize(self):
|
||||
"""Prepares the bot by signing in to the trading account and initializing the symbols for the trading session.
|
||||
|
||||
Raises:
|
||||
SystemExit if sign in was not successful
|
||||
"""
|
||||
init = await self.account.sign_in()
|
||||
logger.info("Login Successful")
|
||||
if not init:
|
||||
logger.warning('Unable to sign in to MetaTrder 5 Terminal')
|
||||
raise SystemExit
|
||||
await self.init_symbols()
|
||||
self.executor.remove_workers()
|
||||
|
||||
def add_func(self, func, kwargs):
|
||||
self.executor.add_func(func, kwargs)
|
||||
|
||||
def add_coro(self, coro, **kwargs):
|
||||
self.executor.add_coro(coro, kwargs)
|
||||
|
||||
def execute(self):
|
||||
"""Execute the bot.
|
||||
"""
|
||||
asyncio.run(self.start())
|
||||
|
||||
async def start(self):
|
||||
"""Starts the bot by calling the initialize method and running the strategies in the executor.
|
||||
"""
|
||||
await self.initialize()
|
||||
await self.executor.execute()
|
||||
|
||||
def add_strategy(self, strategy: Strategy):
|
||||
"""Add a strategy to the executor. An added strategy will only run if it's symbol was successfully initialized.
|
||||
|
||||
Args:
|
||||
strategy (Strategy): A Strategy instance to run on bot
|
||||
|
||||
Notes:
|
||||
Make sure the symbol has been added to the market
|
||||
"""
|
||||
self.symbols.add(strategy.symbol)
|
||||
self.executor.add_worker(strategy)
|
||||
|
||||
def add_strategies(self, strategies: Iterable[Strategy]):
|
||||
"""Add multiple strategies at the same time
|
||||
|
||||
Args:
|
||||
strategies: A list of strategies
|
||||
"""
|
||||
[self.add_strategy(strategy) for strategy in strategies]
|
||||
|
||||
def add_strategy_all(self, *, 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
|
||||
|
||||
Keyword Args:
|
||||
strategy (Strategy): Strategy class
|
||||
params (dict): A dictionary of parameters for the strategy
|
||||
"""
|
||||
[self.add_strategy(strategy(symbol=symbol, params=params)) for symbol in self.symbols]
|
||||
|
||||
async def init_symbols(self):
|
||||
"""Initialize the symbols for the current trading session. This method is called internally by the bot.
|
||||
"""
|
||||
syms = [self.init_symbol(symbol) for symbol in self.symbols]
|
||||
await asyncio.gather(*syms, return_exceptions=True)
|
||||
|
||||
async def init_symbol(self, symbol: Symbol) -> Symbol:
|
||||
"""Initialize a symbol before the beginning of a trading sessions.
|
||||
Removes it from the list of symbols if it was not successfully initialized or not available
|
||||
for the account.
|
||||
|
||||
Args:
|
||||
symbol (Symbol): Symbol object to be initialized
|
||||
|
||||
Returns:
|
||||
Symbol: if successfully initialized
|
||||
"""
|
||||
if self.account.has_symbol(symbol):
|
||||
init = await symbol.init()
|
||||
if init:
|
||||
return symbol
|
||||
self.symbols.discard(symbol)
|
||||
logger.warning(f'Unable to initialize symbol {symbol}')
|
||||
|
||||
self.symbols.remove(symbol)
|
||||
logger.warning(f'{symbol} not a available for this market')
|
||||
@@ -0,0 +1,234 @@
|
||||
"""Candle and Candles classes for handling bars from the MetaTrader 5 terminal."""
|
||||
|
||||
from typing import Type, TypeVar, Generic, Iterable
|
||||
from logging import getLogger
|
||||
import reprlib
|
||||
|
||||
from pandas import DataFrame, Series
|
||||
import pandas_ta as ta
|
||||
|
||||
from .core.constants import TimeFrame
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
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:
|
||||
time (int): Period start time.
|
||||
open (int): Open price
|
||||
high (float): The highest price of the period
|
||||
low (float): The lowest price of the period
|
||||
close (float): Close price
|
||||
tick_volume (float): Tick volume
|
||||
real_volume (float): Trade volume
|
||||
spread (float): Spread
|
||||
Index (int): Custom attribute representing the position of the candle in a sequence.
|
||||
"""
|
||||
time: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
real_volume: float
|
||||
spread: float
|
||||
open: float
|
||||
tick_volume: float
|
||||
Index: int
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Create a Candle object from keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
**kwargs: Candle attributes and values as keyword arguments.
|
||||
"""
|
||||
self.time = kwargs.pop('time', 0)
|
||||
self.Index = kwargs.pop('Index', 0)
|
||||
self.set_attributes(**kwargs)
|
||||
def __repr__(self):
|
||||
keys = reprlib.repr(', '.join('%s=%s' % (i, j) for i, j in self.__dict__.items()))[1:-1]
|
||||
return '%(class)s(%(args)s)' % {'class': self.__class__.__name__, 'args': keys}
|
||||
|
||||
def __eq__(self, other: 'Candle'):
|
||||
return self.time == other.time
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.time)
|
||||
|
||||
def __lt__(self, other: 'Candle'):
|
||||
return self.time < other.time
|
||||
|
||||
def __gt__(self, other: 'Candle'):
|
||||
return self.time > other.time
|
||||
|
||||
def set_attributes(self, **kwargs):
|
||||
"""Set keyword arguments as instance attributes
|
||||
|
||||
Keyword Args:
|
||||
**kwargs: Instance attributes and values as keyword arguments
|
||||
"""
|
||||
[setattr(self, i, j) for i, j in kwargs.items()]
|
||||
|
||||
@property
|
||||
def mid(self) -> float:
|
||||
"""The median of open and close
|
||||
|
||||
Returns:
|
||||
float: The median of open and close
|
||||
"""
|
||||
return (self.open + self.close) / 2
|
||||
|
||||
def is_bullish(self) -> bool:
|
||||
""" A simple check to see if the candle is bullish.
|
||||
|
||||
Returns:
|
||||
bool: True or False
|
||||
"""
|
||||
return self.close >= self.open
|
||||
|
||||
def is_bearish(self) -> bool:
|
||||
"""A simple check to see if the candle is bearish.
|
||||
|
||||
Returns:
|
||||
bool: True or False
|
||||
"""
|
||||
return self.open > self.close
|
||||
|
||||
_Candle = TypeVar('_Candle', bound=Candle)
|
||||
_Candles = TypeVar('_Candles', bound='Candles')
|
||||
|
||||
|
||||
class Candles(Generic[_Candle]):
|
||||
"""An iterable container class of Candle objects in chronological order.
|
||||
|
||||
Attributes:
|
||||
Index (Series['int']): A pandas Series of the indexes of all candles in the object.
|
||||
time (Series['int']): A pandas Series of the time of all candles in the object.
|
||||
open (Series[float]): A pandas Series of the opening price of all candles in the object.
|
||||
high (Series[float]): A pandas Series of the high price of all candles in the object.
|
||||
low (Series[float]): A pandas Series of the low price of all candles in the object.
|
||||
close (Series[float]): A pandas Series of the closing price of all candles in the object.
|
||||
tick_volume (Series[float]): A pandas Series of the tick volume of all candles in the object.
|
||||
real_volume (Series[float]): A pandas Series of the real volume of all candles in the object.
|
||||
spread (Series[float]): A pandas Series of the spread of all candles in the object.
|
||||
timeframe (TimeFrame): The timeframe of the candles in the object.
|
||||
Candle (Type[Candle]): The Candle class for representing the candles in the object.
|
||||
|
||||
properties:
|
||||
data (DataFrame): A pandas DataFrame of all candles in the object.
|
||||
|
||||
Notes:
|
||||
The candle class can be customized by subclassing the Candle class and passing the subclass as the candle keyword argument.
|
||||
Or defining it on the class body as a class attribute.
|
||||
"""
|
||||
Index: Series
|
||||
time: Series
|
||||
open: Series
|
||||
high: Series
|
||||
low: Series
|
||||
close: Series
|
||||
tick_volume: Series
|
||||
real_volume: Series
|
||||
spread: Series
|
||||
Candle: Type[Candle]
|
||||
timeframe: TimeFrame
|
||||
|
||||
def __init__(self, *, data: DataFrame | _Candles | Iterable, flip=False, candle_class: Type[_Candle] = None):
|
||||
"""A container class of Candle objects in chronological order.
|
||||
|
||||
Args:
|
||||
data (DataFrame|Candles|Iterable): A pandas dataframe, a Candles object or any suitable iterable
|
||||
|
||||
Keyword Args:
|
||||
flip (bool): Reverse the chronological order of the candles to the oldest first. Defaults to False.
|
||||
candle_class: A subclass of Candle to use as the candle class. Defaults to Candle.
|
||||
"""
|
||||
if isinstance(data, DataFrame):
|
||||
data = data
|
||||
elif isinstance(data, type(self)):
|
||||
data = DataFrame(data.data)
|
||||
elif isinstance(data, Iterable):
|
||||
data = DataFrame(data)
|
||||
else:
|
||||
raise ValueError(f'Cannot create DataFrame from object of {type(data)}')
|
||||
|
||||
self._data = data.iloc[::-1] if flip else data
|
||||
self.Candle = candle_class or Candle
|
||||
|
||||
def __repr__(self):
|
||||
return self._data.__repr__()
|
||||
|
||||
def __len__(self):
|
||||
return self._data.shape[0]
|
||||
|
||||
def __contains__(self, item: _Candle):
|
||||
return item.time == self[item.Index].time
|
||||
|
||||
def __getitem__(self, index) -> _Candle | _Candles:
|
||||
if isinstance(index, slice):
|
||||
cls = self.__class__
|
||||
data = self._data.iloc[index]
|
||||
data.reset_index(drop=True, inplace=True)
|
||||
return cls(data=data)
|
||||
|
||||
if isinstance(index, str):
|
||||
return self._data[index]
|
||||
|
||||
item = self._data.iloc[index]
|
||||
return self.Candle(Index=index, **item)
|
||||
|
||||
def __setitem__(self, index, value: Series):
|
||||
if isinstance(value, Series):
|
||||
self._data[index] = value
|
||||
return
|
||||
raise TypeError(f'Expected Series got {type(value)}')
|
||||
|
||||
def __getattr__(self, item):
|
||||
if item in list(self._data.columns.values):
|
||||
return self._data[item]
|
||||
raise AttributeError(f'Attribute {item} not defined on class {self.__class__.__name__}')
|
||||
|
||||
def __iter__(self):
|
||||
return (self.Candle(**row._asdict()) for row in self._data.itertuples())
|
||||
|
||||
@property
|
||||
def timeframe(self):
|
||||
tf = self.time[1] - self.time[0]
|
||||
return TimeFrame.get(abs(tf))
|
||||
|
||||
@property
|
||||
def ta(self):
|
||||
"""Access to the pandas_ta library for performing technical analysis on the underlying data attribute.
|
||||
|
||||
Returns:
|
||||
pandas_ta: The pandas_ta library
|
||||
"""
|
||||
return self._data.ta
|
||||
|
||||
@property
|
||||
def ta_lib(self):
|
||||
"""Access to the ta library for performing technical analysis. Not dependent on the underlying data attribute.
|
||||
|
||||
Returns:
|
||||
ta: The ta library
|
||||
"""
|
||||
return ta
|
||||
|
||||
@property
|
||||
def data(self) -> DataFrame:
|
||||
"""The original data passed to the class as a pandas DataFrame"""
|
||||
return self._data
|
||||
|
||||
def rename(self, inplace=True, **kwargs) -> _Candles | None :
|
||||
"""Rename columns of the candles class.
|
||||
|
||||
Keyword Args:
|
||||
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:
|
||||
Candles: A new instance of the class with the renamed columns if inplace is False.
|
||||
None: If inplace is True
|
||||
"""
|
||||
res = self._data.rename(columns=kwargs, inplace=inplace)
|
||||
return res if inplace else self.__class__(data=res)
|
||||
@@ -0,0 +1,7 @@
|
||||
from .meta_trader import MetaTrader
|
||||
from .config import Config
|
||||
from .models import *
|
||||
from .constants import *
|
||||
from .base import Base
|
||||
from .errors import Error
|
||||
from .exceptions import *
|
||||
@@ -0,0 +1,137 @@
|
||||
from functools import cache
|
||||
import reprlib
|
||||
from logging import getLogger
|
||||
|
||||
from .config import Config
|
||||
from .meta_trader import MetaTrader
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
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
|
||||
class is instantiated.
|
||||
|
||||
Keyword Args:
|
||||
**kwargs: Object attributes and values as keyword arguments. Only added if they are annotated on the class body.
|
||||
|
||||
Class Attributes:
|
||||
mt5 (MetaTrader): An instance of the MetaTrader class
|
||||
config (Config): An instance of the Config class
|
||||
Meta (Type[Meta]): The Meta class for configuration of the data model class
|
||||
"""
|
||||
mt5: MetaTrader = MetaTrader()
|
||||
config = Config()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.set_attributes(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
keys = reprlib.repr(', '.join('%s=%s' % (i, j) for i, j in self.__dict__.items()))[1:-1]
|
||||
return '%(class)s(%(args)s)' % {'class': self.__class__.__name__, 'args': keys}
|
||||
|
||||
def set_attributes(self, **kwargs):
|
||||
"""Set keyword arguments as object attributes
|
||||
|
||||
Keyword Args:
|
||||
**kwargs: Object attributes and values as keyword arguments
|
||||
|
||||
Raises:
|
||||
AttributeError: When assigning an attribute that does not belong to the class or any parent class
|
||||
|
||||
Notes:
|
||||
Only sets attributes that have been annotated on the class body.
|
||||
"""
|
||||
for i, j in kwargs.items():
|
||||
try:
|
||||
setattr(self, i, self.annotations[i](j))
|
||||
except KeyError:
|
||||
logger.warning(f"Attribute {i} does not belong to class {self.__class__.__name__}")
|
||||
continue
|
||||
|
||||
except ValueError:
|
||||
logger.warning(f'Cannot covert object of type {type(j)} to type {self.annotations[i]}')
|
||||
continue
|
||||
|
||||
except Exception as exe:
|
||||
logger.warning(f'Did not set attribute {i} on class {self.__class__.__name__} due to {exe}')
|
||||
continue
|
||||
|
||||
@property
|
||||
@cache
|
||||
def annotations(self) -> dict:
|
||||
"""Class annotations from all ancestor classes and the current class.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of class annotations
|
||||
"""
|
||||
annots = {}
|
||||
for base in self.__class__.__mro__[-3::-1]:
|
||||
annots |= getattr(base, '__annotations__', {})
|
||||
return annots
|
||||
|
||||
def get_dict(self, exclude: set = None, include: set = None) -> dict:
|
||||
"""Returns class attributes as a dict, with the ability to filter
|
||||
|
||||
Keyword Args:
|
||||
exclude: A set of attributes to be excluded
|
||||
include: Specific attributes to be returned
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of specified class attributes
|
||||
|
||||
Notes:
|
||||
You can only set either of include or exclude. If you set both, include will take precedence
|
||||
"""
|
||||
exclude, include = exclude or set(), include or set()
|
||||
filter_ = include or set(self.dict.keys()).difference(exclude)
|
||||
return {key: value for key, value in self.dict.items() if key in filter_}
|
||||
|
||||
@property
|
||||
@cache
|
||||
def class_vars(self):
|
||||
"""Annotated class attributes
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of available class attributes in all ancestor classes and the current class.
|
||||
"""
|
||||
clss = self.__class__.__mro__[-3::-1]
|
||||
cls_dict = {}
|
||||
for cls in clss:
|
||||
cls_dict |= cls.__dict__
|
||||
return {key: value for key, value in cls_dict.items() if key in self.annotations}
|
||||
|
||||
@property
|
||||
def dict(self) -> dict:
|
||||
"""All instance and class attributes as a dictionary, except those excluded in the Meta class.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of instance and class attributes
|
||||
"""
|
||||
try:
|
||||
return {key: value for key, value in (self.class_vars | self.__dict__).items() if key not in self.Meta.filter}
|
||||
except Exception as err:
|
||||
logger.warning(err)
|
||||
|
||||
class Meta:
|
||||
"""A class for defining class attributes to be excluded or included in the dict property
|
||||
|
||||
Attributes:
|
||||
exclude (set): A set of attributes to be excluded
|
||||
include (set): Specific attributes to be returned. Include supercedes exclude.
|
||||
"""
|
||||
exclude = {'mt5', "Config"}
|
||||
include = set()
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def filter(cls) -> set:
|
||||
"""Combine the exclude and include attributes to return a set of attributes to be excluded.
|
||||
|
||||
Returns:
|
||||
set: A set of attributes to be excluded
|
||||
"""
|
||||
return cls.exclude.difference(cls.include)
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from sys import _getframe
|
||||
from typing import Iterator
|
||||
import json
|
||||
from logging import getLogger
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Config:
|
||||
"""A class for handling configuration settings for the aiomql package.
|
||||
|
||||
Keyword Args:
|
||||
**kwargs: Configuration settings as keyword arguments.
|
||||
Variables set this way supersede those set in the config file.
|
||||
|
||||
Attributes:
|
||||
record_trades (bool): Whether to keep record of trades or not.
|
||||
filename (str): Name of the config file
|
||||
records_dir (str): Path to the directory where trade records are saved
|
||||
win_percentage (float): Percentage of achieved target profit in a trade to be considered a win
|
||||
login (int): Trading account number
|
||||
password (str): Trading account password
|
||||
server (str): Broker server
|
||||
path (str): Path to terminal file
|
||||
timeout (int): Timeout for terminal connection
|
||||
|
||||
Notes:
|
||||
By default, the config class looks for a file named aiomql.json.
|
||||
You can change this by passing the filename keyword argument to the constructor.
|
||||
By passing reload=True to the load_config method, you can reload and search again for the config file.
|
||||
"""
|
||||
login: int = 0
|
||||
password: str = ''
|
||||
server: str = ''
|
||||
path: str = ''
|
||||
timeout: int = 60000
|
||||
record_trades: bool = True
|
||||
filename: str = 'aiomql.json'
|
||||
win_percentage: float = 0.85
|
||||
records_dir = Path.home() / 'Documents' / 'Aiomql' / 'Trade Records' if record_trades else None
|
||||
_load = 1
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not hasattr(cls, '_instance'):
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.load_config(reload=False)
|
||||
[setattr(self, key, value) for key, value in kwargs]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def walk_to_root(path: str) -> Iterator[str]:
|
||||
|
||||
if not os.path.exists(path):
|
||||
raise IOError('Starting path not found')
|
||||
|
||||
if os.path.isfile(path):
|
||||
path = os.path.dirname(path)
|
||||
|
||||
last_dir = None
|
||||
current_dir = os.path.abspath(path)
|
||||
while last_dir != current_dir:
|
||||
yield current_dir
|
||||
parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir))
|
||||
last_dir, current_dir = current_dir, parent_dir
|
||||
|
||||
def find_config(self):
|
||||
current_file = __file__
|
||||
frame = _getframe()
|
||||
while frame.f_code.co_filename == current_file:
|
||||
if frame.f_back is None:
|
||||
return None
|
||||
frame = frame.f_back
|
||||
frame_filename = frame.f_code.co_filename
|
||||
path = os.path.dirname(os.path.abspath(frame_filename))
|
||||
|
||||
for dirname in self.walk_to_root(path):
|
||||
check_path = os.path.join(dirname, self.filename)
|
||||
if os.path.isfile(check_path):
|
||||
return check_path
|
||||
return None
|
||||
|
||||
def load_config(self, file: str = None, reload: bool = True):
|
||||
if reload:
|
||||
self._load = 1
|
||||
if self._load != 1:
|
||||
return
|
||||
|
||||
self._load = 0
|
||||
data = {}
|
||||
if (file := (file or self.find_config())) is None:
|
||||
logger.warning('No Config File Found')
|
||||
else:
|
||||
fh = open(file, mode='r')
|
||||
data = json.load(fh)
|
||||
fh.close()
|
||||
[setattr(self, key, value) for key, value in data.items()]
|
||||
self.records_dir.mkdir(parents=True, exist_ok=True) if self.records_dir else ...
|
||||
|
||||
def account_info(self) -> dict['login', 'password', 'server']:
|
||||
"""Returns Account login details as found in the config object if available
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of login details
|
||||
"""
|
||||
return {'login': self.login, 'password': self.password, 'server': self.server}
|
||||
@@ -0,0 +1,786 @@
|
||||
from enum import IntEnum, IntFlag
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
"""
|
||||
MetaTrader5 constants as IntEnum types with Python style class names and nice string representation
|
||||
|
||||
Examples:
|
||||
>>> from aiomql import OrderFilling
|
||||
>>> fok = OrderFilling.FOK
|
||||
>>> print(fok)
|
||||
"ORDER_FILLING_FOK"
|
||||
"""
|
||||
|
||||
|
||||
class Repr:
|
||||
__enum_name__ = ""
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.__enum_name__}_{self.name}"
|
||||
|
||||
|
||||
class TradeAction(Repr, IntEnum):
|
||||
"""TRADE_REQUEST_ACTION Enum.
|
||||
|
||||
Attributes:
|
||||
DEAL (int): Delete the pending order placed previously Place a trade order for an immediate execution with the
|
||||
specified parameters (market order).
|
||||
PENDING (int): Delete the pending order placed previously
|
||||
SLTP (int): Modify Stop Loss and Take Profit values of an opened position
|
||||
MODIFY (int): Modify the parameters of the order placed previously
|
||||
REMOVE (int): Delete the pending order placed previously
|
||||
CLOSE_BY (int): Close a position by an opposite one
|
||||
"""
|
||||
__enum_name__ = "TRADE_ACTION"
|
||||
DEAL = mt5.TRADE_ACTION_DEAL
|
||||
PENDING = mt5.TRADE_ACTION_PENDING
|
||||
SLTP = mt5.TRADE_ACTION_SLTP
|
||||
MODIFY = mt5.TRADE_ACTION_MODIFY
|
||||
REMOVE = mt5.TRADE_ACTION_MODIFY
|
||||
CLOSE_BY = mt5.TRADE_ACTION_CLOSE_BY
|
||||
|
||||
|
||||
class OrderFilling(Repr, IntEnum):
|
||||
"""ORDER_TYPE_FILLING Enum.
|
||||
|
||||
Attributes:
|
||||
FOK (int): This execution policy means that an order can be executed only in the specified volume.
|
||||
If the necessary amount of a financial instrument is currently unavailable in the market, the order will
|
||||
not be executed. The desired volume can be made up of several available offers.
|
||||
|
||||
IOC (int): An agreement to execute a deal at the maximum volume available in the market within the volume
|
||||
specified in the order. If the request cannot be filled completely, an order with the available volume will
|
||||
be executed, and the remaining volume will be canceled.
|
||||
|
||||
RETURN (int): This policy is used only for market (ORDER_TYPE_BUY and ORDER_TYPE_SELL), limit and stop limit
|
||||
orders (ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT,ORDER_TYPE_BUY_STOP_LIMIT and
|
||||
ORDER_TYPE_SELL_STOP_LIMIT) and only for the symbols with Market or Exchange execution modes. If filled
|
||||
partially, a market or limit order with the remaining volume is not canceled, and is processed further.
|
||||
During activation of the ORDER_TYPE_BUY_STOP_LIMIT and ORDER_TYPE_SELL_STOP_LIMIT orders, an appropriate
|
||||
limit order ORDER_TYPE_BUY_LIMIT/ORDER_TYPE_SELL_LIMIT with the ORDER_FILLING_RETURN type is created.
|
||||
"""
|
||||
__enum_name__ = "ORDER_FILLING"
|
||||
FOK = mt5.ORDER_FILLING_FOK
|
||||
IOC = mt5.ORDER_FILLING_IOC
|
||||
RETURN = mt5.ORDER_FILLING_RETURN
|
||||
|
||||
|
||||
class OrderTime(Repr, IntEnum):
|
||||
"""ORDER_TIME Enum.
|
||||
|
||||
Attributes:
|
||||
GTC (int): Good till cancel order
|
||||
DAY (int): Good till current trade day order
|
||||
SPECIFIED (int): The order is active until the specified date
|
||||
SPECIFIED_DAY (int): The order is active until 23:59:59 of the specified day. If this time appears to be out of
|
||||
a trading session, the expiration is processed at the nearest trading time.
|
||||
"""
|
||||
__enum_name__ = "ORDER_TIME"
|
||||
GTC = mt5.ORDER_TIME_GTC
|
||||
DAY = mt5.ORDER_TIME_DAY
|
||||
SPECIFIED = mt5.ORDER_TIME_SPECIFIED
|
||||
SPECIFIED_DAY = mt5.ORDER_TIME_SPECIFIED_DAY
|
||||
|
||||
|
||||
class OrderType(Repr, IntEnum):
|
||||
"""ORDER_TYPE Enum.
|
||||
|
||||
Attributes:
|
||||
BUY (int): Market buy order
|
||||
SELL (int): Market sell order
|
||||
BUY_LIMIT (int): Buy Limit pending order
|
||||
SELL_LIMIT (int): Sell Limit pending order
|
||||
BUY_STOP (int): Buy Stop pending order
|
||||
SELL_STOP (int): Sell Stop pending order
|
||||
BUY_STOP_LIMIT (int): Upon reaching the order price, Buy Limit pending order is placed at StopLimit price
|
||||
SELL_STOP_LIMIT (int): Upon reaching the order price, Sell Limit pending order is placed at StopLimit price
|
||||
CLOSE_BY (int): Order for closing a position by an opposite one
|
||||
|
||||
Properties:
|
||||
opposite (int): Gets the opposite of an order type
|
||||
"""
|
||||
__enum_name__ = "ORDER_TYPE"
|
||||
BUY = mt5.ORDER_TYPE_BUY
|
||||
SELL = mt5.ORDER_TYPE_SELL
|
||||
BUY_LIMIT = mt5.ORDER_TYPE_BUY_LIMIT
|
||||
SELL_LIMIT = mt5.ORDER_TYPE_SELL_LIMIT
|
||||
BUY_STOP = mt5.ORDER_TYPE_BUY_STOP
|
||||
SELL_STOP = mt5.ORDER_TYPE_SELL_STOP
|
||||
BUY_STOP_LIMIT = mt5.ORDER_TYPE_BUY_STOP_LIMIT
|
||||
SELL_STOP_LIMIT = mt5.ORDER_TYPE_SELL_STOP_LIMIT
|
||||
CLOSE_BY = mt5.ORDER_TYPE_CLOSE_BY
|
||||
|
||||
@property
|
||||
def opposite(self):
|
||||
"""Gets the opposite of an order type for closing an open position
|
||||
|
||||
Returns:
|
||||
int: integer value of opposite order type
|
||||
"""
|
||||
return {0: 1, 1: 0, 2: 3, 3: 2, 4: 5, 5: 4, 6: 7, 7: 6, 8: 8}[self]
|
||||
|
||||
|
||||
class BookType(Repr, IntEnum):
|
||||
"""BOOK_TYPE Enum.
|
||||
|
||||
Attributes:
|
||||
SELL (int): Sell order (Offer)
|
||||
BUY (int): Buy order (Bid)
|
||||
SELL_MARKET (int): Sell order by Market
|
||||
BUY_MARKET (int): Buy order by Market
|
||||
"""
|
||||
__enum_name__ = "BOOK_TYPE"
|
||||
SELL = mt5.BOOK_TYPE_SELL
|
||||
BUY = mt5.BOOK_TYPE_BUY
|
||||
SELL_MARKET = mt5.BOOK_TYPE_SELL_MARKET
|
||||
BUY_MARKET = mt5.BOOK_TYPE_BUY_MARKET
|
||||
|
||||
|
||||
class TimeFrame(Repr, IntEnum):
|
||||
"""TIMEFRAME Enum.
|
||||
|
||||
Attributes:
|
||||
M1 (int): One Minute
|
||||
M2 (int): Two Minutes
|
||||
M3 (int): Three Minutes
|
||||
M4 (int): Four Minutes
|
||||
M5 (int): Five Minutes
|
||||
M6 (int): Six Minutes
|
||||
M10 (int): Ten Minutes
|
||||
M15 (int): Fifteen Minutes
|
||||
M20 (int): Twenty Minutes
|
||||
M30 (int): Thirty Minutes
|
||||
H1 (int): One Hour
|
||||
H2 (int): Two Hours
|
||||
H3 (int): Three Hours
|
||||
H4 (int): Four Hours
|
||||
H6 (int): Six Hours
|
||||
H8 (int): Eight Hours
|
||||
D1 (int): One Day
|
||||
W1 (int): One Week
|
||||
MN1 (int): One Month
|
||||
|
||||
Properties:
|
||||
time: return the value of the timeframe object in seconds. Used as a property
|
||||
|
||||
Methods:
|
||||
get: get a timeframe object from a time value in seconds
|
||||
"""
|
||||
__enum_name__ = "TIMEFRAME"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
M1 = mt5.TIMEFRAME_M1
|
||||
M2 = mt5.TIMEFRAME_M2
|
||||
M3 = mt5.TIMEFRAME_M3
|
||||
M4 = mt5.TIMEFRAME_M4
|
||||
M5 = mt5.TIMEFRAME_M5
|
||||
M6 = mt5.TIMEFRAME_M6
|
||||
M10 = mt5.TIMEFRAME_M10
|
||||
M15 = mt5.TIMEFRAME_M15
|
||||
M20 = mt5.TIMEFRAME_M20
|
||||
M30 = mt5.TIMEFRAME_M30
|
||||
H1 = mt5.TIMEFRAME_H1
|
||||
H2 = mt5.TIMEFRAME_H2
|
||||
H3 = mt5.TIMEFRAME_H3
|
||||
H4 = mt5.TIMEFRAME_H4
|
||||
H6 = mt5.TIMEFRAME_H6
|
||||
H8 = mt5.TIMEFRAME_H8
|
||||
H12 = mt5.TIMEFRAME_H12
|
||||
D1 = mt5.TIMEFRAME_D1
|
||||
W1 = mt5.TIMEFRAME_W1
|
||||
MN1 = mt5.TIMEFRAME_MN1
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
"""The number of seconds in a TIMEFRAME
|
||||
|
||||
Returns:
|
||||
int: The number of seconds in a TIMEFRAME
|
||||
|
||||
Examples:
|
||||
>>> t = TimeFrame.H1
|
||||
>>> print(t.time)
|
||||
3600
|
||||
"""
|
||||
times = {1: 60, 2: 120, 3: 180, 4: 240, 5: 300, 6: 360, 10: 600, 15: 900, 20: 1200, 30: 1800, 16385: 3600,
|
||||
16386: 7200, 16387: 10800, 16388: 14400, 16390: 21600, 16392: 28800, 16396: 43200, 16408: 86400,
|
||||
32769: 604800, 49153: 2592000}
|
||||
return times[self]
|
||||
|
||||
@classmethod
|
||||
def get(cls, time: int):
|
||||
times = {60: 1, 120: 2, 180: 3, 240: 4, 300: 5, 360: 6, 600: 10, 900: 15, 1200: 20, 1800: 30, 3600: 16385,
|
||||
7200: 16386, 10800: 16387, 14400: 16388, 21600: 16390, 28800: 16392, 43200: 16396, 86400: 16408,
|
||||
604800: 32769, 2592000: 49153}
|
||||
return TimeFrame(times[int(time)])
|
||||
|
||||
|
||||
class CopyTicks(Repr, IntEnum):
|
||||
"""COPY_TICKS Enum. This defines the types of ticks that can be requested using the copy_ticks_from() and
|
||||
copy_ticks_range() functions.
|
||||
|
||||
Attributes:
|
||||
ALL (int): All ticks
|
||||
INFO (int): Ticks containing Bid and/or Ask price changes
|
||||
TRADE (int): Ticks containing Last and/or Volume price changes
|
||||
"""
|
||||
__enum_name__ = "COPY_TICKS"
|
||||
ALL = mt5.COPY_TICKS_ALL
|
||||
INFO = mt5.COPY_TICKS_INFO
|
||||
TRADE = mt5.COPY_TICKS_TRADE
|
||||
|
||||
|
||||
class PositionType(Repr, IntEnum):
|
||||
"""POSITION_TYPE Enum. Direction of an open position (buy or sell)
|
||||
|
||||
Attributes:
|
||||
BUY (int): Buy
|
||||
SELL (int): Sell
|
||||
"""
|
||||
__enum_name__ = "POSITION_TYPE"
|
||||
BUY = mt5.POSITION_TYPE_BUY
|
||||
SELL = mt5.POSITION_TYPE_SELL
|
||||
|
||||
|
||||
class PositionReason(Repr, IntEnum):
|
||||
"""POSITION_REASON Enum. The reason for opening a position is contained in the POSITION_REASON Enum
|
||||
|
||||
Attributes:
|
||||
CLIENT (int): The position was opened as a result of activation of an order placed from a desktop terminal
|
||||
MOBILE (int): The position was opened as a result of activation of an order placed from a mobile application
|
||||
WEB (int): The position was opened as a result of activation of an order placed from the web platform
|
||||
EXPERT (int): The position was opened as a result of activation of an order placed from an MQL5 program,
|
||||
i.e. an Expert Advisor or a script
|
||||
"""
|
||||
__enum_name__ = "POSITION_REASON"
|
||||
CLIENT = mt5.POSITION_REASON_CLIENT
|
||||
MOBILE = mt5.POSITION_REASON_MOBILE
|
||||
WEB = mt5.POSITION_REASON_WEB
|
||||
EXPERT = mt5.POSITION_REASON_EXPERT
|
||||
|
||||
|
||||
class DealType(Repr, IntEnum):
|
||||
"""DEAL_TYPE enum. Each deal is characterized by a type, allowed values are enumerated in this enum
|
||||
|
||||
Attributes:
|
||||
BUY (int): Buy
|
||||
SELL (int): Sell
|
||||
BALANCE (int): Balance
|
||||
CREDIT (int): Credit
|
||||
CHARGE (int): Additional Charge
|
||||
CORRECTION (int): Correction
|
||||
BONUS (int): Bonus
|
||||
COMMISSION (int): Additional Commission
|
||||
COMMISSION_DAILY (int): Daily Commission
|
||||
COMMISSION_MONTHLY (int): Monthly Commission
|
||||
COMMISSION_AGENT_DAILY (int): Daily Agent Commission
|
||||
COMMISSION_AGENT_MONTHLY (int): Monthly Agent Commission
|
||||
INTEREST (int): Interest Rate
|
||||
DEAL_DIVIDEND (int): Dividend Operations
|
||||
DEAL_DIVIDEND_FRANKED (int): Franked (non-taxable) dividend operations
|
||||
DEAL_TAX (int): Tax Charges
|
||||
|
||||
BUY_CANCELED (int): Canceled buy deal. There can be a situation when a previously executed buy deal is canceled.
|
||||
In this case, the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED,
|
||||
and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated
|
||||
balance operation
|
||||
|
||||
SELL_CANCELED (int): Canceled sell deal. There can be a situation when a previously executed sell deal is
|
||||
canceled. In this case, the type of the previously executed deal (DEAL_TYPE_SELL) is changed to
|
||||
DEAL_TYPE_SELL_CANCELED, and its profit/loss is zeroized. Previously obtained profit/loss is
|
||||
charged/withdrawn using a separated balance operation.
|
||||
"""
|
||||
__enum_name__ = "DEAL_TYPE"
|
||||
BUY = mt5.DEAL_TYPE_BUY
|
||||
SELL = mt5.DEAL_TYPE_SELL
|
||||
BALANCE = mt5.DEAL_TYPE_BALANCE
|
||||
CREDIT = mt5.DEAL_TYPE_CREDIT
|
||||
CHARGE = mt5.DEAL_TYPE_CHARGE
|
||||
CORRECTION = mt5.DEAL_TYPE_CORRECTION
|
||||
BONUS = mt5.DEAL_TYPE_BONUS
|
||||
COMMISSION = mt5.DEAL_TYPE_COMMISSION
|
||||
COMMISSION_DAILY = mt5.DEAL_TYPE_COMMISSION_DAILY
|
||||
COMMISSION_MONTHLY = mt5.DEAL_TYPE_COMMISSION_MONTHLY
|
||||
COMMISSION_AGENT_DAILY = mt5.DEAL_TYPE_COMMISSION_AGENT_DAILY
|
||||
COMMISSION_AGENT_MONTHLY = mt5.DEAL_TYPE_COMMISSION_AGENT_MONTHLY
|
||||
INTEREST = mt5.DEAL_TYPE_INTEREST
|
||||
BUY_CANCELED = mt5.DEAL_TYPE_BUY_CANCELED
|
||||
SELL_CANCELED = mt5.DEAL_TYPE_SELL_CANCELED
|
||||
DEAL_DIVIDEND = mt5.DEAL_DIVIDEND
|
||||
DEAL_DIVIDEND_FRANKED = mt5.DEAL_DIVIDEND_FRANKED
|
||||
DEAL_TAX = mt5.DEAL_TAX
|
||||
|
||||
def __str__(self):
|
||||
if self.name in ('DEAL_DIVIDEND', 'DEAL_DIVIDEND_FRANKED', 'DEAL_TAX'):
|
||||
return self.name
|
||||
return super().__str__()
|
||||
|
||||
|
||||
class DealEntry(Repr, IntEnum):
|
||||
"""DEAL_ENTRY Enum. Deals differ not only in their types set in DEAL_TYPE enum, but also in the way they change
|
||||
positions. This can be a simple position opening, or accumulation of a previously opened position (market entering),
|
||||
position closing by an opposite deal of a corresponding volume (market exiting), or position reversing, if the
|
||||
opposite-direction deal covers the volume of the previously opened position.
|
||||
|
||||
Attributes:
|
||||
IN (int): Entry In
|
||||
OUT (int): Entry Out
|
||||
INOUT (int): Reverse
|
||||
OUT_BY (int): Close a position by an opposite one
|
||||
"""
|
||||
__enum_name__ = "DEAL_ENTRY"
|
||||
IN = mt5.DEAL_ENTRY_IN
|
||||
OUT = mt5.DEAL_ENTRY_OUT
|
||||
INOUT = mt5.DEAL_ENTRY_INOUT
|
||||
OUT_BY = mt5.DEAL_ENTRY_OUT_BY
|
||||
|
||||
|
||||
class DealReason(Repr, IntEnum):
|
||||
"""DEAL_REASON Enum. The reason for deal execution is contained in the DEAL_REASON property. A deal can be executed
|
||||
as a result of triggering of an order placed from a mobile application or an MQL5 program, as well as as a result
|
||||
of the StopOut event, variation margin calculation, etc.
|
||||
|
||||
Attributes:
|
||||
CLIENT (int): The deal was executed as a result of activation of an order placed from a desktop terminal
|
||||
MOBILE (int): The deal was executed as a result of activation of an order placed from a desktop terminal
|
||||
WEB (int): The deal was executed as a result of activation of an order placed from the web platform
|
||||
EXPERT (int): The deal was executed as a result of activation of an order placed from an MQL5 program, i.e.
|
||||
an Expert Advisor or a script
|
||||
SL (int): The deal was executed as a result of Stop Loss activation
|
||||
TP (int): The deal was executed as a result of Take Profit activation
|
||||
SO (int): The deal was executed as a result of the Stop Out event
|
||||
ROLLOVER (int): The deal was executed due to a rollover
|
||||
VMARGIN (int): The deal was executed after charging the variation margin
|
||||
SPLIT (int): The deal was executed after the split (price reduction) of an instrument, which had an open
|
||||
position during split announcement
|
||||
"""
|
||||
__enum_name__ = "DEAL_REASON"
|
||||
CLIENT = mt5.DEAL_REASON_CLIENT
|
||||
MOBILE = mt5.DEAL_REASON_MOBILE
|
||||
WEB = mt5.DEAL_REASON_WEB
|
||||
EXPERT = mt5.DEAL_REASON_EXPERT
|
||||
SL = mt5.DEAL_REASON_SL
|
||||
TP = mt5.DEAL_REASON_TP
|
||||
SO = mt5.DEAL_REASON_SO
|
||||
ROLLOVER = mt5.DEAL_REASON_ROLLOVER
|
||||
VMARGIN = mt5.DEAL_REASON_VMARGIN
|
||||
SPLIT = mt5.DEAL_REASON_SPLIT
|
||||
|
||||
|
||||
class OrderReason(Repr, IntEnum):
|
||||
"""ORDER_REASON Enum.
|
||||
|
||||
Attributes:
|
||||
CLIENT (int): The order was placed from a desktop terminal
|
||||
MOBILE (int): The order was placed from a mobile application
|
||||
WEB (int): The order was placed from a web platform
|
||||
EXPERT (int): The order was placed from an MQL5-program, i.e. by an Expert Advisor or a script
|
||||
SL (int): The order was placed as a result of Stop Loss activation
|
||||
TP (int): The order was placed as a result of Take Profit activation
|
||||
SO (int): The order was placed as a result of the Stop Out event
|
||||
"""
|
||||
__enum_name__ = "ORDER_REASON"
|
||||
CLIENT = mt5.ORDER_REASON_CLIENT
|
||||
MOBILE = mt5.ORDER_REASON_MOBILE
|
||||
WEB = mt5.ORDER_REASON_WEB
|
||||
EXPERT = mt5.ORDER_REASON_EXPERT
|
||||
SL = mt5.ORDER_REASON_SL
|
||||
TP = mt5.ORDER_REASON_TP
|
||||
SO = mt5.ORDER_REASON_SO
|
||||
|
||||
|
||||
class SymbolChartMode(Repr, IntEnum):
|
||||
"""SYMBOL_CHART_MODE Enum. A symbol price chart can be based on Bid or Last prices. The price selected for symbol
|
||||
charts also affects the generation and display of bars in the terminal.
|
||||
Possible values of the SYMBOL_CHART_MODE property are described in this enum
|
||||
|
||||
Attributes:
|
||||
BID (int): Bars are based on Bid prices
|
||||
LAST (int): Bars are based on last prices
|
||||
"""
|
||||
__enum_name__ = "SYMBOL_CHART_MODE"
|
||||
BID = mt5.SYMBOL_CHART_MODE_BID
|
||||
LAST = mt5.SYMBOL_CHART_MODE_LAST
|
||||
|
||||
|
||||
class SymbolCalcMode(Repr, IntEnum):
|
||||
"""SYMBOL_CALC_MODE Enum. The SYMBOL_CALC_MODE enumeration is used for obtaining information about how the margin
|
||||
requirements for a symbol are calculated.
|
||||
|
||||
Attributes:
|
||||
FOREX (int): Forex mode - calculation of profit and margin for Forex
|
||||
FOREX_NO_LEVERAGE (int): Forex No Leverage mode – calculation of profit and margin for Forex symbols without
|
||||
taking into account the leverage
|
||||
FUTURES (int): Futures mode - calculation of margin and profit for futures
|
||||
CFD (int): CFD mode - calculation of margin and profit for CFD
|
||||
CFDINDEX (int): CFD index mode - calculation of margin and profit for CFD by indexes
|
||||
CFDLEVERAGE (int): CFD Leverage mode - calculation of margin and profit for CFD at leverage trading
|
||||
EXCH_STOCKS (int): Calculation of margin and profit for trading securities on a stock exchange
|
||||
EXCH_FUTURES (int): Calculation of margin and profit for trading futures contracts on a stock exchange
|
||||
EXCH_OPTIONS (int): value is 34
|
||||
EXCH_OPTIONS_MARGIN (int): value is 36
|
||||
EXCH_BONDS (int): Exchange Bonds mode – calculation of margin and profit for trading bonds on a stock exchange
|
||||
STOCKS_MOEX (int): Exchange MOEX Stocks mode –calculation of margin and profit for trading securities on MOEX
|
||||
EXCH_BONDS_MOEX (int): Exchange MOEX Bonds mode – calculation of margin and profit for trading bonds on MOEX
|
||||
|
||||
SERV_COLLATERAL (int): Collateral mode - a symbol is used as a non-tradable asset on a trading account.
|
||||
The market value of an open position is calculated based on the volume, current market price, contract size
|
||||
and liquidity ratio. The value is included into Assets, which are added to Equity. Open positions of such
|
||||
symbols increase the Free Margin amount and are used as additional margin (collateral) for open positions
|
||||
"""
|
||||
__enum_name__ = "SYMBOL_CALC_MODE"
|
||||
FOREX = mt5.SYMBOL_CALC_MODE_FOREX
|
||||
FOREX_NO_LEVERAGE = mt5.SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE
|
||||
FUTURES = mt5.SYMBOL_CALC_MODE_FUTURES
|
||||
CFD = mt5.SYMBOL_CALC_MODE_CFD
|
||||
CFDINDEX = mt5.SYMBOL_CALC_MODE_CFDINDEX
|
||||
CFDLEVERAGE = mt5.SYMBOL_CALC_MODE_CFDLEVERAGE
|
||||
EXCH_STOCKS = mt5.SYMBOL_CALC_MODE_EXCH_STOCKS
|
||||
EXCH_FUTURES = mt5.SYMBOL_CALC_MODE_EXCH_FUTURES
|
||||
EXCH_OPTIONS = mt5.SYMBOL_CALC_MODE_EXCH_OPTIONS
|
||||
EXCH_OPTIONS_MARGIN = mt5.SYMBOL_CALC_MODE_EXCH_OPTIONS_MARGIN
|
||||
EXCH_BONDS = mt5.SYMBOL_CALC_MODE_EXCH_BONDS
|
||||
EXCH_STOCKS_MOEX = mt5.SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX
|
||||
EXCH_BONDS_MOEX = mt5.SYMBOL_CALC_MODE_EXCH_BONDS_MOEX
|
||||
SERV_COLLATERAL = mt5.SYMBOL_CALC_MODE_SERV_COLLATERAL
|
||||
|
||||
|
||||
class SymbolTradeMode(Repr, IntEnum):
|
||||
"""SYMBOL_TRADE_MODE Enum. There are several symbol trading modes. Information about trading modes of a certain
|
||||
symbol is reflected in the values this enumeration
|
||||
|
||||
Attributes:
|
||||
DISABLED (int): Trade is disabled for the symbol
|
||||
LONGONLY (int): Allowed only long positions
|
||||
SHORTONLY (int): Allowed only short positions
|
||||
CLOSEONLY (int): Allowed only position close operations
|
||||
FULL (int): No trade restrictions
|
||||
"""
|
||||
|
||||
__enum_name__ = "SYMBOL_TRADE_MODE"
|
||||
DISABLED = mt5.SYMBOL_TRADE_MODE_DISABLED
|
||||
LONGONLY = mt5.SYMBOL_TRADE_MODE_LONGONLY
|
||||
SHORTONLY = mt5.SYMBOL_TRADE_MODE_SHORTONLY
|
||||
CLOSEONLY = mt5.SYMBOL_TRADE_MODE_CLOSEONLY
|
||||
FULL = mt5.SYMBOL_TRADE_MODE_FULL
|
||||
|
||||
|
||||
class SymbolTradeExecution(Repr, IntEnum):
|
||||
"""SYMBOL_TRADE_EXECUTION Enum. The modes, or execution policies, define the rules for cases when the price has
|
||||
changed or the requested volume cannot be completely fulfilled at the moment.
|
||||
|
||||
Attributes:
|
||||
REQUEST (int): Executing a market order at the price previously received from the broker. Prices for a certain
|
||||
market order are requested from the broker before the order is sent. Upon receiving the prices, order
|
||||
execution at the given price can be either confirmed or rejected.
|
||||
|
||||
INSTANT (int): Executing a market order at the specified price immediately. When sending a trade request to be
|
||||
executed, the platform automatically adds the current prices to the order.
|
||||
- If the broker accepts the price, the order is executed.
|
||||
- If the broker does not accept the requested price, a "Requote" is sent — the broker returns prices,
|
||||
at which this order can be executed.
|
||||
|
||||
MARKET (int): A broker makes a decision about the order execution price without any additional discussion with the trader.
|
||||
Sending the order in such a mode means advance consent to its execution at this price.
|
||||
|
||||
EXCHANGE (int): Trade operations are executed at the prices of the current market offers.
|
||||
"""
|
||||
|
||||
__enum_name__ = "SYMBOL_TRADE_EXECUTION"
|
||||
REQUEST = mt5.SYMBOL_TRADE_EXECUTION_REQUEST
|
||||
INSTANT = mt5.SYMBOL_TRADE_EXECUTION_INSTANT
|
||||
MARKET = mt5.SYMBOL_TRADE_EXECUTION_MARKET
|
||||
EXCHANGE = mt5.SYMBOL_TRADE_EXECUTION_EXCHANGE
|
||||
|
||||
|
||||
class SymbolSwapMode(Repr, IntEnum):
|
||||
"""SYMBOL_SWAP_MODE Enum. Methods of swap calculation at position transfer are specified in enumeration
|
||||
ENUM_SYMBOL_SWAP_MODE. The method of swap calculation determines the units of measure of the SYMBOL_SWAP_LONG and
|
||||
SYMBOL_SWAP_SHORT parameters. For example, if swaps are charged in the client deposit currency, then the values of
|
||||
those parameters are specified as an amount of money in the client deposit currency.
|
||||
|
||||
Attributes:
|
||||
DISABLED (int): Swaps disabled (no swaps)
|
||||
POINTS (int): Swaps are charged in points
|
||||
CURRENCY_SYMBOL (int): Swaps are charged in money in base currency of the symbol
|
||||
CURRENCY_MARGIN (int): Swaps are charged in money in margin currency of the symbol
|
||||
CURRENCY_DEPOSIT (int): Swaps are charged in money, in client deposit currency
|
||||
|
||||
INTEREST_CURRENT (int): Swaps are charged as the specified annual interest from the instrument price at
|
||||
calculation of swap (standard bank year is 360 days)
|
||||
|
||||
INTEREST_OPEN (int): Swaps are charged as the specified annual interest from the open price of position
|
||||
(standard bank year is 360 days)
|
||||
|
||||
REOPEN_CURRENT (int): Swaps are charged by reopening positions. At the end of a trading day the position is
|
||||
closed. Next day it is reopened by the close price +/- specified number of points
|
||||
(parameters SYMBOL_SWAP_LONG and SYMBOL_SWAP_SHORT)
|
||||
|
||||
REOPEN_BID (int): Swaps are charged by reopening positions. At the end of a trading day the position is closed.
|
||||
Next day it is reopened by the current Bid price +/- specified number of
|
||||
points (parameters SYMBOL_SWAP_LONG and SYMBOL_SWAP_SHORT)
|
||||
"""
|
||||
__enum_name__ = "SYMBOL_SWAP_MODE"
|
||||
DISABLED = mt5.SYMBOL_SWAP_MODE_DISABLED
|
||||
POINTS = mt5.SYMBOL_SWAP_MODE_POINTS
|
||||
CURRENCY_SYMBOL = mt5.SYMBOL_SWAP_MODE_CURRENCY_SYMBOL
|
||||
CURRENCY_MARGIN = mt5.SYMBOL_SWAP_MODE_CURRENCY_MARGIN
|
||||
CURRENCY_DEPOSIT = mt5.SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT
|
||||
INTEREST_CURRENT = mt5.SYMBOL_SWAP_MODE_INTEREST_CURRENT
|
||||
INTEREST_OPEN = mt5.SYMBOL_SWAP_MODE_INTEREST_OPEN
|
||||
REOPEN_CURRENT = mt5.SYMBOL_SWAP_MODE_REOPEN_CURRENT
|
||||
REOPEN_BID = mt5.SYMBOL_SWAP_MODE_REOPEN_BID
|
||||
|
||||
|
||||
class DayOfWeek(Repr, IntEnum):
|
||||
"""DAY_OF_WEEK Enum.
|
||||
|
||||
Attributes:
|
||||
SUNDAY (int): Sunday
|
||||
MONDAY (int): Monday
|
||||
TUESDAY (int): Tuesday
|
||||
WEDNESDAY (int): Wednesday
|
||||
THURSDAY (int): Thursday
|
||||
FRIDAY (int): Friday
|
||||
SATURDAY (int): Saturday
|
||||
"""
|
||||
__enum__name__ = "DAY_OF_WEEK"
|
||||
SUNDAY = mt5.DAY_OF_WEEK_SUNDAY
|
||||
MONDAY = mt5.DAY_OF_WEEK_MONDAY
|
||||
TUESDAY = mt5.DAY_OF_WEEK_TUESDAY
|
||||
WEDNESDAY = mt5.DAY_OF_WEEK_WEDNESDAY
|
||||
THURSDAY = mt5.DAY_OF_WEEK_THURSDAY
|
||||
FRIDAY = mt5.DAY_OF_WEEK_FRIDAY
|
||||
SATURDAY = mt5.DAY_OF_WEEK_SATURDAY
|
||||
|
||||
|
||||
class SymbolOrderGTCMode(Repr, IntEnum):
|
||||
"""SYMBOL_ORDER_GTC_MODE Enum. If the SYMBOL_EXPIRATION_MODE property is set to SYMBOL_EXPIRATION_GTC
|
||||
(good till canceled), the expiration of pending orders, as well as of
|
||||
Stop Loss/Take Profit orders should be additionally set using the ENUM_SYMBOL_ORDER_GTC_MODE enumeration.
|
||||
|
||||
Attributes:
|
||||
GTC (int): Pending orders and Stop Loss/Take Profit levels are valid for an unlimited period
|
||||
until theirConstants, Enumerations and explicit cancellation
|
||||
|
||||
DAILY (int): Orders are valid during one trading day. At the end of the day, all Stop Loss and
|
||||
Take Profit levels, as well as pending orders are deleted.
|
||||
|
||||
DAILY_NO_STOPS (int): When a trade day changes, only pending orders are deleted,
|
||||
while Stop Loss and Take Profit levels are preserved
|
||||
"""
|
||||
__enum_name__ = "SYMBOL_ORDERS"
|
||||
GTC = mt5.SYMBOL_ORDERS_GTC
|
||||
DAILY = mt5.SYMBOL_ORDERS_DAILY
|
||||
DAILY_NO_STOPS = mt5.SYMBOL_ORDERS_DAILY_NO_STOPS
|
||||
|
||||
|
||||
class SymbolOptionRight(Repr, IntEnum):
|
||||
"""SYMBOL_OPTION_RIGHT Enum. An option is a contract, which gives the right, but not the obligation,
|
||||
to buy or sell an underlying asset (goods, stocks, futures, etc.) at a specified price on or before a specific date.
|
||||
The following enumerations describe option properties, including the option type and the right arising from it.
|
||||
|
||||
Attributes:
|
||||
CALL (int): A call option gives you the right to buy an asset at a specified price.
|
||||
PUT (int): A put option gives you the right to sell an asset at a specified price.
|
||||
"""
|
||||
__enum_name__ = "SYMBOL_OPTION_RIGHT"
|
||||
CALL = mt5.SYMBOL_OPTION_RIGHT_CALL
|
||||
PUT = mt5.SYMBOL_OPTION_RIGHT_PUT
|
||||
|
||||
|
||||
class SymbolOptionMode(Repr, IntEnum):
|
||||
"""SYMBOL_OPTION_MODE Enum.
|
||||
|
||||
Attributes:
|
||||
EUROPEAN (int): European option may only be exercised on a specified date (expiration, execution date, delivery date)
|
||||
AMERICAN (int): American option may be exercised on any trading day or before expiry. The period within which
|
||||
a buyer can exercise the option is specified for it.
|
||||
"""
|
||||
__enum_name__ = "SYMBOL_OPTION_MODE"
|
||||
EUROPEAN = mt5.SYMBOL_OPTION_MODE_EUROPEAN
|
||||
AMERICAN = mt5.SYMBOL_OPTION_MODE_AMERICAN
|
||||
|
||||
|
||||
class AccountTradeMode(Repr, IntEnum):
|
||||
"""ACCOUNT_TRADE_MODE Enum. There are several types of accounts that can be opened on a trade server.
|
||||
The type of account on which an MQL5 program is running can be found out using
|
||||
the ENUM_ACCOUNT_TRADE_MODE enumeration.
|
||||
|
||||
Attributes:
|
||||
DEMO: Demo account
|
||||
CONTEST: Contest account
|
||||
REAL: Real Account
|
||||
"""
|
||||
__enum_name__ = "ACCOUNT_TRADE_MODE"
|
||||
DEMO = mt5.ACCOUNT_TRADE_MODE_DEMO
|
||||
CONTEST = mt5.ACCOUNT_TRADE_MODE_CONTEST
|
||||
REAL = mt5.ACCOUNT_TRADE_MODE_REAL
|
||||
|
||||
|
||||
class TickFlag(Repr, IntFlag):
|
||||
"""TICK_FLAG Enum. TICK_FLAG defines possible flags for ticks. These flags are used to describe ticks obtained by the
|
||||
copy_ticks_from() and copy_ticks_range() functions.
|
||||
|
||||
Attributes:
|
||||
BID (int): Bid price changed
|
||||
ASK (int): Ask price changed
|
||||
LAST (int): Last price changed
|
||||
VOLUME (int): Volume changed
|
||||
BUY (int): last Buy price changed
|
||||
SELL (int): last Sell price changed
|
||||
"""
|
||||
__enum_name__ = "TICK_FLAG"
|
||||
BID = mt5.TICK_FLAG_BID
|
||||
ASK = mt5.TICK_FLAG_ASK
|
||||
LAST = mt5.TICK_FLAG_LAST
|
||||
VOLUME = mt5.TICK_FLAG_VOLUME
|
||||
BUY = mt5.TICK_FLAG_BUY
|
||||
SELL = mt5.TICK_FLAG_SELL
|
||||
|
||||
|
||||
class TradeRetcode(Repr, IntEnum):
|
||||
"""TRADE_RETCODE Enum. Return codes for order send/check operations
|
||||
|
||||
Attributes:
|
||||
REQUOTE (int): Requote
|
||||
REJECT (int): Request rejected
|
||||
CANCEL (int): Request canceled by trader
|
||||
PLACED (int): Order placed
|
||||
DONE (int): Request completed
|
||||
DONE_PARTIAL (int): Only part of the request was completed
|
||||
ERROR (int): Request processing error
|
||||
TIMEOUT (int): Request canceled by timeout
|
||||
INVALID (int): Invalid request
|
||||
INVALID_VOLUME (int): Invalid volume in the request
|
||||
INVALID_PRICE (int): Invalid price in the request
|
||||
INVALID_STOPS (int): Invalid stops in the request
|
||||
TRADE_DISABLED (int): Trade is disabled
|
||||
MARKET_CLOSED (int): Market is closed
|
||||
NO_MONEY (int): There is not enough money to complete the request
|
||||
PRICE_CHANGED (int): Prices changed
|
||||
PRICE_OFF (int): There are no quotes to process the request
|
||||
INVALID_EXPIRATION (int): Invalid order expiration date in the request
|
||||
ORDER_CHANGED (int): Order state changed
|
||||
TOO_MANY_REQUESTS (int): Too frequent requests
|
||||
NO_CHANGES (int): No changes in request
|
||||
SERVER_DISABLES_AT (int): Autotrading disabled by server
|
||||
CLIENT_DISABLES_AT (int): Autotrading disabled by client terminal
|
||||
LOCKED (int): Request locked for processing
|
||||
FROZEN (int): Order or position frozen
|
||||
INVALID_FILL (int): Invalid order filling type
|
||||
CONNECTION (int): No connection with the trade server
|
||||
ONLY_REAL (int): Operation is allowed only for live accounts
|
||||
LIMIT_ORDERS (int): The number of pending orders has reached the limit
|
||||
LIMIT_VOLUME (int): The volume of orders and positions for the symbol has reached the limit
|
||||
INVALID_ORDER (int): Incorrect or prohibited order type
|
||||
POSITION_CLOSED (int): Position with the specified POSITION_IDENTIFIER has already been closed
|
||||
INVALID_CLOSE_VOLUME (int): A close volume exceeds the current position volume
|
||||
|
||||
CLOSE_ORDER_EXIST (int): A close order already exists for a specified position. This may happen when working in
|
||||
the hedging system:
|
||||
· when attempting to close a position with an opposite one, while close orders for the position already exist
|
||||
· when attempting to fully or partially close a position if the total volume of the already present close
|
||||
orders and the newly placed one exceeds the current position volume
|
||||
|
||||
LIMIT_POSITIONS (int): The number of open positions simultaneously present on an account can be limited by the
|
||||
server settings.After a limit is reached, the server returns the TRADE_RETCODE_LIMIT_POSITIONS error when
|
||||
attempting to place an order. The limitation operates differently depending on the position accounting type:
|
||||
· Netting — number of open positions is considered. When a limit is reached, the platform does not let
|
||||
placing new orders whose execution may increase the number of open positions. In fact, the platform
|
||||
allows placing orders only for the symbols that already have open positions.
|
||||
The current pending orders are not considered since their execution may lead to changes in the current
|
||||
positions but it cannot increase their number.
|
||||
|
||||
· Hedging — pending orders are considered together with open positions, since a pending order activation
|
||||
always leads to opening a new position. When a limit is reached, the platform does not allow placing
|
||||
both new market orders for opening positions and pending orders.
|
||||
|
||||
REJECT_CANCEL (int): The pending order activation request is rejected, the order is canceled.
|
||||
LONG_ONLY (int): The request is rejected, because the "Only long positions are allowed" rule is set for the
|
||||
symbol (POSITION_TYPE_BUY)
|
||||
SHORT_ONLY (int): The request is rejected, because the "Only short positions are allowed" rule is set for the
|
||||
symbol (POSITION_TYPE_SELL)
|
||||
CLOSE_ONLY (int): The request is rejected, because the "Only position closing is allowed" rule is set for the
|
||||
symbol
|
||||
FIFO_CLOSE (int): The request is rejected, because "Position closing is allowed only by FIFO rule" flag is set
|
||||
for the trading account (ACCOUNT_FIFO_CLOSE=true)
|
||||
"""
|
||||
__enum_name__ = "TRADE_RETCODE"
|
||||
REQUOTE = mt5.TRADE_RETCODE_REQUOTE
|
||||
REJECT = mt5.TRADE_RETCODE_REJECT
|
||||
CANCEL = mt5.TRADE_RETCODE_CANCEL
|
||||
PLACED = mt5.TRADE_RETCODE_PLACED
|
||||
DONE = mt5.TRADE_RETCODE_DONE
|
||||
DONE_PARTIAL = mt5.TRADE_RETCODE_DONE_PARTIAL
|
||||
ERROR = mt5.TRADE_RETCODE_ERROR
|
||||
TIMEOUT = mt5.TRADE_RETCODE_TIMEOUT
|
||||
INVALID = mt5.TRADE_RETCODE_INVALID
|
||||
INVALID_VOLUME = mt5.TRADE_RETCODE_INVALID_VOLUME
|
||||
INVALID_PRICE = mt5.TRADE_RETCODE_INVALID_PRICE
|
||||
INVALID_STOPS = mt5.TRADE_RETCODE_INVALID_STOPS
|
||||
TRADE_DISABLED = mt5.TRADE_RETCODE_TRADE_DISABLED
|
||||
MARKET_CLOSED = mt5.TRADE_RETCODE_MARKET_CLOSED
|
||||
NO_MONEY = mt5.TRADE_RETCODE_NO_MONEY
|
||||
PRICE_CHANGED = mt5.TRADE_RETCODE_PRICE_CHANGED
|
||||
PRICE_OFF = mt5.TRADE_RETCODE_PRICE_OFF
|
||||
INVALID_EXPIRATION = mt5.TRADE_RETCODE_INVALID_EXPIRATION
|
||||
ORDER_CHANGED = mt5.TRADE_RETCODE_ORDER_CHANGED
|
||||
TOO_MANY_REQUESTS = mt5.TRADE_RETCODE_TOO_MANY_REQUESTS
|
||||
NO_CHANGES = mt5.TRADE_RETCODE_NO_CHANGES
|
||||
SERVER_DISABLES_AT = mt5.TRADE_RETCODE_SERVER_DISABLES_AT
|
||||
CLIENT_DISABLES_AT = mt5.TRADE_RETCODE_CLIENT_DISABLES_AT
|
||||
LOCKED = mt5.TRADE_RETCODE_LOCKED
|
||||
FROZEN = mt5.TRADE_RETCODE_FROZEN
|
||||
INVALID_FILL = mt5.TRADE_RETCODE_INVALID_FILL
|
||||
CONNECTION = mt5.TRADE_RETCODE_CONNECTION
|
||||
ONLY_REAL = mt5.TRADE_RETCODE_ONLY_REAL
|
||||
LIMIT_ORDERS = mt5.TRADE_RETCODE_LIMIT_ORDERS
|
||||
LIMIT_VOLUME = mt5.TRADE_RETCODE_LIMIT_VOLUME
|
||||
INVALID_ORDER = mt5.TRADE_RETCODE_INVALID_ORDER
|
||||
POSITION_CLOSED = mt5.TRADE_RETCODE_POSITION_CLOSED
|
||||
INVALID_CLOSE_VOLUME = mt5.TRADE_RETCODE_INVALID_CLOSE_VOLUME
|
||||
CLOSE_ORDER_EXIST = mt5.TRADE_RETCODE_CLOSE_ORDER_EXIST
|
||||
LIMIT_POSITIONS = mt5.TRADE_RETCODE_LIMIT_POSITIONS
|
||||
REJECT_CANCEL = mt5.TRADE_RETCODE_REJECT_CANCEL
|
||||
LONG_ONLY = mt5.TRADE_RETCODE_LONG_ONLY
|
||||
SHORT_ONLY = mt5.TRADE_RETCODE_SHORT_ONLY
|
||||
CLOSE_ONLY = mt5.TRADE_RETCODE_CLOSE_ONLY
|
||||
FIFO_CLOSE = mt5.TRADE_RETCODE_FIFO_CLOSE
|
||||
|
||||
|
||||
class AccountStopOutMode(Repr, IntEnum):
|
||||
"""ACCOUNT_STOPOUT_MODE Enum.
|
||||
|
||||
Attributes:
|
||||
PERCENT (int): Account stop out mode in percents
|
||||
MONEY (int): Account stop out mode in money
|
||||
"""
|
||||
|
||||
__enum_name__ = "ACCOUNT_STOPOUT_MODE"
|
||||
PERCENT = mt5.ACCOUNT_STOPOUT_MODE_PERCENT
|
||||
MONEY = mt5.ACCOUNT_STOPOUT_MODE_MONEY
|
||||
|
||||
|
||||
class AccountMarginMode(Repr, IntEnum):
|
||||
"""ACCOUNT_MARGIN_MODE Enum.
|
||||
|
||||
Attributes:
|
||||
RETAIL_NETTING (int): Used for the OTC markets to interpret positions in the "netting"
|
||||
mode (only one position can exist for one symbol). The margin is calculated based on the symbol
|
||||
type (SYMBOL_TRADE_CALC_MODE).
|
||||
|
||||
EXCHANGE (int): Used for the exchange markets. Margin is calculated based on the discounts specified in
|
||||
symbol settings. Discounts are set by the broker, but not less than the values set by the exchange.
|
||||
|
||||
HEDGING (int): Used for the exchange markets where individual positions are possible
|
||||
(hedging, multiple positions can exist for one symbol). The margin is calculated based on the symbol
|
||||
type (SYMBOL_TRADE_CALC_MODE) taking into account the hedged margin (SYMBOL_MARGIN_HEDGED).
|
||||
"""
|
||||
__enum_name__ = "ACCOUNT_MARGIN_MODE"
|
||||
RETAIL_NETTING = mt5.ACCOUNT_MARGIN_MODE_RETAIL_NETTING
|
||||
EXCHANGE = mt5.ACCOUNT_MARGIN_MODE_EXCHANGE
|
||||
RETAIL_HEDGING = mt5.ACCOUNT_MARGIN_MODE_RETAIL_HEDGING
|
||||
@@ -0,0 +1,30 @@
|
||||
class Error:
|
||||
"""Error class for handling errors from MetaTrader 5."""
|
||||
descriptions = {
|
||||
# common errors
|
||||
1: 'Successful',
|
||||
-1: 'generic fail',
|
||||
-2: 'invalid arguments/parameters',
|
||||
-3: 'no memory condition',
|
||||
-4: 'no history',
|
||||
-5: 'invalid version',
|
||||
-6: 'authorization failed',
|
||||
-7: 'unsupported method',
|
||||
-8: 'auto-trading disabled',
|
||||
# internal errors
|
||||
-10000: 'internal IPC general error',
|
||||
-10001: 'internal IPC send failed',
|
||||
-10002: 'internal IPC recv failed',
|
||||
-10003: 'internal IPC initialization fail',
|
||||
-10004: 'internal IPC no ipc',
|
||||
-10005: 'internal timeout',
|
||||
}
|
||||
def __init__(self, code: int, description: str = ''):
|
||||
self.code = code
|
||||
self.description = description or self.descriptions.get(code, 'Unknown Error')
|
||||
|
||||
def __repr__(self):
|
||||
return f"""
|
||||
Error Code: {self.code}
|
||||
Error Description: {self.description}
|
||||
"""
|
||||
@@ -0,0 +1,19 @@
|
||||
"""Exceptions for the aiomql package."""
|
||||
|
||||
__all__ = ['LoginError', 'VolumeError', 'SymbolError', 'OrderError']
|
||||
|
||||
class LoginError(Exception):
|
||||
"""Raised when an error occurs when logging in."""
|
||||
pass
|
||||
|
||||
class VolumeError(Exception):
|
||||
"""Raised when a volume is not valid or out of range for a symbol."""
|
||||
pass
|
||||
|
||||
|
||||
class SymbolError(Exception):
|
||||
"""Raised when a symbol is not provided where required or not available in the Market Watch."""
|
||||
|
||||
|
||||
class OrderError(Exception):
|
||||
"""Raised when an error occurs when working with the order class."""
|
||||
@@ -0,0 +1,355 @@
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
from logging import getLogger
|
||||
from typing import Callable
|
||||
|
||||
import MetaTrader5
|
||||
|
||||
from MetaTrader5 import BookInfo, SymbolInfo, AccountInfo, Tick, TerminalInfo, TradeOrder, TradeDeal,\
|
||||
TradePosition, OrderSendResult, OrderCheckResult
|
||||
|
||||
from .constants import TimeFrame, CopyTicks, OrderType
|
||||
from .errors import Error
|
||||
from .config import Config
|
||||
|
||||
logger = getLogger()
|
||||
|
||||
|
||||
class BaseMeta(type):
|
||||
def __new__(mcs, cls_name, bases, cls_dict):
|
||||
defaults = MetaTrader5.__dict__
|
||||
defaults = {f'_{key}': value for key, value in defaults.items() if not key.startswith('_')}
|
||||
cls_dict |= defaults
|
||||
return super().__new__(mcs, cls_name, bases, cls_dict)
|
||||
|
||||
|
||||
class MetaTrader(metaclass=BaseMeta):
|
||||
_account_info: Callable
|
||||
_copy_rates_from: Callable
|
||||
_copy_rates_from_pos: Callable
|
||||
_copy_rates_range: Callable
|
||||
_copy_ticks_from: Callable
|
||||
_copy_ticks_range: Callable
|
||||
_history_deals_get: Callable
|
||||
_history_deals_total: Callable
|
||||
_history_orders_get: Callable
|
||||
_history_orders_total: Callable
|
||||
_initialize: Callable
|
||||
_last_error: Callable
|
||||
_login: Callable
|
||||
_market_book_add: Callable
|
||||
_market_book_get: Callable
|
||||
_market_book_release: Callable
|
||||
_order_calc_margin: Callable
|
||||
_order_calc_profit: Callable
|
||||
_order_check: Callable
|
||||
_order_send: Callable
|
||||
_orders_get: Callable
|
||||
_orders_total: Callable
|
||||
_positions_get: Callable
|
||||
_positions_total: Callable
|
||||
_shutdown: Callable
|
||||
_symbol_info: Callable
|
||||
_symbol_info_tick: Callable
|
||||
_symbol_select: Callable
|
||||
_symbols_get: Callable
|
||||
_symbols_total: Callable
|
||||
_terminal_info: Callable
|
||||
_version: Callable
|
||||
|
||||
async def __aenter__(self) -> 'MetaTrader':
|
||||
"""
|
||||
Async context manager entry point.
|
||||
Initializes the connection to the MetaTrader terminal.
|
||||
|
||||
Returns:
|
||||
MetaTrader: An instance of the MetaTrader class.
|
||||
"""
|
||||
await self.initialize(**Config().account_info())
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
Async context manager exit point. Closes the connection to the MetaTrader terminal.
|
||||
"""
|
||||
await self.shutdown()
|
||||
|
||||
async def login(self, login: int, password: str, server: str, timeout: int = 60000) -> bool:
|
||||
"""
|
||||
Connects to the MetaTrader terminal using the specified login, password and server.
|
||||
|
||||
Args:
|
||||
login (int): The trading account number.
|
||||
password (str): The trading account password.
|
||||
server (str): The trading server name.
|
||||
timeout (int): The timeout for the connection in seconds.
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise.
|
||||
"""
|
||||
return await asyncio.to_thread(self._login, login, password=password, server=server, timeout=timeout)
|
||||
|
||||
async def initialize(self, 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.
|
||||
|
||||
Keyword Args:
|
||||
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): The timeout for the connection in seconds.
|
||||
portable (bool): If True, the terminal will be launched in portable mode.
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise.
|
||||
"""
|
||||
args = (path,) if path else ()
|
||||
kwargs = {key: value for key, value in (('login', login), ('password', password), ('server', server),
|
||||
('timeout', timeout), ('portable', portable)) if value}
|
||||
return await asyncio.to_thread(self._initialize, *args, **kwargs)
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
"""
|
||||
Closes the connection to the MetaTrader terminal.
|
||||
|
||||
Returns:
|
||||
None: None
|
||||
"""
|
||||
return await asyncio.to_thread(self._shutdown)
|
||||
|
||||
async def last_error(self) -> tuple[int, str]:
|
||||
return await asyncio.to_thread(self._last_error)
|
||||
|
||||
async def version(self) -> tuple[int, int, str] | None:
|
||||
""""""
|
||||
res = await asyncio.to_thread(self._version)
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining version information.{Error(*err)}')
|
||||
return res
|
||||
|
||||
async def account_info(self) -> AccountInfo | None:
|
||||
""""""
|
||||
res = await asyncio.to_thread(self._account_info)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining account information.{Error(*err)}')
|
||||
|
||||
return res
|
||||
|
||||
async def terminal_info(self) -> TerminalInfo | None:
|
||||
res = await asyncio.to_thread(self._terminal_info)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining terminal information.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def symbols_total(self) -> int:
|
||||
return await asyncio.to_thread(self._symbols_total)
|
||||
|
||||
async def symbols_get(self, group: str = "") -> tuple[SymbolInfo] | None:
|
||||
kwargs = {'group': group} if group else {}
|
||||
res = await asyncio.to_thread(self._symbols_get, **kwargs)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining symbols.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def symbol_info(self, symbol: str) -> SymbolInfo | None:
|
||||
res = await asyncio.to_thread(self._symbol_info, symbol)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining information for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def symbol_info_tick(self, symbol: str) -> Tick | None:
|
||||
res = await asyncio.to_thread(self._symbol_info_tick, symbol)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining tick for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def symbol_select(self, symbol: str, enable: bool) -> bool:
|
||||
return await asyncio.to_thread(self._symbol_select, symbol, enable)
|
||||
|
||||
async def market_book_add(self, symbol: str) -> bool:
|
||||
return await asyncio.to_thread(self._market_book_add, symbol)
|
||||
|
||||
async def market_book_get(self, symbol: str) -> tuple[BookInfo] | None:
|
||||
res = await asyncio.to_thread(self._market_book_get, symbol)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining market depth content for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def market_book_release(self, symbol: str) -> bool:
|
||||
return await asyncio.to_thread(self._market_book_release, symbol)
|
||||
|
||||
async def copy_rates_from(self, symbol: str, timeframe: TimeFrame, date_from: datetime | int, count: int):
|
||||
res = await asyncio.to_thread(self._copy_rates_from, symbol, timeframe, date_from, count)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining rates for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def copy_rates_from_pos(self, symbol: str, timeframe: TimeFrame, start_pos: int, count: int):
|
||||
res = await asyncio.to_thread(self._copy_rates_from_pos, symbol, timeframe, start_pos, count)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining rates for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def copy_rates_range(self, symbol: str, timeframe: TimeFrame, date_from: datetime | int,
|
||||
date_to: datetime | int):
|
||||
res = await asyncio.to_thread(self._copy_rates_range, symbol, timeframe, date_from, date_to)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining rates for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def copy_ticks_from(self, symbol: str, date_from: datetime | int, count: int, flags: CopyTicks):
|
||||
res = await asyncio.to_thread(self._copy_ticks_from, symbol, date_from, count, flags)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining ticks for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def copy_ticks_range(self, symbol: str, date_from: datetime | int, date_to: datetime | int, flags: CopyTicks):
|
||||
res = await asyncio.to_thread(self._copy_ticks_range, symbol, date_from, date_to, flags)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining ticks for {symbol}.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def orders_total(self) -> int:
|
||||
return await asyncio.to_thread(self._orders_total)
|
||||
|
||||
async def orders_get(self, group: str = "", 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.
|
||||
Call without parameters. Return active orders on all symbols
|
||||
|
||||
Keyword Args:
|
||||
symbol (str): Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored.
|
||||
|
||||
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.
|
||||
|
||||
Returns:
|
||||
list[TradeOrder]: A list of active trade orders as TradeOrder objects
|
||||
"""
|
||||
kwargs = {key: value for key, value in (('group', group), ('ticket', ticket), ('symbol', symbol)) if value}
|
||||
res = await asyncio.to_thread(self._orders_get, **kwargs)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining orders.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def order_calc_margin(self, action: OrderType, symbol: str, volume: float, price: float) -> float | None:
|
||||
res = await asyncio.to_thread(self._order_calc_margin, action, symbol, volume, price)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in calculating margin.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def order_calc_profit(self, action: OrderType, symbol: str, volume: float, price_open: float,
|
||||
price_close: float) -> float | None:
|
||||
res = await asyncio.to_thread(self._order_calc_profit, action, symbol, volume, price_open, price_close)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in calculating profit.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def order_check(self, request: dict) -> OrderCheckResult:
|
||||
return await asyncio.to_thread(self._order_check, request)
|
||||
|
||||
async def order_send(self, request: dict) -> OrderSendResult:
|
||||
return await asyncio.to_thread(self._order_send, request)
|
||||
|
||||
async def positions_total(self) -> int:
|
||||
return await asyncio.to_thread(self._positions_total)
|
||||
|
||||
async def positions_get(self, group: str = "", ticket: int = 0, symbol: str = "") -> tuple[TradePosition] | None:
|
||||
kwargs = {key: value for key, value in (('group', group), ('ticket', ticket), ('symbol', symbol)) if value}
|
||||
res = await asyncio.to_thread(self._positions_get, **kwargs)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in obtaining open positions.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def history_orders_total(self, date_from: datetime | int, date_to: datetime | int) -> int:
|
||||
return await asyncio.to_thread(self._history_orders_total, date_from, date_to)
|
||||
|
||||
async def history_orders_get(self, date_from: datetime | int = None, date_to: datetime | int = None, group: str = '',
|
||||
ticket: int = 0, position: int = 0) -> tuple[TradeOrder] | None:
|
||||
kwargs = {key: value for key, value in (('date_from', date_from), ('date_to', date_to), ('group', group),
|
||||
('ticket', ticket), ('position', position)) if value}
|
||||
res = await asyncio.to_thread(self._history_orders_get, **kwargs)
|
||||
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in getting orders.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
|
||||
async def history_deals_total(self, date_from: datetime | int, date_to: datetime | int) -> int:
|
||||
return await asyncio.to_thread(self._history_deals_total, date_from, date_to)
|
||||
|
||||
async def history_deals_get(self, date_from: datetime | int = None, date_to: datetime | int = None, group: str = '',
|
||||
ticket: int = 0, position: int = 0) -> tuple[TradeDeal] | None:
|
||||
kwargs = {key: value for key, value in (('date_from', date_from), ('date_to', date_to), ('group', group),
|
||||
('ticket', ticket), ('position', position)) if value}
|
||||
res = await asyncio.to_thread(self._history_deals_get, **kwargs)
|
||||
if res is None:
|
||||
err = await self.last_error()
|
||||
logger.warning(f'Error in getting deals.{Error(*err)}')
|
||||
return res
|
||||
|
||||
return res
|
||||
@@ -0,0 +1,613 @@
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
from .constants import BookType, TradeAction, OrderType, OrderTime, OrderFilling, PositionReason, DealType, DealEntry,\
|
||||
DealReason, SymbolChartMode, SymbolTradeMode, SymbolCalcMode, SymbolOptionMode, SymbolOrderGTCMode, SymbolOptionRight,\
|
||||
SymbolTradeExecution, SymbolSwapMode, DayOfWeek, AccountTradeMode, AccountStopOutMode, AccountMarginMode, OrderReason
|
||||
|
||||
from .base import Base
|
||||
|
||||
"""
|
||||
This module contains data models used in this library.
|
||||
They are used as base classes to other classes having the same properties but with more methods.
|
||||
"""
|
||||
|
||||
|
||||
class AccountInfo(Base):
|
||||
"""Account Information Class.
|
||||
|
||||
Attributes:
|
||||
login: int
|
||||
password: str
|
||||
server: str
|
||||
trade_mode: AccountTradeMode
|
||||
balance: float
|
||||
leverage: float
|
||||
profit: float
|
||||
point: float
|
||||
amount: float = 0
|
||||
equity: float
|
||||
credit: float
|
||||
margin: float
|
||||
margin_level: float
|
||||
margin_free: float
|
||||
margin_mode: AccountMarginMode
|
||||
margin_so_mode: AccountStopoutMode
|
||||
margin_so_call: float
|
||||
margin_so_so: float
|
||||
margin_initial: float
|
||||
margin_maintenance: float
|
||||
fifo_close: bool
|
||||
limit_orders: float
|
||||
currency: str = "USD"
|
||||
trade_allowed: bool = True
|
||||
trade_expert: bool = True
|
||||
currency_digits: int
|
||||
assets: float
|
||||
liabilities: float
|
||||
commission_blocked: float
|
||||
name: str
|
||||
company: str
|
||||
"""
|
||||
login: int = 0
|
||||
password: str = ''
|
||||
server: str = ''
|
||||
trade_mode: AccountTradeMode
|
||||
balance: float
|
||||
leverage: float
|
||||
profit: float
|
||||
point: float
|
||||
amount: float = 0
|
||||
equity: float
|
||||
credit: float
|
||||
margin: float
|
||||
margin_level: float
|
||||
margin_free: float
|
||||
margin_mode: AccountMarginMode
|
||||
margin_so_mode: AccountStopOutMode
|
||||
margin_so_call: float
|
||||
margin_so_so: float
|
||||
margin_initial: float
|
||||
margin_maintenance: float
|
||||
fifo_close: bool
|
||||
limit_orders: float
|
||||
currency: str = "USD"
|
||||
trade_allowed: bool = True
|
||||
trade_expert: bool = True
|
||||
currency_digits: int
|
||||
assets: float
|
||||
liabilities: float
|
||||
commission_blocked: float
|
||||
name: str
|
||||
company: str
|
||||
|
||||
|
||||
class TerminalInfo(Base):
|
||||
"""Terminal information class. Holds information about the terminal.
|
||||
|
||||
Attributes:
|
||||
community_account: bool
|
||||
community_connection: bool
|
||||
connected: bool
|
||||
dlls_allowed: bool
|
||||
trade_allowed: bool
|
||||
tradeapi_disabled: bool
|
||||
email_enabled: bool
|
||||
ftp_enabled: bool
|
||||
notifications_enabled: bool
|
||||
mqid: bool
|
||||
build: int
|
||||
maxbars: int
|
||||
codepage: int
|
||||
ping_last: int
|
||||
community_balance: float
|
||||
retransmission: float
|
||||
company: str
|
||||
name: str
|
||||
language: str
|
||||
path: str
|
||||
data_path: str
|
||||
commondata_path: str
|
||||
"""
|
||||
community_account: bool
|
||||
community_connection: bool
|
||||
connected: bool
|
||||
dlls_allowed: bool
|
||||
trade_allowed: bool
|
||||
tradeapi_disabled: bool
|
||||
email_enabled: bool
|
||||
ftp_enabled: bool
|
||||
notifications_enabled: bool
|
||||
mqid: bool
|
||||
build: int
|
||||
maxbars: int
|
||||
codepage: int
|
||||
ping_last: int
|
||||
community_balance: float
|
||||
retransmission: float
|
||||
company: str
|
||||
name: str
|
||||
language: str
|
||||
path: str
|
||||
data_path: str
|
||||
commondata_path: str
|
||||
|
||||
|
||||
class SymbolInfo(Base):
|
||||
"""Symbol Information Class. Symbols are financial instruments available for trading in the MetaTrader 5 terminal.
|
||||
|
||||
Attributes:
|
||||
name: str
|
||||
custom: bool
|
||||
chart_mode: SymbolChartMode
|
||||
select: bool
|
||||
visible: bool
|
||||
session_deals: int
|
||||
session_buy_orders: int
|
||||
session_sell_orders: int
|
||||
volume: float
|
||||
volumehigh: float
|
||||
volumelow: float
|
||||
time: int
|
||||
digits: int
|
||||
spread: float
|
||||
spread_float: bool
|
||||
ticks_bookdepth: int
|
||||
trade_calc_mode: SymbolCalcMode
|
||||
trade_mode: SymbolTradeMode
|
||||
start_time: int
|
||||
expiration_time: int
|
||||
trade_stops_level: int
|
||||
trade_freeze_level: int
|
||||
trade_exemode: SymbolTradeExecution
|
||||
swap_mode: SymbolSwapMode
|
||||
swap_rollover3days: DayOfWeek
|
||||
margin_hedged_use_leg: bool
|
||||
expiration_mode: int
|
||||
filling_mode: int
|
||||
order_mode: int
|
||||
order_gtc_mode: SymbolOrderGTCMode
|
||||
option_mode: SymbolOptionMode
|
||||
option_right: SymbolOptionRight
|
||||
bid: float
|
||||
bidhigh: float
|
||||
bidlow: float
|
||||
ask: float
|
||||
askhigh: float
|
||||
asklow: float
|
||||
last: float
|
||||
lasthigh: float
|
||||
lastlow: float
|
||||
volume_real: float
|
||||
volumehigh_real: float
|
||||
volumelow_real: float
|
||||
option_strike: float
|
||||
point: float
|
||||
trade_tick_value: float
|
||||
trade_tick_value_profit: float
|
||||
trade_tick_value_loss: float
|
||||
trade_tick_size: float
|
||||
trade_contract_size: float
|
||||
trade_accrued_interest: float
|
||||
trade_face_value: float
|
||||
trade_liquidity_rate: float
|
||||
volume_min: float
|
||||
volume_max: float
|
||||
volume_step: float
|
||||
volume_limit: float
|
||||
swap_long: float
|
||||
swap_short: float
|
||||
margin_initial: float
|
||||
margin_maintenance: float
|
||||
session_volume: float
|
||||
session_turnover: float
|
||||
session_interest: float
|
||||
session_buy_orders_volume: float
|
||||
session_sell_orders_volume: float
|
||||
session_open: float
|
||||
session_close: float
|
||||
session_aw: float
|
||||
session_price_settlement: float
|
||||
session_price_limit_min: float
|
||||
session_price_limit_max: float
|
||||
margin_hedged: float
|
||||
price_change: float
|
||||
price_volatility: float
|
||||
price_theoretical: float
|
||||
price_greeks_delta: float
|
||||
price_greeks_theta: float
|
||||
price_greeks_gamma: float
|
||||
price_greeks_vega: float
|
||||
price_greeks_rho: float
|
||||
price_greeks_omega: float
|
||||
price_sensitivity: float
|
||||
basis: str
|
||||
category: str
|
||||
currency_base: str
|
||||
currency_profit: str
|
||||
currency_margin: Any
|
||||
bank: str
|
||||
description: str
|
||||
exchange: str
|
||||
formula: Any
|
||||
isin: Any
|
||||
name: str
|
||||
page: str
|
||||
path: str
|
||||
"""
|
||||
custom: bool
|
||||
chart_mode: SymbolChartMode
|
||||
select: bool
|
||||
visible: bool
|
||||
session_deals: int
|
||||
session_buy_orders: int
|
||||
session_sell_orders: int
|
||||
volume: float
|
||||
volumehigh: float
|
||||
volumelow: float
|
||||
time: int
|
||||
digits: int
|
||||
spread: float
|
||||
spread_float: bool
|
||||
ticks_bookdepth: int
|
||||
trade_calc_mode: SymbolCalcMode
|
||||
trade_mode: SymbolTradeMode
|
||||
start_time: int
|
||||
expiration_time: int
|
||||
trade_stops_level: int
|
||||
trade_freeze_level: int
|
||||
trade_exemode: SymbolTradeExecution
|
||||
swap_mode: SymbolSwapMode
|
||||
swap_rollover3days: DayOfWeek
|
||||
margin_hedged_use_leg: bool
|
||||
expiration_mode: int
|
||||
filling_mode: int
|
||||
order_mode: int
|
||||
order_gtc_mode: SymbolOrderGTCMode
|
||||
option_mode: SymbolOptionMode
|
||||
option_right: SymbolOptionRight
|
||||
bid: float
|
||||
bidhigh: float
|
||||
bidlow: float
|
||||
ask: float
|
||||
askhigh: float
|
||||
asklow: float
|
||||
last: float
|
||||
lasthigh: float
|
||||
lastlow: float
|
||||
volume_real: float
|
||||
volumehigh_real: float
|
||||
volumelow_real: float
|
||||
option_strike: float
|
||||
point: float
|
||||
trade_tick_value: float
|
||||
trade_tick_value_profit: float
|
||||
trade_tick_value_loss: float
|
||||
trade_tick_size: float
|
||||
trade_contract_size: float
|
||||
trade_accrued_interest: float
|
||||
trade_face_value: float
|
||||
trade_liquidity_rate: float
|
||||
volume_min: float
|
||||
volume_max: float
|
||||
volume_step: float
|
||||
volume_limit: float
|
||||
swap_long: float
|
||||
swap_short: float
|
||||
margin_initial: float
|
||||
margin_maintenance: float
|
||||
session_volume: float
|
||||
session_turnover: float
|
||||
session_interest: float
|
||||
session_buy_orders_volume: float
|
||||
session_sell_orders_volume: float
|
||||
session_open: float
|
||||
session_close: float
|
||||
session_aw: float
|
||||
session_price_settlement: float
|
||||
session_price_limit_min: float
|
||||
session_price_limit_max: float
|
||||
margin_hedged: float
|
||||
price_change: float
|
||||
price_volatility: float
|
||||
price_theoretical: float
|
||||
price_greeks_delta: float
|
||||
price_greeks_theta: float
|
||||
price_greeks_gamma: float
|
||||
price_greeks_vega: float
|
||||
price_greeks_rho: float
|
||||
price_greeks_omega: float
|
||||
price_sensitivity: float
|
||||
basis: str
|
||||
category: str
|
||||
currency_base: str
|
||||
currency_profit: str
|
||||
currency_margin: str
|
||||
bank: str
|
||||
description: str
|
||||
exchange: str
|
||||
formula: str
|
||||
isin: str
|
||||
name: str
|
||||
page: str
|
||||
path: str
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if 'name' not in kwargs:
|
||||
raise AttributeError('Symbol Object Must be initialized with a name')
|
||||
self.name = kwargs.pop('name')
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __eq__(self, other: "SymbolInfo"):
|
||||
return self.name == other.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.name)
|
||||
|
||||
|
||||
class BookInfo(Base):
|
||||
"""Book Information Class.
|
||||
|
||||
Attributes:
|
||||
type: BookType
|
||||
price: float
|
||||
volume: float
|
||||
volume_dbl: float
|
||||
"""
|
||||
type: BookType
|
||||
price: float
|
||||
volume: float
|
||||
volume_dbl: float
|
||||
|
||||
|
||||
class TradeOrder(Base):
|
||||
"""Trade Order Class.
|
||||
|
||||
Attributes:
|
||||
ticket: int
|
||||
time_setup: int
|
||||
time_setup_msc: int
|
||||
time_expiration: int
|
||||
time_done: int
|
||||
time_done_msc: int
|
||||
type: OrderType
|
||||
type_time: OrderTime
|
||||
type_filling: OrderFilling
|
||||
state: int
|
||||
magic: int
|
||||
position_id: int
|
||||
position_by_id: int
|
||||
reason: OrderReason
|
||||
volume_current: float
|
||||
volume_initial: float
|
||||
price_open: float
|
||||
sl: float
|
||||
tp: float
|
||||
price_current: float
|
||||
price_stoplimit: float
|
||||
symbol: str
|
||||
comment: str
|
||||
external_id: str
|
||||
"""
|
||||
ticket: int
|
||||
time_setup: int
|
||||
time_setup_msc: int
|
||||
time_expiration: int
|
||||
time_done: int
|
||||
time_done_msc: int
|
||||
type: OrderType
|
||||
type_time: OrderTime
|
||||
type_filling: OrderFilling
|
||||
state: int
|
||||
magic: int
|
||||
position_id: int
|
||||
position_by_id: int
|
||||
reason: OrderReason
|
||||
volume_current: float
|
||||
volume_initial: float
|
||||
price_open: float
|
||||
sl: float
|
||||
tp: float
|
||||
price_current: float
|
||||
price_stoplimit: float
|
||||
symbol: str
|
||||
comment: str
|
||||
external_id: str
|
||||
|
||||
|
||||
class TradeRequest(Base):
|
||||
"""Trade Request Class.
|
||||
|
||||
Attributes:
|
||||
action: TradeAction
|
||||
type: OrderType
|
||||
order: int
|
||||
symbol: str
|
||||
volume: float
|
||||
sl: float
|
||||
tp: float
|
||||
price: float
|
||||
deviation: float
|
||||
stop_limit: float
|
||||
type_time: OrderTime
|
||||
type_filling: OrderFilling
|
||||
expiration: int
|
||||
position: int
|
||||
position_by: int
|
||||
comment: str
|
||||
magic: int
|
||||
deviation: int
|
||||
comment: str
|
||||
"""
|
||||
action: TradeAction
|
||||
type: OrderType
|
||||
order: int
|
||||
symbol: str
|
||||
volume: float
|
||||
sl: float
|
||||
tp: float
|
||||
price: float
|
||||
deviation: float
|
||||
stop_limit: float
|
||||
type_time: OrderTime
|
||||
type_filling: OrderFilling
|
||||
expiration: int
|
||||
position: int
|
||||
position_by: int
|
||||
comment: str
|
||||
magic: int
|
||||
deviation: int
|
||||
comment: str
|
||||
|
||||
|
||||
class OrderCheckResult(Base):
|
||||
"""Order Check Result
|
||||
|
||||
Attributes:
|
||||
retcode: int
|
||||
balance: float
|
||||
equity: float
|
||||
profit: float
|
||||
margin: float
|
||||
margin_free: float
|
||||
margin_level: float
|
||||
comment: str
|
||||
request: TradeRequest
|
||||
"""
|
||||
retcode: int
|
||||
balance: float
|
||||
equity: float
|
||||
profit: float
|
||||
margin: float
|
||||
margin_free: float
|
||||
margin_level: float
|
||||
comment: str
|
||||
request: mt5.TradeRequest
|
||||
|
||||
|
||||
class OrderSendResult(Base):
|
||||
"""Order Send Result
|
||||
|
||||
Attributes:
|
||||
retcode: int
|
||||
deal: int
|
||||
order: int
|
||||
volume: float
|
||||
price: float
|
||||
bid: float
|
||||
ask: float
|
||||
comment: str
|
||||
request: TradeRequest
|
||||
request_id: int
|
||||
retcode_external: int
|
||||
profit: float
|
||||
"""
|
||||
retcode: int
|
||||
deal: int
|
||||
order: int
|
||||
volume: float
|
||||
price: float
|
||||
bid: float
|
||||
ask: float
|
||||
comment: str
|
||||
request: mt5.TradeRequest
|
||||
request_id: int
|
||||
retcode_external: int
|
||||
profit: float
|
||||
|
||||
|
||||
class TradePosition(Base):
|
||||
"""Trade Position
|
||||
|
||||
Attributes:
|
||||
ticket: int
|
||||
time: int
|
||||
time_msc: int
|
||||
time_update: int
|
||||
time_update_msc: int
|
||||
type: OrderType
|
||||
magic: float
|
||||
identifier: int
|
||||
reason: PositionReason
|
||||
volume: float
|
||||
price_open: float
|
||||
sl: float
|
||||
tp: float
|
||||
price_current: float
|
||||
swap: float
|
||||
profit: float
|
||||
symbol: str
|
||||
comment: str
|
||||
external_id: str
|
||||
"""
|
||||
ticket: int
|
||||
time: int
|
||||
time_msc: int
|
||||
time_update: int
|
||||
time_update_msc: int
|
||||
type: OrderType
|
||||
magic: float
|
||||
identifier: int
|
||||
reason: PositionReason
|
||||
volume: float
|
||||
price_open: float
|
||||
sl: float
|
||||
tp: float
|
||||
price_current: float
|
||||
swap: float
|
||||
profit: float
|
||||
symbol: str
|
||||
comment: str
|
||||
external_id: str
|
||||
|
||||
|
||||
class TradeDeal(Base):
|
||||
"""Trade Deal
|
||||
|
||||
Attributes:
|
||||
ticket: int
|
||||
order: int
|
||||
time: int
|
||||
time_msc: int
|
||||
type: DealType
|
||||
entry: DealEntry
|
||||
magic: int
|
||||
position_id: int
|
||||
reason: DealReason
|
||||
volume: float
|
||||
price: float
|
||||
commission: float
|
||||
swap: float
|
||||
profit: float
|
||||
fee: float
|
||||
sl: float
|
||||
tp: float
|
||||
symbol: str
|
||||
comment: str
|
||||
external_id: str
|
||||
"""
|
||||
ticket: int
|
||||
order: int
|
||||
time: int
|
||||
time_msc: int
|
||||
type: DealType
|
||||
entry: DealEntry
|
||||
magic: int
|
||||
position_id: int
|
||||
reason: DealReason
|
||||
volume: float
|
||||
price: float
|
||||
commission: float
|
||||
swap: float
|
||||
profit: float
|
||||
fee: float
|
||||
sl: float
|
||||
tp: float
|
||||
symbol: str
|
||||
comment: str
|
||||
external_id: str
|
||||
@@ -0,0 +1,87 @@
|
||||
import asyncio
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import Sequence, Coroutine, Callable
|
||||
|
||||
from .strategy import Strategy
|
||||
|
||||
|
||||
class Executor:
|
||||
"""Executor class for running multiple strategies on multiple symbols concurrently.
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
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.bot = bot
|
||||
|
||||
def add_func(self, func, kwargs):
|
||||
self.funcs[func] = kwargs | {'bot': self.bot}
|
||||
|
||||
def add_coro(self, coro, kwargs):
|
||||
self.coros[coro] = kwargs | {'bot': self.bot}
|
||||
|
||||
def add_workers(self, strategies: Sequence[type(Strategy)]):
|
||||
"""Add multiple strategies at once
|
||||
|
||||
Args:
|
||||
strategies (Sequence[Strategy]): A sequence of strategies.
|
||||
"""
|
||||
self.workers.extend(strategies)
|
||||
|
||||
def remove_workers(self):
|
||||
"""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)):
|
||||
"""Add a strategy instance to the list of workers
|
||||
|
||||
Args:
|
||||
strategy (Strategy): A strategy object
|
||||
"""
|
||||
self.workers.append(strategy)
|
||||
|
||||
@staticmethod
|
||||
def trade(strategy: type(Strategy)):
|
||||
"""Wraps the coroutine trade method of each strategy with 'asyncio.run'.
|
||||
|
||||
Args:
|
||||
strategy (Strategy): A strategy object
|
||||
"""
|
||||
asyncio.run(strategy.trade())
|
||||
|
||||
def run(self, func, kwargs: dict):
|
||||
"""
|
||||
Run a coroutine function
|
||||
|
||||
Args:
|
||||
func: The coroutine. A variadic function.
|
||||
kwargs: A dictionary of keyword arguments for the function
|
||||
"""
|
||||
asyncio.run(func(**kwargs))
|
||||
|
||||
async def execute(self, workers: int = 0):
|
||||
"""Run the strategies with a threadpool executor.
|
||||
|
||||
Args:
|
||||
workers: 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.
|
||||
"""
|
||||
workers = workers or sum([len(self.workers), len(self.funcs), len(self.coros)])
|
||||
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()]
|
||||
@@ -0,0 +1,119 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from logging import getLogger
|
||||
|
||||
from .core.config import Config
|
||||
from .core.meta_trader import MetaTrader
|
||||
from .core.models import TradeDeal, TradeOrder
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class History:
|
||||
"""The history class handles completed trade deals and trade orders in the trading history of an account.
|
||||
|
||||
Attributes:
|
||||
deals (list[TradeDeal]): Iterable of trade deals
|
||||
orders (list[TradeOrder]): Iterable of trade orders
|
||||
total_deals: Total number of deals
|
||||
total_orders (int): Total number orders
|
||||
group (str): Filter for selecting history by symbols.
|
||||
ticket (int): Filter for selecting history by ticket number
|
||||
position (int): Filter for selecting history deals by position
|
||||
initialized (bool): check if initial request has been sent to the terminal to get history.
|
||||
mt5 (MetaTrader): MetaTrader instance
|
||||
config (Config): Config instance
|
||||
"""
|
||||
mt5: MetaTrader = MetaTrader()
|
||||
config: Config = Config()
|
||||
|
||||
def __init__(self, *, date_from: datetime | float = None, date_to: datetime | float = None,
|
||||
group: str = "", ticket: int = 0, position: int = 0):
|
||||
"""
|
||||
Args:
|
||||
date_from (datetime, float): Date the orders are requested from. Set by the 'datetime' object or as a
|
||||
number of seconds elapsed since 1970.01.01. Defaults to twenty-four hours from the current time in 'utc'
|
||||
|
||||
date_to (datetime, float): Date up to which the orders are requested. Set by the 'datetime' object or as a
|
||||
number of seconds elapsed since 1970.01.01. Defaults to the current time in "utc"
|
||||
|
||||
group (str): Filter for selecting history by symbols.
|
||||
ticket (int): Filter for selecting history by ticket number
|
||||
position (int): Filter for selecting history deals by position
|
||||
"""
|
||||
self.date_from = date_from
|
||||
self.date_to = date_to
|
||||
self.group = group
|
||||
self.ticket = ticket
|
||||
self.position = position
|
||||
self.deals: list[TradeDeal] = []
|
||||
self.orders: list[TradeOrder] = []
|
||||
self.total_deals: int = 0
|
||||
self.total_orders: int = 0
|
||||
self.initialized = False
|
||||
|
||||
async def init(self, deals=True, orders=True) -> bool:
|
||||
"""Get history deals and orders
|
||||
|
||||
Keyword Args:
|
||||
deals (bool): If true get history deals during initial request to terminal
|
||||
orders (bool): If true get history orders during initial request to terminal
|
||||
|
||||
Returns:
|
||||
bool: True if all requests were successful else False
|
||||
"""
|
||||
tasks = []
|
||||
tasks.append(self.get_deals()) if deals else ...
|
||||
tasks.append(self.get_orders()) if orders else ...
|
||||
res = await asyncio.gather(*tasks)
|
||||
self.initialized = all(res)
|
||||
return self.initialized
|
||||
|
||||
async def get_deals(self) -> list[TradeDeal]:
|
||||
"""Get deals from trading history using the parameters set in the constructor.
|
||||
|
||||
Returns:
|
||||
list[TradeDeal]: A list of trade deals
|
||||
"""
|
||||
deals = await self.mt5.history_deals_get(date_from=self.date_from, date_to=self.date_to, position=self.position,
|
||||
group=self.group, ticket=self.ticket)
|
||||
if deals is not None:
|
||||
self.deals = [TradeDeal(**deal._asdict()) for deal in deals] if deals else []
|
||||
self.total_deals = len(self.deals)
|
||||
return self.deals
|
||||
|
||||
return self.deals
|
||||
|
||||
async def deals_total(self) -> int:
|
||||
"""Get total number of deals within the specified period in the constructor.
|
||||
|
||||
Returns:
|
||||
int: Total number of Deals
|
||||
"""
|
||||
self.total_deals = await self.mt5.history_deals_total(self.date_from, self.date_to)
|
||||
return self.total_deals
|
||||
|
||||
async def get_orders(self) -> list[TradeOrder]:
|
||||
"""Get orders from trading history using the parameters set in the constructor.
|
||||
|
||||
Returns:
|
||||
list[TradeOrder]: A list of trade orders
|
||||
"""
|
||||
|
||||
orders = await self.mt5.history_orders_get(date_from=self.date_from, date_to=self.date_to, group=self.group,
|
||||
position=self.position, ticket=self.ticket)
|
||||
if orders is None:
|
||||
return self.orders
|
||||
|
||||
self.orders = [TradeOrder(**order._asdict()) for order in orders]
|
||||
self.total_orders = len(self.orders)
|
||||
return self.orders
|
||||
|
||||
async def orders_total(self) -> int:
|
||||
"""Get total number of orders within the specified period in the constructor.
|
||||
|
||||
Returns:
|
||||
int: Total number of orders
|
||||
"""
|
||||
self.total_orders = await self.mt5.history_orders_total(self.date_from, self.date_to)
|
||||
return self.total_orders
|
||||
@@ -0,0 +1,112 @@
|
||||
"""Order Class"""
|
||||
from logging import getLogger
|
||||
|
||||
from .core.models import TradeRequest, OrderSendResult, OrderCheckResult, TradeOrder
|
||||
from .core.constants import TradeAction, OrderTime, OrderFilling
|
||||
from .core.exceptions import SymbolError, OrderError
|
||||
from .symbol import Symbol
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Order(TradeRequest):
|
||||
"""Trade order related functions and properties. Subclass of TradeRequest."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize the order object with keyword arguments, symbol must be provided.
|
||||
Provide default values for action, type_time and type_filling if not provided.
|
||||
|
||||
Args:
|
||||
**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.
|
||||
|
||||
Default Values:
|
||||
action (TradeAction.DEAL): Trade action
|
||||
type_time (OrderTime.DAY): Order time
|
||||
type_filling (OrderFilling.FOK): Order filling
|
||||
|
||||
Raises:
|
||||
SymbolError: If symbol is not provided
|
||||
"""
|
||||
if 'symbol' not in kwargs:
|
||||
raise SymbolError('symbol is required')
|
||||
sym = kwargs.pop('symbol')
|
||||
self.symbol = sym.name if isinstance(sym, Symbol) else sym
|
||||
self.action = kwargs.pop('action', TradeAction.DEAL)
|
||||
self.type_time = kwargs.pop('type_time', OrderTime.DAY)
|
||||
self.type_filling = kwargs.pop('type_filling', OrderFilling.FOK)
|
||||
super().__init__(**kwargs)
|
||||
|
||||
async def orders_total(self):
|
||||
"""Get the number of active orders.
|
||||
|
||||
Returns:
|
||||
(int): total number of active orders
|
||||
"""
|
||||
return await self.mt5.orders_total()
|
||||
|
||||
async def orders(self) -> tuple[TradeOrder]:
|
||||
"""Get the list of active orders for the current symbol.
|
||||
|
||||
Returns:
|
||||
tuple[TradeOrder]: A Tuple of active trade orders as TradeOrder objects
|
||||
"""
|
||||
orders = await self.mt5.orders_get(symbol=self.symbol)
|
||||
orders = (TradeOrder(**order._asdict()) for order in orders)
|
||||
return tuple(orders)
|
||||
|
||||
async def check(self) -> OrderCheckResult:
|
||||
"""Check funds sufficiency for performing a required trading operation and the possibility to execute it at
|
||||
|
||||
Returns:
|
||||
OrderCheckResult: An OrderCheckResult object
|
||||
|
||||
Raises:
|
||||
OrderError: If not successful
|
||||
"""
|
||||
res = await self.mt5.order_check(self.dict)
|
||||
if res is None:
|
||||
raise OrderError(f'Failed to check order {self.symbol} {self.type} {self.volume} {self.price} {res}')
|
||||
return OrderCheckResult(**res._asdict())
|
||||
|
||||
async def send(self) -> OrderSendResult:
|
||||
"""Send a request to perform a trading operation from the terminal to the trade server.
|
||||
|
||||
Returns:
|
||||
OrderSendResult: An OrderSendResult object
|
||||
|
||||
Raises:
|
||||
OrderError: If not successful
|
||||
"""
|
||||
res = await self.mt5.order_send(self.dict)
|
||||
if res is None:
|
||||
raise OrderError(f'Failed to send order {self.symbol} {self.type} {self.volume} {self.price} {res}')
|
||||
return OrderSendResult(**res._asdict())
|
||||
|
||||
async def calc_margin(self) -> float:
|
||||
"""Return the required margin in the account currency to perform a specified trading operation.
|
||||
|
||||
Returns:
|
||||
float: Returns float value if successful
|
||||
|
||||
Raises:
|
||||
OrderError: If not successful
|
||||
"""
|
||||
res = await self.mt5.order_calc_margin(self.type, self.symbol, self.volume, self.price)
|
||||
if res is None:
|
||||
raise OrderError(f'Failed to calculate margin for {self.symbol} {self.type} {self.volume} {self.price} {res}')
|
||||
return res
|
||||
|
||||
async def calc_profit(self) -> float:
|
||||
"""Return profit in the account currency for a specified trading operation.
|
||||
|
||||
Returns:
|
||||
float: Returns float value if successful
|
||||
|
||||
Raises:
|
||||
OrderError: If not successful
|
||||
"""
|
||||
res = await self.mt5.order_calc_profit(self.type, self.symbol, self.volume, self.price, self.tp)
|
||||
if res is None:
|
||||
raise OrderError(
|
||||
f'Failed to calculate profit for {self.symbol} {self.type} {self.volume} {self.price} {self.tp}')
|
||||
return res
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Handle Open positions."""
|
||||
import asyncio
|
||||
from logging import getLogger
|
||||
|
||||
from .core import MetaTrader, TradePosition, TradeAction, OrderType
|
||||
from .order import Order
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
class Positions:
|
||||
"""Get Open Positions.
|
||||
|
||||
Attributes:
|
||||
symbol (str): Financial instrument name.
|
||||
group (str): The filter for arranging a group of necessary symbols. Optional named parameter.
|
||||
If the group is specified, the function returns only positions meeting a specified criteria for a symbol name.
|
||||
ticket (int): Position ticket.
|
||||
mt5 (MetaTrader): MetaTrader instance.
|
||||
"""
|
||||
mt5: MetaTrader = MetaTrader()
|
||||
|
||||
def __init__(self, *, symbol: str = "", group: str = "", ticket: int = 0):
|
||||
"""Get Open Positions.
|
||||
|
||||
Keyword Args:
|
||||
symbol (str): Financial instrument name.
|
||||
group (str): The filter for arranging a group of necessary symbols. Optional named parameter. If the group
|
||||
is specified, the function returns only positions meeting a specified criteria for a symbol name.
|
||||
ticket (int): Position ticket
|
||||
|
||||
"""
|
||||
self.symbol = symbol
|
||||
self.group = group
|
||||
self.ticket = ticket
|
||||
|
||||
async def positions_total(self) -> int:
|
||||
"""Get the number of open positions.
|
||||
|
||||
Returns:
|
||||
int: Return total number of open positions
|
||||
"""
|
||||
return await self.mt5.positions_total()
|
||||
|
||||
async def positions_get(self, symbol: str = '', group: str = '', ticket: int = 0):
|
||||
"""Get open positions with the ability to filter by symbol or ticket.
|
||||
|
||||
Keyword Args:
|
||||
symbol (str): Financial instrument name.
|
||||
group (str): The filter for arranging a group of necessary symbols. Optional named parameter. If the group
|
||||
is specified, the function returns only positions meeting a specified criteria for a symbol name.
|
||||
ticket (int): Position ticket
|
||||
|
||||
Returns:
|
||||
list[TradePosition]: A list of open trade positions
|
||||
"""
|
||||
symbol = symbol or self.symbol
|
||||
group = group or self.group
|
||||
ticket = ticket or self.ticket
|
||||
positions = await self.mt5.positions_get(group=group, symbol=symbol, ticket=ticket)
|
||||
if not positions:
|
||||
return []
|
||||
return [TradePosition(**pos._asdict()) for pos in positions]
|
||||
|
||||
async def close_all(self, symbol: str = '', group: str = '') -> int:
|
||||
"""Close all open positions for the trading account.
|
||||
|
||||
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))]
|
||||
|
||||
results = await asyncio.gather(*[order.send() 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
|
||||
@@ -0,0 +1,64 @@
|
||||
"""Risk Assessment and Management"""
|
||||
from .account import Account
|
||||
from .symbol import Symbol
|
||||
|
||||
|
||||
class RAM:
|
||||
account: Account = Account()
|
||||
risk_to_reward: float
|
||||
risk: float
|
||||
amount: float
|
||||
pips: float
|
||||
volume: float
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Risk Assessment and Management. All provided keyword arguments are set as attributes.
|
||||
|
||||
Args:
|
||||
kwargs (Dict): Keyword arguments.
|
||||
|
||||
Defaults:
|
||||
risk_to_reward (float): Risk to reward ratio 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
|
||||
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()]
|
||||
|
||||
async def get_amount(self, risk: float = 0) -> float:
|
||||
"""Calculate the amount to risk per trade as a percentage of free margin.
|
||||
|
||||
Keyword Args:
|
||||
risk (float): Percentage of account balance to risk per trade. Defaults to zero.
|
||||
|
||||
Returns:
|
||||
float: Amount to risk per trade
|
||||
"""
|
||||
await self.account.refresh()
|
||||
risk = risk or self.risk
|
||||
return self.account.margin_free * 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
|
||||
|
||||
Keyword Args:
|
||||
pips (float): Target pips. Defaults to zero.
|
||||
amount (float): Amount to risk per trade. Defaults to zero.
|
||||
|
||||
Returns:
|
||||
float: Volume to trade
|
||||
"""
|
||||
pips = pips or self.pips
|
||||
amount = amount or self.amount or await self.get_amount()
|
||||
return await symbol.compute_volume(amount=amount, pips=pips)
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
"""This module contains the Records class, which is used to read and update trade records from csv files."""
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
import csv
|
||||
|
||||
from .history import History
|
||||
from .core import Config
|
||||
|
||||
|
||||
class Records:
|
||||
"""This utility class read trade records from csv files, and update them based on their closing positions.
|
||||
|
||||
Attributes:
|
||||
config: Config object
|
||||
records_dir(Path): Path to directory containing record of placed trades, If not given takes the default
|
||||
from the config
|
||||
"""
|
||||
config: Config = Config()
|
||||
|
||||
def __init__(self, records_dir: Path = ''):
|
||||
"""Initialize the Records class. The main method of this class is update_records which you should call to update
|
||||
all the records specified in the records_dir.
|
||||
|
||||
Keyword Args:
|
||||
records_dir (Path): Path to directory containing record of placed trades.
|
||||
"""
|
||||
self.records_dir = records_dir or self.config.records_dir
|
||||
|
||||
async def get_records(self):
|
||||
"""Get trade records from records_dir folder
|
||||
|
||||
Yields:
|
||||
files: Trade record files
|
||||
"""
|
||||
for file in self.records_dir.iterdir():
|
||||
if file.is_file() and file.name.endswith('.csv'):
|
||||
yield file
|
||||
|
||||
async def read_update(self, file: Path):
|
||||
"""Read and update trade records
|
||||
|
||||
Args:
|
||||
file: Trade record file
|
||||
"""
|
||||
fr = open(file, mode='r', newline='')
|
||||
reader = csv.DictReader(fr)
|
||||
rows = [row for row in reader]
|
||||
rows = await self.update_rows(rows)
|
||||
fr.close()
|
||||
fw = open(file, mode='w', newline='')
|
||||
writer = csv.DictWriter(fw, fieldnames=reader.fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
fw.close()
|
||||
|
||||
async def update_rows(self, rows: list[dict]) -> list[dict]:
|
||||
"""Update the rows of entered trades in the csv file with the actual profit.
|
||||
|
||||
Args:
|
||||
rows: A list of dictionaries from the dictionary writer object of the csv file.
|
||||
|
||||
Returns:
|
||||
list[dict]: A list of dictionaries with the actual profit and win status.
|
||||
"""
|
||||
tasks = [History(position=int(row['order'])).get_deals() for row in rows]
|
||||
deals = [deal for deals in await asyncio.gather(*tasks) for deal in deals]
|
||||
deals = {str(deal.position_id): deal.profit for deal in deals if deal.order != deal.position_id}
|
||||
[row.update(actual_profit=(profit := deals[order]), win=profit > 0) for row in rows if (order := row['order']) in deals]
|
||||
return rows
|
||||
|
||||
async def update_records(self):
|
||||
"""Update trade records in the records_dir folder."""
|
||||
records = [self.read_update(record) async for record in self.get_records()]
|
||||
await asyncio.gather(*records)
|
||||
|
||||
async def update_record(self, file: Path | str):
|
||||
"""Update a single trade record file."""
|
||||
await self.read_update(file)
|
||||
@@ -0,0 +1,58 @@
|
||||
import asyncio
|
||||
import csv
|
||||
from logging import getLogger
|
||||
|
||||
from .core import Config
|
||||
from .core.models import OrderSendResult
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Result:
|
||||
"""A base class for handling trade results and strategy parameters for record keeping and reference purpose.
|
||||
The data property must be implemented in the subclass
|
||||
|
||||
Attributes:
|
||||
config (Config): The configuration object
|
||||
name: Any desired name for the result file object
|
||||
"""
|
||||
config = Config()
|
||||
data: dict
|
||||
|
||||
def __init__(self, result: OrderSendResult, parameters: dict = None, name: str = ''):
|
||||
"""
|
||||
Prepare result data
|
||||
Args:
|
||||
result:
|
||||
parameters:
|
||||
name:
|
||||
"""
|
||||
self.parameters = parameters or {}
|
||||
self.result = result
|
||||
self.name = name or parameters.get('name', 'Strategy')
|
||||
|
||||
def get_data(self) -> dict:
|
||||
result = self.result.get_dict(exclude={'retcode', 'retcode_external', 'request_id', 'request'})
|
||||
return self.parameters | result | {'actual_profit': 0, 'closed': False, 'win': False}
|
||||
|
||||
def to_csv(self):
|
||||
"""Record trade results and associated parameters as a csv file
|
||||
"""
|
||||
try:
|
||||
self.data = self.get_data()
|
||||
file = self.config.records_dir / f"{self.name}.csv"
|
||||
exists = file.exists()
|
||||
with open(file, 'a', newline='') as fh:
|
||||
writer = csv.DictWriter(fh, fieldnames=sorted(list(self.data.keys())), extrasaction='ignore', restval=None)
|
||||
if not exists:
|
||||
writer.writeheader()
|
||||
writer.writerow(self.data)
|
||||
except Exception as err:
|
||||
logger.error(f'Error: {err}. Unable to save trade results')
|
||||
|
||||
async def save_csv(self):
|
||||
"""Save trade results and associated parameters as a csv file in a separate thread
|
||||
"""
|
||||
# exe = self.config.executor
|
||||
loop = asyncio.get_running_loop()
|
||||
loop.run_in_executor(None, self.to_csv)
|
||||
@@ -0,0 +1,60 @@
|
||||
from datetime import time, timedelta, datetime
|
||||
from asyncio import sleep
|
||||
|
||||
|
||||
class Session:
|
||||
|
||||
def __init__(self, start: int | time, end: int | time):
|
||||
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)
|
||||
|
||||
def __contains__(self, item: time):
|
||||
return self.start <= item < self.end
|
||||
|
||||
def delta(self, obj):
|
||||
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
|
||||
|
||||
|
||||
class Sessions:
|
||||
def __init__(self, *sessions: Session):
|
||||
self.sessions = list(sessions)
|
||||
self.sessions.sort(key=lambda x: x.start)
|
||||
|
||||
def find(self, obj):
|
||||
for session in self.sessions:
|
||||
if obj in session:
|
||||
return session
|
||||
return None
|
||||
|
||||
def find_next(self, obj):
|
||||
for session in self.sessions:
|
||||
if obj < session.start:
|
||||
return session
|
||||
return self.sessions[-1]
|
||||
|
||||
def __contains__(self, item: time):
|
||||
return True if self.find(item) is not None else False
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
pass
|
||||
|
||||
async def check(self):
|
||||
now = datetime.utcnow().time()
|
||||
if now in self:
|
||||
return
|
||||
next_session = self.find_next(now)
|
||||
secs = next_session.until()
|
||||
print(f'sleeping for {secs} seconds')
|
||||
await sleep(secs)
|
||||
@@ -0,0 +1,73 @@
|
||||
"""The base class for creating strategies."""
|
||||
import asyncio
|
||||
from time import time
|
||||
from typing import TypeVar
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import time as dtime
|
||||
|
||||
from .core.meta_trader import MetaTrader
|
||||
from .symbol import Symbol as _Symbol
|
||||
from .account import Account
|
||||
from .core import Config
|
||||
from .sessions import Sessions, Session
|
||||
|
||||
Symbol = TypeVar('Symbol', bound=_Symbol)
|
||||
|
||||
|
||||
class Strategy(ABC):
|
||||
"""The base class for creating strategies.
|
||||
|
||||
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.
|
||||
"""
|
||||
name: str = ''
|
||||
account = Account()
|
||||
mt5: MetaTrader()
|
||||
config = Config()
|
||||
|
||||
def __init__(self, *, symbol: Symbol, params: dict = None, session: Session):
|
||||
"""Initiate the parameters dict and add name and symbol fields.
|
||||
Use class name as strategy name if name is not provided
|
||||
|
||||
Args:
|
||||
symbol (Symbol): The Financial instrument
|
||||
params (Dict): Trading strategy parameters
|
||||
"""
|
||||
self.symbol = symbol
|
||||
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))
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.name}({self.symbol!r})"
|
||||
|
||||
@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.
|
||||
|
||||
Args:
|
||||
secs (float): The time in seconds. Usually the timeframe you are trading on.
|
||||
"""
|
||||
mod = time() % secs
|
||||
secs = secs - mod if mod != 0 else mod
|
||||
await asyncio.sleep(secs + 0.1)
|
||||
|
||||
|
||||
@abstractmethod
|
||||
async def trade(self):
|
||||
"""Place trades using this method. This is the main method of the strategy.
|
||||
It will be called by the strategy runner.
|
||||
"""
|
||||
@@ -0,0 +1,301 @@
|
||||
"""Symbol class for handling a financial instrument."""
|
||||
from datetime import datetime
|
||||
from logging import getLogger
|
||||
|
||||
from .core.constants import TimeFrame, CopyTicks
|
||||
from .core.models import SymbolInfo, BookInfo
|
||||
from .ticks import Tick
|
||||
from .account import Account
|
||||
from .candle import Candles
|
||||
from .ticks import Ticks
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
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:
|
||||
tick (Tick): Price tick object for instrument
|
||||
account: An instance of the current trading account
|
||||
|
||||
Notes:
|
||||
Full properties are on the SymbolInfo Object.
|
||||
Make sure Symbol is always initialized with a name argument
|
||||
"""
|
||||
tick: Tick
|
||||
account = Account()
|
||||
|
||||
@property
|
||||
def pip(self):
|
||||
"""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.
|
||||
"""
|
||||
return self.point * 10
|
||||
|
||||
async def info_tick(self, *, name: str = "") -> Tick:
|
||||
"""Get the current price tick of a financial instrument.
|
||||
|
||||
Args:
|
||||
name: if name is supplied get price tick of that financial instrument
|
||||
|
||||
Returns:
|
||||
Tick: Return a Tick Object
|
||||
|
||||
Raises:
|
||||
ValueError: If request was unsuccessful and None was returned
|
||||
"""
|
||||
tick = await self.mt5.symbol_info_tick(name or self.name)
|
||||
if tick is None:
|
||||
raise ValueError(f'Could not get tick for {name or self.name}')
|
||||
tick = Tick(**tick._asdict())
|
||||
setattr(self, 'tick', tick) if not name else ...
|
||||
return tick
|
||||
|
||||
async def symbol_select(self, *, enable: bool = True) -> bool:
|
||||
"""Select a symbol in the MarketWatch window or remove a symbol from the window.
|
||||
Update the select property
|
||||
|
||||
Args:
|
||||
enable (bool): Switch. Optional unnamed parameter. If 'false', a symbol should be removed from
|
||||
the MarketWatch window.
|
||||
|
||||
Returns:
|
||||
bool: True if successful, otherwise – False.
|
||||
"""
|
||||
self.select = await self.mt5.symbol_select(self.name, enable)
|
||||
return self.select
|
||||
|
||||
async def info(self) -> SymbolInfo:
|
||||
"""Get data on the specified financial instrument and update the symbol object properties
|
||||
|
||||
Returns:
|
||||
(SymbolInfo): SymbolInfo if successful
|
||||
|
||||
Raises:
|
||||
ValueError: If request was unsuccessful and None was returned
|
||||
"""
|
||||
|
||||
info = await self.mt5.symbol_info(self.name)
|
||||
if info:
|
||||
self.set_attributes(**info._asdict())
|
||||
return SymbolInfo(**info._asdict())
|
||||
raise ValueError(f'Could not get info for {self.name}')
|
||||
|
||||
async def init(self) -> bool:
|
||||
"""Initialized the symbol by pulling properties from the terminal
|
||||
|
||||
Returns:
|
||||
bool: Returns True if symbol info was successful initialized
|
||||
"""
|
||||
try:
|
||||
if await self.symbol_select():
|
||||
await self.book_add()
|
||||
await self.info()
|
||||
return True
|
||||
logger.warning(f'Unable to initialized symbol {self}')
|
||||
return False
|
||||
except Exception as err:
|
||||
self.select = False
|
||||
logger.warning(err)
|
||||
return False
|
||||
|
||||
async def book_add(self) -> 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:
|
||||
bool: True if successful, otherwise – False.
|
||||
"""
|
||||
return await self.mt5.market_book_add(self.name)
|
||||
|
||||
async def book_get(self) -> tuple[BookInfo]:
|
||||
"""Returns a tuple of BookInfo featuring Market Depth entries for the specified symbol.
|
||||
|
||||
Returns:
|
||||
tuple[BookInfo]: Returns the Market Depth contents as a tuples of BookInfo Objects
|
||||
|
||||
Raises:
|
||||
ValueError: If request was unsuccessful and None was returned
|
||||
"""
|
||||
infos = await self.mt5.market_book_get(self.name)
|
||||
if infos is None:
|
||||
raise ValueError(f'Could not get book info for {self.name}')
|
||||
book_infos = (BookInfo(**info._asdict()) for info in infos)
|
||||
return tuple(book_infos)
|
||||
|
||||
async def book_release(self) -> 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.
|
||||
"""
|
||||
return await self.mt5.market_book_release(self.name)
|
||||
|
||||
async def compute_volume(self, *, 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 src\aiomql\lib\ForexSymbol.py
|
||||
|
||||
Args:
|
||||
amount (float): Amount to risk in the trade
|
||||
pips (float): Number of pips to target
|
||||
|
||||
Keyword Args:
|
||||
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
|
||||
"""
|
||||
return self.volume_min
|
||||
|
||||
async def currency_conversion(self, *, amount: float, base: str, quote: str) -> float:
|
||||
"""Convert from one currency to the other.
|
||||
|
||||
Args:
|
||||
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:
|
||||
float: Amount in terms of the base currency or None if it failed to convert
|
||||
|
||||
Raises:
|
||||
ValueError: If conversion is impossible
|
||||
"""
|
||||
try:
|
||||
pair = f'{base}{quote}'
|
||||
if self.account.has_symbol(pair):
|
||||
tick = await self.info_tick(name=pair)
|
||||
if tick is not None:
|
||||
return amount / tick.ask
|
||||
|
||||
pair = f'{quote}{base}'
|
||||
if self.account.has_symbol(pair):
|
||||
tick = await self.info_tick(name=pair)
|
||||
if tick is not None:
|
||||
amount = amount * tick.bid
|
||||
return amount
|
||||
except Exception as err:
|
||||
logger.warning(f'Currency conversion failed: Unable to convert {amount} in {quote} to {base}')
|
||||
raise ValueError(f'Currency Conversion Failed: {err}')
|
||||
else:
|
||||
logger.warning(f'Currency conversion failed: Unable to convert {amount} in {quote} to {base}')
|
||||
|
||||
async def copy_rates_from(self, *, timeframe: TimeFrame, date_from: datetime | int, count: int = 500) -> Candles:
|
||||
"""
|
||||
Get bars from the MetaTrader 5 terminal starting from the specified date.
|
||||
|
||||
Args:
|
||||
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
|
||||
"""
|
||||
rates = await self.mt5.copy_rates_from(self.name, timeframe, date_from, count)
|
||||
if rates is not None:
|
||||
return Candles(data=rates)
|
||||
raise ValueError(f'Could not get rates for {self.name}')
|
||||
|
||||
async def copy_rates_from_pos(self, *,timeframe: TimeFrame, count: int = 500, start_position: int = 0) -> Candles:
|
||||
"""Get bars from the MetaTrader 5 terminal starting from the specified index.
|
||||
|
||||
Args:
|
||||
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
|
||||
"""
|
||||
rates = await self.mt5.copy_rates_from_pos(self.name, timeframe, start_position, count)
|
||||
if rates is not None:
|
||||
return Candles(data=rates)
|
||||
raise ValueError(f'Could not get rates for {self.name}')
|
||||
|
||||
async def copy_rates_range(self, *, timeframe: TimeFrame, date_from: datetime | int,
|
||||
date_to: datetime | int) -> Candles:
|
||||
"""Get bars in the specified date range from the MetaTrader 5 terminal.
|
||||
|
||||
Args:
|
||||
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
|
||||
"""
|
||||
rates = await self.mt5.copy_rates_range(symbol=self.name, timeframe=timeframe, date_from=date_from,
|
||||
date_to=date_to)
|
||||
if rates is not None:
|
||||
return Candles(data=rates)
|
||||
raise ValueError(f'Could not get rates for {self.name}')
|
||||
|
||||
async def copy_ticks_from(self, *, date_from: datetime | int, count: int = 100, flags: CopyTicks = CopyTicks.ALL) -> Ticks:
|
||||
"""
|
||||
Get ticks from the MetaTrader 5 terminal starting from the specified date.
|
||||
|
||||
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
|
||||
"""
|
||||
ticks = await self.mt5.copy_ticks_from(self.name, date_from, count, flags)
|
||||
if ticks is not None:
|
||||
return Ticks(data=ticks)
|
||||
raise ValueError(f'Could not get ticks for {self.name}')
|
||||
|
||||
async def copy_ticks_range(self, *, 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.
|
||||
|
||||
Args:
|
||||
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.
|
||||
"""
|
||||
ticks = await self.mt5.copy_ticks_range(self.name, date_from, date_to, flags)
|
||||
if ticks is not None:
|
||||
return Ticks(data=ticks)
|
||||
raise ValueError(f'Could not get ticks for {self.name}')
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Terminal related functions and properties"""
|
||||
|
||||
from typing import NamedTuple
|
||||
from logging import getLogger
|
||||
from .core.models import TerminalInfo
|
||||
|
||||
logger = getLogger()
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Notes:
|
||||
Other attributes are defined in the TerminalInfo Class
|
||||
"""
|
||||
|
||||
Version = NamedTuple("Version", (('version', str), ('build', int), ('release_date', str)))
|
||||
|
||||
async def initialize(self) -> 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:
|
||||
bool: True if successful else False
|
||||
"""
|
||||
self.connected = await self.mt5.initialize(**self.config.account_info())
|
||||
|
||||
if not self.connected:
|
||||
err = await self.mt5.last_error()
|
||||
logger.critical(f'Failed to initialize Terminal. Error Code: {err}')
|
||||
raise SystemExit
|
||||
return self.connected
|
||||
|
||||
async def version(self):
|
||||
"""Get the MetaTrader 5 terminal version. This method returns the terminal version, build and release date as
|
||||
a tuple of three values
|
||||
|
||||
Returns:
|
||||
Version: version of tuple as Version object
|
||||
|
||||
Raises:
|
||||
ValueError: If the terminal version cannot be obtained
|
||||
"""
|
||||
res = await self.mt5.version()
|
||||
if res is None:
|
||||
raise ValueError('Failed to get terminal version')
|
||||
return self.Version(*res)
|
||||
|
||||
async def info(self):
|
||||
"""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.
|
||||
"""
|
||||
info = await self.mt5.terminal_info()
|
||||
self.set_attributes(**info._asdict())
|
||||
return self
|
||||
|
||||
async def symbols_total(self) -> int:
|
||||
"""Get the number of all financial instruments in the MetaTrader 5 terminal.
|
||||
|
||||
Returns:
|
||||
int: Total number of available symbols
|
||||
"""
|
||||
return await self.mt5.symbols_total()
|
||||
@@ -0,0 +1,167 @@
|
||||
"""Module for working with price ticks."""
|
||||
|
||||
from typing import TypeVar, Iterable
|
||||
import reprlib
|
||||
|
||||
from pandas import DataFrame, Series
|
||||
import pandas_ta as ta
|
||||
|
||||
from .core.constants import TickFlag
|
||||
|
||||
|
||||
Self = TypeVar('Self', bound='Ticks')
|
||||
|
||||
|
||||
class Tick:
|
||||
"""Price Tick of a Financial Instrument.
|
||||
|
||||
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.
|
||||
"""
|
||||
time: float
|
||||
bid: float
|
||||
ask: float
|
||||
last: float
|
||||
volume: float
|
||||
time_msc:float
|
||||
flags: float
|
||||
volume_real:float
|
||||
Index: int
|
||||
def __init__(self, **kwargs):
|
||||
self.time = kwargs.pop('time', 0)
|
||||
self.Index = kwargs.pop('Index', 0)
|
||||
self.set_attributes(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
keys = reprlib.repr(', '.join('%s=%s' % (i, j) for i, j in self.__dict__.items()))[1:-1]
|
||||
return '%(class)s(%(args)s)' % {'class': self.__class__.__name__, 'args': keys}
|
||||
|
||||
|
||||
def set_attributes(self, **kwargs):
|
||||
"""Set attributes from keyword arguments"""
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
_Ticks = TypeVar('_Ticks', bound='Ticks')
|
||||
|
||||
class Ticks:
|
||||
"""Container data class for price ticks. Arrange in chronological order.
|
||||
Supports iteration, slicing and assignment
|
||||
|
||||
Args:
|
||||
data (DataFrame | tuple[tuple]): Dataframe of price ticks or a tuple of tuples
|
||||
|
||||
Keyword Args:
|
||||
flip (bool): If flip is True reverse data chronological order.
|
||||
|
||||
Attributes:
|
||||
data: Dataframe Object holding the ticks
|
||||
"""
|
||||
time: Series
|
||||
bid: Series
|
||||
ask: Series
|
||||
last: Series
|
||||
volume: Series
|
||||
time_msc: Series
|
||||
flags: Series
|
||||
volume_real: Series
|
||||
Index: Series
|
||||
|
||||
def __init__(self, *, data: DataFrame | Iterable, flip=False):
|
||||
"""Initialize the Ticks class. Creates a DataFrame of price ticks from the data argument.
|
||||
|
||||
Args:
|
||||
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.
|
||||
"""
|
||||
if isinstance(data, DataFrame):
|
||||
data = data
|
||||
elif isinstance(data, type(self)):
|
||||
data = DataFrame(data.data)
|
||||
elif isinstance(data, Iterable):
|
||||
data = DataFrame(data)
|
||||
else:
|
||||
raise ValueError(f'Cannot create DataFrame from object of {type(data)}')
|
||||
self._data = data.iloc[::-1] if flip else data
|
||||
|
||||
def __repr__(self):
|
||||
return self._data.__repr__()
|
||||
|
||||
def __len__(self):
|
||||
return self._data.shape[0]
|
||||
|
||||
def __contains__(self, item: Tick) -> bool:
|
||||
return item.time_msc == self[item.Index].time_msc
|
||||
|
||||
def __getattr__(self, item):
|
||||
if item in list(self._data.columns.values):
|
||||
return self._data[item]
|
||||
raise AttributeError(f'Attribute {item} not defined on class {self.__class__.__name__}')
|
||||
|
||||
def __getitem__(self, index) -> Tick | Self:
|
||||
if isinstance(index, slice):
|
||||
cls = self.__class__
|
||||
data = self._data.iloc[index]
|
||||
data.reset_index(drop=True, inplace=True)
|
||||
return cls(data=data)
|
||||
|
||||
if isinstance(index, str):
|
||||
return self._data[index]
|
||||
|
||||
item = self._data.iloc[index]
|
||||
return Tick(Index=index, **item)
|
||||
|
||||
def __setitem__(self, index, value: Series):
|
||||
if isinstance(value, Series):
|
||||
self._data[index] = value
|
||||
return
|
||||
raise TypeError(f'Expected Series got {type(value)}')
|
||||
|
||||
def __iter__(self):
|
||||
return (Tick(**row._asdict()) for row in self._data.itertuples())
|
||||
|
||||
@property
|
||||
def ta(self):
|
||||
"""Access to the pandas_ta library for performing technical analysis on the underlying data attribute.
|
||||
|
||||
Returns:
|
||||
pandas_ta: The pandas_ta library
|
||||
"""
|
||||
return self._data.ta
|
||||
|
||||
@property
|
||||
def ta_lib(self):
|
||||
"""Access to the ta library for performing technical analysis. Not dependent on the underlying data attribute.
|
||||
|
||||
Returns:
|
||||
ta: The ta library
|
||||
"""
|
||||
return ta
|
||||
|
||||
@property
|
||||
def data(self) -> DataFrame:
|
||||
"""DataFrame of price ticks arranged in chronological order."""
|
||||
return self._data
|
||||
|
||||
def rename(self, inplace=True, **kwargs) -> _Ticks | None :
|
||||
"""Rename columns of the candle class.
|
||||
|
||||
Keyword Args:
|
||||
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
|
||||
"""
|
||||
res = self._data.rename(columns=kwargs, inplace=inplace)
|
||||
return res if inplace else self.__class__(data=res)
|
||||
@@ -0,0 +1,121 @@
|
||||
"""Trader class module. Handles the creation of an order and the placing of trades"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TypeVar
|
||||
from logging import getLogger
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from .order import Order
|
||||
from .symbol import Symbol as _Symbol
|
||||
from .ram import RAM
|
||||
from .core.models import OrderType
|
||||
from .core.config import Config
|
||||
from .utils import dict_to_string
|
||||
from .result import Result
|
||||
|
||||
logger = getLogger(__name__)
|
||||
Symbol = TypeVar('Symbol', bound=_Symbol)
|
||||
|
||||
|
||||
class Trader:
|
||||
"""Base class for creating a Trader object. Handles the creation of an order and the placing of trades
|
||||
|
||||
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.
|
||||
"""
|
||||
config = Config()
|
||||
|
||||
def __init__(self, *, symbol: Symbol, ram: RAM = None):
|
||||
"""Initializes the order object and RAM instance
|
||||
|
||||
Args:
|
||||
symbol (Symbol): Financial instrument
|
||||
ram (RAM): Risk Assessment and Management instance
|
||||
"""
|
||||
self.symbol = symbol
|
||||
self.order = Order(symbol=symbol.name)
|
||||
self.ram = ram or RAM()
|
||||
|
||||
async def create_order(self, *, order_type: OrderType, **kwargs):
|
||||
"""Complete the order object with the required values. Creates a simple order.
|
||||
Uses the ram instance to set the volume.
|
||||
|
||||
Args:
|
||||
order_type (OrderType): Type of order
|
||||
kwargs: keyword arguments as required for the specific trader
|
||||
"""
|
||||
# check if pips is passed in as a keyword argument, if not use the pips attribute of the ram instance
|
||||
pips = kwargs.get('pips', 0) or self.ram.pips
|
||||
self.order.volume = self.ram.volume or await self.ram.get_volume(symbol=self.symbol, pips=pips)
|
||||
self.order.type = order_type
|
||||
await self.set_order_limits(pips=pips)
|
||||
|
||||
async def set_order_limits(self, pips: float):
|
||||
"""Sets the stop loss and take profit for the order.
|
||||
This method uses pips as defined for forex instruments.
|
||||
|
||||
Args:
|
||||
pips: Target pips
|
||||
"""
|
||||
# use passed in pips and the pip value of the symbol to calculate the stop loss and take profit.
|
||||
# this is sure to work for forex instruments.
|
||||
pips = pips * self.symbol.pip
|
||||
sl, tp = pips, pips * self.ram.risk_to_reward
|
||||
tick = await self.symbol.info_tick()
|
||||
if self.order.type == OrderType.BUY:
|
||||
self.order.sl, self.order.tp = tick.ask - sl, tick.ask + tp
|
||||
self.order.price = tick.ask
|
||||
else:
|
||||
self.order.sl, self.order.tp = tick.bid + sl, tick.bid - tp
|
||||
self.order.price = tick.bid
|
||||
|
||||
async def place_trade(self, order_type: OrderType, params: dict = None, **kwargs):
|
||||
"""Places a trade based on the order_type.
|
||||
|
||||
Args:
|
||||
order_type (OrderType): Type of order
|
||||
params: parameters to be saved with the trade
|
||||
kwargs: keyword arguments as required for the specific trader
|
||||
"""
|
||||
try:
|
||||
await self.create_order(order_type=order_type, **kwargs)
|
||||
|
||||
# Check the order before placing it
|
||||
check = await self.order.check()
|
||||
if check.retcode != 0:
|
||||
logger.warning(
|
||||
f"Symbol: {self.order.symbol}\nResult:\n{dict_to_string(check.get_dict(include={'comment', 'retcode'}), multi=True)}")
|
||||
return
|
||||
|
||||
# check expected profit
|
||||
profit = await self.order.calc_profit()
|
||||
|
||||
# Send the order.
|
||||
result = await self.order.send()
|
||||
if result.retcode != 10009:
|
||||
logger.warning(
|
||||
f"Symbol: {self.order.symbol}\nResult:\n{dict_to_string(result.get_dict(include={'comment', 'retcode'}), multi=True)}")
|
||||
return
|
||||
|
||||
logger.info(f"Symbol: {self.order.symbol}\nOrder: {dict_to_string(result.dict, multi=True)}\n")
|
||||
|
||||
# save trade result and passed in parameters
|
||||
if result.retcode == 10009 and self.config.record_trades:
|
||||
params = params or {}
|
||||
params['expected_profit'] = profit
|
||||
date = datetime.utcnow()
|
||||
date = date.replace(tzinfo=ZoneInfo('UTC'))
|
||||
params['date'] = date
|
||||
params['time'] = date.timestamp()
|
||||
res = Result(result=result, parameters=params)
|
||||
await res.save_csv()
|
||||
except Exception as err:
|
||||
logger.error(f"{err}. Symbol: {self.order.symbol}\n {self.__class__.__name__}.place_trade")
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Utility functions for aiomql."""
|
||||
def dict_to_string(data: dict, multi=False) -> str:
|
||||
"""Convert a dict to a string. Use for logging.
|
||||
|
||||
Args:
|
||||
data (dict): The dict to convert.
|
||||
multi (bool, optional): If True, each key-value pair will be on a new line. Defaults to False.
|
||||
|
||||
Returns:
|
||||
str: The string representation of the dict.
|
||||
"""
|
||||
sep = '\n' if multi else ', '
|
||||
return f"{sep}".join(f"{key}: {value}\n" for key, value in data.items())
|
||||
@@ -0,0 +1,29 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import pytz
|
||||
from aiomql import MetaTrader, Symbol, TimeFrame, Account, ForexSymbol
|
||||
|
||||
|
||||
async def main():
|
||||
async with Account() as account:
|
||||
d = datetime.now()
|
||||
start = d.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=pytz.timezone('UTC'))
|
||||
print(start.timestamp())
|
||||
end = d.replace(hour=7, minute=0, second=0, microsecond=0, tzinfo=pytz.timezone('UTC'))
|
||||
# print(end.timestamp())
|
||||
s = ForexSymbol(name='EURUSD')
|
||||
s1 = ForexSymbol(name='USDJPY')
|
||||
await s.init()
|
||||
await s1.init()
|
||||
# t = await s.copy_ticks_range(date_from=start, date_to=end)
|
||||
# t1 = await s1.copy_ticks_range(date_from=start, date_to=end)
|
||||
r = await s1.copy_rates_range(date_from=start, date_to=end, timeframe=TimeFrame.M1)
|
||||
# rc = await s1.copy_rates_from(date_from=end, timeframe=TimeFrame.M15, count=96)
|
||||
print(datetime.fromtimestamp(r[0].time, tz=pytz.timezone('UTC')), datetime.fromtimestamp(r[-1].time), len(r))
|
||||
# f = await s.copy_ticks_range(date_from=start, date_to=end)
|
||||
# print(datetime.fromtimestamp(f[0].time), datetime.fromtimestamp(f[-1].time), len(f))
|
||||
# print(len(f), len(rc), rc[50].open)
|
||||
# print(len(r), r[-1].time, len(rc), rc[-1].time - rc[-2].time, end.timestamp(),rc[0].time)
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,28 @@
|
||||
# import asyncio
|
||||
# from pprint import pprint as pp
|
||||
# from aiomql import Order, Account, ForexSymbol, RAM, OrderType
|
||||
#
|
||||
#
|
||||
# async def test_send_order():
|
||||
# await Account().sign_in()
|
||||
# symbol = ForexSymbol(name='Volatility 50 Index')
|
||||
# await symbol.init()
|
||||
# tick = await symbol.info_tick()
|
||||
# pips = 100
|
||||
# volume = await symbol.compute_volume(amount=100, pips=pips)
|
||||
# sls = symbol.trade_stops_level
|
||||
# cls = pips * symbol.pip
|
||||
# print(sls, cls)
|
||||
# sl = tick.ask - (cls)
|
||||
# tp = tick.ask + (cls)
|
||||
# sls = symbol.trade_stops_level
|
||||
# po = sls * symbol.point
|
||||
# pi = po * 10
|
||||
# # print(sls, po, pi, sl)
|
||||
# print(volume)
|
||||
# order = Order(symbol=symbol.name, type=OrderType.BUY, sl=sl, tp=tp, volume=volume, price=tick.ask)
|
||||
# res = await order.send()
|
||||
# pp(res.dict)
|
||||
|
||||
asyncio.run(test_send_order())
|
||||
|
||||
Reference in New Issue
Block a user