|
|
|
|
@ -1,8 +1,14 @@
|
|
|
|
|
from copy import deepcopy
|
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from freqtrade.data.history.history_utils import get_timerange
|
|
|
|
|
from freqtrade.optimize.backtesting import Backtesting
|
|
|
|
|
from freqtrade.persistence import Trade, disable_database_use, enable_database_use
|
|
|
|
|
from freqtrade.persistence.custom_data import CustomDataWrapper
|
|
|
|
|
from tests.conftest import EXMS, create_mock_trades_usdt, get_patched_freqtradebot
|
|
|
|
|
from tests.conftest import (EXMS, create_mock_trades_usdt, generate_test_data,
|
|
|
|
|
get_patched_freqtradebot, patch_exchange)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures("init_persistence")
|
|
|
|
|
@ -49,9 +55,7 @@ def test_trade_custom_data_strategy_compat(mocker, default_conf_usdt, fee):
|
|
|
|
|
|
|
|
|
|
mocker.patch(f'{EXMS}.get_rate', return_value=0.50)
|
|
|
|
|
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=None)
|
|
|
|
|
default_conf_usdt["minimal_roi"] = {
|
|
|
|
|
"0": 100
|
|
|
|
|
}
|
|
|
|
|
default_conf_usdt["minimal_roi"] = {"0": 100}
|
|
|
|
|
|
|
|
|
|
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
|
|
|
|
create_mock_trades_usdt(fee)
|
|
|
|
|
@ -81,3 +85,74 @@ def test_trade_custom_data_strategy_compat(mocker, default_conf_usdt, fee):
|
|
|
|
|
assert ff_spy.call_count == 2
|
|
|
|
|
|
|
|
|
|
assert trade_after.exit_reason == 'test_value_1'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_trade_custom_data_strategy_backtest_compat(mocker, default_conf_usdt, fee):
|
|
|
|
|
|
|
|
|
|
mocker.patch(f'{EXMS}.get_fee', fee)
|
|
|
|
|
mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=10)
|
|
|
|
|
mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float('inf'))
|
|
|
|
|
mocker.patch(f"{EXMS}.get_max_leverage", return_value=10)
|
|
|
|
|
mocker.patch(f"{EXMS}.get_maintenance_ratio_and_amt", return_value=(0.1, 0.1))
|
|
|
|
|
mocker.patch('freqtrade.optimize.backtesting.Backtesting._run_funding_fees')
|
|
|
|
|
|
|
|
|
|
patch_exchange(mocker)
|
|
|
|
|
default_conf_usdt.update({
|
|
|
|
|
"stake_amount": 100.0,
|
|
|
|
|
"max_open_trades": 2,
|
|
|
|
|
"dry_run_wallet": 1000.0,
|
|
|
|
|
"strategy": "StrategyTestV3",
|
|
|
|
|
"trading_mode": "futures",
|
|
|
|
|
"margin_mode": "isolated",
|
|
|
|
|
"stoploss": -2,
|
|
|
|
|
"minimal_roi": {"0": 100},
|
|
|
|
|
})
|
|
|
|
|
default_conf_usdt['pairlists'] = [{'method': 'StaticPairList', 'allow_inactive': True}]
|
|
|
|
|
backtesting = Backtesting(default_conf_usdt)
|
|
|
|
|
|
|
|
|
|
df = generate_test_data(default_conf_usdt['timeframe'], 100, '2022-01-01 00:00:00+00:00')
|
|
|
|
|
|
|
|
|
|
pair_exp = 'XRP/USDT:USDT'
|
|
|
|
|
|
|
|
|
|
def custom_exit(pair, trade, **kwargs):
|
|
|
|
|
custom_val = trade.get_custom_data('test_str')
|
|
|
|
|
custom_val_i = trade.get_custom_data('test_int', 0)
|
|
|
|
|
|
|
|
|
|
if pair == pair_exp:
|
|
|
|
|
trade.set_custom_data('test_str', 'test_value')
|
|
|
|
|
trade.set_custom_data('test_int', custom_val_i + 1)
|
|
|
|
|
|
|
|
|
|
if custom_val_i >= 2:
|
|
|
|
|
return f"{custom_val}_{custom_val_i}"
|
|
|
|
|
|
|
|
|
|
backtesting._set_strategy(backtesting.strategylist[0])
|
|
|
|
|
processed = backtesting.strategy.advise_all_indicators({
|
|
|
|
|
pair_exp: df,
|
|
|
|
|
'BTC/USDT:USDT': df,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
def fun(dataframe, *args, **kwargs):
|
|
|
|
|
dataframe.loc[dataframe.index == 50, 'enter_long'] = 1
|
|
|
|
|
return dataframe
|
|
|
|
|
|
|
|
|
|
backtesting.strategy.advise_entry = fun
|
|
|
|
|
backtesting.strategy.leverage = MagicMock(return_value=1)
|
|
|
|
|
backtesting.strategy.custom_exit = custom_exit
|
|
|
|
|
ff_spy = mocker.spy(backtesting.strategy, 'custom_exit')
|
|
|
|
|
|
|
|
|
|
min_date, max_date = get_timerange(processed)
|
|
|
|
|
|
|
|
|
|
result = backtesting.backtest(
|
|
|
|
|
processed=deepcopy(processed),
|
|
|
|
|
start_date=min_date,
|
|
|
|
|
end_date=max_date,
|
|
|
|
|
)
|
|
|
|
|
results = result['results']
|
|
|
|
|
assert not results.empty
|
|
|
|
|
assert len(results) == 2
|
|
|
|
|
assert results['pair'][0] == pair_exp
|
|
|
|
|
assert results['pair'][1] == 'BTC/USDT:USDT'
|
|
|
|
|
assert results['exit_reason'][0] == 'test_value_2'
|
|
|
|
|
assert results['exit_reason'][1] == 'exit_signal'
|
|
|
|
|
|
|
|
|
|
assert ff_spy.call_count == 7
|
|
|
|
|
|