diff --git a/CHANGELOG.md b/CHANGELOG.md index d5a64e5..d13d36e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [4.0.14](https://github.com/Ichinga-Samuel/aiomql/releases/tag/v4.0.13) - 2025-03-24 + +### Added + +- Add visualization for `Candles` object. +- Update `Config` class + ## [4.0.13](https://github.com/Ichinga-Samuel/aiomql/releases/tag/v4.0.13) - 2025-03-24 ### Fixed @@ -65,5 +72,5 @@ - `add` method for adding dataframes or series objects to the Candles object. ### Fixed -- + - Candles timeframe attribute returns the correct TimeFrame object. diff --git a/docs/lib/bot.md b/docs/lib/bot.md index da2c839..02e0ea6 100644 --- a/docs/lib/bot.md +++ b/docs/lib/bot.md @@ -144,9 +144,9 @@ Use this to run a single strategy on multiple symbols with the same parameters a ```python @classmethod -def process_pool(cls, bots: dict[Callable: dict] = None, num_workers: int = None): +def process_pool(cls, processes: dict[Callable: dict] = None, num_workers: int = None): ``` -Run multiple functions (scripts, bots) at the same time in parallel with different accounts. +Run multiple processes (scripts, bots) at the same time in parallel with different accounts. Running multiple functions is useful when you want to run different strategies on different accounts. The callable can for example be a bot instance that defines its own Config instance within the function scope. The dictionary should contain the callable as the key and the dictionary of keyword arguments to pass to the callable as @@ -155,7 +155,7 @@ The num_workers parameter specifies the number of workers to use. If not specifi number of bots. #### Parameters -| Name | Type | Description | -|--------------|------------------------|---------------------------------------------------------------------------------| -| `bots` | `dict[Callable: dict]` | A dictionary of callables and their keyword arguments to run as bots | +| Name | Type | Description | +|---------------|------------------------|---------------------------------------------------------------------------------| +| `processes` | `dict[Callable: dict]` | A dictionary of callables and their keyword arguments to run as processes | | `num_workers` | `int` | The number of workers to use. If not specified, the number of bots will be used | diff --git a/pyproject.toml b/pyproject.toml index b907c2f..9baab36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "aiomql" -version = "4.0.13" +version = "4.0.14" readme = "README.md" requires-python = ">=3.11" classifiers = [ diff --git a/requirements.txt b/requirements.txt index fa86efa..59d63b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,118 +1,160 @@ --e git+ssh://git@github.com/VChijioke/aiomql.git@626658d68ac771353b424d50a33e7dd0de6a9054#egg=aiomql -anyio==4.9.0 -argon2-cffi==25.1.0 +-e git+ssh://git@github.com/Chimezirim-Bassey/aiomql.git@8e0a5516774894505d8d915bbd510bf88c6e3e48#egg=aiomql +anyio==4.3.0 +argon2-cffi==23.1.0 argon2-cffi-bindings==21.2.0 arrow==1.3.0 -asttokens==3.0.0 -async-lru==2.0.5 -attrs==25.3.0 -babel==2.17.0 -beautifulsoup4==4.13.4 -bleach==6.2.0 -certifi==2025.4.26 -cffi==1.17.1 -charset-normalizer==3.4.2 +asttokens==2.4.1 +async-lru==2.0.4 +attrs==23.2.0 +Babel==2.14.0 +beautifulsoup4==4.12.3 +black==23.9.1 +bleach==6.1.0 +build==1.2.2.post1 +certifi==2023.7.22 +cffi==1.16.0 +charset-normalizer==3.3.0 +click==8.1.7 colorama==0.4.6 comm==0.2.2 -contourpy==1.3.2 +contourpy==1.2.1 cycler==0.12.1 -debugpy==1.8.14 -decorator==5.2.1 +databind.core==4.4.1 +databind.json==4.4.1 +debugpy==1.8.1 +decorator==5.1.1 defusedxml==0.7.1 -executing==2.2.0 -fastjsonschema==2.21.1 -fonttools==4.58.2 +Deprecated==1.2.14 +docspec==2.2.1 +docspec-python==2.2.1 +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 -h11==0.16.0 -httpcore==1.0.9 -httpx==0.28.1 -idna==3.10 -iniconfig==2.1.0 -ipykernel==6.29.5 -ipython==9.3.0 -ipython_pygments_lexers==1.1.1 -ipywidgets==8.1.7 +h11==0.14.0 +httpcore==1.0.5 +httpx==0.27.0 +id==1.5.0 +idna==3.4 +importlib-metadata==6.8.0 +iniconfig==2.0.0 +ipykernel==6.29.4 +ipython==8.23.0 +ipywidgets==8.1.2 isoduration==20.11.0 -jedi==0.19.2 -Jinja2==3.1.6 -json5==0.12.0 -jsonpointer==3.0.0 -jsonschema==4.24.0 -jsonschema-specifications==2025.4.1 -jupyter==1.1.1 +jaraco.classes==3.3.0 +jedi==0.19.1 +Jinja2==3.1.2 +json5==0.9.24 +jsonpointer==2.4 +jsonschema==4.21.1 +jsonschema-specifications==2023.12.1 +jupyter==1.0.0 jupyter-console==6.6.3 -jupyter-events==0.12.0 +jupyter-events==0.10.0 jupyter-lsp==2.2.5 -jupyter_client==8.6.3 -jupyter_core==5.8.1 -jupyter_server==2.16.0 +jupyter_client==8.6.1 +jupyter_core==5.7.2 +jupyter_server==2.13.0 jupyter_server_terminals==0.5.3 -jupyterlab==4.4.3 +jupyterlab==4.1.6 jupyterlab_pygments==0.3.0 -jupyterlab_server==2.27.3 -jupyterlab_widgets==3.0.15 -kiwisolver==1.4.8 -MarkupSafe==3.0.2 -matplotlib==3.10.3 -matplotlib-inline==0.1.7 -MetaTrader5==5.0.5050 -mistune==3.1.3 +jupyterlab_server==2.26.0 +jupyterlab_widgets==3.0.10 +keyring==24.2.0 +kiwisolver==1.4.5 +markdown-it-py==3.0.0 +MarkupSafe==2.1.3 +matplotlib==3.8.4 +matplotlib-inline==0.1.6 +mdurl==0.1.2 +MetaTrader5==5.0.4424 +mistune==3.0.2 +more-itertools==10.1.0 mplfinance==0.12.10b0 -nbclient==0.10.2 -nbconvert==7.16.6 +mypy-extensions==1.0.0 +nbclient==0.10.0 +nbconvert==7.16.3 nbformat==5.10.4 nest-asyncio==1.6.0 -notebook==7.4.3 +nh3==0.2.14 +notebook==7.1.2 notebook_shim==0.2.4 +nr-date==2.1.0 +nr-stream==1.1.5 +nr.util==0.8.12 numpy==1.26.0 overrides==7.7.0 packaging==25.0 -pandas==2.3.0 -pandas_ta==0.3.14b0 +pandas==2.1.1 +pandas-ta==0.3.14b0 pandocfilters==1.5.1 parso==0.8.4 -pillow==11.2.1 -platformdirs==4.3.8 -pluggy==1.6.0 -prometheus_client==0.22.1 -prompt_toolkit==3.0.51 -psutil==7.0.0 -pure_eval==0.2.3 +pathspec==0.11.2 +pillow==10.3.0 +pkginfo==1.9.6 +platformdirs==3.11.0 +pluggy==1.5.0 +prometheus_client==0.20.0 +prompt-toolkit==3.0.43 +psutil==5.9.8 +pure-eval==0.2.2 pycparser==2.22 -Pygments==2.19.1 -pyparsing==3.2.3 -pytest==8.4.1 -pytest-asyncio==1.0.0 +pydoc-markdown==4.8.2 +Pygments==2.16.1 +pyparsing==3.1.2 +pyproject_hooks==1.0.0 +pytest==8.3.3 +pytest-asyncio==0.24.0 pytest-order==1.3.0 -python-dateutil==2.9.0.post0 -python-json-logger==3.3.0 -pytz==2025.2 -pywin32==310 -pywinpty==2.0.15 -PyYAML==6.0.2 -pyzmq==26.4.0 -referencing==0.36.2 -requests==2.32.3 +python-dateutil==2.8.2 +python-json-logger==2.0.7 +python-telegram-bot==21.0.1 +pytz==2023.3.post1 +pywin32==306 +pywin32-ctypes==0.2.2 +pywinpty==2.0.13 +PyYAML==6.0.1 +pyzmq==25.1.2 +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 +rfc3986==2.0.0 rfc3986-validator==0.1.1 -rpds-py==0.25.1 +rich==13.6.0 +rpds-py==0.18.0 +ruff==0.7.3 Send2Trash==1.8.3 -setuptools==80.9.0 -six==1.17.0 +six==1.16.0 sniffio==1.3.1 -soupsieve==2.7 +soupsieve==2.5 stack-data==0.6.3 terminado==0.18.1 -tinycss2==1.4.0 -tornado==6.5.1 -traitlets==5.14.3 -types-python-dateutil==2.9.0.20250516 -typing_extensions==4.14.0 -tzdata==2025.2 +tinycss2==1.2.1 +tomli==2.0.1 +tomli_w==1.0.0 +tornado==6.4 +traitlets==5.14.2 +twine==6.1.0 +typeapi==2.1.1 +types-python-dateutil==2.9.0.20240316 +typing_extensions==4.6.3 +tzdata==2023.3 uri-template==1.3.0 -urllib3==2.4.0 +urllib3==2.0.6 +watchdog==3.0.0 wcwidth==0.2.13 -webcolors==24.11.1 +webcolors==1.13 webencodings==0.5.1 -websocket-client==1.8.0 -widgetsnbextension==4.0.14 +websocket-client==1.7.0 +widgetsnbextension==4.0.10 +wrapt==1.15.0 +yapf==0.40.2 +zipp==3.17.0 diff --git a/src/aiomql/_utils.py b/src/aiomql/_utils.py index b0c62c5..133878a 100644 --- a/src/aiomql/_utils.py +++ b/src/aiomql/_utils.py @@ -53,37 +53,35 @@ def dict_to_string(data: dict, multi=False) -> str: return f"{sep}".join(f"{key}: {value}" for key, value in data.items()) -def backoff_decorator(func=None, *, max_retries: int = 2, retries: int = 0, error="") -> callable: +def backoff_decorator(func=None, *, max_retries: int = 3, retries: int = 0) -> callable: """A decorator to retry a function a number of times before giving up. Args: func (callable, optional): The function to decorate. Defaults to None. - max_retries (int, optional): The maximum number of retries. Defaults to 2. - retries (int, optional): The number of retries. Defaults to 0. - error (Any, optional): The error to raise when the maximum number of retries is reached. Defaults to "". + max_retries (int, optional): The maximum number of retries. The default is 3. + retries (int, optional): The number of retries. The default is 0 """ if func is None: - return partial(backoff_decorator, max_retries=max_retries, retries=retries, error=error) + return partial(backoff_decorator, max_retries=max_retries, retries=retries) @wraps(func) async def wrapper(*args, **kwargs): nonlocal retries - if max_retries == retries: - retries = 0 - await func(*args, **kwargs) try: - retries += 1 res = await func(*args, **kwargs) - if error != "" and res == error: - raise TypeError("Invalid return type") - else: - retries = 0 - return res + retries = 0 + return res except Exception as err: - logger.error("Error in %s: %s", func.__name__, err) + if max_retries == retries: + retries = 0 + logger.error("An Error %s: occurred in %s", err, func.__name__) + raise err + retries += 1 if Config().mode != "backtest": - await asyncio.sleep(2**retries + random.uniform(0, max_retries)) - await wrapper(*args, **kwargs) - + delay = 2 ** retries + random.uniform(0, 1) + logger.warning("An Error %s: occurred in %s, trying again in %f seconds", + err, func.__name__, delay) + await asyncio.sleep(delay) + return await wrapper(*args, **kwargs) return wrapper