freqtrade_origin/tests/persistence/test_trade_custom_data.py

167 lines
5.7 KiB
Python
Raw Normal View History

2024-02-20 19:25:12 +00:00
from copy import deepcopy
from unittest.mock import MagicMock
2024-02-13 06:10:11 +00:00
import pytest
2024-02-20 19:25:12 +00:00
from freqtrade.data.history.history_utils import get_timerange
from freqtrade.optimize.backtesting import Backtesting
2024-02-13 06:16:20 +00:00
from freqtrade.persistence import Trade, disable_database_use, enable_database_use
from freqtrade.persistence.custom_data import CustomDataWrapper
2024-05-12 13:08:40 +00:00
from tests.conftest import (
EXMS,
create_mock_trades_usdt,
generate_test_data,
get_patched_freqtradebot,
patch_exchange,
)
2024-02-13 06:10:11 +00:00
@pytest.mark.usefixtures("init_persistence")
2024-02-13 06:16:20 +00:00
@pytest.mark.parametrize("use_db", [True, False])
def test_trade_custom_data(fee, use_db):
if not use_db:
2024-05-12 14:04:01 +00:00
disable_database_use("5m")
2024-02-13 06:16:20 +00:00
Trade.reset_trades()
CustomDataWrapper.reset_custom_data()
2024-02-13 06:10:11 +00:00
2024-02-13 06:16:20 +00:00
create_mock_trades_usdt(fee, use_db=use_db)
trade1 = Trade.get_trades_proxy()[0]
if not use_db:
trade1.id = 1
2024-02-13 06:10:11 +00:00
assert trade1.get_all_custom_data() == []
2024-05-12 14:04:01 +00:00
trade1.set_custom_data("test_str", "test_value")
trade1.set_custom_data("test_int", 1)
trade1.set_custom_data("test_float", 1.55)
trade1.set_custom_data("test_bool", True)
trade1.set_custom_data("test_dict", {"test": "dict"})
2024-02-13 06:10:11 +00:00
2024-02-13 06:16:20 +00:00
assert len(trade1.get_all_custom_data()) == 5
2024-05-12 14:04:01 +00:00
assert trade1.get_custom_data("test_str") == "test_value"
trade1.set_custom_data("test_str", "test_value_updated")
assert trade1.get_custom_data("test_str") == "test_value_updated"
2024-02-13 06:10:11 +00:00
2024-05-12 14:04:01 +00:00
assert trade1.get_custom_data("test_int") == 1
assert isinstance(trade1.get_custom_data("test_int"), int)
2024-02-13 06:10:11 +00:00
2024-05-12 14:04:01 +00:00
assert trade1.get_custom_data("test_float") == 1.55
assert isinstance(trade1.get_custom_data("test_float"), float)
2024-02-13 06:10:11 +00:00
2024-05-12 14:04:01 +00:00
assert trade1.get_custom_data("test_bool") is True
assert isinstance(trade1.get_custom_data("test_bool"), bool)
2024-02-13 06:10:11 +00:00
2024-05-12 14:04:01 +00:00
assert trade1.get_custom_data("test_dict") == {"test": "dict"}
assert isinstance(trade1.get_custom_data("test_dict"), dict)
2024-02-22 18:01:33 +00:00
if not use_db:
enable_database_use()
2024-02-20 19:00:45 +00:00
def test_trade_custom_data_strategy_compat(mocker, default_conf_usdt, fee):
2024-05-12 14:04:01 +00:00
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}
2024-02-20 19:00:45 +00:00
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
create_mock_trades_usdt(fee)
2024-05-12 14:04:01 +00:00
trade1 = Trade.get_trades_proxy(pair="ADA/USDT")[0]
trade1.set_custom_data("test_str", "test_value")
trade1.set_custom_data("test_int", 1)
2024-02-20 19:00:45 +00:00
def custom_exit(pair, trade, **kwargs):
2024-05-12 14:04:01 +00:00
if pair == "ADA/USDT":
custom_val = trade.get_custom_data("test_str")
custom_val_i = trade.get_custom_data("test_int")
2024-02-20 19:00:45 +00:00
return f"{custom_val}_{custom_val_i}"
freqtrade.strategy.custom_exit = custom_exit
2024-05-12 14:04:01 +00:00
ff_spy = mocker.spy(freqtrade.strategy, "custom_exit")
2024-02-20 19:00:45 +00:00
trades = Trade.get_open_trades()
freqtrade.exit_positions(trades)
Trade.commit()
2024-05-12 14:04:01 +00:00
trade_after = Trade.get_trades_proxy(pair="ADA/USDT")[0]
assert trade_after.get_custom_data("test_str") == "test_value"
assert trade_after.get_custom_data("test_int") == 1
2024-02-20 19:00:45 +00:00
# 2 open pairs eligible for exit
assert ff_spy.call_count == 2
2024-05-12 14:04:01 +00:00
assert trade_after.exit_reason == "test_value_1"
2024-02-20 19:25:12 +00:00
def test_trade_custom_data_strategy_backtest_compat(mocker, default_conf_usdt, fee):
2024-05-12 14:04:01 +00:00
mocker.patch(f"{EXMS}.get_fee", fee)
2024-02-20 19:25:12 +00:00
mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=10)
2024-05-12 14:04:01 +00:00
mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float("inf"))
2024-02-20 19:25:12 +00:00
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))
2024-05-12 14:04:01 +00:00
mocker.patch("freqtrade.optimize.backtesting.Backtesting._run_funding_fees")
2024-02-20 19:25:12 +00:00
patch_exchange(mocker)
2024-05-12 14:04:01 +00:00
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}]
2024-02-20 19:25:12 +00:00
backtesting = Backtesting(default_conf_usdt)
2024-05-12 14:04:01 +00:00
df = generate_test_data(default_conf_usdt["timeframe"], 100, "2022-01-01 00:00:00+00:00")
2024-02-20 19:25:12 +00:00
2024-05-12 14:04:01 +00:00
pair_exp = "XRP/USDT:USDT"
2024-02-20 19:25:12 +00:00
def custom_exit(pair, trade, **kwargs):
2024-05-12 14:04:01 +00:00
custom_val = trade.get_custom_data("test_str")
custom_val_i = trade.get_custom_data("test_int", 0)
2024-02-20 19:25:12 +00:00
if pair == pair_exp:
2024-05-12 14:04:01 +00:00
trade.set_custom_data("test_str", "test_value")
trade.set_custom_data("test_int", custom_val_i + 1)
2024-02-20 19:25:12 +00:00
if custom_val_i >= 2:
return f"{custom_val}_{custom_val_i}"
backtesting._set_strategy(backtesting.strategylist[0])
2024-05-12 14:04:01 +00:00
processed = backtesting.strategy.advise_all_indicators(
{
pair_exp: df,
"BTC/USDT:USDT": df,
}
)
2024-02-20 19:25:12 +00:00
def fun(dataframe, *args, **kwargs):
2024-05-12 14:04:01 +00:00
dataframe.loc[dataframe.index == 50, "enter_long"] = 1
2024-02-20 19:25:12 +00:00
return dataframe
backtesting.strategy.advise_entry = fun
backtesting.strategy.leverage = MagicMock(return_value=1)
backtesting.strategy.custom_exit = custom_exit
2024-05-12 14:04:01 +00:00
ff_spy = mocker.spy(backtesting.strategy, "custom_exit")
2024-02-20 19:25:12 +00:00
min_date, max_date = get_timerange(processed)
result = backtesting.backtest(
processed=deepcopy(processed),
start_date=min_date,
end_date=max_date,
)
2024-05-12 14:04:01 +00:00
results = result["results"]
2024-02-20 19:25:12 +00:00
assert not results.empty
assert len(results) == 2
2024-05-12 14:04:01 +00:00
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"
2024-02-20 19:25:12 +00:00
assert ff_spy.call_count == 7
2024-02-22 18:01:33 +00:00
Backtesting.cleanup()