mirror of
https://github.com/freqtrade/freqtrade.git
synced 2026-04-29 13:31:22 +00:00
Merge branch 'develop' into fix/remove_deprecation_warning
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import MagicMock, PropertyMock
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import RetryableOrderError
|
||||
from freqtrade.enums import CandleType, MarginMode, TradingMode
|
||||
from freqtrade.exceptions import OperationalException, 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
|
||||
@@ -120,3 +120,76 @@ def test_bitget_ohlcv_candle_limit(mocker, default_conf_usdt):
|
||||
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
|
||||
|
||||
|
||||
def test_additional_exchange_init_bitget(default_conf, mocker):
|
||||
default_conf["dry_run"] = False
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
api_mock = MagicMock()
|
||||
api_mock.set_position_mode = MagicMock(return_value={})
|
||||
|
||||
get_patched_exchange(mocker, default_conf, exchange="bitget", api_mock=api_mock)
|
||||
assert api_mock.set_position_mode.call_count == 1
|
||||
|
||||
ccxt_exceptionhandlers(
|
||||
mocker, default_conf, api_mock, "bitget", "additional_exchange_init", "set_position_mode"
|
||||
)
|
||||
|
||||
|
||||
def test_dry_run_liquidation_price_cross_bitget(default_conf, mocker):
|
||||
default_conf["dry_run"] = True
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.CROSS
|
||||
api_mock = MagicMock()
|
||||
mocker.patch(f"{EXMS}.get_maintenance_ratio_and_amt", MagicMock(return_value=(0.005, 0.0)))
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="bitget", api_mock=api_mock)
|
||||
|
||||
with pytest.raises(
|
||||
OperationalException, match="Freqtrade currently only supports isolated futures for bitget"
|
||||
):
|
||||
exchange.dry_run_liquidation_price(
|
||||
"ETH/USDT:USDT",
|
||||
100_000,
|
||||
False,
|
||||
0.1,
|
||||
100,
|
||||
10,
|
||||
100,
|
||||
[],
|
||||
)
|
||||
|
||||
|
||||
def test__lev_prep_bitget(default_conf, mocker):
|
||||
api_mock = MagicMock()
|
||||
api_mock.set_margin_mode = MagicMock()
|
||||
api_mock.set_leverage = MagicMock()
|
||||
type(api_mock).has = PropertyMock(return_value={"setMarginMode": True, "setLeverage": True})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bitget")
|
||||
exchange._lev_prep("BTC/USDC:USDC", 3.2, "buy")
|
||||
|
||||
assert api_mock.set_margin_mode.call_count == 0
|
||||
assert api_mock.set_leverage.call_count == 0
|
||||
|
||||
# test in futures mode
|
||||
api_mock.set_margin_mode.reset_mock()
|
||||
api_mock.set_leverage.reset_mock()
|
||||
default_conf["dry_run"] = False
|
||||
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bitget")
|
||||
exchange._lev_prep("BTC/USDC:USDC", 3.2, "buy")
|
||||
|
||||
assert api_mock.set_margin_mode.call_count == 0
|
||||
assert api_mock.set_leverage.call_count == 1
|
||||
api_mock.set_leverage.assert_called_with(symbol="BTC/USDC:USDC", leverage=3.2)
|
||||
|
||||
api_mock.reset_mock()
|
||||
|
||||
exchange._lev_prep("BTC/USDC:USDC", 19.99, "sell")
|
||||
|
||||
assert api_mock.set_margin_mode.call_count == 0
|
||||
assert api_mock.set_leverage.call_count == 1
|
||||
api_mock.set_leverage.assert_called_with(symbol="BTC/USDC:USDC", leverage=19.99)
|
||||
|
||||
@@ -5942,29 +5942,32 @@ def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers):
|
||||
assert exchange.get_max_leverage("TIA/USDT:USDT", 130.008) == 40
|
||||
|
||||
|
||||
@pytest.mark.parametrize("exchange_name", ["binance", "kraken", "gate", "okx", "bybit"])
|
||||
def test__get_params(mocker, default_conf, exchange_name):
|
||||
@pytest.mark.parametrize(
|
||||
"exchange_name, add_params_spot, add_params_futures",
|
||||
[
|
||||
("binance", {}, {}),
|
||||
("kraken", {}, {"leverage": 3.0}),
|
||||
("gate", {}, {}),
|
||||
("okx", {}, {"tdMode": "isolated", "posSide": "net"}),
|
||||
("bybit", {}, {"position_idx": 0}),
|
||||
("bitget", {}, {"marginMode": "isolated"}),
|
||||
],
|
||||
)
|
||||
def test__get_params(mocker, default_conf, exchange_name, add_params_spot, add_params_futures):
|
||||
api_mock = MagicMock()
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange._params = {"test": True}
|
||||
|
||||
params1 = {"test": True}
|
||||
params2 = {
|
||||
params1.update(add_params_spot)
|
||||
|
||||
params_fut = {
|
||||
"test": True,
|
||||
"timeInForce": "IOC",
|
||||
"reduceOnly": True,
|
||||
}
|
||||
|
||||
if exchange_name == "kraken":
|
||||
params2["leverage"] = 3.0
|
||||
|
||||
if exchange_name == "okx":
|
||||
params2["tdMode"] = "isolated"
|
||||
params2["posSide"] = "net"
|
||||
|
||||
if exchange_name == "bybit":
|
||||
params2["position_idx"] = 0
|
||||
params_fut.update(add_params_futures)
|
||||
|
||||
assert (
|
||||
exchange._get_params(
|
||||
@@ -6012,7 +6015,7 @@ def test__get_params(mocker, default_conf, exchange_name):
|
||||
time_in_force="IOC",
|
||||
leverage=3.0,
|
||||
)
|
||||
== params2
|
||||
== params_fut
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -422,6 +422,10 @@ EXCHANGES = {
|
||||
"hasQuoteVolume": True,
|
||||
"timeframe": "1h",
|
||||
"candle_count": 1000,
|
||||
"futures": True,
|
||||
"futures_pair": "BTC/USDT:USDT",
|
||||
"leverage_tiers_public": True,
|
||||
"leverage_in_spot_market": True,
|
||||
},
|
||||
"coinex": {
|
||||
"pair": "BTC/USDT",
|
||||
|
||||
@@ -1132,7 +1132,9 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmp_path, fee) -> None
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
||||
def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path, fee) -> None:
|
||||
def test_in_strategy_auto_hyperopt_with_parallel(
|
||||
mocker, hyperopt_conf, tmp_path, fee, caplog
|
||||
) -> None:
|
||||
mocker.patch(f"{EXMS}.validate_config", MagicMock())
|
||||
mocker.patch(f"{EXMS}.get_fee", fee)
|
||||
mocker.patch(f"{EXMS}.reload_markets")
|
||||
@@ -1175,6 +1177,8 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path
|
||||
assert len(list(buy_rsi_range)) == 51
|
||||
|
||||
hyperopt.start()
|
||||
# Test logs from parallel workers are shown.
|
||||
assert log_has("Test: Bot loop started", caplog)
|
||||
|
||||
|
||||
def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmp_path, fee) -> None:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
import logging
|
||||
|
||||
from pandas import DataFrame
|
||||
from strategy_test_v3 import StrategyTestV3
|
||||
|
||||
@@ -7,6 +9,9 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.strategy import BooleanParameter, DecimalParameter, IntParameter, RealParameter
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HyperoptableStrategy(StrategyTestV3):
|
||||
"""
|
||||
Default Strategy provided by freqtrade bot.
|
||||
@@ -16,6 +21,7 @@ class HyperoptableStrategy(StrategyTestV3):
|
||||
for samples and inspiration.
|
||||
"""
|
||||
|
||||
INTERFACE_VERSION = 3
|
||||
buy_params = {
|
||||
"buy_rsi": 35,
|
||||
# Intentionally not specified, so "default" is tested
|
||||
@@ -54,34 +60,13 @@ class HyperoptableStrategy(StrategyTestV3):
|
||||
|
||||
def bot_loop_start(self, **kwargs):
|
||||
self.bot_loop_started = True
|
||||
logger.info("Test: Bot loop started")
|
||||
|
||||
def bot_start(self, **kwargs) -> None:
|
||||
"""
|
||||
Parameters can also be defined here ...
|
||||
"""
|
||||
self.bot_started = True
|
||||
self.buy_rsi = IntParameter([0, 50], default=30, space="buy")
|
||||
|
||||
def informative_pairs(self):
|
||||
"""
|
||||
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||
These pair/interval combinations are non-tradeable, unless they are part
|
||||
of the whitelist as well.
|
||||
For more information, please consult the documentation
|
||||
:return: List of tuples in the format (pair, interval)
|
||||
Sample: return [("ETH/USDT", "5m"),
|
||||
("BTC/USDT", "15m"),
|
||||
]
|
||||
"""
|
||||
return []
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the buy signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param metadata: Additional information, like the currently traded pair
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe["rsi"] < self.buy_rsi.value)
|
||||
@@ -90,18 +75,12 @@ class HyperoptableStrategy(StrategyTestV3):
|
||||
& (dataframe["plus_di"] > self.buy_plusdi.value)
|
||||
)
|
||||
| ((dataframe["adx"] > 65) & (dataframe["plus_di"] > self.buy_plusdi.value)),
|
||||
"buy",
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the sell signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param metadata: Additional information, like the currently traded pair
|
||||
:return: DataFrame with sell column
|
||||
"""
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(
|
||||
@@ -112,6 +91,6 @@ class HyperoptableStrategy(StrategyTestV3):
|
||||
& (dataframe["minus_di"] > 0)
|
||||
)
|
||||
| ((dataframe["adx"] > 70) & (dataframe["minus_di"] > self.sell_minusdi.value)),
|
||||
"sell",
|
||||
"exit_long",
|
||||
] = 1
|
||||
return dataframe
|
||||
|
||||
Reference in New Issue
Block a user