Merge remote-tracking branch 'upstream/develop' into feature/fetch-public-trades

This commit is contained in:
Joe Schr
2024-06-19 20:38:50 +02:00
65 changed files with 1276 additions and 824 deletions

View File

@@ -67,10 +67,10 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, use
"enter_tag_long_b",
],
"exit_reason": [
ExitType.ROI,
ExitType.EXIT_SIGNAL,
ExitType.STOP_LOSS,
ExitType.TRAILING_STOP_LOSS,
ExitType.ROI.value,
ExitType.EXIT_SIGNAL.value,
ExitType.STOP_LOSS.value,
ExitType.TRAILING_STOP_LOSS.value,
],
}
)

View File

@@ -7,7 +7,7 @@ from unittest.mock import MagicMock, Mock, PropertyMock, patch
import ccxt
import pytest
from numpy import NaN
from numpy import nan
from pandas import DataFrame, to_datetime
from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS
@@ -5014,7 +5014,7 @@ def test_get_max_leverage_from_margin(default_conf, mocker, pair, nominal_value,
(10, 0.0001, 2.0, 1.0, 0.002, 0.002),
(10, 0.0002, 2.0, 0.01, 0.004, 0.00004),
(10, 0.0002, 2.5, None, 0.005, None),
(10, 0.0002, NaN, None, 0.0, None),
(10, 0.0002, nan, None, 0.0, None),
],
)
def test_calculate_funding_fees(

View File

@@ -1650,11 +1650,11 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
]
args = get_args(args)
start_backtesting(args)
# 2 backtests, 4 tables
# 2 backtests, 6 tables (entry, exit, mixed - each 2x)
assert backtestmock.call_count == 2
assert text_table_mock.call_count == 4
assert strattable_mock.call_count == 1
assert tag_metrics_mock.call_count == 4
assert tag_metrics_mock.call_count == 6
assert strat_summary.call_count == 1
# check the logs, that will contain the backtest result
@@ -1709,7 +1709,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
"open_rate": [0.104445, 0.10302485],
"close_rate": [0.104969, 0.103541],
"is_short": [False, False],
"exit_reason": [ExitType.ROI, ExitType.ROI],
"exit_reason": [ExitType.ROI.value, ExitType.ROI.value],
}
)
result2 = pd.DataFrame(
@@ -1729,7 +1729,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
"open_rate": [0.104445, 0.10302485, 0.122541],
"close_rate": [0.104969, 0.103541, 0.123541],
"is_short": [False, False, False],
"exit_reason": [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS],
"exit_reason": [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value],
}
)
backtestmock = MagicMock(

View File

@@ -415,10 +415,10 @@ def test_hyperopt_format_results(hyperopt):
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"exit_reason": [
ExitType.ROI,
ExitType.STOP_LOSS,
ExitType.ROI,
ExitType.FORCE_EXIT,
ExitType.ROI.value,
ExitType.STOP_LOSS.value,
ExitType.ROI.value,
ExitType.FORCE_EXIT.value,
],
}
),
@@ -507,10 +507,10 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"exit_reason": [
ExitType.ROI,
ExitType.STOP_LOSS,
ExitType.ROI,
ExitType.FORCE_EXIT,
ExitType.ROI.value,
ExitType.STOP_LOSS.value,
ExitType.ROI.value,
ExitType.FORCE_EXIT.value,
],
}
),

View File

@@ -70,13 +70,13 @@ def test_text_table_bt_results():
)
result_str = (
"| Pair | Entries | Avg Profit % | Tot Profit BTC | "
"| Pair | Trades | Avg Profit % | Tot Profit BTC | "
"Tot Profit % | Avg Duration | Win Draw Loss Win% |\n"
"|---------+-----------+----------------+------------------+"
"|---------+----------+----------------+------------------+"
"----------------+----------------+-------------------------|\n"
"| ETH/BTC | 3 | 8.33 | 0.50000000 | "
"| ETH/BTC | 3 | 8.33 | 0.50000000 | "
"12.50 | 0:20:00 | 2 0 1 66.7 |\n"
"| TOTAL | 3 | 8.33 | 0.50000000 | "
"| TOTAL | 3 | 8.33 | 0.50000000 | "
"12.50 | 0:20:00 | 2 0 1 66.7 |"
)
@@ -116,10 +116,10 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmp_path):
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"exit_reason": [
ExitType.ROI,
ExitType.STOP_LOSS,
ExitType.ROI,
ExitType.FORCE_EXIT,
ExitType.ROI.value,
ExitType.STOP_LOSS.value,
ExitType.ROI.value,
ExitType.FORCE_EXIT.value,
],
}
),
@@ -183,10 +183,10 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmp_path):
"is_short": [False, False, False, False],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"exit_reason": [
ExitType.ROI,
ExitType.ROI,
ExitType.STOP_LOSS,
ExitType.FORCE_EXIT,
ExitType.ROI.value,
ExitType.ROI.value,
ExitType.STOP_LOSS.value,
ExitType.FORCE_EXIT.value,
],
}
),
@@ -444,7 +444,7 @@ def test_text_table_exit_reason():
"wins": [2, 0, 0],
"draws": [0, 0, 0],
"losses": [0, 0, 1],
"exit_reason": [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS],
"exit_reason": [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value],
}
)
@@ -509,13 +509,13 @@ def test_text_table_strategy(testdatadir):
bt_res_data_comparison = bt_res_data.pop("strategy_comparison")
result_str = (
"| Strategy | Entries | Avg Profit % | Tot Profit BTC |"
"| Strategy | Trades | Avg Profit % | Tot Profit BTC |"
" Tot Profit % | Avg Duration | Win Draw Loss Win% | Drawdown |\n"
"|----------------+-----------+----------------+------------------+"
"|----------------+----------+----------------+------------------+"
"----------------+----------------+-------------------------+-----------------------|\n"
"| StrategyTestV2 | 179 | 0.08 | 0.02608550 |"
"| StrategyTestV2 | 179 | 0.08 | 0.02608550 |"
" 260.85 | 3:40:00 | 170 0 9 95.0 | 0.00308222 BTC 8.67% |\n"
"| TestStrategy | 179 | 0.08 | 0.02608550 |"
"| TestStrategy | 179 | 0.08 | 0.02608550 |"
" 260.85 | 3:40:00 | 170 0 9 95.0 | 0.00308222 BTC 8.67% |"
)

View File

@@ -401,11 +401,11 @@ def test_load_dry_run(default_conf, mocker, config_value, expected, arglist) ->
assert validated_conf["runmode"] == (RunMode.DRY_RUN if expected else RunMode.LIVE)
def test_load_custom_strategy(default_conf, mocker) -> None:
def test_load_custom_strategy(default_conf, mocker, tmp_path) -> None:
default_conf.update(
{
"strategy": "CustomStrategy",
"strategy_path": "/tmp/strategies",
"strategy_path": f"{tmp_path}/strategies",
}
)
patched_configuration_load_config_file(mocker, default_conf)
@@ -415,7 +415,7 @@ def test_load_custom_strategy(default_conf, mocker) -> None:
validated_conf = configuration.load_config()
assert validated_conf.get("strategy") == "CustomStrategy"
assert validated_conf.get("strategy_path") == "/tmp/strategies"
assert validated_conf.get("strategy_path") == f"{tmp_path}/strategies"
def test_show_info(default_conf, mocker, caplog) -> None:
@@ -469,7 +469,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
assert "timerange" not in config
def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> None:
def test_setup_configuration_with_arguments(mocker, default_conf, caplog, tmp_path) -> None:
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch("freqtrade.configuration.configuration.create_datadir", lambda c, x: x)
mocker.patch(
@@ -485,7 +485,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
"--datadir",
"/foo/bar",
"--userdir",
"/tmp/freqtrade",
f"{tmp_path}/freqtrade",
"--timeframe",
"1m",
"--enable-position-stacking",
@@ -509,7 +509,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
assert "pair_whitelist" in config["exchange"]
assert "datadir" in config
assert log_has("Using data directory: {} ...".format("/foo/bar"), caplog)
assert log_has("Using user-data directory: {} ...".format(Path("/tmp/freqtrade")), caplog)
assert log_has(f"Using user-data directory: {tmp_path / 'freqtrade'} ...", caplog)
assert "user_data_dir" in config
assert "timeframe" in config

View File

@@ -24,16 +24,16 @@ def test_create_datadir(mocker, default_conf, caplog) -> None:
assert log_has("Created data directory: /foo/bar", caplog)
def test_create_userdata_dir(mocker, default_conf, caplog) -> None:
def test_create_userdata_dir(mocker, tmp_path, caplog) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
md = mocker.patch.object(Path, "mkdir", MagicMock())
x = create_userdata_dir("/tmp/bar", create_dir=True)
x = create_userdata_dir(tmp_path / "bar", create_dir=True)
assert md.call_count == 10
assert md.call_args[1]["parents"] is False
assert log_has(f'Created user-data directory: {Path("/tmp/bar")}', caplog)
assert log_has(f'Created user-data directory: {tmp_path / "bar"}', caplog)
assert isinstance(x, Path)
assert str(x) == str(Path("/tmp/bar"))
assert str(x) == str(tmp_path / "bar")
def test_create_userdata_dir_and_chown(mocker, tmp_path, caplog) -> None:
@@ -54,63 +54,57 @@ def test_create_userdata_dir_and_chown(mocker, tmp_path, caplog) -> None:
del os.environ["FT_APP_ENV"]
def test_create_userdata_dir_exists(mocker, default_conf, caplog) -> None:
def test_create_userdata_dir_exists(mocker, tmp_path) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
md = mocker.patch.object(Path, "mkdir", MagicMock())
create_userdata_dir("/tmp/bar")
create_userdata_dir(f"{tmp_path}/bar")
assert md.call_count == 0
def test_create_userdata_dir_exists_exception(mocker, default_conf, caplog) -> None:
def test_create_userdata_dir_exists_exception(mocker, tmp_path) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
md = mocker.patch.object(Path, "mkdir", MagicMock())
with pytest.raises(
OperationalException, match=r"Directory `.{1,2}tmp.{1,2}bar` does not exist.*"
):
create_userdata_dir("/tmp/bar", create_dir=False)
with pytest.raises(OperationalException, match=r"Directory `.*.{1,2}bar` does not exist.*"):
create_userdata_dir(f"{tmp_path}/bar", create_dir=False)
assert md.call_count == 0
def test_copy_sample_files(mocker, default_conf, caplog) -> None:
def test_copy_sample_files(mocker, tmp_path) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
copymock = mocker.patch("shutil.copy", MagicMock())
copy_sample_files(Path("/tmp/bar"))
copy_sample_files(Path(f"{tmp_path}/bar"))
assert copymock.call_count == 3
assert copymock.call_args_list[0][0][1] == str(
Path("/tmp/bar") / "strategies/sample_strategy.py"
)
assert copymock.call_args_list[0][0][1] == str(tmp_path / "bar/strategies/sample_strategy.py")
assert copymock.call_args_list[1][0][1] == str(
Path("/tmp/bar") / "hyperopts/sample_hyperopt_loss.py"
tmp_path / "bar/hyperopts/sample_hyperopt_loss.py"
)
assert copymock.call_args_list[2][0][1] == str(
Path("/tmp/bar") / "notebooks/strategy_analysis_example.ipynb"
tmp_path / "bar/notebooks/strategy_analysis_example.ipynb"
)
def test_copy_sample_files_errors(mocker, default_conf, caplog) -> None:
def test_copy_sample_files_errors(mocker, tmp_path, caplog) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
mocker.patch("shutil.copy", MagicMock())
with pytest.raises(
OperationalException, match=r"Directory `.{1,2}tmp.{1,2}bar` does not exist\."
):
copy_sample_files(Path("/tmp/bar"))
with pytest.raises(OperationalException, match=r"Directory `.*.{1,2}bar` does not exist\."):
copy_sample_files(Path(f"{tmp_path}/bar"))
mocker.patch.object(Path, "is_dir", MagicMock(side_effect=[True, False]))
with pytest.raises(
OperationalException,
match=r"Directory `.{1,2}tmp.{1,2}bar.{1,2}strategies` does not exist\.",
match=r"Directory `.*.{1,2}bar.{1,2}strategies` does not exist\.",
):
copy_sample_files(Path("/tmp/bar"))
copy_sample_files(Path(f"{tmp_path}/bar"))
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
copy_sample_files(Path("/tmp/bar"))
copy_sample_files(Path(f"{tmp_path}/bar"))
assert log_has_re(r"File `.*` exists already, not deploying sample file\.", caplog)
caplog.clear()
copy_sample_files(Path("/tmp/bar"), overwrite=True)
copy_sample_files(Path(f"{tmp_path}/bar"), overwrite=True)
assert log_has_re(r"File `.*` exists already, overwriting\.", caplog)