Merge pull request #17 from VChijioke/main

Add Visualization
This commit is contained in:
Chimezirim Bassey
2025-06-29 17:36:38 +01:00
committed by GitHub
8 changed files with 208 additions and 159 deletions
+1 -2
View File
@@ -78,7 +78,6 @@ aiomql.json
# development # development
terminals/ terminals/
*.pkl
backtesting/ backtesting/
trade_records/ trade_records/
plots/
+1
View File
@@ -29,6 +29,7 @@ A single instance of this class is created and used per bot instance.
| `root` | `Path` | The root directory of the project | | `root` | `Path` | The root directory of the project |
| `record_trades` | `bool` | To record trades or not. Default is True | | `record_trades` | `bool` | To record trades or not. Default is True |
| `records_dir` | `Path` | The directory to store trade records, relative to the root directory | | `records_dir` | `Path` | The directory to store trade records, relative to the root directory |
| `plots_dir` | `Path` | Save chart plots as images |
| `backtest_dir` | `Path` | The directory to store backtest results, relative to the root directory | | `backtest_dir` | `Path` | The directory to store backtest results, relative to the root directory |
| `task_queue` | `TaskQueue` | The TaskQueue object for handling background tasks | | `task_queue` | `TaskQueue` | The TaskQueue object for handling background tasks |
| `_backtest_engine` | `BackTestEngine` | The backtest engine object | | `_backtest_engine` | `BackTestEngine` | The backtest engine object |
+64 -27
View File
@@ -14,6 +14,8 @@ Candle and Candles classes for handling bars from the MetaTrader 5 terminal.
- [ta_lib](#candles.ta_lib) - [ta_lib](#candles.ta_lib)
- [data](#candles.data) - [data](#candles.data)
- [rename](#candles.rename) - [rename](#candles.rename)
- [plot](#candles.plot)
- [make_subplot](#candles.make_subplot)
<a id="candle.candle"></a> <a id="candle.candle"></a>
### Candle ### Candle
@@ -22,18 +24,21 @@ class Candle
``` ```
A class representing bars from the MetaTrader 5 terminal as a customized class analogous to Japanese Candlesticks. 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. You can subclass this class for added customization.
### Attributes ### Attributes
| Name | Type | Description |
|---------------|---------|-------------------------------------------------------------------------| | Name | Type | Description |
| `time` | `int` | Period start time | |---------------|-------------|-------------------------------------------------------------------------|
| `open` | `int` | Open price | | `time` | `int` | Period start time |
| `high` | `float` | The highest price of the period | | `open` | `int` | Open price |
| `low` | `float` | The lowest price of the period | | `high` | `float` | The highest price of the period |
| `close` | `float` | Close price | | `low` | `float` | The lowest price of the period |
| `tick_volume` | `float` | Tick volume | | `close` | `float` | Close price |
| `real_volume` | `float` | Trade volume | | `tick_volume` | `float` | Tick volume |
| `spread` | `float` | Spread | | `real_volume` | `float` | Trade volume |
| `Index` | `int` | Custom attribute representing the position of the candle in a sequence. | | `spread` | `float` | Spread |
| `Index` | `int` | Custom attribute representing the position of the candle in a sequence. |
| `index` | `Timestamp` | Index of the object in the DataFrame, as a timestamp. |
<a id='candle.__init__'></a> <a id='candle.__init__'></a>
### \_\_init\_\_ ### \_\_init\_\_
@@ -118,24 +123,25 @@ object for accessing the columns of the underlying data attribute.
The attributes of this class vary depending on the columns of underlying **data** attribute. i.e. each column of the **data** The attributes of this class vary depending on the columns of underlying **data** attribute. i.e. each column of the **data**
attribute is an attribute of the class. attribute is an attribute of the class.
| Name | Type | Description | | Name | Type | Description |
|---------------|-----------------|-------------------------------------------------------------------| |---------------|-----------------------|-------------------------------------------------------------------|
| `data` | `DataFrame` | The pandas DataFrame containing the data. | | `data` | `DataFrame` | The pandas DataFrame containing the data. |
| `Index` | `Series['int']` | A pandas Series of the indexes 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 | | `index` | `Series['Timestamp']` | DatetimeIndex of the underlying DataFrame object. |
| `open` | `Series[float]` | A pandas Series of the opening price of all candles in the object | | `time` | `Series['int']` | A pandas Series of the time of all candles in the object |
| `high` | `Series[float]` | A pandas Series of the high price of all candles in the object | | `open` | `Series[float]` | A pandas Series of the opening price of all candles in the object |
| `low` | `Series[float]` | A pandas Series of the low price of all candles in the object | | `high` | `Series[float]` | A pandas Series of the high price of all candles in the object |
| `close` | `Series[float]` | A pandas Series of the closing price of all candles in the object | | `low` | `Series[float]` | A pandas Series of the low price of all candles in the object |
| `tick_volume` | `Series[float]` | A pandas Series of the tick volume of all candles in the object | | `close` | `Series[float]` | A pandas Series of the closing price of all candles in the object |
| `real_volume` | `Series[float]` | A pandas Series of the real volume of all candles in the object | | `tick_volume` | `Series[float]` | A pandas Series of the tick volume of all candles in the object |
| `spread` | `Series[float]` | A pandas Series of the spread of all candles in the object | | `real_volume` | `Series[float]` | A pandas Series of the real volume of all candles in the object |
| `timeframe` | `TimeFrame` | The timeframe of the candles in the object | | `spread` | `Series[float]` | A pandas Series of the spread of all candles in the object |
| `Candle` | `Type[Candle]` | The Candle class for representing the candles in the object. | | `timeframe` | `TimeFrame` | The timeframe of the candles in the object |
| `data` | `DataFrame` | A pandas DataFrame of all 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 #### Notes
When subclassing this class make sure the Candle attribute is set to your desired candle class. When subclassing this class, make sure the Candle attribute is set to your desired candle class.
<a id="candles.__init__"></a> <a id="candles.__init__"></a>
### \_\_init\_\_ ### \_\_init\_\_
@@ -203,3 +209,34 @@ Rename columns of the data object.
| Type | Description | | Type | Description |
|-----------|---------------------------------------------------------------------------| |-----------|---------------------------------------------------------------------------|
| `Candles` | A new instance of the class with the renamed columns if inplace is False. | | `Candles` | A new instance of the class with the renamed columns if inplace is False. |
<a id="candles.plot"></a>
### plot
```python
def plot(subplots=None, span: int = None, filename="", **kwargs):
```
Create a plot with mplfinance, can be saved as png.
#### Parameters:
| Name | Type | Description | Default |
|------------|--------|-------------------------|---------|
| `subplots` | `dict` | Add subplots | None |
| `span` | `int` | Take the last n candles | None |
| `filename` | `str` | A name to save plot | "" |
| `**kwargs` | `Any` | Kwargs to plot function | |
<a id="candles.make_subplot"></a>
### make_subplot
```python
def make_subplot(column: str | list[str], span: int = None, **kwargs):
```
Create a plot with mplfinance, can be saved as png.
#### Parameters:
| Name | Type | Description | Default |
|------------|-------------------|--------------------------------------------------|---------|
| `column` | `list[str]\| str` | An iterable of column names as a list or strings | None |
| `span` | `int` | Take the last n candles | None |
| `**kwargs` | `Any` | Kwargs to plot function | |
+3 -1
View File
@@ -33,6 +33,7 @@ Price Tick of a Financial Instrument.
| `flags` | `TickFlag` | Tick flags | None | | `flags` | `TickFlag` | Tick flags | None |
| `volume_real` | `float` | Volume for the current Last price | None | | `volume_real` | `float` | Volume for the current Last price | None |
| `Index` | `int` | Custom attribute representing the position of the tick in a sequence. | None | | `Index` | `int` | Custom attribute representing the position of the tick in a sequence. | None |
| `index` | `int` | Index of the tick in the input dataframe object. | None |
<a id="tick.__init__"></a> <a id="tick.__init__"></a>
@@ -86,12 +87,13 @@ Supports iteration, slicing and assignment. Similar to `Candles` class but for p
| `flags` | `Series` | Tick flags | None | | `flags` | `Series` | Tick flags | None |
| `volume_real` | `Series` | Volume for the current Last price | None | | `volume_real` | `Series` | Volume for the current Last price | None |
| `Index` | `Series` | Custom attribute representing the position of the tick in a sequence | None | | `Index` | `Series` | Custom attribute representing the position of the tick in a sequence | None |
| `index` | `Series` | Custom attribute representing the index of the tick in the DataFrame | None |
<a id="ticks.__init__"></a> <a id="ticks.__init__"></a>
### \__init\__ ### \__init\__
```python ```python
def __init__(*, data: DataFrame | Iterable, flip=False) def __init__(*, data: DataFrame | Iterable, flip=False):
``` ```
Initialize the Ticks class. Creates a DataFrame of price ticks from the data argument. Initialize the Ticks class. Creates a DataFrame of price ticks from the data argument.
#### Arguments: #### Arguments:
+87 -127
View File
@@ -1,158 +1,118 @@
anyio==4.3.0 -e git+ssh://git@github.com/VChijioke/aiomql.git@626658d68ac771353b424d50a33e7dd0de6a9054#egg=aiomql
argon2-cffi==23.1.0 anyio==4.9.0
argon2-cffi==25.1.0
argon2-cffi-bindings==21.2.0 argon2-cffi-bindings==21.2.0
arrow==1.3.0 arrow==1.3.0
asttokens==2.4.1 asttokens==3.0.0
async-lru==2.0.4 async-lru==2.0.5
attrs==23.2.0 attrs==25.3.0
Babel==2.14.0 babel==2.17.0
beautifulsoup4==4.12.3 beautifulsoup4==4.13.4
black==23.9.1 bleach==6.2.0
bleach==6.1.0 certifi==2025.4.26
build==1.2.2.post1 cffi==1.17.1
certifi==2023.7.22 charset-normalizer==3.4.2
cffi==1.16.0
charset-normalizer==3.3.0
click==8.1.7
colorama==0.4.6 colorama==0.4.6
comm==0.2.2 comm==0.2.2
contourpy==1.2.1 contourpy==1.3.2
cycler==0.12.1 cycler==0.12.1
databind.core==4.4.1 debugpy==1.8.14
databind.json==4.4.1 decorator==5.2.1
debugpy==1.8.1
decorator==5.1.1
defusedxml==0.7.1 defusedxml==0.7.1
Deprecated==1.2.14 executing==2.2.0
docspec==2.2.1 fastjsonschema==2.21.1
docspec-python==2.2.1 fonttools==4.58.2
docstring-parser==0.11
docutils==0.20.1
docutils-stubs==0.0.22
executing==2.0.1
fastjsonschema==2.19.1
fonttools==4.51.0
fqdn==1.5.1 fqdn==1.5.1
h11==0.14.0 h11==0.16.0
httpcore==1.0.5 httpcore==1.0.9
httpx==0.27.0 httpx==0.28.1
idna==3.4 idna==3.10
importlib-metadata==6.8.0 iniconfig==2.1.0
iniconfig==2.0.0 ipykernel==6.29.5
ipykernel==6.29.4 ipython==9.3.0
ipython==8.23.0 ipython_pygments_lexers==1.1.1
ipywidgets==8.1.2 ipywidgets==8.1.7
isoduration==20.11.0 isoduration==20.11.0
jaraco.classes==3.3.0 jedi==0.19.2
jedi==0.19.1 Jinja2==3.1.6
Jinja2==3.1.2 json5==0.12.0
json5==0.9.24 jsonpointer==3.0.0
jsonpointer==2.4 jsonschema==4.24.0
jsonschema==4.21.1 jsonschema-specifications==2025.4.1
jsonschema-specifications==2023.12.1 jupyter==1.1.1
jupyter==1.0.0
jupyter-console==6.6.3 jupyter-console==6.6.3
jupyter-events==0.10.0 jupyter-events==0.12.0
jupyter-lsp==2.2.5 jupyter-lsp==2.2.5
jupyter_client==8.6.1 jupyter_client==8.6.3
jupyter_core==5.7.2 jupyter_core==5.8.1
jupyter_server==2.13.0 jupyter_server==2.16.0
jupyter_server_terminals==0.5.3 jupyter_server_terminals==0.5.3
jupyterlab==4.1.6 jupyterlab==4.4.3
jupyterlab_pygments==0.3.0 jupyterlab_pygments==0.3.0
jupyterlab_server==2.26.0 jupyterlab_server==2.27.3
jupyterlab_widgets==3.0.10 jupyterlab_widgets==3.0.15
keyring==24.2.0 kiwisolver==1.4.8
kiwisolver==1.4.5 MarkupSafe==3.0.2
markdown-it-py==3.0.0 matplotlib==3.10.3
MarkupSafe==2.1.3 matplotlib-inline==0.1.7
matplotlib==3.8.4 MetaTrader5==5.0.5050
matplotlib-inline==0.1.6 mistune==3.1.3
mdurl==0.1.2
MetaTrader5==5.0.4424
mistune==3.0.2
more-itertools==10.1.0
mplfinance==0.12.10b0 mplfinance==0.12.10b0
mypy-extensions==1.0.0 nbclient==0.10.2
nbclient==0.10.0 nbconvert==7.16.6
nbconvert==7.16.3
nbformat==5.10.4 nbformat==5.10.4
nest-asyncio==1.6.0 nest-asyncio==1.6.0
nh3==0.2.14 notebook==7.4.3
notebook==7.1.2
notebook_shim==0.2.4 notebook_shim==0.2.4
nr-date==2.1.0
nr-stream==1.1.5
nr.util==0.8.12
numpy==1.26.0 numpy==1.26.0
overrides==7.7.0 overrides==7.7.0
packaging==23.2 packaging==25.0
pandas==2.1.1 pandas==2.3.0
pandas-ta==0.3.14b0 pandas_ta==0.3.14b0
pandocfilters==1.5.1 pandocfilters==1.5.1
parso==0.8.4 parso==0.8.4
pathspec==0.11.2 pillow==11.2.1
pillow==10.3.0 platformdirs==4.3.8
pkginfo==1.9.6 pluggy==1.6.0
platformdirs==3.11.0 prometheus_client==0.22.1
pluggy==1.5.0 prompt_toolkit==3.0.51
prometheus_client==0.20.0 psutil==7.0.0
prompt-toolkit==3.0.43 pure_eval==0.2.3
psutil==5.9.8
pure-eval==0.2.2
pycparser==2.22 pycparser==2.22
pydoc-markdown==4.8.2 Pygments==2.19.1
Pygments==2.16.1 pyparsing==3.2.3
pyparsing==3.1.2 pytest==8.4.1
pyproject_hooks==1.0.0 pytest-asyncio==1.0.0
pytest==8.3.3
pytest-asyncio==0.24.0
pytest-order==1.3.0 pytest-order==1.3.0
python-dateutil==2.8.2 python-dateutil==2.9.0.post0
python-json-logger==2.0.7 python-json-logger==3.3.0
python-telegram-bot==21.0.1 pytz==2025.2
pytz==2023.3.post1 pywin32==310
pywin32==306 pywinpty==2.0.15
pywin32-ctypes==0.2.2 PyYAML==6.0.2
pywinpty==2.0.13 pyzmq==26.4.0
PyYAML==6.0.1 referencing==0.36.2
pyzmq==25.1.2 requests==2.32.3
qtconsole==5.5.1
QtPy==2.4.1
readme-renderer==42.0
referencing==0.34.0
requests==2.31.0
requests-toolbelt==1.0.0
rfc3339-validator==0.1.4 rfc3339-validator==0.1.4
rfc3986==2.0.0
rfc3986-validator==0.1.1 rfc3986-validator==0.1.1
rich==13.6.0 rpds-py==0.25.1
rpds-py==0.18.0
ruff==0.7.3
Send2Trash==1.8.3 Send2Trash==1.8.3
six==1.16.0 setuptools==80.9.0
six==1.17.0
sniffio==1.3.1 sniffio==1.3.1
soupsieve==2.5 soupsieve==2.7
stack-data==0.6.3 stack-data==0.6.3
terminado==0.18.1 terminado==0.18.1
tinycss2==1.2.1 tinycss2==1.4.0
tomli==2.0.1 tornado==6.5.1
tomli_w==1.0.0 traitlets==5.14.3
tornado==6.4 types-python-dateutil==2.9.0.20250516
traitlets==5.14.2 typing_extensions==4.14.0
twine==5.1.1 tzdata==2025.2
typeapi==2.1.1
types-python-dateutil==2.9.0.20240316
typing_extensions==4.6.3
tzdata==2023.3
uri-template==1.3.0 uri-template==1.3.0
urllib3==2.0.6 urllib3==2.4.0
watchdog==3.0.0
wcwidth==0.2.13 wcwidth==0.2.13
webcolors==1.13 webcolors==24.11.1
webencodings==0.5.1 webencodings==0.5.1
websocket-client==1.7.0 websocket-client==1.8.0
widgetsnbextension==4.0.10 widgetsnbextension==4.0.14
wrapt==1.15.0
yapf==0.40.2
zipp==3.17.0
+12 -2
View File
@@ -25,8 +25,10 @@ class Config:
root: Path root: Path
record_trades: bool record_trades: bool
records_dir: Path records_dir: Path
plots_dir: Path
backtest_dir: Path backtest_dir: Path
records_dir_name: str records_dir_name: str
plots_dir_name: str
backtest_dir_name: str #Todo: add to docs backtest_dir_name: str #Todo: add to docs
task_queue: TaskQueue task_queue: TaskQueue
_backtest_engine: BackTestEngine _backtest_engine: BackTestEngine
@@ -54,6 +56,7 @@ class Config:
"shutdown": False, "shutdown": False,
"force_shutdown": False, "force_shutdown": False,
"root": None, "root": None,
"plots_dir_name": "plots"
} }
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
@@ -110,7 +113,7 @@ class Config:
if config_file.exists(): if config_file.exists():
return config_file return config_file
if current == self.root: if current == self.root:
return return None
for dirname in current.parents: for dirname in current.parents:
config_file = dirname / self.filename config_file = dirname / self.filename
if config_file.exists(): if config_file.exists():
@@ -118,9 +121,10 @@ class Config:
if self.root == dirname: if self.root == dirname:
break break
return None
except Exception as err: except Exception as err:
logger.debug(f"Error finding config file: {err}") logger.debug(f"Error finding config file: {err}")
return None
def load_config(self, *, config_file: str | Path = None, filename: str = None, root: str | Path = None, **kwargs) -> Self: def load_config(self, *, config_file: str | Path = None, filename: str = None, root: str | Path = None, **kwargs) -> Self:
"""Load configuration settings from a file and reset the config object. """Load configuration settings from a file and reset the config object.
@@ -182,6 +186,12 @@ class Config:
b_dir.mkdir(parents=True, exist_ok=True) if b_dir.exists() is False else ... b_dir.mkdir(parents=True, exist_ok=True) if b_dir.exists() is False else ...
return b_dir return b_dir
@property
def plots_dir(self):
p_dir = self.root / self.plots_dir_name or "plots"
p_dir.mkdir(parents=True, exist_ok=True) if p_dir.exists() is False else ...
return p_dir
def account_info(self) -> dict[str, int | str]: def account_info(self) -> dict[str, int | str]:
"""Returns Account login details as found in the config object if available """Returns Account login details as found in the config object if available
+39
View File
@@ -5,10 +5,12 @@ from typing import Type, Self, Iterable
from logging import getLogger from logging import getLogger
import pandas as pd import pandas as pd
import mplfinance as mpf
import pandas_ta as ta import pandas_ta as ta
from pandas import DataFrame, Series, DatetimeIndex, Timestamp from pandas import DataFrame, Series, DatetimeIndex, Timestamp
from ..core.constants import TimeFrame from ..core.constants import TimeFrame
from ..core._core import Config
logger = getLogger(__name__) logger = getLogger(__name__)
@@ -203,6 +205,7 @@ class Candles:
self._data.index = pd.DatetimeIndex(self._data.time, dtype=dtype) self._data.index = pd.DatetimeIndex(self._data.time, dtype=dtype)
self.Candle = candle_class or Candle self.Candle = candle_class or Candle
self.config = Config()
def __repr__(self): def __repr__(self):
return repr(self._data) return repr(self._data)
@@ -346,3 +349,39 @@ class Candles:
return self return self
else: else:
raise TypeError("Expected Series, DataFrame or Candle, got {}".format(type(obj))) raise TypeError("Expected Series, DataFrame or Candle, got {}".format(type(obj)))
def plot(self, subplots: dict = None, span: int = None, filename="", **kwargs):
"""
Create a plot of the candles
Args:
subplots (dict): Subplots to bed added to the main plot
span (int): Last 'n' candles to be used for making the subplot
filename (str): A filename to saved the plot
**kwargs: Kwargs to be passed to the plot
"""
type_ = kwargs.pop("type", "candle")
subplots = subplots or []
span = 0 if span is None else span
data = self._data[-span:]
if filename and not kwargs.get("savefig"):
kwargs["savefig"] = self.config.plots_dir / filename
mpf.plot(data, type=type_, addplot=subplots, **kwargs)
def make_subplot(self, *, column: str | list[str], span: int = None, **kwargs) -> dict:
"""
Create a subplot
Args:
column (list[str] | str): Name of columns for the subplot
span (int): Last 'n' candles to be used for making the subplot
**kwargs: Keywords arguments to pass to the subplot
Returns:
dict: Subplots
"""
column = column if isinstance(column, list) else [column]
span = 0 if span is None else span
data = self._data[-span:]
data = data[column]
return mpf.make_addplot(data, **kwargs)
+1
View File
@@ -23,6 +23,7 @@ class Tick:
flags (TickFlag): Tick flags flags (TickFlag): Tick flags
volume_real (float): Volume for the current Last price volume_real (float): Volume for the current Last price
Index (int): Custom attribute representing the position of the tick in a sequence. Index (int): Custom attribute representing the position of the tick in a sequence.
index (int): Index of the tick in the input dataframe object.
""" """
time: float time: float
bid: float bid: float