Merge branch 'develop' into binance-public-data

This commit is contained in:
Meng Xiangzhuo
2024-11-13 12:14:50 +08:00
174 changed files with 5221 additions and 2809 deletions
+41 -13
View File
@@ -1,5 +1,6 @@
import json
import re
import shutil
from datetime import datetime, timedelta
from io import BytesIO
from pathlib import Path
@@ -44,7 +45,7 @@ from freqtrade.enums import RunMode
from freqtrade.exceptions import OperationalException
from freqtrade.persistence.models import init_db
from freqtrade.persistence.pairlock_middleware import PairLocks
from freqtrade.util import dt_floor_day, dt_now, dt_utc
from freqtrade.util import dt_utc
from tests.conftest import (
CURRENT_TEST_STRATEGY,
EXMS,
@@ -571,7 +572,7 @@ def test_create_datadir_failed(caplog):
assert log_has("`create-userdir` requires --userdir to be set.", caplog)
def test_create_datadir(caplog, mocker):
def test_create_datadir(mocker):
cud = mocker.patch(
"freqtrade.configuration.directory_operations.create_userdata_dir", MagicMock()
)
@@ -585,26 +586,46 @@ def test_create_datadir(caplog, mocker):
assert csf.call_count == 1
def test_start_new_strategy(mocker, caplog):
wt_mock = mocker.patch.object(Path, "write_text", MagicMock())
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
def test_start_new_strategy(caplog, user_dir):
strategy_dir = user_dir / "strategies"
strategy_dir.mkdir(parents=True, exist_ok=True)
assert strategy_dir.is_dir()
args = ["new-strategy", "--strategy", "CoolNewStrategy"]
start_new_strategy(get_args(args))
assert strategy_dir.exists()
assert (strategy_dir / "CoolNewStrategy.py").exists()
assert wt_mock.call_count == 1
assert "CoolNewStrategy" in wt_mock.call_args_list[0][0][0]
assert log_has_re("Writing strategy to .*", caplog)
mocker.patch("freqtrade.configuration.setup_utils_configuration")
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
with pytest.raises(
OperationalException, match=r".* already exists. Please choose another Strategy Name\."
):
start_new_strategy(get_args(args))
args = ["new-strategy", "--strategy", "CoolNewStrategy", "--strategy-path", str(user_dir)]
start_new_strategy(get_args(args))
assert (user_dir / "CoolNewStrategy.py").exists()
def test_start_new_strategy_no_arg(mocker, caplog):
# strategy-path that doesn't exist
args = [
"new-strategy",
"--strategy",
"CoolNewStrategy",
"--strategy-path",
str(user_dir / "nonexistent"),
]
start_new_strategy(get_args(args))
assert (user_dir / "CoolNewStrategy.py").exists()
assert log_has_re("Creating strategy directory .*", caplog)
assert (user_dir / "nonexistent").is_dir()
assert (user_dir / "nonexistent" / "CoolNewStrategy.py").exists()
shutil.rmtree(str(user_dir))
def test_start_new_strategy_no_arg():
args = [
"new-strategy",
]
@@ -757,7 +778,13 @@ def test_download_data_keyboardInterrupt(mocker, markets):
assert dl_mock.call_count == 1
def test_download_data_timerange(mocker, markets):
@pytest.mark.parametrize("time", ["00:00", "00:03", "00:30", "23:56"])
@pytest.mark.parametrize(
"tzoffset",
["00:00", "+01:00", "-01:00", "+05:00", "-05:00"],
)
def test_download_data_timerange(mocker, markets, time_machine, time, tzoffset):
time_machine.move_to(f"2024-11-01 {time}:00 {tzoffset}")
dl_mock = mocker.patch(
"freqtrade.data.history.history_utils.refresh_backtest_ohlcv_data",
MagicMock(return_value=["ETH/BTC", "XRP/BTC"]),
@@ -797,8 +824,9 @@ def test_download_data_timerange(mocker, markets):
start_download_data(pargs)
assert dl_mock.call_count == 1
# 20days ago
days_ago = dt_floor_day(dt_now() - timedelta(days=20)).timestamp()
assert dl_mock.call_args_list[0][1]["timerange"].startts == days_ago
days_ago = datetime.now() - timedelta(days=20)
days_ago = dt_utc(days_ago.year, days_ago.month, days_ago.day)
assert dl_mock.call_args_list[0][1]["timerange"].startts == days_ago.timestamp()
dl_mock.reset_mock()
args = [
+6 -7
View File
@@ -5,7 +5,6 @@ import re
from copy import deepcopy
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Optional
from unittest.mock import MagicMock, Mock, PropertyMock
import numpy as np
@@ -124,7 +123,7 @@ def get_args(args):
return Arguments(args).get_parsed_arg()
def generate_trades_history(n_rows, start_date: Optional[datetime] = None, days=5):
def generate_trades_history(n_rows, start_date: datetime | None = None, days=5):
np.random.seed(42)
if not start_date:
start_date = datetime(2020, 1, 1, tzinfo=timezone.utc)
@@ -206,7 +205,7 @@ def generate_test_data_raw(timeframe: str, size: int, start: str = "2020-07-05",
"""Generates data in the ohlcv format used by ccxt"""
df = generate_test_data(timeframe, size, start, random_seed)
df["date"] = df.loc[:, "date"].astype(np.int64) // 1000 // 1000
return list(list(x) for x in zip(*(df[x].values.tolist() for x in df.columns)))
return list(list(x) for x in zip(*(df[x].values.tolist() for x in df.columns), strict=False))
# Source: https://stackoverflow.com/questions/29881236/how-to-mock-asyncio-coroutines
@@ -363,8 +362,8 @@ def patch_get_signal(
exit_long=False,
enter_short=False,
exit_short=False,
enter_tag: Optional[str] = None,
exit_tag: Optional[str] = None,
enter_tag: str | None = None,
exit_tag: str | None = None,
) -> None:
"""
:param mocker: mocker to patch IStrategy class
@@ -395,7 +394,7 @@ def patch_get_signal(
freqtrade.exchange.refresh_latest_ohlcv = lambda p: None
def create_mock_trades(fee, is_short: Optional[bool] = False, use_db: bool = True):
def create_mock_trades(fee, is_short: bool | None = False, use_db: bool = True):
"""
Create some fake trades ...
:param is_short: Optional bool, None creates a mix of long and short trades.
@@ -474,7 +473,7 @@ def create_mock_trades_with_leverage(fee, use_db: bool = True):
Trade.session.flush()
def create_mock_trades_usdt(fee, is_short: Optional[bool] = False, use_db: bool = True):
def create_mock_trades_usdt(fee, is_short: bool | None = False, use_db: bool = True):
"""
Create some fake trades ...
"""
+4 -4
View File
@@ -503,7 +503,7 @@ def test_calculate_max_drawdown2():
]
dates = [dt_utc(2020, 1, 1) + timedelta(days=i) for i in range(len(values))]
df = DataFrame(zip(values, dates), columns=["profit", "open_date"])
df = DataFrame(zip(values, dates, strict=False), columns=["profit", "open_date"])
# sort by profit and reset index
df = df.sort_values("profit").reset_index(drop=True)
df1 = df.copy()
@@ -522,11 +522,11 @@ def test_calculate_max_drawdown2():
assert drawdown.drawdown_abs == 0.091755
assert pytest.approx(drawdown.relative_account_drawdown) == 0.32129575
df = DataFrame(zip(values[:5], dates[:5]), columns=["profit", "open_date"])
df = DataFrame(zip(values[:5], dates[:5], strict=False), columns=["profit", "open_date"])
with pytest.raises(ValueError, match="No losing trade, therefore no drawdown."):
calculate_max_drawdown(df, date_col="open_date", value_col="profit")
df1 = DataFrame(zip(values[:5], dates[:5]), columns=["profit", "open_date"])
df1 = DataFrame(zip(values[:5], dates[:5], strict=False), columns=["profit", "open_date"])
df1.loc[:, "profit"] = df1["profit"] * -1
# No winning trade ...
drawdown = calculate_max_drawdown(df1, date_col="open_date", value_col="profit")
@@ -548,7 +548,7 @@ def test_calculate_max_drawdown_abs(profits, relative, highd, lowdays, result, r
"""
init_date = datetime(2020, 1, 1, tzinfo=timezone.utc)
dates = [init_date + timedelta(days=i) for i in range(len(profits))]
df = DataFrame(zip(profits, dates), columns=["profit_abs", "open_date"])
df = DataFrame(zip(profits, dates, strict=False), columns=["profit_abs", "open_date"])
# sort by profit and reset index
df = df.sort_values("profit_abs").reset_index(drop=True)
df1 = df.copy()
-1
View File
@@ -1069,7 +1069,6 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name, leverag
assert order["type"] == "limit"
assert order["symbol"] == "ETH/BTC"
assert order["amount"] == 1
assert order["leverage"] == leverage
assert order["cost"] == 1 * 200
+5 -4
View File
@@ -3483,16 +3483,17 @@ def test_locked_pairs(
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
)
trade.close(ticker_usdt_sell_down()["bid"])
assert freqtrade.strategy.is_pair_locked(trade.pair, side="*")
assert not freqtrade.strategy.is_pair_locked(trade.pair, side="*")
# Both sides are locked
assert freqtrade.strategy.is_pair_locked(trade.pair, side="long")
assert freqtrade.strategy.is_pair_locked(trade.pair, side="short")
assert freqtrade.strategy.is_pair_locked(trade.pair, side="long") != is_short
assert freqtrade.strategy.is_pair_locked(trade.pair, side="short") == is_short
# reinit - should buy other pair.
caplog.clear()
freqtrade.enter_positions()
direction = "short" if is_short else "long"
assert log_has_re(rf"Pair {trade.pair} \* is locked.*", caplog)
assert log_has_re(rf"Pair {trade.pair} {direction} is locked.*", caplog)
@pytest.mark.parametrize("is_short", [False, True])
+7 -7
View File
@@ -1,5 +1,5 @@
from datetime import timedelta
from typing import NamedTuple, Optional
from typing import NamedTuple
from pandas import DataFrame
@@ -20,7 +20,7 @@ class BTrade(NamedTuple):
exit_reason: ExitType
open_tick: int
close_tick: int
enter_tag: Optional[str] = None
enter_tag: str | None = None
is_short: bool = False
@@ -36,15 +36,15 @@ class BTContainer(NamedTuple):
profit_perc: float
trailing_stop: bool = False
trailing_only_offset_is_reached: bool = False
trailing_stop_positive: Optional[float] = None
trailing_stop_positive: float | None = None
trailing_stop_positive_offset: float = 0.0
use_exit_signal: bool = False
use_custom_stoploss: bool = False
custom_entry_price: Optional[float] = None
custom_exit_price: Optional[float] = None
custom_entry_price: float | None = None
custom_exit_price: float | None = None
leverage: float = 1.0
timeout: Optional[int] = None
adjust_entry_price: Optional[float] = None
timeout: int | None = None
adjust_entry_price: float | None = None
def _get_frame_time_from_offset(offset):
+67
View File
@@ -1121,6 +1121,70 @@ tc53 = BTContainer(
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2, is_short=True)],
)
# Test 54: Switch position from long to short
tc54 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5050, 4950, 5000, 6172, 1, 0, 0, 0],
[1, 5000, 5000, 4951, 5000, 6172, 0, 0, 0, 0],
[2, 4910, 5150, 4910, 5100, 6172, 0, 0, 1, 0], # Enter short signal being ignored
[3, 5100, 5100, 4950, 4950, 6172, 0, 1, 1, 0], # exit - re-enter short
[4, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 1],
[5, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 0],
],
stop_loss=-0.10,
roi={"0": 0.10},
profit_perc=0.00,
use_exit_signal=True,
trades=[
BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=False),
BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=4, close_tick=5, is_short=True),
],
)
# Test 55: Switch position from short to long
tc55 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5050, 4950, 5000, 6172, 0, 0, 1, 0],
[1, 5000, 5000, 4951, 5000, 6172, 1, 0, 0, 0], # Enter long signal being ignored
[2, 4910, 5150, 4910, 5100, 6172, 1, 0, 0, 1], # Exit - reenter long
[3, 5100, 5100, 4950, 4950, 6172, 0, 0, 0, 0],
[4, 5000, 5100, 4950, 4950, 6172, 0, 1, 0, 0],
[5, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 0],
],
stop_loss=-0.10,
roi={"0": 0.10},
profit_perc=-0.04,
use_exit_signal=True,
trades=[
BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=3, is_short=True),
BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=3, close_tick=5, is_short=False),
],
)
# Test 56: Switch position from long to short
tc56 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5050, 4950, 5000, 6172, 1, 0, 0, 0],
[1, 5000, 5000, 4951, 5000, 6172, 0, 0, 0, 0],
[2, 4910, 5150, 4910, 5100, 6172, 0, 0, 1, 0], # exit on stoploss - re-enter short
[3, 5100, 5100, 4888, 4950, 6172, 0, 0, 0, 0],
[4, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 1],
[5, 5000, 5100, 4950, 4950, 6172, 0, 0, 0, 0],
],
stop_loss=-0.02,
roi={"0": 0.10},
profit_perc=-0.0,
use_exit_signal=True,
trades=[
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3, is_short=False),
BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=3, close_tick=5, is_short=True),
],
)
TESTS = [
tc0,
tc1,
@@ -1176,6 +1240,9 @@ TESTS = [
tc51,
tc52,
tc53,
tc54,
tc55,
tc56,
]
+127 -16
View File
@@ -189,7 +189,6 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
"--timeframe",
"1m",
"--enable-position-stacking",
"--disable-max-market-positions",
"--timerange",
":100",
"--export-filename",
@@ -214,10 +213,6 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
assert "position_stacking" in config
assert log_has("Parameter --enable-position-stacking detected ...", caplog)
assert "use_max_market_positions" in config
assert log_has("Parameter --disable-max-market-positions detected ...", caplog)
assert log_has("max_open_trades set to unlimited ...", caplog)
assert "timerange" in config
assert log_has("Parameter --timerange detected: {} ...".format(config["timerange"]), caplog)
@@ -1681,6 +1676,131 @@ def test_backtest_multi_pair_detail(
assert len(evaluate_result_multi(results["results"], "5m", 1)) == 0
@pytest.mark.parametrize("use_detail", [True, False])
@pytest.mark.parametrize("pair", ["ADA/USDT", "LTC/USDT"])
@pytest.mark.parametrize("tres", [0, 20, 30])
def test_backtest_multi_pair_detail_simplified(
default_conf_usdt,
fee,
mocker,
tres,
pair,
use_detail,
):
"""
literally the same as test_backtest_multi_pair_detail
but with an "always enter" strategy, exiting after about half of the candle duration.
"""
def _always_buy(dataframe, metadata):
"""
Buy every xth candle - sell every other xth -2 (hold on to pairs a bit)
"""
dataframe["enter_long"] = 1
dataframe["enter_short"] = 0
dataframe["exit_short"] = 0
return dataframe
def custom_exit(
trade: Trade,
current_time: datetime,
**kwargs,
) -> str | bool | None:
# Exit within the same candle.
if (trade.open_date_utc + timedelta(minutes=20)) < current_time:
return "exit after 20 minutes"
default_conf_usdt.update(
{
"runmode": "backtest",
"stoploss": -1.0,
"minimal_roi": {"0": 100},
}
)
if use_detail:
default_conf_usdt["timeframe_detail"] = "5m"
mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=0.00001)
mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float("inf"))
mocker.patch(f"{EXMS}.get_fee", fee)
patch_exchange(mocker)
raw_candles_5m = generate_test_data("5m", 1000, "2022-01-03 12:00:00+00:00")
raw_candles = ohlcv_fill_up_missing_data(raw_candles_5m, "1h", "dummy")
pairs = ["ADA/USDT", "DASH/USDT", "ETH/USDT", "LTC/USDT", "NXT/USDT"]
data = {pair: raw_candles for pair in pairs}
detail_data = {pair: raw_candles_5m for pair in pairs}
# Only use 500 lines to increase performance
data = trim_dictlist(data, -200)
# Remove data for one pair from the beginning of the data
if tres > 0:
data[pair] = data[pair][tres:].reset_index()
default_conf_usdt["timeframe"] = "1h"
default_conf_usdt["max_open_trades"] = 3
backtesting = Backtesting(default_conf_usdt)
vr_spy = mocker.spy(backtesting, "validate_row")
bl_spy = mocker.spy(backtesting, "backtest_loop")
backtesting.detail_data = detail_data
backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.bot_loop_start = MagicMock()
backtesting.strategy.advise_entry = _always_buy # Override
backtesting.strategy.advise_exit = _always_buy # Override
backtesting.strategy.custom_exit = custom_exit # Override
processed = backtesting.strategy.advise_all_indicators(data)
min_date, max_date = get_timerange(processed)
backtest_conf = {
"processed": deepcopy(processed),
"start_date": min_date,
"end_date": max_date,
}
results = backtesting.backtest(**backtest_conf)
# bot_loop_start is called once per candle.
# assert backtesting.strategy.bot_loop_start.call_count == 83
# Validated row once per candle and pair
assert vr_spy.call_count == 415
if use_detail:
# Backtest loop is called once per candle per pair
# Exact numbers depend on trade state - but should be around 3_800
assert bl_spy.call_count > 3_350
assert bl_spy.call_count < 3_800
else:
assert bl_spy.call_count < 995
# Make sure we have parallel trades
assert len(evaluate_result_multi(results["results"], "1h", 2)) > 0
# make sure we don't have trades with more than configured max_open_trades
assert len(evaluate_result_multi(results["results"], "1h", 3)) == 0
# # Cached data correctly removed amounts
offset = 1 if tres == 0 else 0
removed_candles = len(data[pair]) - offset
assert len(backtesting.dataprovider.get_analyzed_dataframe(pair, "1h")[0]) == removed_candles
assert (
len(backtesting.dataprovider.get_analyzed_dataframe("NXT/USDT", "1h")[0])
== len(data["NXT/USDT"]) - 1
)
backtesting.strategy.max_open_trades = 1
backtesting.config.update({"max_open_trades": 1})
backtest_conf = {
"processed": deepcopy(processed),
"start_date": min_date,
"end_date": max_date,
}
results = backtesting.backtest(**backtest_conf)
assert len(evaluate_result_multi(results["results"], "1h", 1)) == 0
@pytest.mark.parametrize("use_detail", [True, False])
def test_backtest_multi_pair_long_short_switch(
default_conf_usdt,
@@ -1774,7 +1894,7 @@ def test_backtest_multi_pair_long_short_switch(
if use_detail:
# Backtest loop is called once per candle per pair
assert bl_spy.call_count == 1071
assert bl_spy.call_count == 1523
else:
assert bl_spy.call_count == 479
@@ -1784,7 +1904,7 @@ def test_backtest_multi_pair_long_short_switch(
assert len(evaluate_result_multi(results["results"], "5m", 1)) == 0
# Expect 26 results initially
assert len(results["results"]) == 30
assert len(results["results"]) == 53
def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
@@ -1811,14 +1931,12 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
"--timerange",
"1510694220-1510700340",
"--enable-position-stacking",
"--disable-max-market-positions",
]
args = get_args(args)
start_backtesting(args)
# check the logs, that will contain the backtest result
exists = [
"Parameter -i/--timeframe detected ... Using timeframe: 1m ...",
"Ignoring max_open_trades (--disable-max-market-positions was used) ...",
"Parameter --timerange detected: 1510694220-1510700340 ...",
f"Using data directory: {testdatadir} ...",
"Loading data from 2017-11-14 20:57:00 up to 2017-11-14 22:59:00 (0 days).",
@@ -1892,7 +2010,6 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
"--timerange",
"1510694220-1510700340",
"--enable-position-stacking",
"--disable-max-market-positions",
"--strategy-list",
CURRENT_TEST_STRATEGY,
"StrategyTestV2",
@@ -1909,7 +2026,6 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
# check the logs, that will contain the backtest result
exists = [
"Parameter -i/--timeframe detected ... Using timeframe: 1m ...",
"Ignoring max_open_trades (--disable-max-market-positions was used) ...",
"Parameter --timerange detected: 1510694220-1510700340 ...",
f"Using data directory: {testdatadir} ...",
"Loading data from 2017-11-14 20:57:00 up to 2017-11-14 22:59:00 (0 days).",
@@ -2030,7 +2146,6 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
"--timerange",
"1510694220-1510700340",
"--enable-position-stacking",
"--disable-max-market-positions",
"--breakdown",
"day",
"--strategy-list",
@@ -2043,7 +2158,6 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
# check the logs, that will contain the backtest result
exists = [
"Parameter -i/--timeframe detected ... Using timeframe: 1m ...",
"Ignoring max_open_trades (--disable-max-market-positions was used) ...",
"Parameter --timerange detected: 1510694220-1510700340 ...",
f"Using data directory: {testdatadir} ...",
"Loading data from 2017-11-14 20:57:00 up to 2017-11-14 22:59:00 (0 days).",
@@ -2468,7 +2582,6 @@ def test_backtest_start_multi_strat_caching(
"--timerange",
"1510694220-1510700340",
"--enable-position-stacking",
"--disable-max-market-positions",
"--cache",
cache,
"--strategy-list",
@@ -2495,7 +2608,6 @@ def test_backtest_start_multi_strat_caching(
exists = [
"Running backtesting for Strategy StrategyTestV2",
"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:59:00 (0 days).",
]
elif run_id == "2" and min_backtest_date < start_time:
@@ -2508,7 +2620,6 @@ def test_backtest_start_multi_strat_caching(
exists = [
"Reusing result of previous backtest for StrategyTestV2",
"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:59:00 (0 days).",
]
assert backtestmock.call_count == 1
+186 -150
View File
@@ -14,7 +14,7 @@ from freqtrade.data.history import load_data
from freqtrade.enums import ExitType, RunMode
from freqtrade.exceptions import OperationalException
from freqtrade.optimize.hyperopt import Hyperopt
from freqtrade.optimize.hyperopt_auto import HyperOptAuto
from freqtrade.optimize.hyperopt.hyperopt_auto import HyperOptAuto
from freqtrade.optimize.hyperopt_tools import HyperoptTools
from freqtrade.optimize.optimize_reports import generate_strategy_stats
from freqtrade.optimize.space import SKDecimal
@@ -102,7 +102,6 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
"--timerange",
":100",
"--enable-position-stacking",
"--disable-max-market-positions",
"--epochs",
"1000",
"--spaces",
@@ -126,10 +125,6 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
assert "position_stacking" in config
assert log_has("Parameter --enable-position-stacking detected ...", caplog)
assert "use_max_market_positions" in config
assert log_has("Parameter --disable-max-market-positions detected ...", caplog)
assert log_has("max_open_trades set to unlimited ...", caplog)
assert "timerange" in config
assert log_has("Parameter --timerange detected: {} ...".format(config["timerange"]), caplog)
@@ -227,7 +222,7 @@ def test_start_no_data(mocker, hyperopt_conf, tmp_path) -> None:
patched_configuration_load_config_file(mocker, hyperopt_conf)
mocker.patch("freqtrade.data.history.load_pair_history", MagicMock(return_value=pd.DataFrame))
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -320,12 +315,17 @@ def test_roi_table_generation(hyperopt) -> None:
"roi_p3": 3,
}
assert hyperopt.custom_hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0}
assert hyperopt.hyperopter.custom_hyperopt.generate_roi_table(params) == {
0: 6,
15: 3,
25: 1,
30: 0,
}
def test_params_no_optimize_details(hyperopt) -> None:
hyperopt.config["spaces"] = ["buy"]
res = hyperopt._get_no_optimize_details()
hyperopt.hyperopter.config["spaces"] = ["buy"]
res = hyperopt.hyperopter._get_no_optimize_details()
assert isinstance(res, dict)
assert "trailing" in res
assert res["trailing"]["trailing_stop"] is False
@@ -338,21 +338,23 @@ def test_params_no_optimize_details(hyperopt) -> None:
def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
# Dummy-reduce points to ensure scikit-learn is forced to generate new values
mocker.patch("freqtrade.optimize.hyperopt.INITIAL_POINTS", 2)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.INITIAL_POINTS", 2)
parallel = mocker.patch(
"freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel",
@@ -372,8 +374,8 @@ def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
del hyperopt_conf["timeframe"]
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -384,10 +386,12 @@ def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
# Should be called for historical candle data
assert dumper.call_count == 1
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
assert hasattr(hyperopt.backtesting, "_position_stacking")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_entry")
assert (
hyperopt.hyperopter.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
)
assert hasattr(hyperopt.hyperopter.backtesting, "_position_stacking")
def test_hyperopt_format_results(hyperopt):
@@ -466,7 +470,7 @@ def test_hyperopt_format_results(hyperopt):
def test_populate_indicators(hyperopt, testdatadir) -> None:
data = load_data(testdatadir, "1m", ["UNITTEST/BTC"], fill_up_missing=True)
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
dataframes = hyperopt.hyperopter.backtesting.strategy.advise_all_indicators(data)
dataframe = dataframes["UNITTEST/BTC"]
# Check if some indicators are generated. We will not test all of them
@@ -526,15 +530,20 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
"final_balance": 1000,
}
mocker.patch("freqtrade.optimize.hyperopt.Backtesting.backtest", return_value=backtest_result)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.Backtesting.backtest",
return_value=backtest_result,
)
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
return_value=(dt_utc(2017, 12, 10), dt_utc(2017, 12, 13)),
)
patch_exchange(mocker)
mocker.patch.object(Path, "open")
mocker.patch("freqtrade.configuration.config_validation.validate_config_schema")
mocker.patch("freqtrade.optimize.hyperopt.load", return_value={"XRP/BTC": None})
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.load", return_value={"XRP/BTC": None}
)
optimizer_param = {
"buy_plusdi": 0.02,
@@ -594,10 +603,12 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
}
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.min_date = dt_utc(2017, 12, 10)
hyperopt.max_date = dt_utc(2017, 12, 13)
hyperopt.init_spaces()
generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values()))
hyperopt.hyperopter.min_date = dt_utc(2017, 12, 10)
hyperopt.hyperopter.max_date = dt_utc(2017, 12, 13)
hyperopt.hyperopter.init_spaces()
generate_optimizer_value = hyperopt.hyperopter.generate_optimizer(
list(optimizer_param.values())
)
assert generate_optimizer_value == response_expected
@@ -608,8 +619,8 @@ def test_clean_hyperopt(mocker, hyperopt_conf, caplog):
"freqtrade.strategy.hyper.HyperStrategyMixin.load_params_from_file",
MagicMock(return_value={}),
)
mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True))
unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.Path.unlink", MagicMock())
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.Path.is_file", MagicMock(return_value=True))
unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.hyperopt.Path.unlink", MagicMock())
h = Hyperopt(hyperopt_conf)
assert unlinkmock.call_count == 2
@@ -617,17 +628,19 @@ def test_clean_hyperopt(mocker, hyperopt_conf, caplog):
def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -663,8 +676,8 @@ def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None:
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -682,16 +695,18 @@ def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None:
def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -719,8 +734,8 @@ def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None:
hyperopt_conf.update({"print_json": True})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -737,16 +752,18 @@ def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None:
def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -775,8 +792,8 @@ def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -790,16 +807,18 @@ def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -821,8 +840,8 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
hyperopt_conf.update({"spaces": "roi stoploss"})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -833,21 +852,23 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
assert dumper.call_count == 1
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
assert hasattr(hyperopt.backtesting, "_position_stacking")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_entry")
assert (
hyperopt.hyperopter.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
)
assert hasattr(hyperopt.hyperopter.backtesting, "_position_stacking")
def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None:
mocker.patch("freqtrade.optimize.hyperopt.dump", MagicMock())
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump", MagicMock())
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -860,34 +881,37 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None:
)
mocker.patch(
"freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space", return_value=[]
"freqtrade.optimize.hyperopt.hyperopt_auto.HyperOptAuto._generate_indicator_space",
return_value=[],
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
with pytest.raises(OperationalException, match=r"The 'protection' space is included into *"):
hyperopt.init_spaces()
hyperopt.hyperopter.init_spaces()
hyperopt.config["hyperopt_ignore_missing_space"] = True
caplog.clear()
hyperopt.init_spaces()
hyperopt.hyperopter.init_spaces()
assert log_has_re(r"The 'protection' space is included into *", caplog)
assert hyperopt.protection_space == []
assert hyperopt.hyperopter.protection_space == []
def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -909,8 +933,8 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
hyperopt_conf.update({"spaces": "buy"})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -921,23 +945,27 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
assert dumper.called
assert dumper.call_count == 1
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
assert hasattr(hyperopt.backtesting, "_position_stacking")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_entry")
assert (
hyperopt.hyperopter.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
)
assert hasattr(hyperopt.hyperopter.backtesting, "_position_stacking")
def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
dumper = mocker.patch("freqtrade.optimize.hyperopt.dump")
dumper = mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump")
dumper2 = mocker.patch("freqtrade.optimize.hyperopt.Hyperopt._save_result")
mocker.patch("freqtrade.optimize.hyperopt.calculate_market_change", return_value=1.5)
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.hyperopt.hyperopt_optimizer.calculate_market_change", return_value=1.5
)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
@@ -963,8 +991,8 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.start()
@@ -975,10 +1003,12 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
assert dumper.called
assert dumper.call_count == 1
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
assert hasattr(hyperopt.backtesting, "_position_stacking")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.hyperopter.backtesting.strategy, "advise_entry")
assert (
hyperopt.hyperopter.backtesting.strategy.max_open_trades == hyperopt_conf["max_open_trades"]
)
assert hasattr(hyperopt.hyperopter.backtesting, "_position_stacking")
@pytest.mark.parametrize(
@@ -990,18 +1020,19 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
],
)
def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None:
mocker.patch("freqtrade.optimize.hyperopt.dump", MagicMock())
mocker.patch("freqtrade.optimize.hyperopt.file_dump_json")
mocker.patch("freqtrade.optimize.hyperopt.hyperopt_optimizer.dump", MagicMock())
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.file_dump_json")
mocker.patch(
"freqtrade.optimize.backtesting.Backtesting.load_bt_data",
MagicMock(return_value=(MagicMock(), None)),
)
mocker.patch(
"freqtrade.optimize.hyperopt.get_timerange",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.get_timerange",
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))),
)
mocker.patch(
"freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space", return_value=[]
"freqtrade.optimize.hyperopt.hyperopt_auto.HyperOptAuto._generate_indicator_space",
return_value=[],
)
patch_exchange(mocker)
@@ -1009,8 +1040,8 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None:
hyperopt_conf.update({"spaces": space})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.hyperopter.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
with pytest.raises(OperationalException, match=f"The '{space}' space is included into *"):
hyperopt.start()
@@ -1020,7 +1051,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmp_path, fee) -> None
patch_exchange(mocker)
mocker.patch(f"{EXMS}.get_fee", fee)
# Dummy-reduce points to ensure scikit-learn is forced to generate new values
mocker.patch("freqtrade.optimize.hyperopt.INITIAL_POINTS", 2)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.INITIAL_POINTS", 2)
(tmp_path / "hyperopt_results").mkdir(parents=True)
# No hyperopt needed
hyperopt_conf.update(
@@ -1032,32 +1063,33 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmp_path, fee) -> None
}
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)
assert hyperopt.backtesting.strategy.bot_started is True
assert hyperopt.backtesting.strategy.bot_loop_started is False
opt = hyperopt.hyperopter
opt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
assert isinstance(opt.custom_hyperopt, HyperOptAuto)
assert isinstance(opt.backtesting.strategy.buy_rsi, IntParameter)
assert opt.backtesting.strategy.bot_started is True
assert opt.backtesting.strategy.bot_loop_started is False
assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
assert hyperopt.backtesting.strategy.buy_rsi.value == 35
assert hyperopt.backtesting.strategy.sell_rsi.value == 74
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
assert hyperopt.backtesting.strategy.max_open_trades == 1
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
assert opt.backtesting.strategy.buy_rsi.in_space is True
assert opt.backtesting.strategy.buy_rsi.value == 35
assert opt.backtesting.strategy.sell_rsi.value == 74
assert opt.backtesting.strategy.protection_cooldown_lookback.value == 30
assert opt.backtesting.strategy.max_open_trades == 1
buy_rsi_range = opt.backtesting.strategy.buy_rsi.range
assert isinstance(buy_rsi_range, range)
# Range from 0 - 50 (inclusive)
assert len(list(buy_rsi_range)) == 51
hyperopt.start()
# All values should've changed.
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value != 30
assert hyperopt.backtesting.strategy.buy_rsi.value != 35
assert hyperopt.backtesting.strategy.sell_rsi.value != 74
assert hyperopt.backtesting.strategy.max_open_trades != 1
assert opt.backtesting.strategy.protection_cooldown_lookback.value != 30
assert opt.backtesting.strategy.buy_rsi.value != 35
assert opt.backtesting.strategy.sell_rsi.value != 74
assert opt.backtesting.strategy.max_open_trades != 1
hyperopt.custom_hyperopt.generate_estimator = lambda *args, **kwargs: "ET1"
opt.custom_hyperopt.generate_estimator = lambda *args, **kwargs: "ET1"
with pytest.raises(OperationalException, match="Estimator ET1 not supported."):
hyperopt.get_optimizer([], 2)
opt.get_optimizer(2, 42, 2, 2)
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
@@ -1068,7 +1100,7 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path
mocker.patch(f"{EXMS}.markets", PropertyMock(return_value=get_markets()))
(tmp_path / "hyperopt_results").mkdir(parents=True)
# Dummy-reduce points to ensure scikit-learn is forced to generate new values
mocker.patch("freqtrade.optimize.hyperopt.INITIAL_POINTS", 2)
mocker.patch("freqtrade.optimize.hyperopt.hyperopt.INITIAL_POINTS", 2)
# No hyperopt needed
hyperopt_conf.update(
{
@@ -1083,21 +1115,22 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path
}
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.exchange.get_max_leverage = lambda *x, **xx: 1.0
hyperopt.backtesting.exchange.get_min_pair_stake_amount = lambda *x, **xx: 0.00001
hyperopt.backtesting.exchange.get_max_pair_stake_amount = lambda *x, **xx: 100.0
hyperopt.backtesting.exchange._markets = get_markets()
opt = hyperopt.hyperopter
opt.backtesting.exchange.get_max_leverage = lambda *x, **xx: 1.0
opt.backtesting.exchange.get_min_pair_stake_amount = lambda *x, **xx: 0.00001
opt.backtesting.exchange.get_max_pair_stake_amount = lambda *x, **xx: 100.0
opt.backtesting.exchange._markets = get_markets()
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)
assert hyperopt.backtesting.strategy.bot_started is True
assert hyperopt.backtesting.strategy.bot_loop_started is False
assert isinstance(opt.custom_hyperopt, HyperOptAuto)
assert isinstance(opt.backtesting.strategy.buy_rsi, IntParameter)
assert opt.backtesting.strategy.bot_started is True
assert opt.backtesting.strategy.bot_loop_started is False
assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
assert hyperopt.backtesting.strategy.buy_rsi.value == 35
assert hyperopt.backtesting.strategy.sell_rsi.value == 74
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
assert opt.backtesting.strategy.buy_rsi.in_space is True
assert opt.backtesting.strategy.buy_rsi.value == 35
assert opt.backtesting.strategy.sell_rsi.value == 74
assert opt.backtesting.strategy.protection_cooldown_lookback.value == 30
buy_rsi_range = opt.backtesting.strategy.buy_rsi.range
assert isinstance(buy_rsi_range, range)
# Range from 0 - 50 (inclusive)
assert len(list(buy_rsi_range)) == 51
@@ -1121,7 +1154,7 @@ def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmp_path, fe
}
)
go = mocker.patch(
"freqtrade.optimize.hyperopt.Hyperopt.generate_optimizer",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.HyperOptimizer.generate_optimizer",
return_value={
"loss": 0.05,
"results_explanation": "foo result",
@@ -1130,17 +1163,18 @@ def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmp_path, fe
},
)
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)
assert hyperopt.backtesting.strategy.bot_loop_started is False
assert hyperopt.backtesting.strategy.bot_started is True
opt = hyperopt.hyperopter
opt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
assert isinstance(opt.custom_hyperopt, HyperOptAuto)
assert isinstance(opt.backtesting.strategy.buy_rsi, IntParameter)
assert opt.backtesting.strategy.bot_loop_started is False
assert opt.backtesting.strategy.bot_started is True
assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
assert hyperopt.backtesting.strategy.buy_rsi.value == 35
assert hyperopt.backtesting.strategy.sell_rsi.value == 74
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
assert opt.backtesting.strategy.buy_rsi.in_space is True
assert opt.backtesting.strategy.buy_rsi.value == 35
assert opt.backtesting.strategy.sell_rsi.value == 74
assert opt.backtesting.strategy.protection_cooldown_lookback.value == 30
buy_rsi_range = opt.backtesting.strategy.buy_rsi.range
assert isinstance(buy_rsi_range, range)
# Range from 0 - 50 (inclusive)
assert len(list(buy_rsi_range)) == 51
@@ -1184,17 +1218,17 @@ def test_stake_amount_unlimited_max_open_trades(mocker, hyperopt_conf, tmp_path,
)
hyperopt = Hyperopt(hyperopt_conf)
mocker.patch(
"freqtrade.optimize.hyperopt.Hyperopt._get_params_dict",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.HyperOptimizer._get_params_dict",
return_value={"max_open_trades": -1},
)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.hyperopter.custom_hyperopt, HyperOptAuto)
assert hyperopt.backtesting.strategy.max_open_trades == 1
assert hyperopt.hyperopter.backtesting.strategy.max_open_trades == 1
hyperopt.start()
assert hyperopt.backtesting.strategy.max_open_trades == 1
assert hyperopt.hyperopter.backtesting.strategy.max_open_trades == 1
def test_max_open_trades_dump(mocker, hyperopt_conf, tmp_path, fee, capsys) -> None:
@@ -1213,11 +1247,11 @@ def test_max_open_trades_dump(mocker, hyperopt_conf, tmp_path, fee, capsys) -> N
)
hyperopt = Hyperopt(hyperopt_conf)
mocker.patch(
"freqtrade.optimize.hyperopt.Hyperopt._get_params_dict",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.HyperOptimizer._get_params_dict",
return_value={"max_open_trades": -1},
)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.hyperopter.custom_hyperopt, HyperOptAuto)
hyperopt.start()
@@ -1232,11 +1266,11 @@ def test_max_open_trades_dump(mocker, hyperopt_conf, tmp_path, fee, capsys) -> N
hyperopt = Hyperopt(hyperopt_conf)
mocker.patch(
"freqtrade.optimize.hyperopt.Hyperopt._get_params_dict",
"freqtrade.optimize.hyperopt.hyperopt_optimizer.HyperOptimizer._get_params_dict",
return_value={"max_open_trades": -1},
)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.hyperopter.custom_hyperopt, HyperOptAuto)
hyperopt.start()
@@ -1267,9 +1301,9 @@ def test_max_open_trades_consistency(mocker, hyperopt_conf, tmp_path, fee) -> No
)
hyperopt = Hyperopt(hyperopt_conf)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert isinstance(hyperopt.hyperopter.custom_hyperopt, HyperOptAuto)
hyperopt.custom_hyperopt.max_open_trades_space = lambda: [
hyperopt.hyperopter.custom_hyperopt.max_open_trades_space = lambda: [
Integer(1, 10, name="max_open_trades")
]
@@ -1287,11 +1321,13 @@ def test_max_open_trades_consistency(mocker, hyperopt_conf, tmp_path, fee) -> No
return wrapper
hyperopt.backtesting.wallets._calculate_unlimited_stake_amount = stake_amount_interceptor(
hyperopt.backtesting.wallets._calculate_unlimited_stake_amount
hyperopt.hyperopter.backtesting.wallets._calculate_unlimited_stake_amount = (
stake_amount_interceptor(
hyperopt.hyperopter.backtesting.wallets._calculate_unlimited_stake_amount
)
)
hyperopt.start()
assert hyperopt.backtesting.strategy.max_open_trades == 8
assert hyperopt.hyperopter.backtesting.strategy.max_open_trades == 8
assert hyperopt.config["max_open_trades"] == 8
+31
View File
@@ -2144,6 +2144,7 @@ def test_Trade_object_idem():
"bt_trades_open",
"bt_trades_open_pp",
"bt_open_open_trade_count",
"bt_open_open_trade_count_candle",
"bt_total_profit",
"from_json",
)
@@ -2682,6 +2683,36 @@ def test_select_filled_orders(fee):
assert len(orders) == 0
@pytest.mark.usefixtures("init_persistence")
def test_select_filled_orders_usdt(fee):
create_mock_trades_usdt(fee)
trades = Trade.get_trades().all()
# Closed buy order, no sell order
orders = trades[0].select_filled_orders("buy")
assert isinstance(orders, list)
assert len(orders) == 1
assert orders[0].amount == 2.0
assert orders[0].filled == 2.0
assert orders[0].side == "buy"
assert orders[0].price == 10.0
assert orders[0].stake_amount == 20
assert orders[0].stake_amount_filled == 20
orders = trades[3].select_filled_orders("buy")
assert isinstance(orders, list)
assert len(orders) == 0
orders = trades[3].select_filled_or_open_orders()
assert isinstance(orders, list)
assert len(orders) == 1
assert orders[0].price == 2.0
assert orders[0].amount == 10
assert orders[0].filled == 0
assert orders[0].stake_amount == 20
assert orders[0].stake_amount_filled == 0
@pytest.mark.usefixtures("init_persistence")
def test_order_to_ccxt(limit_buy_order_open, limit_sell_order_usdt_open):
order = Order.parse_from_ccxt_object(limit_buy_order_open, "mocked", "buy")
+4 -6
View File
@@ -2450,7 +2450,7 @@ def test_MarketCapPairList_filter_special_no_pair_from_coingecko(
assert pm.whitelist == []
def test_MarketCapPairList_exceptions(mocker, default_conf_usdt):
def test_MarketCapPairList_exceptions(mocker, default_conf_usdt, caplog):
exchange = get_patched_exchange(mocker, default_conf_usdt)
default_conf_usdt["pairlists"] = [{"method": "MarketCapPairList"}]
with pytest.raises(OperationalException, match=r"`number_assets` not specified.*"):
@@ -2458,13 +2458,11 @@ def test_MarketCapPairList_exceptions(mocker, default_conf_usdt):
PairListManager(exchange, default_conf_usdt)
default_conf_usdt["pairlists"] = [
{"method": "MarketCapPairList", "number_assets": 20, "max_rank": 260}
{"method": "MarketCapPairList", "number_assets": 20, "max_rank": 500}
]
with pytest.raises(
OperationalException, match="This filter only support marketcap rank up to 250."
):
with caplog.at_level(logging.WARNING):
PairListManager(exchange, default_conf_usdt)
assert log_has_re("The max rank you have set \\(500\\) is quite high", caplog)
# Test invalid coinmarkets list
mocker.patch(
"freqtrade.plugins.pairlist.MarketCapPairList.FtCoinGeckoApi.get_coins_categories_list",
+91 -9
View File
@@ -2355,8 +2355,8 @@ def test_send_msg_exit_notification(default_conf, mocker) -> None:
"*Direction:* `Long`\n"
"*Amount:* `1333.33333333`\n"
"*Open Rate:* `0.00075 ETH`\n"
"*Current Rate:* `0.00032 ETH`\n"
"*Exit Rate:* `0.00032 ETH`\n"
"*Current Rate:* `0.0003201 ETH`\n"
"*Exit Rate:* `0.0003201 ETH`\n"
"*Duration:* `1:00:00 (60.0 min)`"
)
@@ -2398,8 +2398,8 @@ def test_send_msg_exit_notification(default_conf, mocker) -> None:
"*Direction:* `Long`\n"
"*Amount:* `1333.33333333`\n"
"*Open Rate:* `0.00075 ETH`\n"
"*Current Rate:* `0.00032 ETH`\n"
"*Exit Rate:* `0.00032 ETH`\n"
"*Current Rate:* `0.0003201 ETH`\n"
"*Exit Rate:* `0.0003201 ETH`\n"
"*Remaining:* `0.01 ETH / -24.812 USD`"
)
@@ -2437,8 +2437,8 @@ def test_send_msg_exit_notification(default_conf, mocker) -> None:
"*Direction:* `Long`\n"
"*Amount:* `1333.33333333`\n"
"*Open Rate:* `0.00075 ETH`\n"
"*Current Rate:* `0.00032 ETH`\n"
"*Exit Rate:* `0.00032 ETH`\n"
"*Current Rate:* `0.0003201 ETH`\n"
"*Exit Rate:* `0.0003201 ETH`\n"
"*Duration:* `1 day, 2:30:00 (1590.0 min)`"
)
# Reset singleton function to avoid random breaks
@@ -2536,7 +2536,7 @@ def test_send_msg_exit_fill_notification(
f"{leverage_text}"
"*Amount:* `1333.33333333`\n"
"*Open Rate:* `0.00075 ETH`\n"
"*Exit Rate:* `0.00032 ETH`\n"
"*Exit Rate:* `0.0003201 ETH`\n"
"*Duration:* `1 day, 2:30:00 (1590.0 min)`"
)
@@ -2686,8 +2686,8 @@ def test_send_msg_exit_notification_no_fiat(
f"{leverage_text}`\n"
"*Amount:* `1333.33333333`\n"
"*Open Rate:* `0.00075 ETH`\n"
"*Current Rate:* `0.00032 ETH`\n"
"*Exit Rate:* `0.00032 ETH`\n"
"*Current Rate:* `0.0003201 ETH`\n"
"*Exit Rate:* `0.0003201 ETH`\n"
"*Duration:* `2:35:03 (155.1 min)`"
)
@@ -2885,3 +2885,85 @@ async def test_telegram_list_custom_data(default_conf_usdt, update, ticker, fee,
) in msg_mock.call_args_list[2][0][0]
msg_mock.reset_mock()
def test_noficiation_settings(default_conf_usdt, mocker):
(telegram, _, _) = get_telegram_testobject(mocker, default_conf_usdt)
telegram._config["telegram"].update(
{
"notification_settings": {
"status": "silent",
"warning": "on",
"startup": "off",
"entry": "silent",
"entry_fill": "on",
"entry_cancel": "silent",
"exit": {
"roi": "silent",
"emergency_exit": "on",
"force_exit": "on",
"exit_signal": "silent",
"trailing_stop_loss": "on",
"stop_loss": "on",
"stoploss_on_exchange": "on",
"custom_exit": "silent",
"partial_exit": "off",
},
"exit_fill": {
"roi": "silent",
"partial_exit": "off",
"*": "silent", # Default to silent
},
"exit_cancel": "on",
"protection_trigger": "off",
"protection_trigger_global": "on",
"strategy_msg": "off",
"show_candle": "off",
}
}
)
loudness = telegram._message_loudness
assert loudness({"type": RPCMessageType.ENTRY, "exit_reason": ""}) == "silent"
assert loudness({"type": RPCMessageType.ENTRY_FILL, "exit_reason": ""}) == "on"
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": ""}) == "on"
# Default to silent due to "*" definition
assert loudness({"type": RPCMessageType.EXIT_FILL, "exit_reason": ""}) == "silent"
assert loudness({"type": RPCMessageType.PROTECTION_TRIGGER, "exit_reason": ""}) == "off"
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": "roi"}) == "silent"
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": "partial_exit"}) == "off"
# Not given key defaults to on
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": "cust_exit112"}) == "on"
assert loudness({"type": RPCMessageType.EXIT_FILL, "exit_reason": "roi"}) == "silent"
assert loudness({"type": RPCMessageType.EXIT_FILL, "exit_reason": "partial_exit"}) == "off"
# Default to silent due to "*" definition
assert loudness({"type": RPCMessageType.EXIT_FILL, "exit_reason": "cust_exit112"}) == "silent"
# Simplified setup for exit
telegram._config["telegram"].update(
{
"notification_settings": {
"status": "silent",
"warning": "on",
"startup": "off",
"entry": "silent",
"entry_fill": "on",
"entry_cancel": "silent",
"exit": "off",
"exit_cancel": "on",
"exit_fill": "on",
"protection_trigger": "off",
"protection_trigger_global": "on",
"strategy_msg": "off",
"show_candle": "off",
}
}
)
assert loudness({"type": RPCMessageType.EXIT_FILL, "exit_reason": "roi"}) == "on"
# All regular exits are off
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": "roi"}) == "off"
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": "partial_exit"}) == "off"
assert loudness({"type": RPCMessageType.EXIT, "exit_reason": "cust_exit112"}) == "off"
+3 -4
View File
@@ -1,7 +1,6 @@
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
from datetime import datetime
from typing import Optional
import talib.abstract as ta
from pandas import DataFrame
@@ -175,7 +174,7 @@ class StrategyTestV3(IStrategy):
current_rate: float,
proposed_leverage: float,
max_leverage: float,
entry_tag: Optional[str],
entry_tag: str | None,
side: str,
**kwargs,
) -> float:
@@ -190,14 +189,14 @@ class StrategyTestV3(IStrategy):
current_time: datetime,
current_rate: float,
current_profit: float,
min_stake: Optional[float],
min_stake: float | None,
max_stake: float,
current_entry_rate: float,
current_exit_rate: float,
current_entry_profit: float,
current_exit_profit: float,
**kwargs,
) -> Optional[float]:
) -> float | None:
if current_profit < -0.0075:
orders = trade.select_filled_orders(trade.entry_side)
return round(orders[0].stake_amount, 0)
@@ -1,7 +1,6 @@
# 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
@@ -34,10 +33,10 @@ class StrategyTestV3CustomEntryPrice(StrategyTestV3):
def custom_entry_price(
self,
pair: str,
trade: Optional[Trade],
trade: Trade | None,
current_time: datetime,
proposed_rate: float,
entry_tag: Optional[str],
entry_tag: str | None,
side: str,
**kwargs,
) -> float:
-7
View File
@@ -489,7 +489,6 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog, tmp_pa
"--timeframe",
"1m",
"--enable-position-stacking",
"--disable-max-market-positions",
"--timerange",
":100",
"--export",
@@ -518,10 +517,6 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog, tmp_pa
assert "position_stacking" in config
assert log_has("Parameter --enable-position-stacking detected ...", caplog)
assert "use_max_market_positions" in config
assert log_has("Parameter --disable-max-market-positions detected ...", caplog)
assert log_has("max_open_trades set to unlimited ...", caplog)
assert "timerange" in config
assert log_has("Parameter --timerange detected: {} ...".format(config["timerange"]), caplog)
@@ -570,8 +565,6 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non
assert "position_stacking" not in config
assert "use_max_market_positions" not in config
assert "timerange" not in config
assert "export" in config
+11
View File
@@ -1,4 +1,5 @@
from freqtrade.util import decimals_per_coin, fmt_coin, round_value
from freqtrade.util.formatters import fmt_coin2
def test_decimals_per_coin():
@@ -25,6 +26,16 @@ def test_fmt_coin():
assert fmt_coin(222.2, "USDT", False, True) == "222.200"
def test_fmt_coin2():
assert fmt_coin2(222.222222, "USDT") == "222.222222 USDT"
assert fmt_coin2(222.2, "XRP", 3, keep_trailing_zeros=True) == "222.200 XRP"
assert fmt_coin2(222.2, "USDT") == "222.2 USDT"
assert fmt_coin2(222.12745, "EUR") == "222.12745 EUR"
assert fmt_coin2(0.1274512123, "BTC") == "0.12745121 BTC"
assert fmt_coin2(0.1274512123, "ETH") == "0.12745121 ETH"
assert fmt_coin2(0.00001245, "PEPE") == "0.00001245 PEPE"
def test_round_value():
assert round_value(222.222222, 3) == "222.222"
assert round_value(222.2, 3) == "222.2"