Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DCA] fix time based DCA #1068

Merged
merged 2 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Trading/Mode/dca_trading_mode/dca_trading.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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}")

Expand Down
60 changes: 60 additions & 0 deletions Trading/Mode/dca_trading_mode/tests/test_dca_trading_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import os.path
import mock
import decimal
import asyncio

import async_channel.util as channel_util

Expand Down Expand Up @@ -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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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))
Expand Down