From 56dcf080a906645df2a2872618c3666c129d8973 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 5 Nov 2018 20:03:04 +0100 Subject: [PATCH] Add explicit test for parallel trades --- freqtrade/tests/optimize/test_backtesting.py | 71 ++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index b0d4f2cbd..e03e011f3 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -655,6 +655,77 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker): assert len(results.loc[results.open_at_end]) == 0 +def test_backtest_multi_pair(default_conf, fee, mocker): + + def evaluate_result_multi(results, freq, max_open_trades): + # Find overlapping trades by expanding each trade once per period + # and then counting overlaps + dates = [pd.Series(pd.date_range(row[1].open_time, row[1].close_time, freq=freq)) + for row in results[['open_time', 'close_time']].iterrows()] + deltas = [len(x) for x in dates] + dates = pd.Series(pd.concat(dates).values, name='date') + df2 = pd.DataFrame(np.repeat(results.values, deltas, axis=0), columns=results.columns) + + df2 = df2.astype(dtype={"open_time": "datetime64", "close_time": "datetime64"}) + df2 = pd.concat([dates, df2], axis=1) + df2 = df2.set_index('date') + df_final = df2.resample(freq)[['pair']].count() + return df_final[df_final['pair'] > max_open_trades] + + def _trend_alternate_hold(dataframe=None, metadata=None): + """ + Buy every 8th candle - sell every other 8th -2 (hold on to pairs a bit) + """ + multi = 8 + dataframe['buy'] = np.where(dataframe.index % multi == 0, 1, 0) + dataframe['sell'] = np.where((dataframe.index + multi - 2) % multi == 0, 1, 0) + if metadata['pair'] in('ETH/BTC', 'LTC/BTC'): + dataframe['buy'] = dataframe['buy'].shift(-4) + dataframe['sell'] = dataframe['sell'].shift(-4) + return dataframe + + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + pairs = ['ADA/BTC', 'DASH/BTC', 'ETH/BTC', 'LTC/BTC', 'NXT/BTC'] + data = optimize.load_data(None, ticker_interval='5m', pairs=pairs) + data = trim_dictlist(data, -500) + # We need to enable sell-signal - otherwise it sells on ROI!! + default_conf['experimental'] = {"use_sell_signal": True} + default_conf['ticker_interval'] = '5m' + + backtesting = Backtesting(default_conf) + backtesting.advise_buy = _trend_alternate_hold # Override + backtesting.advise_sell = _trend_alternate_hold # Override + + data_processed = backtesting.strategy.tickerdata_to_dataframe(data) + min_date, max_date = get_timeframe(data_processed) + backtest_conf = { + 'stake_amount': default_conf['stake_amount'], + 'processed': data_processed, + 'max_open_trades': 3, + 'position_stacking': False, + 'start_date': min_date, + 'end_date': max_date, + } + + results = backtesting.backtest(backtest_conf) + + # Make sure we have parallel trades + assert len(evaluate_result_multi(results, '5min', 2)) > 0 + # make sure we don't have trades with more than configured max_open_trades + assert len(evaluate_result_multi(results, '5min', 3)) == 0 + + backtest_conf = { + 'stake_amount': default_conf['stake_amount'], + 'processed': data_processed, + 'max_open_trades': 1, + 'position_stacking': False, + 'start_date': min_date, + 'end_date': max_date, + } + results = backtesting.backtest(backtest_conf) + assert len(evaluate_result_multi(results, '5min', 1)) == 0 + + def test_backtest_record(default_conf, fee, mocker): names = [] records = []