Merge branch 'develop' into pr/nicolaspapp/6715
This commit is contained in:
@@ -22,7 +22,7 @@ from freqtrade.data.history import get_timerange
|
||||
from freqtrade.enums import ExitType, RunMode
|
||||
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.optimize.backtest_caching import get_strategy_run_id
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.persistence import LocalTrade
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
@@ -312,6 +312,7 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None:
|
||||
get_fee.assert_called()
|
||||
assert backtesting.fee == 0.5
|
||||
assert not backtesting.strategy.order_types["stoploss_on_exchange"]
|
||||
assert backtesting.strategy.bot_started is True
|
||||
|
||||
|
||||
def test_backtesting_init_no_timeframe(mocker, default_conf, caplog) -> None:
|
||||
@@ -384,14 +385,16 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
|
||||
mocker.patch('freqtrade.optimize.backtesting.generate_backtest_stats')
|
||||
mocker.patch('freqtrade.optimize.backtesting.show_backtest_results')
|
||||
sbs = mocker.patch('freqtrade.optimize.backtesting.store_backtest_stats')
|
||||
sbc = mocker.patch('freqtrade.optimize.backtesting.store_backtest_signal_candles')
|
||||
mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
|
||||
PropertyMock(return_value=['UNITTEST/BTC']))
|
||||
|
||||
default_conf['timeframe'] = '1m'
|
||||
default_conf['datadir'] = testdatadir
|
||||
default_conf['export'] = 'trades'
|
||||
default_conf['export'] = 'signals'
|
||||
default_conf['exportfilename'] = 'export.txt'
|
||||
default_conf['timerange'] = '-1510694220'
|
||||
default_conf['runmode'] = RunMode.BACKTEST
|
||||
|
||||
backtesting = Backtesting(default_conf)
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
@@ -407,6 +410,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
|
||||
assert backtesting.strategy.dp._pairlists is not None
|
||||
assert backtesting.strategy.bot_loop_start.call_count == 1
|
||||
assert sbs.call_count == 1
|
||||
assert sbc.call_count == 1
|
||||
|
||||
|
||||
def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> None:
|
||||
@@ -497,7 +501,7 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti
|
||||
Backtesting(default_conf)
|
||||
|
||||
# Multiple strategies
|
||||
default_conf['strategy_list'] = [CURRENT_TEST_STRATEGY, 'TestStrategyLegacyV1']
|
||||
default_conf['strategy_list'] = [CURRENT_TEST_STRATEGY, 'StrategyTestV2']
|
||||
with pytest.raises(OperationalException,
|
||||
match='PrecisionFilter not allowed for backtesting multiple strategies.'):
|
||||
Backtesting(default_conf)
|
||||
@@ -711,7 +715,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
|
||||
)
|
||||
|
||||
# No data available.
|
||||
res = backtesting._get_sell_trade_entry(trade, row_sell)
|
||||
res = backtesting._get_exit_trade_entry(trade, row_sell)
|
||||
assert res is not None
|
||||
assert res.exit_reason == ExitType.ROI.value
|
||||
assert res.close_date_utc == datetime(2020, 1, 1, 5, 0, tzinfo=timezone.utc)
|
||||
@@ -724,13 +728,13 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
|
||||
[], columns=['date', 'open', 'high', 'low', 'close', 'enter_long', 'exit_long',
|
||||
'enter_short', 'exit_short', 'long_tag', 'short_tag', 'exit_tag'])
|
||||
|
||||
res = backtesting._get_sell_trade_entry(trade, row)
|
||||
res = backtesting._get_exit_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)
|
||||
res = backtesting._get_exit_trade_entry(trade, row_sell)
|
||||
assert res is not None
|
||||
assert res.exit_reason == ExitType.ROI.value
|
||||
# Sell at minute 3 (not available above!)
|
||||
@@ -1195,7 +1199,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'--disable-max-market-positions',
|
||||
'--strategy-list',
|
||||
CURRENT_TEST_STRATEGY,
|
||||
'TestStrategyLegacyV1',
|
||||
'StrategyTestV2',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
@@ -1218,14 +1222,13 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
]
|
||||
|
||||
for line in exists:
|
||||
assert log_has(line, caplog)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdatadir, capsys):
|
||||
default_conf.update({
|
||||
"use_exit_signal": True,
|
||||
@@ -1307,7 +1310,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'--breakdown', 'day',
|
||||
'--strategy-list',
|
||||
CURRENT_TEST_STRATEGY,
|
||||
'TestStrategyLegacyV1',
|
||||
'StrategyTestV2',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
@@ -1324,7 +1327,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
]
|
||||
|
||||
for line in exists:
|
||||
@@ -1339,6 +1342,39 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
assert 'STRATEGY SUMMARY' in captured.out
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_backtest_start_futures_noliq(default_conf_usdt, mocker,
|
||||
caplog, testdatadir, capsys):
|
||||
# Tests detail-data loading
|
||||
default_conf_usdt.update({
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "isolated",
|
||||
"use_exit_signal": True,
|
||||
"exit_profit_only": False,
|
||||
"exit_profit_offset": 0.0,
|
||||
"ignore_roi_if_entry_signal": False,
|
||||
"strategy": CURRENT_TEST_STRATEGY,
|
||||
})
|
||||
patch_exchange(mocker)
|
||||
|
||||
mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
|
||||
PropertyMock(return_value=['HULUMULU/USDT', 'XRP/USDT']))
|
||||
# mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock)
|
||||
|
||||
patched_configuration_load_config_file(mocker, default_conf_usdt)
|
||||
|
||||
args = [
|
||||
'backtesting',
|
||||
'--config', 'config.json',
|
||||
'--datadir', str(testdatadir),
|
||||
'--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'),
|
||||
'--timeframe', '1h',
|
||||
]
|
||||
args = get_args(args)
|
||||
with pytest.raises(OperationalException, match=r"Pairs .* got no leverage tiers available\."):
|
||||
start_backtesting(args)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
|
||||
caplog, testdatadir, capsys):
|
||||
@@ -1589,7 +1625,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
min_backtest_date = now - timedelta(weeks=4)
|
||||
load_backtest_metadata = MagicMock(return_value={
|
||||
'StrategyTestV2': {'run_id': '1', 'backtest_start_time': now.timestamp()},
|
||||
'TestStrategyLegacyV1': {'run_id': run_id, 'backtest_start_time': start_time.timestamp()}
|
||||
'StrategyTestV3': {'run_id': run_id, 'backtest_start_time': start_time.timestamp()}
|
||||
})
|
||||
load_backtest_stats = MagicMock(side_effect=[
|
||||
{
|
||||
@@ -1598,9 +1634,9 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'strategy_comparison': [{'key': 'StrategyTestV2'}]
|
||||
},
|
||||
{
|
||||
'metadata': {'TestStrategyLegacyV1': {'run_id': '2'}},
|
||||
'strategy': {'TestStrategyLegacyV1': {}},
|
||||
'strategy_comparison': [{'key': 'TestStrategyLegacyV1'}]
|
||||
'metadata': {'StrategyTestV3': {'run_id': '2'}},
|
||||
'strategy': {'StrategyTestV3': {}},
|
||||
'strategy_comparison': [{'key': 'StrategyTestV3'}]
|
||||
}
|
||||
])
|
||||
mocker.patch('pathlib.Path.glob', return_value=[
|
||||
@@ -1624,7 +1660,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'--cache', cache,
|
||||
'--strategy-list',
|
||||
'StrategyTestV2',
|
||||
'TestStrategyLegacyV1',
|
||||
'StrategyTestV3',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
@@ -1646,7 +1682,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
assert backtestmock.call_count == 2
|
||||
exists = [
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV3',
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:58:00 (0 days).',
|
||||
]
|
||||
@@ -1654,12 +1690,12 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
assert backtestmock.call_count == 0
|
||||
exists = [
|
||||
'Reusing result of previous backtest for StrategyTestV2',
|
||||
'Reusing result of previous backtest for TestStrategyLegacyV1',
|
||||
'Reusing result of previous backtest for StrategyTestV3',
|
||||
]
|
||||
else:
|
||||
exists = [
|
||||
'Reusing result of previous backtest for StrategyTestV2',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV3',
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:58:00 (0 days).',
|
||||
]
|
||||
|
@@ -94,6 +94,7 @@ def test_edge_init(mocker, edge_conf) -> None:
|
||||
assert edge_cli.config == edge_conf
|
||||
assert edge_cli.config['stake_amount'] == 'unlimited'
|
||||
assert callable(edge_cli.edge.calculate)
|
||||
assert edge_cli.strategy.bot_started is True
|
||||
|
||||
|
||||
def test_edge_init_fee(mocker, edge_conf) -> None:
|
||||
|
@@ -41,6 +41,7 @@ def generate_result_metrics():
|
||||
'max_drawdown_abs': 0.001,
|
||||
'loss': 0.001,
|
||||
'is_initial_point': 0.001,
|
||||
'is_random': False,
|
||||
'is_best': 1,
|
||||
}
|
||||
|
||||
@@ -247,6 +248,7 @@ def test_log_results_if_loss_improves(hyperopt, capsys) -> None:
|
||||
'total_profit': 0,
|
||||
'current_epoch': 2, # This starts from 1 (in a human-friendly manner)
|
||||
'is_initial_point': False,
|
||||
'is_random': False,
|
||||
'is_best': True
|
||||
}
|
||||
)
|
||||
|
@@ -4,7 +4,7 @@ from unittest.mock import MagicMock
|
||||
import pytest
|
||||
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.optimize.hyperopt_loss_short_trade_dur import ShortTradeDurHyperOptLoss
|
||||
from freqtrade.optimize.hyperopt_loss.hyperopt_loss_short_trade_dur import ShortTradeDurHyperOptLoss
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver
|
||||
|
||||
|
||||
|
@@ -2,6 +2,7 @@ import re
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import joblib
|
||||
import pandas as pd
|
||||
import pytest
|
||||
from arrow import Arrow
|
||||
@@ -19,6 +20,7 @@ from freqtrade.optimize.optimize_reports import (_get_resample_from_period, gene
|
||||
generate_periodic_breakdown_stats,
|
||||
generate_strategy_comparison,
|
||||
generate_trading_stats, show_sorted_pairlist,
|
||||
store_backtest_signal_candles,
|
||||
store_backtest_stats, text_table_bt_results,
|
||||
text_table_exit_reason, text_table_strategy)
|
||||
from freqtrade.resolvers.strategy_resolver import StrategyResolver
|
||||
@@ -201,6 +203,62 @@ def test_store_backtest_stats(testdatadir, mocker):
|
||||
assert str(dump_mock.call_args_list[0][0][0]).startswith(str(testdatadir / 'testresult'))
|
||||
|
||||
|
||||
def test_store_backtest_candles(testdatadir, mocker):
|
||||
|
||||
dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_joblib')
|
||||
|
||||
candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}}
|
||||
|
||||
# mock directory exporting
|
||||
store_backtest_signal_candles(testdatadir, candle_dict)
|
||||
|
||||
assert dump_mock.call_count == 1
|
||||
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
|
||||
assert str(dump_mock.call_args_list[0][0][0]).endswith(str('_signals.pkl'))
|
||||
|
||||
dump_mock.reset_mock()
|
||||
# mock file exporting
|
||||
filename = Path(testdatadir / 'testresult')
|
||||
store_backtest_signal_candles(filename, candle_dict)
|
||||
assert dump_mock.call_count == 1
|
||||
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
|
||||
# result will be testdatadir / testresult-<timestamp>_signals.pkl
|
||||
assert str(dump_mock.call_args_list[0][0][0]).endswith(str('_signals.pkl'))
|
||||
dump_mock.reset_mock()
|
||||
|
||||
|
||||
def test_write_read_backtest_candles(tmpdir):
|
||||
|
||||
candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}}
|
||||
|
||||
# test directory exporting
|
||||
stored_file = store_backtest_signal_candles(Path(tmpdir), candle_dict)
|
||||
scp = open(stored_file, "rb")
|
||||
pickled_signal_candles = joblib.load(scp)
|
||||
scp.close()
|
||||
|
||||
assert pickled_signal_candles.keys() == candle_dict.keys()
|
||||
assert pickled_signal_candles['DefStrat'].keys() == pickled_signal_candles['DefStrat'].keys()
|
||||
assert pickled_signal_candles['DefStrat']['UNITTEST/BTC'] \
|
||||
.equals(pickled_signal_candles['DefStrat']['UNITTEST/BTC'])
|
||||
|
||||
_clean_test_file(stored_file)
|
||||
|
||||
# test file exporting
|
||||
filename = Path(tmpdir / 'testresult')
|
||||
stored_file = store_backtest_signal_candles(filename, candle_dict)
|
||||
scp = open(stored_file, "rb")
|
||||
pickled_signal_candles = joblib.load(scp)
|
||||
scp.close()
|
||||
|
||||
assert pickled_signal_candles.keys() == candle_dict.keys()
|
||||
assert pickled_signal_candles['DefStrat'].keys() == pickled_signal_candles['DefStrat'].keys()
|
||||
assert pickled_signal_candles['DefStrat']['UNITTEST/BTC'] \
|
||||
.equals(pickled_signal_candles['DefStrat']['UNITTEST/BTC'])
|
||||
|
||||
_clean_test_file(stored_file)
|
||||
|
||||
|
||||
def test_generate_pair_metrics():
|
||||
|
||||
results = pd.DataFrame(
|
||||
@@ -228,7 +286,7 @@ def test_generate_pair_metrics():
|
||||
|
||||
def test_generate_daily_stats(testdatadir):
|
||||
|
||||
filename = testdatadir / "backtest-result_new.json"
|
||||
filename = testdatadir / "backtest_results/backtest-result_new.json"
|
||||
bt_data = load_backtest_data(filename)
|
||||
res = generate_daily_stats(bt_data)
|
||||
assert isinstance(res, dict)
|
||||
@@ -248,7 +306,7 @@ def test_generate_daily_stats(testdatadir):
|
||||
|
||||
|
||||
def test_generate_trading_stats(testdatadir):
|
||||
filename = testdatadir / "backtest-result_new.json"
|
||||
filename = testdatadir / "backtest_results/backtest-result_new.json"
|
||||
bt_data = load_backtest_data(filename)
|
||||
res = generate_trading_stats(bt_data)
|
||||
assert isinstance(res, dict)
|
||||
@@ -332,7 +390,7 @@ def test_generate_sell_reason_stats():
|
||||
|
||||
|
||||
def test_text_table_strategy(testdatadir):
|
||||
filename = testdatadir / "backtest-result_multistrat.json"
|
||||
filename = testdatadir / "backtest_results/backtest-result_multistrat.json"
|
||||
bt_res_data = load_backtest_stats(filename)
|
||||
|
||||
bt_res_data_comparison = bt_res_data.pop('strategy_comparison')
|
||||
@@ -364,7 +422,7 @@ def test_generate_edge_table():
|
||||
|
||||
|
||||
def test_generate_periodic_breakdown_stats(testdatadir):
|
||||
filename = testdatadir / "backtest-result_new.json"
|
||||
filename = testdatadir / "backtest_results/backtest-result_new.json"
|
||||
bt_data = load_backtest_data(filename).to_dict(orient='records')
|
||||
|
||||
res = generate_periodic_breakdown_stats(bt_data, 'day')
|
||||
@@ -392,7 +450,7 @@ def test__get_resample_from_period():
|
||||
|
||||
|
||||
def test_show_sorted_pairlist(testdatadir, default_conf, capsys):
|
||||
filename = testdatadir / "backtest-result_new.json"
|
||||
filename = testdatadir / "backtest_results/backtest-result_new.json"
|
||||
bt_data = load_backtest_stats(filename)
|
||||
default_conf['backtest_show_pair_list'] = True
|
||||
|
||||
|
Reference in New Issue
Block a user