Add explicit test for get_sell_trade_entry

This commit is contained in:
Matthias 2021-08-14 17:36:02 +02:00
parent 3406b889b6
commit fa4ec9f83e
2 changed files with 89 additions and 4 deletions

View File

@ -376,7 +376,7 @@ class Backtesting:
return None return None
def _get_sell_trade_entry(self, trade: LocalTrade, sell_row: Tuple) -> Optional[LocalTrade]: def _get_sell_trade_entry(self, trade: LocalTrade, sell_row: Tuple) -> Optional[LocalTrade]:
if self.timeframe_detail: if self.timeframe_detail and trade.pair in self.detail_data:
sell_candle_time = sell_row[DATE_IDX].to_pydatetime() sell_candle_time = sell_row[DATE_IDX].to_pydatetime()
sell_candle_end = sell_candle_time + timedelta(minutes=self.timeframe_min) sell_candle_end = sell_candle_time + timedelta(minutes=self.timeframe_min)
@ -385,6 +385,9 @@ class Backtesting:
(detail_data['date'] >= sell_candle_time) & (detail_data['date'] >= sell_candle_time) &
(detail_data['date'] < sell_candle_end) (detail_data['date'] < sell_candle_end)
] ]
if len(detail_data) == 0:
# Fall back to "regular" data if no detail data was found for this candle
return self._get_sell_trade_entry_for_candle(trade, sell_row)
detail_data['buy'] = sell_row[BUY_IDX] detail_data['buy'] = sell_row[BUY_IDX]
detail_data['sell'] = sell_row[SELL_IDX] detail_data['sell'] = sell_row[SELL_IDX]
headers = ['date', 'buy', 'open', 'close', 'sell', 'low', 'high'] headers = ['date', 'buy', 'open', 'close', 'sell', 'low', 'high']

View File

@ -1,7 +1,7 @@
# pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument # pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument
import random import random
from datetime import timedelta from datetime import datetime, timedelta, timezone
from pathlib import Path from pathlib import Path
from unittest.mock import MagicMock, PropertyMock from unittest.mock import MagicMock, PropertyMock
@ -500,7 +500,7 @@ def test_backtest__enter_trade(default_conf, fee, mocker) -> None:
pair = 'UNITTEST/BTC' pair = 'UNITTEST/BTC'
row = [ row = [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0), pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0),
1, # Sell 1, # Buy
0.001, # Open 0.001, # Open
0.0011, # Close 0.0011, # Close
0, # Sell 0, # Sell
@ -548,6 +548,88 @@ def test_backtest__enter_trade(default_conf, fee, mocker) -> None:
backtesting.cleanup() backtesting.cleanup()
def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
default_conf['use_sell_signal'] = False
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
patch_exchange(mocker)
default_conf['timeframe_detail'] = '1m'
default_conf['max_open_trades'] = 2
backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0])
pair = 'UNITTEST/BTC'
row = [
pd.Timestamp(year=2020, month=1, day=1, hour=4, minute=55, tzinfo=timezone.utc),
1, # Buy
200, # Open
201, # Close
0, # Sell
195, # Low
201.5, # High
'', # Buy Signal Name
]
trade = backtesting._enter_trade(pair, row=row)
assert isinstance(trade, LocalTrade)
row_sell = [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0, tzinfo=timezone.utc),
0, # Buy
200, # Open
201, # Close
0, # Sell
195, # Low
210.5, # High
'', # Buy Signal Name
]
row_detail = pd.DataFrame(
[
[
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0, tzinfo=timezone.utc),
1, 200, 199, 0, 197, 200.1, '',
], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=1, tzinfo=timezone.utc),
0, 199, 199.5, 0, 199, 199.7, '',
], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=2, tzinfo=timezone.utc),
0, 199.5, 200.5, 0, 199, 200.8, '',
], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=3, tzinfo=timezone.utc),
0, 200.5, 210.5, 0, 193, 210.5, '', # ROI sell (?)
], [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=4, tzinfo=timezone.utc),
0, 200, 199, 0, 193, 200.1, '',
],
], columns=["date", "buy", "open", "close", "sell", "low", "high", "buy_tag"]
)
# No data available.
res = backtesting._get_sell_trade_entry(trade, row_sell)
assert res is not None
assert res.sell_reason == SellType.ROI.value
assert res.close_date_utc == datetime(2020, 1, 1, 5, 0, tzinfo=timezone.utc)
# Enter new trade
trade = backtesting._enter_trade(pair, row=row)
assert isinstance(trade, LocalTrade)
# Assign empty ... no result.
backtesting.detail_data[pair] = pd.DataFrame(
[], columns=["date", "buy", "open", "close", "sell", "low", "high", "buy_tag"])
res = backtesting._get_sell_trade_entry(trade, row)
assert res is None
# Assign backtest-detail data
backtesting.detail_data[pair] = row_detail
res = backtesting._get_sell_trade_entry(trade, row_sell)
assert res is not None
assert res.sell_reason == SellType.ROI.value
# Sell at minute 3 (not available above!)
assert res.close_date_utc == datetime(2020, 1, 1, 5, 3, tzinfo=timezone.utc)
assert round(res.close_rate, 3) == round(209.0225, 3)
def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None: def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_sell_signal'] = False default_conf['use_sell_signal'] = False
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
@ -1127,7 +1209,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
'--timeframe-detail', '1m', '--timeframe-detail', '1m',
'--strategy-list', '--strategy-list',
'DefaultStrategy' 'DefaultStrategy'
] ]
args = get_args(args) args = get_args(args)
start_backtesting(args) start_backtesting(args)