Merge pull request #7596 from iprogger/fix/backtest-counting-available-slots
Fix counting available trade slots in backtesting.
This commit is contained in:
commit
2b70106019
@ -1123,6 +1123,7 @@ class Backtesting:
|
||||
if self.manage_open_orders(t, current_time, row):
|
||||
# Close trade
|
||||
open_trade_count -= 1
|
||||
open_trade_count_start -= 1
|
||||
open_trades[pair].remove(t)
|
||||
LocalTrade.trades_open.remove(t)
|
||||
self.wallets.update()
|
||||
|
@ -799,6 +799,35 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
|
||||
t["close_rate"], 6) < round(ln.iloc[0]["high"], 6))
|
||||
|
||||
|
||||
def test_backtest_timedout_entry_orders(default_conf, fee, mocker, testdatadir) -> None:
|
||||
# This strategy intentionally places unfillable orders.
|
||||
default_conf['strategy'] = 'StrategyTestV3CustomEntryPrice'
|
||||
default_conf['startup_candle_count'] = 0
|
||||
# Cancel unfilled order after 4 minutes on 5m timeframe.
|
||||
default_conf["unfilledtimeout"] = {"entry": 4}
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf'))
|
||||
patch_exchange(mocker)
|
||||
backtesting = Backtesting(default_conf)
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
# Testing dataframe contains 11 candles. Expecting 10 timed out orders.
|
||||
timerange = TimeRange('date', 'date', 1517227800, 1517231100)
|
||||
data = history.load_data(datadir=testdatadir, timeframe='5m', pairs=['UNITTEST/BTC'],
|
||||
timerange=timerange)
|
||||
min_date, max_date = get_timerange(data)
|
||||
|
||||
result = backtesting.backtest(
|
||||
processed=deepcopy(data),
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=1,
|
||||
position_stacking=False,
|
||||
)
|
||||
|
||||
assert result['timedout_entry_orders'] == 10
|
||||
|
||||
|
||||
def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None:
|
||||
default_conf['use_exit_signal'] = False
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
|
@ -1457,6 +1457,7 @@ def test_api_strategies(botclient, tmpdir):
|
||||
'InformativeDecoratorTest',
|
||||
'StrategyTestV2',
|
||||
'StrategyTestV3',
|
||||
'StrategyTestV3CustomEntryPrice',
|
||||
'StrategyTestV3Futures',
|
||||
'freqai_test_classifier',
|
||||
'freqai_test_multimodel_strat',
|
||||
|
37
tests/strategy/strats/strategy_test_v3_custom_entry_price.py
Normal file
37
tests/strategy/strats/strategy_test_v3_custom_entry_price.py
Normal file
@ -0,0 +1,37 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pandas import DataFrame
|
||||
from strategy_test_v3 import StrategyTestV3
|
||||
|
||||
|
||||
class StrategyTestV3CustomEntryPrice(StrategyTestV3):
|
||||
"""
|
||||
Strategy used by tests freqtrade bot.
|
||||
Please do not modify this strategy, it's intended for internal use only.
|
||||
Please look at the SampleStrategy in the user_data/strategy directory
|
||||
or strategy repository https://github.com/freqtrade/freqtrade-strategies
|
||||
for samples and inspiration.
|
||||
"""
|
||||
new_entry_price: float = 0.001
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe.loc[
|
||||
dataframe['volume'] > 0,
|
||||
'enter_long'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
return dataframe
|
||||
|
||||
def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float,
|
||||
entry_tag: Optional[str], side: str, **kwargs) -> float:
|
||||
|
||||
return self.new_entry_price
|
@ -34,7 +34,7 @@ def test_search_all_strategies_no_failed():
|
||||
directory = Path(__file__).parent / "strats"
|
||||
strategies = StrategyResolver._search_all_objects(directory, enum_failed=False)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 9
|
||||
assert len(strategies) == 10
|
||||
assert isinstance(strategies[0], dict)
|
||||
|
||||
|
||||
@ -42,10 +42,11 @@ def test_search_all_strategies_with_failed():
|
||||
directory = Path(__file__).parent / "strats"
|
||||
strategies = StrategyResolver._search_all_objects(directory, enum_failed=True)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 10
|
||||
assert len(strategies) == 11
|
||||
# with enum_failed=True search_all_objects() shall find 2 good strategies
|
||||
# and 1 which fails to load
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 9
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 10
|
||||
|
||||
assert len([x for x in strategies if x['class'] is None]) == 1
|
||||
|
||||
directory = Path(__file__).parent / "strats_nonexistingdir"
|
||||
|
Loading…
Reference in New Issue
Block a user