Merge branch 'freqtrade:develop' into allow-pairs-with-prefix-in-marketcap-pairList

This commit is contained in:
mrpabloyeah
2025-08-25 13:51:16 +02:00
committed by GitHub
85 changed files with 4717 additions and 4107 deletions

View File

@@ -1862,8 +1862,10 @@ def test_backtesting_show(mocker, testdatadir, capsys):
sbr = mocker.patch("freqtrade.optimize.optimize_reports.show_backtest_results")
args = [
"backtesting-show",
"--export-directory",
f"{testdatadir / 'backtest_results'}",
"--export-filename",
f"{testdatadir / 'backtest_results/backtest-result.json'}",
"backtest-result.json",
"--show-pair-list",
]
pargs = get_args(args)

View File

@@ -521,7 +521,11 @@ def patch_torch_initlogs(mocker) -> None:
mocked_module = types.ModuleType(module_name)
sys.modules[module_name] = mocked_module
else:
mocker.patch("torch._logging._init_logs")
try:
mocker.patch("torch._logging._init_logs")
except ModuleNotFoundError:
# Allow running limited tests to run without freqAI dependencies
pass
@pytest.fixture(autouse=True)

View File

@@ -0,0 +1,122 @@
from datetime import timedelta
from unittest.mock import MagicMock
import pytest
from freqtrade.enums import CandleType
from freqtrade.exceptions import RetryableOrderError
from freqtrade.exchange.common import API_RETRY_COUNT
from freqtrade.util import dt_now, dt_ts
from tests.conftest import EXMS, get_patched_exchange
from tests.exchange.test_exchange import ccxt_exceptionhandlers
@pytest.mark.usefixtures("init_persistence")
def test_fetch_stoploss_order_bitget(default_conf, mocker):
default_conf["dry_run"] = False
mocker.patch("freqtrade.exchange.common.time.sleep")
api_mock = MagicMock()
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bitget")
api_mock.fetch_open_orders = MagicMock(return_value=[])
api_mock.fetch_canceled_and_closed_orders = MagicMock(return_value=[])
with pytest.raises(RetryableOrderError):
exchange.fetch_stoploss_order("1234", "ETH/BTC")
assert api_mock.fetch_open_orders.call_count == API_RETRY_COUNT + 1
assert api_mock.fetch_canceled_and_closed_orders.call_count == API_RETRY_COUNT + 1
api_mock.fetch_open_orders.reset_mock()
api_mock.fetch_canceled_and_closed_orders.reset_mock()
api_mock.fetch_canceled_and_closed_orders = MagicMock(
return_value=[{"id": "1234", "status": "closed", "clientOrderId": "123455"}]
)
api_mock.fetch_open_orders = MagicMock(return_value=[{"id": "50110", "clientOrderId": "1234"}])
resp = exchange.fetch_stoploss_order("1234", "ETH/BTC")
assert api_mock.fetch_open_orders.call_count == 2
assert api_mock.fetch_canceled_and_closed_orders.call_count == 2
assert resp["id"] == "1234"
assert resp["id_stop"] == "50110"
assert resp["type"] == "stoploss"
default_conf["dry_run"] = True
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bitget")
dro_mock = mocker.patch(f"{EXMS}.fetch_dry_run_order", MagicMock(return_value={"id": "123455"}))
api_mock.fetch_open_orders.reset_mock()
api_mock.fetch_canceled_and_closed_orders.reset_mock()
resp = exchange.fetch_stoploss_order("1234", "ETH/BTC")
assert api_mock.fetch_open_orders.call_count == 0
assert api_mock.fetch_canceled_and_closed_orders.call_count == 0
assert dro_mock.call_count == 1
def test_fetch_stoploss_order_bitget_exceptions(default_conf_usdt, mocker):
default_conf_usdt["dry_run"] = False
api_mock = MagicMock()
# Test emulation of the stoploss getters
api_mock.fetch_canceled_and_closed_orders = MagicMock(return_value=[])
ccxt_exceptionhandlers(
mocker,
default_conf_usdt,
api_mock,
"bitget",
"fetch_stoploss_order",
"fetch_open_orders",
retries=API_RETRY_COUNT + 1,
order_id="12345",
pair="ETH/USDT",
)
def test_bitget_ohlcv_candle_limit(mocker, default_conf_usdt):
# This test is also a live test - so we're sure our limits are correct.
api_mock = MagicMock()
api_mock.options = {
"fetchOHLCV": {
"maxRecentDaysPerTimeframe": {
"1m": 30,
"5m": 30,
"15m": 30,
"30m": 30,
"1h": 60,
"4h": 60,
"1d": 60,
}
}
}
exch = get_patched_exchange(mocker, default_conf_usdt, api_mock, exchange="bitget")
timeframes = ("1m", "5m", "1h")
for timeframe in timeframes:
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 200
start_time = dt_ts(dt_now() - timedelta(days=17))
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200
start_time = dt_ts(dt_now() - timedelta(days=48))
length = 200 if timeframe in ("1m", "5m") else 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200
start_time = dt_ts(dt_now() - timedelta(days=61))
length = 200
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200

View File

@@ -541,24 +541,24 @@ class TestCCXTExchange:
for timeframe in timeframes:
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK) == 200
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 200
start_time = dt_ts(dt_now() - timedelta(days=17))
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 200
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200
start_time = dt_ts(dt_now() - timedelta(days=48))
length = 200 if timeframe in ("1m", "5m") else 1000
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 200
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200
start_time = dt_ts(dt_now() - timedelta(days=61))
length = 200
assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 200
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200

View File

@@ -1528,6 +1528,25 @@ def test_handle_trade(
assert trade.close_date is not None
assert trade.exit_reason == "sell_signal1"
correct_profit_ratio = trade.calc_profit_ratio(
rate=trade.close_rate, amount=trade.amount, open_rate=trade.open_rate
)
profit_ratio_1 = trade.calc_profit_ratio(rate=trade.close_rate, open_rate=trade.open_rate)
profit_ratio_2 = trade.calc_profit_ratio(
rate=trade.close_rate, open_rate=trade.open_rate * 1.02
)
profit_ratio_3 = trade.calc_profit_ratio(rate=trade.close_rate, amount=trade.amount)
profit_ratio_4 = trade.calc_profit_ratio(rate=trade.close_rate)
profit_ratio_5 = trade.calc_profit_ratio(
rate=trade.close_rate, amount=trade.amount, open_rate=trade.open_rate * 1.02
)
assert correct_profit_ratio == close_profit
assert correct_profit_ratio == profit_ratio_1
assert correct_profit_ratio != profit_ratio_2
assert correct_profit_ratio == profit_ratio_3
assert correct_profit_ratio == profit_ratio_4
assert correct_profit_ratio != profit_ratio_5
@pytest.mark.parametrize("is_short", [False, True])
def test_handle_overlapping_signals(
@@ -5729,7 +5748,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
@pytest.mark.parametrize(
"data",
[
# tuple 1 - side amount, price
# tuple 1 - side, amount, price
# tuple 2 - amount, open_rate, stake_amount, cumulative_profit, realized_profit, rel_profit
(
(("buy", 100, 10), (100.0, 10.0, 1000.0, 0.0, None, None)),

View File

@@ -236,7 +236,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmp_path):
filename_last = tmp_path / LAST_BT_RESULT_FN
_backup_file(filename_last, copy_file=True)
assert not filename.is_file()
default_conf["exportfilename"] = filename
default_conf["exportdirectory"] = filename
store_backtest_results(default_conf, stats, "2022_01_01_15_05_13")
@@ -263,7 +263,7 @@ def test_store_backtest_results(testdatadir, mocker):
zip_mock = mocker.patch("freqtrade.optimize.optimize_reports.bt_storage.ZipFile")
data = {"metadata": {}, "strategy": {}, "strategy_comparison": []}
store_backtest_results(
{"exportfilename": testdatadir, "original_config": {}}, data, "2022_01_01_15_05_13"
{"exportdirectory": testdatadir, "original_config": {}}, data, "2022_01_01_15_05_13"
)
assert dump_mock.call_count == 2
@@ -275,7 +275,7 @@ def test_store_backtest_results(testdatadir, mocker):
zip_mock.reset_mock()
filename = testdatadir / "testresult.json"
store_backtest_results(
{"exportfilename": filename, "original_config": {}}, data, "2022_01_01_15_05_13"
{"exportdirectory": filename, "original_config": {}}, data, "2022_01_01_15_05_13"
)
assert dump_mock.call_count == 2
assert zip_mock.call_count == 1
@@ -287,7 +287,7 @@ def test_store_backtest_results(testdatadir, mocker):
def test_store_backtest_results_real(tmp_path, caplog):
data = {"metadata": {}, "strategy": {}, "strategy_comparison": []}
config = {
"exportfilename": tmp_path,
"exportdirectory": tmp_path,
"original_config": {},
}
store_backtest_results(
@@ -356,7 +356,7 @@ def test_write_read_backtest_candles(tmp_path):
bt_results = {"metadata": {}, "strategy": {}, "strategy_comparison": []}
mock_conf = {
"exportfilename": tmp_path,
"exportdirectory": tmp_path,
"export": "signals",
"runmode": "backtest",
"original_config": {},
@@ -393,33 +393,6 @@ def test_write_read_backtest_candles(tmp_path):
_clean_test_file(stored_file)
# test file exporting
filename = tmp_path / "testresult"
mock_conf["exportfilename"] = filename
store_backtest_results(mock_conf, bt_results, sample_date, analysis_results=data)
stored_file = tmp_path / f"testresult-{sample_date}.zip"
signals_pkl = f"testresult-{sample_date}_signals.pkl"
rejected_pkl = f"testresult-{sample_date}_rejected.pkl"
exited_pkl = f"testresult-{sample_date}_exited.pkl"
assert not (tmp_path / signals_pkl).is_file()
assert stored_file.is_file()
with ZipFile(stored_file, "r") as zipf:
assert signals_pkl in zipf.namelist()
assert rejected_pkl in zipf.namelist()
assert exited_pkl in zipf.namelist()
with zipf.open(signals_pkl) as scp:
pickled_signal_candles2 = joblib.load(scp)
assert pickled_signal_candles2.keys() == candle_dict.keys()
assert pickled_signal_candles2["DefStrat"].keys() == pickled_signal_candles2["DefStrat"].keys()
assert pickled_signal_candles2["DefStrat"]["UNITTEST/BTC"].equals(
pickled_signal_candles2["DefStrat"]["UNITTEST/BTC"]
)
_clean_test_file(stored_file)
def test_generate_pair_metrics():
results = pd.DataFrame(

View File

@@ -1883,7 +1883,12 @@ def test_pairlistmanager_no_pairlist(mocker, whitelist_conf):
whitelist_conf["pairlists"] = []
with pytest.raises(OperationalException, match=r"No Pairlist Handlers defined"):
with pytest.raises(OperationalException, match=r"\[\] should be non-empty"):
get_patched_freqtradebot(mocker, whitelist_conf)
del whitelist_conf["pairlists"]
with pytest.raises(OperationalException, match=r"'pairlists' is a required property"):
get_patched_freqtradebot(mocker, whitelist_conf)

View File

@@ -2802,8 +2802,8 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmp_path):
ftbot.config["export"] = "trades"
ftbot.config["backtest_cache"] = "day"
ftbot.config["user_data_dir"] = tmp_path
ftbot.config["exportfilename"] = tmp_path / "backtest_results"
ftbot.config["exportfilename"].mkdir()
ftbot.config["exportdirectory"] = tmp_path / "backtest_results"
ftbot.config["exportdirectory"].mkdir()
# start backtesting
data = {

View File

@@ -12,20 +12,13 @@ from freqtrade.configuration import TimeRange
from freqtrade.constants import CUSTOM_TAG_MAX_LENGTH
from freqtrade.data.dataprovider import DataProvider
from freqtrade.data.history import load_data
from freqtrade.enums import ExitCheckTuple, ExitType, HyperoptState, SignalDirection
from freqtrade.enums import ExitCheckTuple, ExitType, SignalDirection
from freqtrade.exceptions import OperationalException, StrategyError
from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer
from freqtrade.optimize.space import SKDecimal
from freqtrade.persistence import PairLocks, Trade
from freqtrade.resolvers import StrategyResolver
from freqtrade.strategy.hyper import detect_parameters
from freqtrade.strategy.parameters import (
BaseParameter,
BooleanParameter,
CategoricalParameter,
DecimalParameter,
IntParameter,
RealParameter,
)
from freqtrade.strategy.strategy_validation import StrategyResultValidator
from freqtrade.util import dt_now
@@ -930,95 +923,6 @@ def test_is_informative_pairs_callback(default_conf):
assert [] == strategy.gather_informative_pairs()
def test_hyperopt_parameters():
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
from optuna.distributions import CategoricalDistribution, FloatDistribution, IntDistribution
with pytest.raises(OperationalException, match=r"Name is determined.*"):
IntParameter(low=0, high=5, default=1, name="hello")
with pytest.raises(OperationalException, match=r"IntParameter space must be.*"):
IntParameter(low=0, default=5, space="buy")
with pytest.raises(OperationalException, match=r"RealParameter space must be.*"):
RealParameter(low=0, default=5, space="buy")
with pytest.raises(OperationalException, match=r"DecimalParameter space must be.*"):
DecimalParameter(low=0, default=5, space="buy")
with pytest.raises(OperationalException, match=r"IntParameter space invalid\."):
IntParameter([0, 10], high=7, default=5, space="buy")
with pytest.raises(OperationalException, match=r"RealParameter space invalid\."):
RealParameter([0, 10], high=7, default=5, space="buy")
with pytest.raises(OperationalException, match=r"DecimalParameter space invalid\."):
DecimalParameter([0, 10], high=7, default=5, space="buy")
with pytest.raises(OperationalException, match=r"CategoricalParameter space must.*"):
CategoricalParameter(["aa"], default="aa", space="buy")
with pytest.raises(TypeError):
BaseParameter(opt_range=[0, 1], default=1, space="buy")
intpar = IntParameter(low=0, high=5, default=1, space="buy")
assert intpar.value == 1
assert isinstance(intpar.get_space(""), IntDistribution)
assert isinstance(intpar.range, range)
assert len(list(intpar.range)) == 1
# Range contains ONLY the default / value.
assert list(intpar.range) == [intpar.value]
intpar.in_space = True
assert len(list(intpar.range)) == 6
assert list(intpar.range) == [0, 1, 2, 3, 4, 5]
fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space="buy")
assert fltpar.value == 1
assert isinstance(fltpar.get_space(""), FloatDistribution)
fltpar = DecimalParameter(low=0.0, high=0.5, default=0.14, decimals=1, space="buy")
assert fltpar.value == 0.1
assert isinstance(fltpar.get_space(""), SKDecimal)
assert isinstance(fltpar.range, list)
assert len(list(fltpar.range)) == 1
# Range contains ONLY the default / value.
assert list(fltpar.range) == [fltpar.value]
fltpar.in_space = True
assert len(list(fltpar.range)) == 6
assert list(fltpar.range) == [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
catpar = CategoricalParameter(
["buy_rsi", "buy_macd", "buy_none"], default="buy_macd", space="buy"
)
assert catpar.value == "buy_macd"
assert isinstance(catpar.get_space(""), CategoricalDistribution)
assert isinstance(catpar.range, list)
assert len(list(catpar.range)) == 1
# Range contains ONLY the default / value.
assert list(catpar.range) == [catpar.value]
catpar.in_space = True
assert len(list(catpar.range)) == 3
assert list(catpar.range) == ["buy_rsi", "buy_macd", "buy_none"]
boolpar = BooleanParameter(default=True, space="buy")
assert boolpar.value is True
assert isinstance(boolpar.get_space(""), CategoricalDistribution)
assert isinstance(boolpar.range, list)
assert len(list(boolpar.range)) == 1
boolpar.in_space = True
assert len(list(boolpar.range)) == 2
assert list(boolpar.range) == [True, False]
HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE)
assert len(list(intpar.range)) == 1
assert len(list(fltpar.range)) == 1
assert len(list(catpar.range)) == 1
assert len(list(boolpar.range)) == 1
def test_auto_hyperopt_interface(default_conf):
default_conf.update({"strategy": "HyperoptableStrategyV2"})
PairLocks.timeframe = default_conf["timeframe"]

View File

@@ -0,0 +1,136 @@
# pragma pylint: disable=missing-docstring, C0103
import pytest
from freqtrade.enums import HyperoptState
from freqtrade.exceptions import OperationalException
from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer
from freqtrade.strategy.parameters import (
BaseParameter,
BooleanParameter,
CategoricalParameter,
DecimalParameter,
IntParameter,
RealParameter,
)
def test_hyperopt_int_parameter():
from optuna.distributions import IntDistribution
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
with pytest.raises(OperationalException, match=r"Name is determined.*"):
IntParameter(low=0, high=5, default=1, name="hello")
with pytest.raises(OperationalException, match=r"IntParameter space must be.*"):
IntParameter(low=0, default=5, space="buy")
with pytest.raises(OperationalException, match=r"IntParameter space invalid\."):
IntParameter([0, 10], high=7, default=5, space="buy")
intpar = IntParameter(low=0, high=5, default=1, space="buy")
assert intpar.value == 1
assert isinstance(intpar.get_space(""), IntDistribution)
assert isinstance(intpar.range, range)
assert len(list(intpar.range)) == 1
# Range contains ONLY the default / value.
assert list(intpar.range) == [intpar.value]
intpar.in_space = True
assert len(list(intpar.range)) == 6
assert list(intpar.range) == [0, 1, 2, 3, 4, 5]
HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE)
assert len(list(intpar.range)) == 1
def test_hyperopt_real_parameter():
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
from optuna.distributions import FloatDistribution
with pytest.raises(OperationalException, match=r"RealParameter space must be.*"):
RealParameter(low=0, default=5, space="buy")
with pytest.raises(OperationalException, match=r"RealParameter space invalid\."):
RealParameter([0, 10], high=7, default=5, space="buy")
fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space="buy")
assert fltpar.value == 1.0
assert isinstance(fltpar.get_space(""), FloatDistribution)
assert not hasattr(fltpar, "range")
def test_hyperopt_decimal_parameter():
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
# TODO: Check for get_space??
from freqtrade.optimize.space import SKDecimal
with pytest.raises(OperationalException, match=r"DecimalParameter space must be.*"):
DecimalParameter(low=0, default=5, space="buy")
with pytest.raises(OperationalException, match=r"DecimalParameter space invalid\."):
DecimalParameter([0, 10], high=7, default=5, space="buy")
decimalpar = DecimalParameter(low=0.0, high=0.5, default=0.14, decimals=1, space="buy")
assert decimalpar.value == 0.1
assert isinstance(decimalpar.get_space(""), SKDecimal)
assert isinstance(decimalpar.range, list)
assert len(list(decimalpar.range)) == 1
# Range contains ONLY the default / value.
assert list(decimalpar.range) == [decimalpar.value]
decimalpar.in_space = True
assert len(list(decimalpar.range)) == 6
assert list(decimalpar.range) == [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
decimalpar2 = DecimalParameter(low=0.01, high=0.03, decimals=3, default=0.02, space="buy")
decimalpar2.in_space = True
assert len(list(decimalpar2.range)) == 21
expected_range = [round(0.01 + i * 0.001, 3) for i in range(21)]
assert list(decimalpar2.range) == expected_range
assert decimalpar2.value == 0.02
decimalpar2.value = 0.022222
assert decimalpar2.value == 0.022
HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE)
assert len(list(decimalpar.range)) == 1
def test_hyperopt_categorical_parameter():
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
from optuna.distributions import CategoricalDistribution
with pytest.raises(OperationalException, match=r"CategoricalParameter space must.*"):
CategoricalParameter(["aa"], default="aa", space="buy")
with pytest.raises(TypeError):
BaseParameter(opt_range=[0, 1], default=1, space="buy")
catpar = CategoricalParameter(
["buy_rsi", "buy_macd", "buy_none"], default="buy_macd", space="buy"
)
assert catpar.value == "buy_macd"
assert isinstance(catpar.get_space(""), CategoricalDistribution)
assert isinstance(catpar.range, list)
assert len(list(catpar.range)) == 1
# Range contains ONLY the default / value.
assert list(catpar.range) == [catpar.value]
catpar.in_space = True
assert len(list(catpar.range)) == 3
assert list(catpar.range) == ["buy_rsi", "buy_macd", "buy_none"]
boolpar = BooleanParameter(default=True, space="buy")
assert boolpar.value is True
assert isinstance(boolpar.get_space(""), CategoricalDistribution)
assert isinstance(boolpar.range, list)
assert len(list(boolpar.range)) == 1
boolpar.in_space = True
assert len(list(boolpar.range)) == 2
assert list(boolpar.range) == [True, False]
HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE)
assert len(list(catpar.range)) == 1
assert len(list(boolpar.range)) == 1

View File

@@ -6,7 +6,6 @@ from pathlib import Path
from unittest.mock import MagicMock
import pytest
from jsonschema import ValidationError
from freqtrade.commands import Arguments
from freqtrade.configuration import (
@@ -51,20 +50,20 @@ def test_load_config_missing_attributes(default_conf) -> None:
conf = deepcopy(default_conf)
conf.pop("exchange")
with pytest.raises(ValidationError, match=r".*'exchange' is a required property.*"):
with pytest.raises(ConfigurationError, match=r".*'exchange' is a required property.*"):
validate_config_schema(conf)
conf = deepcopy(default_conf)
conf.pop("stake_currency")
conf["runmode"] = RunMode.DRY_RUN
with pytest.raises(ValidationError, match=r".*'stake_currency' is a required property.*"):
with pytest.raises(ConfigurationError, match=r".*'stake_currency' is a required property.*"):
validate_config_schema(conf)
def test_load_config_incorrect_stake_amount(default_conf) -> None:
default_conf["stake_amount"] = "fake"
with pytest.raises(ValidationError, match=r".*'fake' does not match 'unlimited'.*"):
with pytest.raises(ConfigurationError, match=r".*'fake' does not match 'unlimited'.*"):
validate_config_schema(default_conf)
@@ -1075,7 +1074,7 @@ def test_load_config_default_exchange(all_conf) -> None:
assert "exchange" not in all_conf
with pytest.raises(ValidationError, match=r"'exchange' is a required property"):
with pytest.raises(ConfigurationError, match=r"'exchange' is a required property"):
validate_config_schema(all_conf)
@@ -1088,14 +1087,14 @@ def test_load_config_default_exchange_name(all_conf) -> None:
assert "name" not in all_conf["exchange"]
with pytest.raises(ValidationError, match=r"'name' is a required property"):
with pytest.raises(ConfigurationError, match=r"'name' is a required property"):
validate_config_schema(all_conf)
def test_load_config_stoploss_exchange_limit_ratio(all_conf) -> None:
all_conf["order_types"]["stoploss_on_exchange_limit_ratio"] = 1.15
with pytest.raises(ValidationError, match=r"1.15 is greater than the maximum"):
with pytest.raises(ConfigurationError, match=r"1.15 is greater than the maximum"):
validate_config_schema(all_conf)

View File

@@ -5,11 +5,11 @@ import talib.abstract as ta
def test_talib_bollingerbands_near_zero_values():
inputs = pd.DataFrame(
[
{"close": 0.00000010},
{"close": 0.00000011},
{"close": 0.00000012},
{"close": 0.00000013},
{"close": 0.00000014},
{"close": 0.000010},
{"close": 0.000011},
{"close": 0.000012},
{"close": 0.000013},
{"close": 0.000014},
]
)
bollinger = ta.BBANDS(inputs, matype=0, timeperiod=2)