diff --git a/Trading/Mode/dca_trading_mode/dca_trading.py b/Trading/Mode/dca_trading_mode/dca_trading.py index 179e347a0..778d50372 100644 --- a/Trading/Mode/dca_trading_mode/dca_trading.py +++ b/Trading/Mode/dca_trading_mode/dca_trading.py @@ -396,10 +396,10 @@ async def dca_task(self): for cryptocurrency, pairs in trading_util.get_traded_pairs_by_currency( self.exchange_manager.config ).items(): - if self.symbol in pairs: + if self.trading_mode.symbol in pairs: await self.trigger_dca( cryptocurrency=cryptocurrency, - symbol=self.symbol, + symbol=self.trading_mode.symbol, state=trading_enums.EvaluatorStates.VERY_LONG ) if self.exchange_manager.is_backtesting: @@ -408,7 +408,7 @@ async def dca_task(self): f"configure another trigger mode to use {self.trading_mode.get_name()} in backtesting." ) return - await asyncio.sleep(self.trading_mode.minutes_before_next_buy) + await asyncio.sleep(self.trading_mode.minutes_before_next_buy * commons_constants.MINUTE_TO_SECONDS) except Exception as e: self.logger.error(f"An error happened during DCA task : {e}") diff --git a/Trading/Mode/dca_trading_mode/tests/test_dca_trading_mode.py b/Trading/Mode/dca_trading_mode/tests/test_dca_trading_mode.py index da8e154a2..052a6a166 100644 --- a/Trading/Mode/dca_trading_mode/tests/test_dca_trading_mode.py +++ b/Trading/Mode/dca_trading_mode/tests/test_dca_trading_mode.py @@ -18,6 +18,7 @@ import os.path import mock import decimal +import asyncio import async_channel.util as channel_util @@ -210,6 +211,65 @@ async def test_init_config_values(tools): assert mode.stop_loss_price_multiplier == decimal.Decimal("0.1") +async def test_inner_start(tools): + mode, producer, consumer, trader = await _init_mode(tools, _get_config(tools, {})) + with mock.patch.object(producer, "dca_task", mock.AsyncMock()) as dca_task_mock, \ + mock.patch.object(producer, "get_channels_registration", mock.Mock(return_value=[])): + # evaluator based + mode.trigger_mode = dca_trading.TriggerMode.MAXIMUM_EVALUATORS_SIGNALS_BASED + await producer.inner_start() + for _ in range(10): + await asyncio_tools.wait_asyncio_next_cycle() + dca_task_mock.assert_not_called() + + # time based + mode.trigger_mode = dca_trading.TriggerMode.TIME_BASED + await producer.inner_start() + for _ in range(10): + await asyncio_tools.wait_asyncio_next_cycle() + dca_task_mock.assert_called_once() + + +async def test_dca_task(tools): + mode, producer, consumer, trader = await _init_mode(tools, _get_config(tools, {})) + calls = [] + try: + def _on_trigger(**kwargs): + if len(calls): + # now stop + producer.should_stop = True + calls.append(kwargs) + producer.exchange_manager.is_backtesting = True + with mock.patch.object(asyncio, "sleep", mock.AsyncMock()) as sleep_mock: + # backtesting: trigger only once + with mock.patch.object(producer, "trigger_dca", mock.AsyncMock(side_effect=_on_trigger)) as trigger_dca_mock: + await producer.dca_task() + assert trigger_dca_mock.call_count == 1 + assert trigger_dca_mock.mock_calls[0].kwargs == { + "cryptocurrency": "Bitcoin", + "symbol": "BTC/USDT", + "state": trading_enums.EvaluatorStates.VERY_LONG + } + sleep_mock.assert_not_called() + + calls.clear() + # live: loop trigger + producer.exchange_manager.is_backtesting = False + with mock.patch.object(producer, "trigger_dca", mock.AsyncMock(side_effect=_on_trigger)) as trigger_dca_mock: + await producer.dca_task() + assert trigger_dca_mock.call_count == 2 + assert trigger_dca_mock.mock_calls[0].kwargs == { + "cryptocurrency": "Bitcoin", + "symbol": "BTC/USDT", + "state": trading_enums.EvaluatorStates.VERY_LONG + } + assert sleep_mock.call_count == 2 + assert sleep_mock.mock_calls[0].args == (10080 * commons_constants.MINUTE_TO_SECONDS, ) + assert sleep_mock.mock_calls[1].args == (10080 * commons_constants.MINUTE_TO_SECONDS, ) + finally: + producer.exchange_manager.is_backtesting = True + + async def test_trigger_dca(tools): update = {} mode, producer, consumer, trader = await _init_mode(tools, _get_config(tools, update))