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):
|
if self.manage_open_orders(t, current_time, row):
|
||||||
# Close trade
|
# Close trade
|
||||||
open_trade_count -= 1
|
open_trade_count -= 1
|
||||||
|
open_trade_count_start -= 1
|
||||||
open_trades[pair].remove(t)
|
open_trades[pair].remove(t)
|
||||||
LocalTrade.trades_open.remove(t)
|
LocalTrade.trades_open.remove(t)
|
||||||
self.wallets.update()
|
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))
|
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:
|
def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None:
|
||||||
default_conf['use_exit_signal'] = False
|
default_conf['use_exit_signal'] = False
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||||
|
@ -1457,6 +1457,7 @@ def test_api_strategies(botclient, tmpdir):
|
|||||||
'InformativeDecoratorTest',
|
'InformativeDecoratorTest',
|
||||||
'StrategyTestV2',
|
'StrategyTestV2',
|
||||||
'StrategyTestV3',
|
'StrategyTestV3',
|
||||||
|
'StrategyTestV3CustomEntryPrice',
|
||||||
'StrategyTestV3Futures',
|
'StrategyTestV3Futures',
|
||||||
'freqai_test_classifier',
|
'freqai_test_classifier',
|
||||||
'freqai_test_multimodel_strat',
|
'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"
|
directory = Path(__file__).parent / "strats"
|
||||||
strategies = StrategyResolver._search_all_objects(directory, enum_failed=False)
|
strategies = StrategyResolver._search_all_objects(directory, enum_failed=False)
|
||||||
assert isinstance(strategies, list)
|
assert isinstance(strategies, list)
|
||||||
assert len(strategies) == 9
|
assert len(strategies) == 10
|
||||||
assert isinstance(strategies[0], dict)
|
assert isinstance(strategies[0], dict)
|
||||||
|
|
||||||
|
|
||||||
@ -42,10 +42,11 @@ def test_search_all_strategies_with_failed():
|
|||||||
directory = Path(__file__).parent / "strats"
|
directory = Path(__file__).parent / "strats"
|
||||||
strategies = StrategyResolver._search_all_objects(directory, enum_failed=True)
|
strategies = StrategyResolver._search_all_objects(directory, enum_failed=True)
|
||||||
assert isinstance(strategies, list)
|
assert isinstance(strategies, list)
|
||||||
assert len(strategies) == 10
|
assert len(strategies) == 11
|
||||||
# with enum_failed=True search_all_objects() shall find 2 good strategies
|
# with enum_failed=True search_all_objects() shall find 2 good strategies
|
||||||
# and 1 which fails to load
|
# 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
|
assert len([x for x in strategies if x['class'] is None]) == 1
|
||||||
|
|
||||||
directory = Path(__file__).parent / "strats_nonexistingdir"
|
directory = Path(__file__).parent / "strats_nonexistingdir"
|
||||||
|
Loading…
Reference in New Issue
Block a user