Merge pull request #6307 from freqtrade/bt_shift
Remove shift in analyzed dataframe columns
This commit is contained in:
commit
a4e1aaa9bd
@ -275,6 +275,13 @@ class Backtesting:
|
|||||||
# Trim startup period from analyzed dataframe
|
# Trim startup period from analyzed dataframe
|
||||||
df_analyzed = processed[pair] = pair_data = trim_dataframe(
|
df_analyzed = processed[pair] = pair_data = trim_dataframe(
|
||||||
df_analyzed, self.timerange, startup_candles=self.required_startup)
|
df_analyzed, self.timerange, startup_candles=self.required_startup)
|
||||||
|
# Update dataprovider cache
|
||||||
|
self.dataprovider._set_cached_df(pair, self.timeframe, df_analyzed)
|
||||||
|
|
||||||
|
# Create a copy of the dataframe before shifting, that way the buy signal/tag
|
||||||
|
# remains on the correct candle for callbacks.
|
||||||
|
df_analyzed = df_analyzed.copy()
|
||||||
|
|
||||||
# To avoid using data from future, we use buy/sell signals shifted
|
# To avoid using data from future, we use buy/sell signals shifted
|
||||||
# from the previous candle
|
# from the previous candle
|
||||||
df_analyzed.loc[:, 'buy'] = df_analyzed.loc[:, 'buy'].shift(1)
|
df_analyzed.loc[:, 'buy'] = df_analyzed.loc[:, 'buy'].shift(1)
|
||||||
@ -282,9 +289,6 @@ class Backtesting:
|
|||||||
df_analyzed.loc[:, 'buy_tag'] = df_analyzed.loc[:, 'buy_tag'].shift(1)
|
df_analyzed.loc[:, 'buy_tag'] = df_analyzed.loc[:, 'buy_tag'].shift(1)
|
||||||
df_analyzed.loc[:, 'exit_tag'] = df_analyzed.loc[:, 'exit_tag'].shift(1)
|
df_analyzed.loc[:, 'exit_tag'] = df_analyzed.loc[:, 'exit_tag'].shift(1)
|
||||||
|
|
||||||
# Update dataprovider cache
|
|
||||||
self.dataprovider._set_cached_df(pair, self.timeframe, df_analyzed)
|
|
||||||
|
|
||||||
df_analyzed = df_analyzed.drop(df_analyzed.head(1).index)
|
df_analyzed = df_analyzed.drop(df_analyzed.head(1).index)
|
||||||
|
|
||||||
# Convert from Pandas to list for performance reasons
|
# Convert from Pandas to list for performance reasons
|
||||||
|
@ -21,6 +21,7 @@ from freqtrade.data.dataprovider import DataProvider
|
|||||||
from freqtrade.data.history import get_timerange
|
from freqtrade.data.history import get_timerange
|
||||||
from freqtrade.enums import RunMode, SellType
|
from freqtrade.enums import RunMode, SellType
|
||||||
from freqtrade.exceptions import DependencyException, OperationalException
|
from freqtrade.exceptions import DependencyException, OperationalException
|
||||||
|
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||||
from freqtrade.misc import get_strategy_run_id
|
from freqtrade.misc import get_strategy_run_id
|
||||||
from freqtrade.optimize.backtesting import Backtesting
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
from freqtrade.persistence import LocalTrade
|
from freqtrade.persistence import LocalTrade
|
||||||
@ -650,6 +651,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
|
|||||||
timerange=timerange)
|
timerange=timerange)
|
||||||
processed = backtesting.strategy.advise_all_indicators(data)
|
processed = backtesting.strategy.advise_all_indicators(data)
|
||||||
min_date, max_date = get_timerange(processed)
|
min_date, max_date = get_timerange(processed)
|
||||||
|
|
||||||
result = backtesting.backtest(
|
result = backtesting.backtest(
|
||||||
processed=deepcopy(processed),
|
processed=deepcopy(processed),
|
||||||
start_date=min_date,
|
start_date=min_date,
|
||||||
@ -741,6 +743,46 @@ def test_processed(default_conf, mocker, testdatadir) -> None:
|
|||||||
assert col in cols
|
assert col in cols
|
||||||
|
|
||||||
|
|
||||||
|
def test_backtest_dataprovider_analyzed_df(default_conf, fee, mocker, testdatadir) -> 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)
|
||||||
|
backtesting = Backtesting(default_conf)
|
||||||
|
backtesting._set_strategy(backtesting.strategylist[0])
|
||||||
|
timerange = TimeRange('date', None, 1517227800, 0)
|
||||||
|
data = history.load_data(datadir=testdatadir, timeframe='5m', pairs=['UNITTEST/BTC'],
|
||||||
|
timerange=timerange)
|
||||||
|
processed = backtesting.strategy.advise_all_indicators(data)
|
||||||
|
min_date, max_date = get_timerange(processed)
|
||||||
|
|
||||||
|
global count
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
def tmp_confirm_entry(pair, current_time, **kwargs):
|
||||||
|
dp = backtesting.strategy.dp
|
||||||
|
df, _ = dp.get_analyzed_dataframe(pair, backtesting.strategy.timeframe)
|
||||||
|
current_candle = df.iloc[-1].squeeze()
|
||||||
|
assert current_candle['buy'] == 1
|
||||||
|
|
||||||
|
candle_date = timeframe_to_next_date(backtesting.strategy.timeframe, current_candle['date'])
|
||||||
|
assert candle_date == current_time
|
||||||
|
# These asserts don't properly raise as they are nested,
|
||||||
|
# therefore we increment count and assert for that.
|
||||||
|
global count
|
||||||
|
count = count + 1
|
||||||
|
|
||||||
|
backtesting.strategy.confirm_trade_entry = tmp_confirm_entry
|
||||||
|
backtesting.backtest(
|
||||||
|
processed=deepcopy(processed),
|
||||||
|
start_date=min_date,
|
||||||
|
end_date=max_date,
|
||||||
|
max_open_trades=10,
|
||||||
|
position_stacking=False,
|
||||||
|
)
|
||||||
|
assert count == 5
|
||||||
|
|
||||||
|
|
||||||
def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatadir) -> None:
|
def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatadir) -> None:
|
||||||
# While this test IS a copy of test_backtest_pricecontours, it's needed to ensure
|
# While this test IS a copy of test_backtest_pricecontours, it's needed to ensure
|
||||||
# results do not carry-over to the next run, which is not given by using parametrize.
|
# results do not carry-over to the next run, which is not given by using parametrize.
|
||||||
|
Loading…
Reference in New Issue
Block a user