diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index a99d410..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -github: Ichinga-Samuel -buy_me_a_coffee: ichingasamuel -patreon: IchingaSamuel diff --git a/CHANGELOG.md b/CHANGELOG.md index 6074a49..3c587cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.0.12](https://github.com/Ichinga-Samuel/aiomql/releases/tag/v4.0.10) - 2025-03-24 + +### Fixed + +- Use correct error handling decorator for modify_stops in backtester + ## [4.0.10](https://github.com/Ichinga-Samuel/aiomql/releases/tag/v4.0.10) - 2025-01-24 ### Changed diff --git a/pyproject.toml b/pyproject.toml index 51b5784..b85c895 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "aiomql" -version = "4.0.11" +version = "4.0.12" readme = "README.md" requires-python = ">=3.11" classifiers = [ diff --git a/src/aiomql/core/backtesting/backtest_engine.py b/src/aiomql/core/backtesting/backtest_engine.py index b083747..81cfee6 100644 --- a/src/aiomql/core/backtesting/backtest_engine.py +++ b/src/aiomql/core/backtesting/backtest_engine.py @@ -456,7 +456,7 @@ class BackTestEngine: self.positions.update(ticket=pos.ticket, **kwargs) await self.check_order(ticket=ticket) - @error_handler_sync + @error_handler async def close_position_manually(self, *, ticket: int): """Close a position manually without. Usually at the end of testing.""" res = await self.close_position(ticket=ticket) @@ -532,7 +532,7 @@ class BackTestEngine: logger.error("Error Closing Position %d: %s", ticket, exe) return False - @error_handler(response=False) + @error_handler_sync(response=False) def modify_stops(self, *, ticket: int, sl: int, tp: int) -> bool: """ Modify the stop loss and take profit levels of an open position. diff --git a/todo/error_handler.py b/todo/error_handler.py new file mode 100644 index 0000000..f34aabb --- /dev/null +++ b/todo/error_handler.py @@ -0,0 +1,58 @@ +""" +Combine error_handler and error_handler_sync into one function + +Author: Abel Nagy +""" +import asyncio +from functools import wraps, partial +from logging import getLogger + +logger = getLogger(__name__) + + +def error_handler(func=None, *, msg="", exe=Exception, response=None, log_error_msg=True): + """A decorator to handle errors in an sync or async function. + Args: + func (callable, optional): The function to decorate. Defaults to None. + msg (str, optional): The error message to log. Defaults to "". + exe (Exception, optional): The exception to catch. Defaults to Exception. + response (Any, optional): The response to return when an error occurs. Defaults to None. + log_error_msg (bool, optional): If True, log the error message. Defaults to True. + """ + if func is None: + return partial( + error_handler, + msg=msg, + exe=exe, + response=response, + log_error_msg=log_error_msg, + ) + + is_async = asyncio.iscoroutinefunction(func) + + if is_async: + # This is the original error_handler for async functions + @wraps(func) + async def async_wrapper(*args, **kwargs): + try: + res = await func(*args, **kwargs) + return res + except exe as err: + if log_error_msg: + logger.error(f"Error in {func.__name__}: {msg or err}") + return response + + return async_wrapper + else: + + @wraps(func) + def sync_wrapper(*args, **kwargs): + try: + res = func(*args, **kwargs) + return res + except exe as err: + if log_error_msg: + logger.error(f"Error in {func.__name__}: {msg or err}") + return response + + return sync_wrapper