mirror of
https://github.com/freqtrade/freqtrade.git
synced 2026-05-03 15:32:15 +00:00
Merge branch 'freqtrade:develop' into feature/stoploss-start-at
This commit is contained in:
@@ -167,7 +167,7 @@ def test_list_timeframes(mocker, capsys):
|
||||
"1h": "hour",
|
||||
"1d": "day",
|
||||
}
|
||||
patch_exchange(mocker, api_mock=api_mock, id="bybit")
|
||||
patch_exchange(mocker, api_mock=api_mock, exchange="bybit")
|
||||
args = [
|
||||
"list-timeframes",
|
||||
]
|
||||
@@ -213,7 +213,7 @@ def test_list_timeframes(mocker, capsys):
|
||||
"1d": "1d",
|
||||
"3d": "3d",
|
||||
}
|
||||
patch_exchange(mocker, api_mock=api_mock, id="binance")
|
||||
patch_exchange(mocker, api_mock=api_mock, exchange="binance")
|
||||
# Test with --exchange binance
|
||||
args = [
|
||||
"list-timeframes",
|
||||
@@ -258,7 +258,7 @@ def test_list_timeframes(mocker, capsys):
|
||||
|
||||
def test_list_markets(mocker, markets_static, capsys):
|
||||
api_mock = MagicMock()
|
||||
patch_exchange(mocker, api_mock=api_mock, id="binance", mock_markets=markets_static)
|
||||
patch_exchange(mocker, api_mock=api_mock, exchange="binance", mock_markets=markets_static)
|
||||
|
||||
# Test with no --config
|
||||
args = [
|
||||
@@ -286,7 +286,7 @@ def test_list_markets(mocker, markets_static, capsys):
|
||||
"LTC/ETH, LTC/USD, NEO/BTC, TKN/BTC, XLTCUSDT, XRP/BTC.\n" in captured.out
|
||||
)
|
||||
|
||||
patch_exchange(mocker, api_mock=api_mock, id="binance", mock_markets=markets_static)
|
||||
patch_exchange(mocker, api_mock=api_mock, exchange="binance", mock_markets=markets_static)
|
||||
# Test with --exchange
|
||||
args = ["list-markets", "--exchange", "binance"]
|
||||
pargs = get_args(args)
|
||||
@@ -295,7 +295,7 @@ def test_list_markets(mocker, markets_static, capsys):
|
||||
captured = capsys.readouterr()
|
||||
assert re.match("\nExchange Binance has 12 active markets:\n", captured.out)
|
||||
|
||||
patch_exchange(mocker, api_mock=api_mock, id="binance", mock_markets=markets_static)
|
||||
patch_exchange(mocker, api_mock=api_mock, exchange="binance", mock_markets=markets_static)
|
||||
# Test with --all: all markets
|
||||
args = [
|
||||
"list-markets",
|
||||
@@ -823,7 +823,7 @@ def test_download_data_no_markets(mocker, caplog):
|
||||
"freqtrade.data.history.history_utils.refresh_backtest_ohlcv_data",
|
||||
MagicMock(return_value=["ETH/BTC", "XRP/BTC"]),
|
||||
)
|
||||
patch_exchange(mocker, id="binance")
|
||||
patch_exchange(mocker, exchange="binance")
|
||||
mocker.patch(f"{EXMS}.get_markets", return_value={})
|
||||
args = [
|
||||
"download-data",
|
||||
@@ -952,7 +952,7 @@ def test_download_data_trades(mocker):
|
||||
|
||||
|
||||
def test_download_data_data_invalid(mocker):
|
||||
patch_exchange(mocker, id="kraken")
|
||||
patch_exchange(mocker, exchange="kraken")
|
||||
mocker.patch(f"{EXMS}.get_markets", return_value={})
|
||||
args = [
|
||||
"download-data",
|
||||
|
||||
@@ -137,7 +137,7 @@ def generate_trades_history(n_rows, start_date: Optional[datetime] = None, days=
|
||||
random_timestamps_in_seconds = np.random.uniform(_start_timestamp, _end_timestamp, n_rows)
|
||||
timestamp = pd.to_datetime(random_timestamps_in_seconds, unit="s")
|
||||
|
||||
id = [
|
||||
trade_id = [
|
||||
f"a{np.random.randint(1e6, 1e7 - 1)}cd{np.random.randint(100, 999)}" for _ in range(n_rows)
|
||||
]
|
||||
|
||||
@@ -155,7 +155,7 @@ def generate_trades_history(n_rows, start_date: Optional[datetime] = None, days=
|
||||
df = pd.DataFrame(
|
||||
{
|
||||
"timestamp": timestamp,
|
||||
"id": id,
|
||||
"id": trade_id,
|
||||
"type": None,
|
||||
"side": side,
|
||||
"price": price,
|
||||
@@ -236,12 +236,12 @@ def patched_configuration_load_config_file(mocker, config) -> None:
|
||||
|
||||
|
||||
def patch_exchange(
|
||||
mocker, api_mock=None, id="binance", mock_markets=True, mock_supported_modes=True
|
||||
mocker, api_mock=None, exchange="binance", mock_markets=True, mock_supported_modes=True
|
||||
) -> None:
|
||||
mocker.patch(f"{EXMS}.validate_config", MagicMock())
|
||||
mocker.patch(f"{EXMS}.validate_timeframes", MagicMock())
|
||||
mocker.patch(f"{EXMS}.id", PropertyMock(return_value=id))
|
||||
mocker.patch(f"{EXMS}.name", PropertyMock(return_value=id.title()))
|
||||
mocker.patch(f"{EXMS}.id", PropertyMock(return_value=exchange))
|
||||
mocker.patch(f"{EXMS}.name", PropertyMock(return_value=exchange.title()))
|
||||
mocker.patch(f"{EXMS}.precisionMode", PropertyMock(return_value=2))
|
||||
# Temporary patch ...
|
||||
mocker.patch("freqtrade.exchange.bybit.Bybit.cache_leverage_tiers")
|
||||
@@ -254,7 +254,8 @@ def patch_exchange(
|
||||
|
||||
if mock_supported_modes:
|
||||
mocker.patch(
|
||||
f"freqtrade.exchange.{id}.{id.capitalize()}._supported_trading_mode_margin_pairs",
|
||||
f"freqtrade.exchange.{exchange}.{exchange.capitalize()}"
|
||||
"._supported_trading_mode_margin_pairs",
|
||||
PropertyMock(
|
||||
return_value=[
|
||||
(TradingMode.MARGIN, MarginMode.CROSS),
|
||||
@@ -274,10 +275,10 @@ def patch_exchange(
|
||||
|
||||
|
||||
def get_patched_exchange(
|
||||
mocker, config, api_mock=None, id="binance", mock_markets=True, mock_supported_modes=True
|
||||
mocker, config, api_mock=None, exchange="binance", mock_markets=True, mock_supported_modes=True
|
||||
) -> Exchange:
|
||||
patch_exchange(mocker, api_mock, id, mock_markets, mock_supported_modes)
|
||||
config["exchange"]["name"] = id
|
||||
patch_exchange(mocker, api_mock, exchange, mock_markets, mock_supported_modes)
|
||||
config["exchange"]["name"] = exchange
|
||||
try:
|
||||
exchange = ExchangeResolver.load_exchange(config, load_leverage_tiers=True)
|
||||
except ImportError:
|
||||
@@ -587,6 +588,7 @@ def get_default_conf(testdatadir):
|
||||
"exchange": {
|
||||
"name": "binance",
|
||||
"key": "key",
|
||||
"enable_ws": False,
|
||||
"secret": "secret",
|
||||
"pair_whitelist": ["ETH/BTC", "LTC/BTC", "XRP/BTC", "NEO/BTC"],
|
||||
"pair_blacklist": [
|
||||
@@ -628,6 +630,7 @@ def get_default_conf_usdt(testdatadir):
|
||||
"name": "binance",
|
||||
"enabled": True,
|
||||
"key": "key",
|
||||
"enable_ws": False,
|
||||
"secret": "secret",
|
||||
"pair_whitelist": [
|
||||
"ETH/USDT",
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_datahandler_ohlcv_regex(filename, pair, timeframe, candletype):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input,expected",
|
||||
"pair,expected",
|
||||
[
|
||||
("XMR_USDT", "XMR/USDT"),
|
||||
("BTC_USDT", "BTC/USDT"),
|
||||
@@ -95,8 +95,8 @@ def test_datahandler_ohlcv_regex(filename, pair, timeframe, candletype):
|
||||
("UNITTEST_USDT", "UNITTEST/USDT"),
|
||||
],
|
||||
)
|
||||
def test_rebuild_pair_from_filename(input, expected):
|
||||
assert IDataHandler.rebuild_pair_from_filename(input) == expected
|
||||
def test_rebuild_pair_from_filename(pair, expected):
|
||||
assert IDataHandler.rebuild_pair_from_filename(pair) == expected
|
||||
|
||||
|
||||
def test_datahandler_ohlcv_get_available_data(testdatadir):
|
||||
|
||||
@@ -250,7 +250,7 @@ def test_refresh(mocker, default_conf):
|
||||
refresh_mock = MagicMock()
|
||||
mocker.patch(f"{EXMS}.refresh_latest_ohlcv", refresh_mock)
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
timeframe = default_conf["timeframe"]
|
||||
pairs = [("XRP/BTC", timeframe), ("UNITTEST/BTC", timeframe)]
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ def test_download_data_main_no_markets(mocker, caplog):
|
||||
"freqtrade.data.history.history_utils.refresh_backtest_ohlcv_data",
|
||||
MagicMock(return_value=["ETH/BTC", "XRP/BTC"]),
|
||||
)
|
||||
patch_exchange(mocker, id="binance")
|
||||
patch_exchange(mocker, exchange="binance")
|
||||
mocker.patch(f"{EXMS}.get_markets", return_value={})
|
||||
config = setup_utils_configuration({"exchange": "binance"}, RunMode.UTIL_EXCHANGE)
|
||||
config.update({"days": 20, "pairs": ["ETH/BTC", "XRP/BTC"], "timeframes": ["5m", "1h"]})
|
||||
@@ -91,7 +91,7 @@ def test_download_data_main_trades(mocker):
|
||||
|
||||
|
||||
def test_download_data_main_data_invalid(mocker):
|
||||
patch_exchange(mocker, id="kraken")
|
||||
patch_exchange(mocker, exchange="kraken")
|
||||
mocker.patch(f"{EXMS}.get_markets", return_value={})
|
||||
config = setup_utils_configuration({"exchange": "kraken"}, RunMode.UTIL_EXCHANGE)
|
||||
config.update(
|
||||
|
||||
@@ -555,7 +555,7 @@ def test_refresh_backtest_ohlcv_data(
|
||||
mocker.patch.object(Path, "unlink", MagicMock())
|
||||
default_conf["trading_mode"] = trademode
|
||||
|
||||
ex = get_patched_exchange(mocker, default_conf, id="bybit")
|
||||
ex = get_patched_exchange(mocker, default_conf, exchange="bybit")
|
||||
timerange = TimeRange.parse_timerange("20190101-20190102")
|
||||
refresh_backtest_ohlcv_data(
|
||||
exchange=ex,
|
||||
|
||||
@@ -17,7 +17,7 @@ def test_import_kraken_trades_from_csv(testdatadir, tmp_path, caplog, default_co
|
||||
|
||||
default_conf_usdt["exchange"]["name"] = "kraken"
|
||||
|
||||
patch_exchange(mocker, id="kraken")
|
||||
patch_exchange(mocker, exchange="kraken")
|
||||
mocker.patch(
|
||||
f"{EXMS}.markets",
|
||||
PropertyMock(
|
||||
|
||||
@@ -12,7 +12,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"side,type,time_in_force,expected",
|
||||
"side,order_type,time_in_force,expected",
|
||||
[
|
||||
("buy", "limit", "gtc", {"timeInForce": "GTC"}),
|
||||
("buy", "limit", "IOC", {"timeInForce": "IOC"}),
|
||||
@@ -22,9 +22,9 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
||||
("sell", "market", "PO", {}),
|
||||
],
|
||||
)
|
||||
def test__get_params_binance(default_conf, mocker, side, type, time_in_force, expected):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
assert exchange._get_params(side, type, 1, False, time_in_force) == expected
|
||||
def test__get_params_binance(default_conf, mocker, side, order_type, time_in_force, expected):
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
assert exchange._get_params(side, order_type, 1, False, time_in_force) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("trademode", [TradingMode.FUTURES, TradingMode.SPOT])
|
||||
@@ -159,7 +159,7 @@ def test_create_stoploss_order_dry_run_binance(default_conf, mocker):
|
||||
"sl1,sl2,sl3,side", [(1501, 1499, 1501, "sell"), (1499, 1501, 1499, "buy")]
|
||||
)
|
||||
def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
order = {
|
||||
"type": "stop_loss_limit",
|
||||
"price": 1500,
|
||||
@@ -378,7 +378,7 @@ def test_fill_leverage_tiers_binance(default_conf, mocker):
|
||||
default_conf["dry_run"] = False
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="binance")
|
||||
exchange.fill_leverage_tiers()
|
||||
|
||||
assert exchange._leverage_tiers == {
|
||||
@@ -497,7 +497,7 @@ def test_fill_leverage_tiers_binance_dryrun(default_conf, mocker, leverage_tiers
|
||||
api_mock = MagicMock()
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="binance")
|
||||
exchange.fill_leverage_tiers()
|
||||
assert len(exchange._leverage_tiers.keys()) > 100
|
||||
for key, value in leverage_tiers.items():
|
||||
@@ -518,10 +518,10 @@ def test_additional_exchange_init_binance(default_conf, mocker):
|
||||
OperationalException,
|
||||
match=r"Hedge Mode is not supported.*\nMulti-Asset Mode is not supported.*",
|
||||
):
|
||||
get_patched_exchange(mocker, default_conf, id="binance", api_mock=api_mock)
|
||||
get_patched_exchange(mocker, default_conf, exchange="binance", api_mock=api_mock)
|
||||
api_mock.fapiPrivateGetPositionSideDual = MagicMock(return_value={"dualSidePosition": False})
|
||||
api_mock.fapiPrivateGetMultiAssetsMargin = MagicMock(return_value={"multiAssetsMargin": False})
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance", api_mock=api_mock)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance", api_mock=api_mock)
|
||||
assert exchange
|
||||
ccxt_exceptionhandlers(
|
||||
mocker,
|
||||
@@ -541,7 +541,7 @@ def test__set_leverage_binance(mocker, default_conf):
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="binance")
|
||||
exchange._set_leverage(3.2, "BTC/USDT:USDT")
|
||||
assert api_mock.set_leverage.call_count == 1
|
||||
# Leverage is rounded to 3.
|
||||
@@ -574,7 +574,7 @@ async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, c
|
||||
]
|
||||
]
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
# Monkey-patch async function
|
||||
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
||||
|
||||
@@ -620,7 +620,7 @@ def test_get_maintenance_ratio_and_amt_binance(
|
||||
amt,
|
||||
):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
exchange._leverage_tiers = leverage_tiers
|
||||
(result_ratio, result_amt) = exchange.get_maintenance_ratio_and_amt(pair, nominal_value)
|
||||
assert (round(result_ratio, 8), round(result_amt, 8)) == (mm_ratio, amt)
|
||||
|
||||
@@ -39,7 +39,7 @@ def test_get_trades_for_order(default_conf, mocker):
|
||||
}
|
||||
]
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
orders = exchange.get_trades_for_order(order_id, "LTC/BTC", since)
|
||||
assert len(orders) == 1
|
||||
|
||||
@@ -18,7 +18,7 @@ def test_additional_exchange_init_bybit(default_conf, mocker, caplog):
|
||||
api_mock.set_position_mode = MagicMock(return_value={"dualSidePosition": False})
|
||||
api_mock.is_unified_enabled = MagicMock(return_value=[False, False])
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="bybit", api_mock=api_mock)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="bybit", api_mock=api_mock)
|
||||
assert api_mock.set_position_mode.call_count == 1
|
||||
assert api_mock.is_unified_enabled.call_count == 1
|
||||
assert exchange.unified_account is False
|
||||
@@ -28,9 +28,9 @@ def test_additional_exchange_init_bybit(default_conf, mocker, caplog):
|
||||
api_mock.set_position_mode.reset_mock()
|
||||
api_mock.is_unified_enabled = MagicMock(return_value=[False, True])
|
||||
with pytest.raises(OperationalException, match=r"Bybit: Unified account is not supported.*"):
|
||||
get_patched_exchange(mocker, default_conf, id="bybit", api_mock=api_mock)
|
||||
get_patched_exchange(mocker, default_conf, exchange="bybit", api_mock=api_mock)
|
||||
assert log_has("Bybit: Unified account.", caplog)
|
||||
# exchange = get_patched_exchange(mocker, default_conf, id="bybit", api_mock=api_mock)
|
||||
# exchange = get_patched_exchange(mocker, default_conf, exchange="bybit", api_mock=api_mock)
|
||||
# assert api_mock.set_position_mode.call_count == 1
|
||||
# assert api_mock.is_unified_enabled.call_count == 1
|
||||
# assert exchange.unified_account is True
|
||||
@@ -45,7 +45,7 @@ async def test_bybit_fetch_funding_rate(default_conf, mocker):
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
api_mock = MagicMock()
|
||||
api_mock.fetch_funding_rate_history = get_mock_coro(return_value=[])
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="bybit", api_mock=api_mock)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="bybit", api_mock=api_mock)
|
||||
limit = 200
|
||||
# Test fetch_funding_rate_history (current data)
|
||||
await exchange._fetch_funding_rate_history(
|
||||
@@ -77,14 +77,14 @@ async def test_bybit_fetch_funding_rate(default_conf, mocker):
|
||||
|
||||
def test_bybit_get_funding_fees(default_conf, mocker):
|
||||
now = datetime.now(timezone.utc)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="bybit")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="bybit")
|
||||
exchange._fetch_and_calculate_funding_fees = MagicMock()
|
||||
exchange.get_funding_fees("BTC/USDT:USDT", 1, False, now)
|
||||
assert exchange._fetch_and_calculate_funding_fees.call_count == 0
|
||||
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="bybit")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="bybit")
|
||||
exchange._fetch_and_calculate_funding_fees = MagicMock()
|
||||
exchange.get_funding_fees("BTC/USDT:USDT", 1, False, now)
|
||||
|
||||
@@ -105,13 +105,13 @@ def test_bybit_fetch_orders(default_conf, mocker, limit_order):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
start_time = datetime.now(timezone.utc) - timedelta(days=20)
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="bybit")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bybit")
|
||||
# Not available in dry-run
|
||||
assert exchange.fetch_orders("mocked", start_time) == []
|
||||
assert api_mock.fetch_orders.call_count == 0
|
||||
default_conf["dry_run"] = False
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="bybit")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bybit")
|
||||
res = exchange.fetch_orders("mocked", start_time)
|
||||
# Bybit will call the endpoint 3 times, as it has a limit of 7 days per call
|
||||
assert api_mock.fetch_orders.call_count == 3
|
||||
@@ -136,7 +136,7 @@ def test_bybit_fetch_order_canceled_empty(default_conf_usdt, mocker):
|
||||
)
|
||||
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, api_mock, id="bybit")
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, api_mock, exchange="bybit")
|
||||
|
||||
res = exchange.fetch_order("123", "BTC/USDT")
|
||||
assert res["remaining"] is None
|
||||
|
||||
@@ -117,19 +117,19 @@ def ccxt_exceptionhandlers(
|
||||
with patch("freqtrade.exchange.common.time.sleep"):
|
||||
with pytest.raises(DDosProtection):
|
||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.DDoSProtection("DDos"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
getattr(exchange, fun)(**kwargs)
|
||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == retries
|
||||
|
||||
with pytest.raises(TemporaryError):
|
||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.OperationFailed("DeaDBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
getattr(exchange, fun)(**kwargs)
|
||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == retries
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
getattr(exchange, fun)(**kwargs)
|
||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == 1
|
||||
|
||||
@@ -303,7 +303,7 @@ def test_exchange_resolver(default_conf, mocker, caplog):
|
||||
def test_validate_order_time_in_force(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
# explicitly test bybit, exchanges implementing other policies need separate tests
|
||||
ex = get_patched_exchange(mocker, default_conf, id="bybit")
|
||||
ex = get_patched_exchange(mocker, default_conf, exchange="bybit")
|
||||
tif = {
|
||||
"buy": "gtc",
|
||||
"sell": "gtc",
|
||||
@@ -345,7 +345,7 @@ def test_validate_order_time_in_force(default_conf, mocker, caplog):
|
||||
)
|
||||
def test_price_get_one_pip(default_conf, mocker, price, precision_mode, precision, expected):
|
||||
markets = PropertyMock(return_value={"ETH/BTC": {"precision": {"price": precision}}})
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
mocker.patch(f"{EXMS}.markets", markets)
|
||||
mocker.patch(f"{EXMS}.precisionMode", PropertyMock(return_value=precision_mode))
|
||||
pair = "ETH/BTC"
|
||||
@@ -353,7 +353,7 @@ def test_price_get_one_pip(default_conf, mocker, price, precision_mode, precisio
|
||||
|
||||
|
||||
def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
stoploss = -0.05
|
||||
markets = {"ETH/BTC": {"symbol": "ETH/BTC"}}
|
||||
|
||||
@@ -462,7 +462,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
markets["ETH/BTC"]["contractSize"] = "0.01"
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
mocker.patch(f"{EXMS}.markets", PropertyMock(return_value=markets))
|
||||
|
||||
# Contract size 0.01
|
||||
@@ -483,7 +483,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
|
||||
|
||||
def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
stoploss = -0.05
|
||||
markets = {"ETH/BTC": {"symbol": "ETH/BTC"}}
|
||||
|
||||
@@ -564,7 +564,7 @@ def test_reload_markets(default_conf, mocker, caplog, time_machine):
|
||||
api_mock.load_markets = get_mock_coro(return_value=initial_markets)
|
||||
default_conf["exchange"]["markets_refresh_interval"] = 10
|
||||
exchange = get_patched_exchange(
|
||||
mocker, default_conf, api_mock, id="binance", mock_markets=False
|
||||
mocker, default_conf, api_mock, exchange="binance", mock_markets=False
|
||||
)
|
||||
lam_spy = mocker.spy(exchange, "_load_async_markets")
|
||||
assert exchange._last_markets_refresh == dt_ts()
|
||||
@@ -599,7 +599,7 @@ def test_reload_markets_exception(default_conf, mocker, caplog):
|
||||
api_mock.load_markets = get_mock_coro(side_effect=ccxt.NetworkError("LoadError"))
|
||||
default_conf["exchange"]["markets_refresh_interval"] = 10
|
||||
exchange = get_patched_exchange(
|
||||
mocker, default_conf, api_mock, id="binance", mock_markets=False
|
||||
mocker, default_conf, api_mock, exchange="binance", mock_markets=False
|
||||
)
|
||||
|
||||
exchange._last_markets_refresh = 2
|
||||
@@ -1152,7 +1152,7 @@ def test_exchange_has(default_conf, mocker):
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
def test_create_dry_run_order(default_conf, mocker, side, exchange_name, leverage):
|
||||
default_conf["dry_run"] = True
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
|
||||
order = exchange.create_dry_run_order(
|
||||
pair="ETH/BTC", ordertype="limit", side=side, amount=1, rate=200, leverage=leverage
|
||||
@@ -1246,7 +1246,7 @@ def test_create_dry_run_order_limit_fill(
|
||||
leverage,
|
||||
):
|
||||
default_conf["dry_run"] = True
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
mocker.patch.multiple(
|
||||
EXMS,
|
||||
exchange_has=MagicMock(return_value=True),
|
||||
@@ -1315,7 +1315,7 @@ def test_create_dry_run_order_market_fill(
|
||||
default_conf, mocker, side, rate, amount, endprice, exchange_name, order_book_l2_usd, leverage
|
||||
):
|
||||
default_conf["dry_run"] = True
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
mocker.patch.multiple(
|
||||
EXMS,
|
||||
exchange_has=MagicMock(return_value=True),
|
||||
@@ -1364,7 +1364,7 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice,
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange._set_leverage = MagicMock()
|
||||
exchange.set_margin_mode = MagicMock()
|
||||
|
||||
@@ -1392,7 +1392,7 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice,
|
||||
"amount": 1,
|
||||
}
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.trading_mode = TradingMode.FUTURES
|
||||
exchange._set_leverage = MagicMock()
|
||||
exchange.set_margin_mode = MagicMock()
|
||||
@@ -1411,7 +1411,7 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice,
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
def test_buy_dry_run(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = True
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
|
||||
order = exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
@@ -1439,7 +1439,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = False
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
order = exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
@@ -1483,7 +1483,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
||||
# test exception handling
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("Not enough funds"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
ordertype=order_type,
|
||||
@@ -1496,7 +1496,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
||||
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
ordertype="limit",
|
||||
@@ -1509,7 +1509,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
||||
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
ordertype="market",
|
||||
@@ -1522,7 +1522,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
||||
|
||||
with pytest.raises(TemporaryError):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("Network disconnect"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
ordertype=order_type,
|
||||
@@ -1535,7 +1535,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
ordertype=order_type,
|
||||
@@ -1558,7 +1558,7 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = False
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
order_type = "limit"
|
||||
time_in_force = "ioc"
|
||||
@@ -1637,7 +1637,7 @@ def test_sell_prod(default_conf, mocker, exchange_name):
|
||||
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
order = exchange.create_order(
|
||||
pair="ETH/BTC", ordertype=order_type, side="sell", amount=1, rate=200, leverage=1.0
|
||||
@@ -1669,14 +1669,14 @@ def test_sell_prod(default_conf, mocker, exchange_name):
|
||||
# test exception handling
|
||||
with pytest.raises(InsufficientFundsError):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC", ordertype=order_type, side="sell", amount=1, rate=200, leverage=1.0
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC", ordertype="limit", side="sell", amount=1, rate=200, leverage=1.0
|
||||
)
|
||||
@@ -1684,21 +1684,21 @@ def test_sell_prod(default_conf, mocker, exchange_name):
|
||||
# Market orders don't require price, so the behaviour is slightly different
|
||||
with pytest.raises(DependencyException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC", ordertype="market", side="sell", amount=1, rate=200, leverage=1.0
|
||||
)
|
||||
|
||||
with pytest.raises(TemporaryError):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("No Connection"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC", ordertype=order_type, side="sell", amount=1, rate=200, leverage=1.0
|
||||
)
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.create_order(
|
||||
pair="ETH/BTC", ordertype=order_type, side="sell", amount=1, rate=200, leverage=1.0
|
||||
)
|
||||
@@ -1715,7 +1715,7 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = False
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
order_type = "limit"
|
||||
time_in_force = "ioc"
|
||||
@@ -1777,7 +1777,7 @@ def test_get_balances_prod(default_conf, mocker, exchange_name):
|
||||
return_value={"1ST": balance_item, "2ND": balance_item, "3RD": balance_item}
|
||||
)
|
||||
default_conf["dry_run"] = False
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert len(exchange.get_balances()) == 3
|
||||
assert exchange.get_balances()["1ST"]["free"] == 10.0
|
||||
assert exchange.get_balances()["1ST"]["total"] == 10.0
|
||||
@@ -1798,12 +1798,12 @@ def test_fetch_positions(default_conf, mocker, exchange_name):
|
||||
{"symbol": "XRP/USDT:USDT", "leverage": 5},
|
||||
]
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.fetch_positions() == []
|
||||
default_conf["dry_run"] = False
|
||||
default_conf["trading_mode"] = "futures"
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
res = exchange.fetch_positions()
|
||||
assert len(res) == 2
|
||||
|
||||
@@ -1830,13 +1830,13 @@ def test_fetch_orders(default_conf, mocker, exchange_name, limit_order):
|
||||
if exchange_name == "bybit":
|
||||
expected = 3
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
# Not available in dry-run
|
||||
assert exchange.fetch_orders("mocked", start_time) == []
|
||||
assert api_mock.fetch_orders.call_count == 0
|
||||
default_conf["dry_run"] = False
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
res = exchange.fetch_orders("mocked", start_time)
|
||||
assert api_mock.fetch_orders.call_count == expected
|
||||
assert api_mock.fetch_open_orders.call_count == 0
|
||||
@@ -1937,7 +1937,7 @@ def test_fetch_trading_fees(default_conf, mocker):
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
api_mock.fetch_trading_fees = MagicMock(return_value=tick)
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
assert "1INCH/USDT:USDT" in exchange._trading_fees
|
||||
assert "ETH/USDT:USDT" in exchange._trading_fees
|
||||
@@ -1952,7 +1952,7 @@ def test_fetch_trading_fees(default_conf, mocker):
|
||||
)
|
||||
|
||||
api_mock.fetch_trading_fees = MagicMock(return_value={})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_trading_fees()
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
assert exchange.fetch_trading_fees() == {}
|
||||
@@ -1977,7 +1977,7 @@ def test_fetch_bids_asks(default_conf, mocker):
|
||||
exchange_name = "binance"
|
||||
api_mock.fetch_bids_asks = MagicMock(return_value=tick)
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
# retrieve original ticker
|
||||
bidsasks = exchange.fetch_bids_asks()
|
||||
|
||||
@@ -2004,11 +2004,11 @@ def test_fetch_bids_asks(default_conf, mocker):
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.fetch_bids_asks = MagicMock(side_effect=ccxt.NotSupported("DeadBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_bids_asks()
|
||||
|
||||
api_mock.fetch_bids_asks = MagicMock(return_value={})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_bids_asks()
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
assert exchange.fetch_bids_asks() == {}
|
||||
@@ -2034,7 +2034,7 @@ def test_get_tickers(default_conf, mocker, exchange_name, caplog):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
api_mock.fetch_tickers = MagicMock(return_value=tick)
|
||||
api_mock.fetch_bids_asks = MagicMock(return_value={})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
# retrieve original ticker
|
||||
tickers = exchange.get_tickers()
|
||||
|
||||
@@ -2064,19 +2064,19 @@ def test_get_tickers(default_conf, mocker, exchange_name, caplog):
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.fetch_tickers = MagicMock(side_effect=ccxt.NotSupported("DeadBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.get_tickers()
|
||||
|
||||
caplog.clear()
|
||||
api_mock.fetch_tickers = MagicMock(side_effect=[ccxt.BadSymbol("SomeSymbol"), []])
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
x = exchange.get_tickers()
|
||||
assert x == []
|
||||
assert log_has_re(r"Could not load tickers due to BadSymbol\..*SomeSymbol", caplog)
|
||||
caplog.clear()
|
||||
|
||||
api_mock.fetch_tickers = MagicMock(return_value={})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.get_tickers()
|
||||
|
||||
api_mock.fetch_tickers.reset_mock()
|
||||
@@ -2084,7 +2084,7 @@ def test_get_tickers(default_conf, mocker, exchange_name, caplog):
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
exchange.get_tickers()
|
||||
assert api_mock.fetch_tickers.call_count == 1
|
||||
@@ -2107,7 +2107,7 @@ def test_fetch_ticker(default_conf, mocker, exchange_name):
|
||||
}
|
||||
api_mock.fetch_ticker = MagicMock(return_value=tick)
|
||||
api_mock.markets = {"ETH/BTC": {"active": True}}
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
# retrieve original ticker
|
||||
ticker = exchange.fetch_ticker(pair="ETH/BTC")
|
||||
|
||||
@@ -2122,7 +2122,7 @@ def test_fetch_ticker(default_conf, mocker, exchange_name):
|
||||
"last": 42,
|
||||
}
|
||||
api_mock.fetch_ticker = MagicMock(return_value=tick)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
# if not caching the result we should get the same ticker
|
||||
# if not fetching a new result we should get the cached ticker
|
||||
@@ -2143,7 +2143,7 @@ def test_fetch_ticker(default_conf, mocker, exchange_name):
|
||||
)
|
||||
|
||||
api_mock.fetch_ticker = MagicMock(return_value={})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_ticker(pair="ETH/BTC")
|
||||
|
||||
with pytest.raises(DependencyException, match=r"Pair XRP/ETH not available"):
|
||||
@@ -2152,7 +2152,7 @@ def test_fetch_ticker(default_conf, mocker, exchange_name):
|
||||
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
def test___now_is_time_to_refresh(default_conf, mocker, exchange_name, time_machine):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
pair = "BTC/USDT"
|
||||
candle_type = CandleType.SPOT
|
||||
start_dt = datetime(2023, 12, 1, 0, 10, 0, tzinfo=timezone.utc)
|
||||
@@ -2181,7 +2181,7 @@ def test___now_is_time_to_refresh(default_conf, mocker, exchange_name, time_mach
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
@pytest.mark.parametrize("candle_type", ["mark", ""])
|
||||
def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_type):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
ohlcv = [
|
||||
[
|
||||
dt_ts(), # unix timestamp ms
|
||||
@@ -2236,7 +2236,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_
|
||||
5, # volume (in quote currency)
|
||||
]
|
||||
]
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
# Monkey-patch async function
|
||||
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
||||
|
||||
@@ -2538,7 +2538,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_
|
||||
]
|
||||
|
||||
caplog.set_level(logging.DEBUG)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
# Monkey-patch async function
|
||||
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
||||
|
||||
@@ -2570,7 +2570,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_
|
||||
OperationalException, match=r"Could not fetch historical candle \(OHLCV\) data.*"
|
||||
):
|
||||
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
await exchange._async_get_candle_history(
|
||||
pair, "5m", CandleType.SPOT, dt_ts(dt_now() - timedelta(seconds=2000))
|
||||
)
|
||||
@@ -2582,7 +2582,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_
|
||||
match=r"Exchange.* does not support fetching " r"historical candle \(OHLCV\) data\..*",
|
||||
):
|
||||
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.NotSupported("Not supported"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
await exchange._async_get_candle_history(
|
||||
pair, "5m", CandleType.SPOT, dt_ts(dt_now() - timedelta(seconds=2000))
|
||||
)
|
||||
@@ -2603,7 +2603,7 @@ async def test__async_kucoin_get_candle_history(default_conf, mocker, caplog):
|
||||
'{"code":"429000","msg":"Too Many Requests"}'
|
||||
)
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kucoin")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="kucoin")
|
||||
mocker.patch(f"{EXMS}.name", PropertyMock(return_value="KuCoin"))
|
||||
|
||||
msg = "Kucoin 429 error, avoid triggering DDosProtection backoff delay"
|
||||
@@ -2725,7 +2725,7 @@ def test_fetch_l2_order_book(default_conf, mocker, order_book_l2, exchange_name)
|
||||
api_mock = MagicMock()
|
||||
|
||||
api_mock.fetch_l2_order_book = order_book_l2
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
order_book = exchange.fetch_l2_order_book(pair="ETH/BTC", limit=10)
|
||||
assert "bids" in order_book
|
||||
assert "asks" in order_book
|
||||
@@ -2753,15 +2753,15 @@ def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name):
|
||||
api_mock = MagicMock()
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NotSupported("Not supported"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_l2_order_book(pair="ETH/BTC", limit=50)
|
||||
with pytest.raises(TemporaryError):
|
||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_l2_order_book(pair="ETH/BTC", limit=50)
|
||||
with pytest.raises(OperationalException):
|
||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_l2_order_book(pair="ETH/BTC", limit=50)
|
||||
|
||||
|
||||
@@ -3058,7 +3058,7 @@ async def test___async_get_candle_history_sort(default_conf, mocker, exchange_na
|
||||
[1527830700000, 0.07652, 0.07652, 0.07651, 0.07652, 10.04822687],
|
||||
[1527830400000, 0.07649, 0.07651, 0.07649, 0.07651, 2.5734867],
|
||||
]
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
|
||||
sort_mock = mocker.patch("freqtrade.exchange.exchange.sorted", MagicMock(side_effect=sort_data))
|
||||
# Test the OHLCV data sort
|
||||
@@ -3128,7 +3128,7 @@ async def test__async_fetch_trades(
|
||||
default_conf, mocker, caplog, exchange_name, fetch_trades_result
|
||||
):
|
||||
caplog.set_level(logging.DEBUG)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
# Monkey-patch async function
|
||||
exchange._api_async.fetch_trades = get_mock_coro(fetch_trades_result)
|
||||
|
||||
@@ -3182,7 +3182,7 @@ async def test__async_fetch_trades(
|
||||
api_mock = MagicMock()
|
||||
with pytest.raises(OperationalException, match=r"Could not fetch trade data*"):
|
||||
api_mock.fetch_trades = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
await exchange._async_fetch_trades(pair, since=dt_ts(dt_now() - timedelta(seconds=2000)))
|
||||
exchange.close()
|
||||
|
||||
@@ -3191,7 +3191,7 @@ async def test__async_fetch_trades(
|
||||
match=r"Exchange.* does not support fetching " r"historical trade data\..*",
|
||||
):
|
||||
api_mock.fetch_trades = MagicMock(side_effect=ccxt.NotSupported("Not supported"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
await exchange._async_fetch_trades(pair, since=dt_ts(dt_now() - timedelta(seconds=2000)))
|
||||
exchange.close()
|
||||
|
||||
@@ -3203,7 +3203,7 @@ async def test__async_fetch_trades_contract_size(
|
||||
caplog.set_level(logging.DEBUG)
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
default_conf["trading_mode"] = "futures"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
# Monkey-patch async function
|
||||
exchange._api_async.fetch_trades = get_mock_coro(
|
||||
[
|
||||
@@ -3246,7 +3246,7 @@ async def test__async_fetch_trades_contract_size(
|
||||
async def test__async_get_trade_history_id(
|
||||
default_conf, mocker, exchange_name, fetch_trades_result
|
||||
):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
if exchange._trades_pagination != "id":
|
||||
exchange.close()
|
||||
pytest.skip("Exchange does not support pagination by trade id")
|
||||
@@ -3305,7 +3305,7 @@ async def test__async_get_trade_history_id(
|
||||
def test__valid_trade_pagination_id(mocker, default_conf_usdt, exchange_name, trade_id, expected):
|
||||
if exchange_name == "kraken":
|
||||
pytest.skip("Kraken has a different pagination id format, and an explicit test.")
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, exchange=exchange_name)
|
||||
|
||||
assert exchange._valid_trade_pagination_id("XRP/USDT", trade_id) == expected
|
||||
|
||||
@@ -3324,7 +3324,7 @@ async def test__async_get_trade_history_time(
|
||||
return fetch_trades_result[-1:]
|
||||
|
||||
caplog.set_level(logging.DEBUG)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
if exchange._trades_pagination != "time":
|
||||
exchange.close()
|
||||
pytest.skip("Exchange does not support pagination by timestamp")
|
||||
@@ -3366,7 +3366,7 @@ async def test__async_get_trade_history_time_empty(
|
||||
return [], None
|
||||
|
||||
caplog.set_level(logging.DEBUG)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
# Monkey-patch async function
|
||||
exchange._async_fetch_trades = MagicMock(side_effect=mock_get_trade_hist)
|
||||
pair = "ETH/BTC"
|
||||
@@ -3387,7 +3387,7 @@ async def test__async_get_trade_history_time_empty(
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
def test_get_historic_trades(default_conf, mocker, caplog, exchange_name, trades_history):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
|
||||
pair = "ETH/BTC"
|
||||
|
||||
@@ -3418,7 +3418,7 @@ def test_get_historic_trades_notsupported(
|
||||
default_conf, mocker, caplog, exchange_name, trades_history
|
||||
):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=False)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
|
||||
pair = "ETH/BTC"
|
||||
|
||||
@@ -3432,7 +3432,7 @@ def test_get_historic_trades_notsupported(
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
def test_cancel_order_dry_run(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = True
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
mocker.patch(f"{EXMS}._dry_is_price_crossed", return_value=True)
|
||||
assert exchange.cancel_order(order_id="123", pair="TKN/BTC") == {}
|
||||
assert exchange.cancel_stoploss_order(order_id="123", pair="TKN/BTC") == {}
|
||||
@@ -3467,7 +3467,7 @@ def test_cancel_order_dry_run(default_conf, mocker, exchange_name):
|
||||
],
|
||||
)
|
||||
def test_check_order_canceled_empty(mocker, default_conf, exchange_name, order, result):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
assert exchange.check_order_canceled_empty(order) == result
|
||||
|
||||
|
||||
@@ -3487,7 +3487,7 @@ def test_check_order_canceled_empty(mocker, default_conf, exchange_name, order,
|
||||
],
|
||||
)
|
||||
def test_is_cancel_order_result_suitable(mocker, default_conf, exchange_name, order, result):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
assert exchange.is_cancel_order_result_suitable(order) == result
|
||||
|
||||
|
||||
@@ -3507,7 +3507,7 @@ def test_cancel_order_with_result(
|
||||
api_mock = MagicMock()
|
||||
api_mock.cancel_order = MagicMock(return_value=corder)
|
||||
api_mock.fetch_order = MagicMock(return_value={})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
res = exchange.cancel_order_with_result("1234", "ETH/BTC", 1234)
|
||||
assert isinstance(res, dict)
|
||||
assert api_mock.cancel_order.call_count == call_corder
|
||||
@@ -3521,7 +3521,7 @@ def test_cancel_order_with_result_error(default_conf, mocker, exchange_name, cap
|
||||
api_mock = MagicMock()
|
||||
api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order"))
|
||||
api_mock.fetch_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
res = exchange.cancel_order_with_result("1234", "ETH/BTC", 1541)
|
||||
assert isinstance(res, dict)
|
||||
@@ -3536,12 +3536,12 @@ def test_cancel_order(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = False
|
||||
api_mock = MagicMock()
|
||||
api_mock.cancel_order = MagicMock(return_value={"id": "123"})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.cancel_order(order_id="_", pair="TKN/BTC") == {"id": "123"}
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.cancel_order(order_id="_", pair="TKN/BTC")
|
||||
assert api_mock.cancel_order.call_count == 1
|
||||
|
||||
@@ -3562,12 +3562,12 @@ def test_cancel_stoploss_order(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = False
|
||||
api_mock = MagicMock()
|
||||
api_mock.cancel_order = MagicMock(return_value={"id": "123"})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.cancel_stoploss_order(order_id="_", pair="TKN/BTC") == {"id": "123"}
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.cancel_stoploss_order(order_id="_", pair="TKN/BTC")
|
||||
assert api_mock.cancel_order.call_count == 1
|
||||
|
||||
@@ -3591,7 +3591,7 @@ def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name):
|
||||
mock_prefix = "freqtrade.exchange.okx.Okx"
|
||||
mocker.patch(f"{EXMS}.fetch_stoploss_order", return_value={"for": 123})
|
||||
mocker.patch(f"{mock_prefix}.fetch_stoploss_order", return_value={"for": 123})
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
|
||||
res = {"fee": {}, "status": "canceled", "amount": 1234}
|
||||
mocker.patch(f"{EXMS}.cancel_stoploss_order", return_value=res)
|
||||
@@ -3616,7 +3616,7 @@ def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name):
|
||||
exc = InvalidOrderException("Did not find order")
|
||||
mocker.patch(f"{EXMS}.cancel_stoploss_order", side_effect=exc)
|
||||
mocker.patch(f"{mock_prefix}.cancel_stoploss_order", side_effect=exc)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
exchange.cancel_stoploss_order_with_result(order_id="_", pair="TKN/BTC", amount=123)
|
||||
|
||||
|
||||
@@ -3630,7 +3630,7 @@ def test_fetch_order(default_conf, mocker, exchange_name, caplog):
|
||||
order.symbol = "TKN/BTC"
|
||||
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
exchange._dry_run_open_orders["X"] = order
|
||||
assert exchange.fetch_order("X", "TKN/BTC").myid == 123
|
||||
|
||||
@@ -3640,18 +3640,18 @@ def test_fetch_order(default_conf, mocker, exchange_name, caplog):
|
||||
default_conf["dry_run"] = False
|
||||
api_mock = MagicMock()
|
||||
api_mock.fetch_order = MagicMock(return_value={"id": "123", "amount": 2, "symbol": "TKN/BTC"})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.fetch_order("X", "TKN/BTC") == {"id": "123", "amount": 2, "symbol": "TKN/BTC"}
|
||||
assert log_has(("API fetch_order: {'id': '123', 'amount': 2, 'symbol': 'TKN/BTC'}"), caplog)
|
||||
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.fetch_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_order(order_id="_", pair="TKN/BTC")
|
||||
assert api_mock.fetch_order.call_count == 1
|
||||
|
||||
api_mock.fetch_order = MagicMock(side_effect=ccxt.OrderNotFound("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
with patch("freqtrade.exchange.common.time.sleep") as tm:
|
||||
with pytest.raises(InvalidOrderException):
|
||||
exchange.fetch_order(order_id="_", pair="TKN/BTC")
|
||||
@@ -3686,7 +3686,7 @@ def test_fetch_order_emulated(default_conf, mocker, exchange_name, caplog):
|
||||
order.myid = 123
|
||||
order.symbol = "TKN/BTC"
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=False)
|
||||
exchange._dry_run_open_orders["X"] = order
|
||||
# Dry run - regular fetch_order behavior
|
||||
@@ -3704,7 +3704,7 @@ def test_fetch_order_emulated(default_conf, mocker, exchange_name, caplog):
|
||||
api_mock.fetch_closed_order = MagicMock(
|
||||
return_value={"id": "123", "amount": 2, "symbol": "TKN/BTC"}
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.fetch_order("X", "TKN/BTC") == {"id": "123", "amount": 2, "symbol": "TKN/BTC"}
|
||||
assert log_has(
|
||||
("API fetch_open_order: {'id': '123', 'amount': 2, 'symbol': 'TKN/BTC'}"), caplog
|
||||
@@ -3718,7 +3718,7 @@ def test_fetch_order_emulated(default_conf, mocker, exchange_name, caplog):
|
||||
api_mock.fetch_closed_order = MagicMock(
|
||||
return_value={"id": "123", "amount": 2, "symbol": "TKN/BTC"}
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.fetch_order("X", "TKN/BTC") == {"id": "123", "amount": 2, "symbol": "TKN/BTC"}
|
||||
assert log_has(
|
||||
("API fetch_closed_order: {'id': '123', 'amount': 2, 'symbol': 'TKN/BTC'}"), caplog
|
||||
@@ -3730,12 +3730,12 @@ def test_fetch_order_emulated(default_conf, mocker, exchange_name, caplog):
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.fetch_open_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
api_mock.fetch_closed_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_order(order_id="_", pair="TKN/BTC")
|
||||
assert api_mock.fetch_open_order.call_count == 1
|
||||
|
||||
api_mock.fetch_open_order = MagicMock(side_effect=ccxt.OrderNotFound("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
ccxt_exceptionhandlers(
|
||||
mocker,
|
||||
@@ -3758,7 +3758,7 @@ def test_fetch_stoploss_order(default_conf, mocker, exchange_name):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
order = MagicMock()
|
||||
order.myid = 123
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
exchange._dry_run_open_orders["X"] = order
|
||||
assert exchange.fetch_stoploss_order("X", "TKN/BTC").myid == 123
|
||||
|
||||
@@ -3768,7 +3768,7 @@ def test_fetch_stoploss_order(default_conf, mocker, exchange_name):
|
||||
default_conf["dry_run"] = False
|
||||
api_mock = MagicMock()
|
||||
api_mock.fetch_order = MagicMock(return_value={"id": "123", "symbol": "TKN/BTC"})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
res = {"id": "123", "symbol": "TKN/BTC"}
|
||||
if exchange_name == "okx":
|
||||
res = {"id": "123", "symbol": "TKN/BTC", "type": "stoploss"}
|
||||
@@ -3779,7 +3779,7 @@ def test_fetch_stoploss_order(default_conf, mocker, exchange_name):
|
||||
return
|
||||
with pytest.raises(InvalidOrderException):
|
||||
api_mock.fetch_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange.fetch_stoploss_order(order_id="_", pair="TKN/BTC")
|
||||
assert api_mock.fetch_order.call_count == 1
|
||||
|
||||
@@ -3797,7 +3797,7 @@ def test_fetch_stoploss_order(default_conf, mocker, exchange_name):
|
||||
|
||||
|
||||
def test_fetch_order_or_stoploss_order(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
fetch_order_mock = MagicMock()
|
||||
fetch_stoploss_order_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
@@ -3824,7 +3824,7 @@ def test_fetch_order_or_stoploss_order(default_conf, mocker):
|
||||
|
||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||
def test_name(default_conf, mocker, exchange_name):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
|
||||
assert exchange.name == exchange_name.title()
|
||||
assert exchange.id == exchange_name
|
||||
@@ -3875,7 +3875,7 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name, trading_mode,
|
||||
]
|
||||
)
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
|
||||
orders = exchange.get_trades_for_order(order_id, "ETH/USDT:USDT", since)
|
||||
assert len(orders) == 1
|
||||
@@ -3914,7 +3914,7 @@ def test_get_fee(default_conf, mocker, exchange_name):
|
||||
api_mock.calculate_fee = MagicMock(
|
||||
return_value={"type": "taker", "currency": "BTC", "rate": 0.025, "cost": 0.05}
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange._config.pop("fee", None)
|
||||
|
||||
assert exchange.get_fee("ETH/BTC") == 0.025
|
||||
@@ -3932,7 +3932,7 @@ def test_get_fee(default_conf, mocker, exchange_name):
|
||||
|
||||
|
||||
def test_stoploss_order_unsupported_exchange(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="bitpanda")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="bitpanda")
|
||||
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
||||
exchange.create_stoploss(
|
||||
pair="ETH/BTC", amount=1, stop_price=220, order_types={}, side="sell", leverage=1.0
|
||||
@@ -3956,7 +3956,7 @@ def test_stoploss_order_unsupported_exchange(default_conf, mocker):
|
||||
],
|
||||
)
|
||||
def test__get_stop_limit_rate(default_conf_usdt, mocker, side, ratio, expected):
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, exchange="binance")
|
||||
|
||||
order_types = {"stoploss_on_exchange_limit_ratio": ratio}
|
||||
if isinstance(expected, type) and issubclass(expected, Exception):
|
||||
@@ -4314,7 +4314,7 @@ def test_get_markets_error(default_conf, mocker):
|
||||
def test_ohlcv_candle_limit(default_conf, mocker, exchange_name):
|
||||
if exchange_name == "okx":
|
||||
pytest.skip("Tested separately for okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
timeframes = ("1m", "5m", "1h")
|
||||
expected = exchange._ft_has["ohlcv_candle_limit"]
|
||||
for timeframe in timeframes:
|
||||
@@ -4383,7 +4383,7 @@ def test_market_is_tradable(
|
||||
) -> None:
|
||||
default_conf["trading_mode"] = trademode
|
||||
mocker.patch(f"{EXMS}.validate_trading_mode_and_margin_mode")
|
||||
ex = get_patched_exchange(mocker, default_conf, id=exchange)
|
||||
ex = get_patched_exchange(mocker, default_conf, exchange=exchange)
|
||||
market = {
|
||||
"symbol": market_symbol,
|
||||
"base": base,
|
||||
@@ -4654,7 +4654,7 @@ def test_get_funding_fees(default_conf_usdt, mocker, exchange_name, caplog):
|
||||
now = datetime.now(timezone.utc)
|
||||
default_conf_usdt["trading_mode"] = "futures"
|
||||
default_conf_usdt["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, exchange=exchange_name)
|
||||
exchange._fetch_and_calculate_funding_fees = MagicMock(side_effect=ExchangeError)
|
||||
assert exchange.get_funding_fees("BTC/USDT:USDT", 1, False, now) == 0.0
|
||||
assert exchange._fetch_and_calculate_funding_fees.call_count == 1
|
||||
@@ -4707,7 +4707,7 @@ def test__get_funding_fees_from_exchange(default_conf, mocker, exchange_name):
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchFundingHistory": True})
|
||||
|
||||
# mocker.patch(f'{EXMS}.get_funding_fees', lambda pair, since: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
date_time = datetime.strptime("2021-09-01T00:00:01.000Z", "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
unix_time = int(date_time.timestamp())
|
||||
expected_fees = -0.001 # 0.14542341 + -0.14642341
|
||||
@@ -4737,7 +4737,7 @@ def test__get_funding_fees_from_exchange(default_conf, mocker, exchange_name):
|
||||
def test_get_stake_amount_considering_leverage(
|
||||
exchange, stake_amount, leverage, min_stake_with_lev, mocker, default_conf
|
||||
):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange)
|
||||
assert (
|
||||
exchange._get_stake_amount_considering_leverage(stake_amount, leverage)
|
||||
== min_stake_with_lev
|
||||
@@ -4804,7 +4804,7 @@ def test_validate_trading_mode_and_margin_mode(
|
||||
default_conf, mocker, exchange_name, trading_mode, margin_mode, exception_thrown
|
||||
):
|
||||
exchange = get_patched_exchange(
|
||||
mocker, default_conf, id=exchange_name, mock_supported_modes=False
|
||||
mocker, default_conf, exchange=exchange_name, mock_supported_modes=False
|
||||
)
|
||||
if exception_thrown:
|
||||
with pytest.raises(OperationalException):
|
||||
@@ -4831,7 +4831,7 @@ def test_validate_trading_mode_and_margin_mode(
|
||||
def test__ccxt_config(default_conf, mocker, exchange_name, trading_mode, ccxt_config):
|
||||
default_conf["trading_mode"] = trading_mode
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
assert exchange._ccxt_config == ccxt_config
|
||||
|
||||
|
||||
@@ -4850,7 +4850,7 @@ def test_get_max_leverage_from_margin(default_conf, mocker, pair, nominal_value,
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
api_mock = MagicMock()
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchLeverageTiers": False})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="gate")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="gate")
|
||||
assert exchange.get_max_leverage(pair, nominal_value) == max_lev
|
||||
|
||||
|
||||
@@ -4867,7 +4867,7 @@ def test_calculate_funding_fees(
|
||||
default_conf, mocker, size, funding_rate, mark_price, funding_fee, kraken_fee, time_in_ratio
|
||||
):
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
kraken = get_patched_exchange(mocker, default_conf, id="kraken")
|
||||
kraken = get_patched_exchange(mocker, default_conf, exchange="kraken")
|
||||
prior_date = timeframe_to_prev_date("1h", datetime.now(timezone.utc) - timedelta(hours=1))
|
||||
trade_date = timeframe_to_prev_date("1h", datetime.now(timezone.utc))
|
||||
funding_rates = DataFrame(
|
||||
@@ -5092,7 +5092,7 @@ def test__fetch_and_calculate_funding_fees(
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchOHLCV": True})
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchFundingRateHistory": True})
|
||||
|
||||
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||
ex = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange)
|
||||
mocker.patch(f"{EXMS}.timeframes", PropertyMock(return_value=["1h", "4h", "8h"]))
|
||||
funding_fees = ex._fetch_and_calculate_funding_fees(
|
||||
pair="ADA/USDT:USDT", amount=amount, is_short=True, open_date=d1, close_date=d2
|
||||
@@ -5106,7 +5106,7 @@ def test__fetch_and_calculate_funding_fees(
|
||||
|
||||
# Return empty "refresh_latest"
|
||||
mocker.patch(f"{EXMS}.refresh_latest_ohlcv", return_value={})
|
||||
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||
ex = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange)
|
||||
with pytest.raises(ExchangeError, match="Could not find funding rates."):
|
||||
ex._fetch_and_calculate_funding_fees(
|
||||
pair="ADA/USDT:USDT", amount=amount, is_short=False, open_date=d1, close_date=d2
|
||||
@@ -5137,7 +5137,7 @@ def test__fetch_and_calculate_funding_fees_datetime_called(
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchOHLCV": True})
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchFundingRateHistory": True})
|
||||
mocker.patch(f"{EXMS}.timeframes", PropertyMock(return_value=["4h", "8h"]))
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange)
|
||||
d1 = datetime.strptime("2021-08-31 23:00:01 +0000", "%Y-%m-%d %H:%M:%S %z")
|
||||
|
||||
time_machine.move_to("2021-09-01 08:00:00 +00:00")
|
||||
@@ -5454,7 +5454,7 @@ def test_liquidation_price_is_none(
|
||||
):
|
||||
default_conf["trading_mode"] = trading_mode
|
||||
default_conf["margin_mode"] = margin_mode
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
assert (
|
||||
exchange.get_liquidation_price(
|
||||
pair="DOGE/USDT",
|
||||
@@ -5553,7 +5553,7 @@ def test_liquidation_price_binance(
|
||||
default_conf["trading_mode"] = trading_mode
|
||||
default_conf["margin_mode"] = margin_mode
|
||||
default_conf["liquidation_buffer"] = 0.0
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name)
|
||||
exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(mm_ratio, maintenance_amt))
|
||||
assert (
|
||||
pytest.approx(
|
||||
@@ -5703,7 +5703,7 @@ def test_load_leverage_tiers(mocker, default_conf, exchange_name):
|
||||
)
|
||||
|
||||
# SPOT
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.load_leverage_tiers() == {}
|
||||
|
||||
default_conf["trading_mode"] = "futures"
|
||||
@@ -5712,12 +5712,12 @@ def test_load_leverage_tiers(mocker, default_conf, exchange_name):
|
||||
if exchange_name != "binance":
|
||||
# FUTURES has.fetchLeverageTiers == False
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchLeverageTiers": False})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.load_leverage_tiers() == {}
|
||||
|
||||
# FUTURES regular
|
||||
type(api_mock).has = PropertyMock(return_value={"fetchLeverageTiers": True})
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
assert exchange.load_leverage_tiers() == {
|
||||
"ADA/USDT:USDT": [
|
||||
{
|
||||
@@ -5869,13 +5869,13 @@ def test_get_maintenance_ratio_and_amt(
|
||||
|
||||
def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers):
|
||||
# Test Spot
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
assert exchange.get_max_leverage("BNB/USDT", 100.0) == 1.0
|
||||
|
||||
# Test Futures
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="binance")
|
||||
|
||||
exchange._leverage_tiers = leverage_tiers
|
||||
|
||||
@@ -5899,7 +5899,7 @@ def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers):
|
||||
def test__get_params(mocker, default_conf, exchange_name):
|
||||
api_mock = MagicMock()
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange._params = {"test": True}
|
||||
|
||||
params1 = {"test": True}
|
||||
@@ -5954,7 +5954,7 @@ def test__get_params(mocker, default_conf, exchange_name):
|
||||
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
|
||||
exchange._params = {"test": True}
|
||||
|
||||
assert (
|
||||
@@ -6171,7 +6171,7 @@ def test_get_liquidation_price(
|
||||
default_conf_usdt["exchange"]["name"] = exchange_name
|
||||
default_conf_usdt["margin_mode"] = margin_mode
|
||||
mocker.patch("freqtrade.exchange.gate.Gate.validate_ordertypes")
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, id=exchange_name)
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, exchange=exchange_name)
|
||||
|
||||
exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(0.01, 0.01))
|
||||
exchange.name = exchange_name
|
||||
|
||||
69
tests/exchange/test_exchange_ws.py
Normal file
69
tests/exchange/test_exchange_ws.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import asyncio
|
||||
import threading
|
||||
from time import sleep
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exchange.exchange_ws import ExchangeWS
|
||||
|
||||
|
||||
def test_exchangews_init(mocker):
|
||||
config = MagicMock()
|
||||
ccxt_object = MagicMock()
|
||||
mocker.patch("freqtrade.exchange.exchange_ws.ExchangeWS._start_forever", MagicMock())
|
||||
|
||||
exchange_ws = ExchangeWS(config, ccxt_object)
|
||||
sleep(0.1)
|
||||
|
||||
assert exchange_ws.config == config
|
||||
assert exchange_ws.ccxt_object == ccxt_object
|
||||
assert exchange_ws._thread.name == "ccxt_ws"
|
||||
assert exchange_ws._background_tasks == set()
|
||||
assert exchange_ws._klines_watching == set()
|
||||
assert exchange_ws._klines_scheduled == set()
|
||||
assert exchange_ws.klines_last_refresh == {}
|
||||
assert exchange_ws.klines_last_request == {}
|
||||
# Cleanup
|
||||
exchange_ws.cleanup()
|
||||
|
||||
|
||||
def patch_eventloop_threading(exchange):
|
||||
is_init = False
|
||||
|
||||
def thread_fuck():
|
||||
nonlocal is_init
|
||||
exchange._loop = asyncio.new_event_loop()
|
||||
is_init = True
|
||||
exchange._loop.run_forever()
|
||||
|
||||
x = threading.Thread(target=thread_fuck, daemon=True)
|
||||
x.start()
|
||||
while not is_init:
|
||||
pass
|
||||
|
||||
|
||||
async def test_exchangews_ohlcv(mocker):
|
||||
config = MagicMock()
|
||||
ccxt_object = MagicMock()
|
||||
ccxt_object.watch_ohlcv = AsyncMock()
|
||||
ccxt_object.close = AsyncMock()
|
||||
mocker.patch("freqtrade.exchange.exchange_ws.ExchangeWS._start_forever", MagicMock())
|
||||
|
||||
exchange_ws = ExchangeWS(config, ccxt_object)
|
||||
patch_eventloop_threading(exchange_ws)
|
||||
try:
|
||||
assert exchange_ws._klines_watching == set()
|
||||
assert exchange_ws._klines_scheduled == set()
|
||||
|
||||
exchange_ws.schedule_ohlcv("ETH/BTC", "1m", CandleType.SPOT)
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
assert exchange_ws._klines_watching == {("ETH/BTC", "1m", CandleType.SPOT)}
|
||||
assert exchange_ws._klines_scheduled == {("ETH/BTC", "1m", CandleType.SPOT)}
|
||||
await asyncio.sleep(0.1)
|
||||
assert ccxt_object.watch_ohlcv.call_count == 1
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
# Cleanup
|
||||
exchange_ws.cleanup()
|
||||
@@ -9,7 +9,7 @@ from tests.conftest import EXMS, get_patched_exchange
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_fetch_stoploss_order_gate(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="gate")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="gate")
|
||||
|
||||
fetch_order_mock = MagicMock()
|
||||
exchange.fetch_order = fetch_order_mock
|
||||
@@ -23,7 +23,7 @@ def test_fetch_stoploss_order_gate(default_conf, mocker):
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="gate")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="gate")
|
||||
|
||||
exchange.fetch_order = MagicMock(
|
||||
return_value={
|
||||
@@ -41,7 +41,7 @@ def test_fetch_stoploss_order_gate(default_conf, mocker):
|
||||
|
||||
|
||||
def test_cancel_stoploss_order_gate(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="gate")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="gate")
|
||||
|
||||
cancel_order_mock = MagicMock()
|
||||
exchange.cancel_order = cancel_order_mock
|
||||
@@ -57,7 +57,7 @@ def test_cancel_stoploss_order_gate(default_conf, mocker):
|
||||
"sl1,sl2,sl3,side", [(1501, 1499, 1501, "sell"), (1499, 1501, 1499, "buy")]
|
||||
)
|
||||
def test_stoploss_adjust_gate(mocker, default_conf, sl1, sl2, sl3, side):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="gate")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="gate")
|
||||
order = {
|
||||
"price": 1500,
|
||||
"stopPrice": 1500,
|
||||
@@ -111,7 +111,7 @@ def test_fetch_my_trades_gate(mocker, default_conf, takerormaker, rate, cost):
|
||||
}
|
||||
]
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock=api_mock, id="gate")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock=api_mock, exchange="gate")
|
||||
exchange._trading_fees = tick
|
||||
trades = exchange.get_trades_for_order("22255", "ETH/USDT:USDT", datetime.now(timezone.utc))
|
||||
trade = trades[0]
|
||||
|
||||
@@ -128,7 +128,7 @@ def test_create_stoploss_order_dry_run_htx(default_conf, mocker):
|
||||
|
||||
|
||||
def test_stoploss_adjust_htx(mocker, default_conf):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="htx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="htx")
|
||||
order = {
|
||||
"type": "stop",
|
||||
"price": 1500,
|
||||
|
||||
@@ -32,7 +32,7 @@ def test_kraken_trading_agreement(default_conf, mocker, order_type, time_in_forc
|
||||
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y, **kwargs: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="kraken")
|
||||
|
||||
order = exchange.create_order(
|
||||
pair="ETH/BTC",
|
||||
@@ -121,7 +121,7 @@ def test_get_balances_prod(default_conf, mocker):
|
||||
]
|
||||
api_mock.fetch_open_orders = MagicMock(return_value=kraken_open_orders)
|
||||
default_conf["dry_run"] = False
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="kraken")
|
||||
balances = exchange.get_balances()
|
||||
assert len(balances) == 6
|
||||
|
||||
@@ -256,7 +256,7 @@ def test_create_stoploss_order_dry_run_kraken(default_conf, mocker, side):
|
||||
"sl1,sl2,sl3,side", [(1501, 1499, 1501, "sell"), (1499, 1501, 1499, "buy")]
|
||||
)
|
||||
def test_stoploss_adjust_kraken(mocker, default_conf, sl1, sl2, sl3, side):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="kraken")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="kraken")
|
||||
order = {
|
||||
"type": "market",
|
||||
"stopLossPrice": 1500,
|
||||
@@ -278,5 +278,5 @@ def test_stoploss_adjust_kraken(mocker, default_conf, sl1, sl2, sl3, side):
|
||||
],
|
||||
)
|
||||
def test__valid_trade_pagination_id_kraken(mocker, default_conf_usdt, trade_id, expected):
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, id="kraken")
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt, exchange="kraken")
|
||||
assert exchange._valid_trade_pagination_id("XRP/USDT", trade_id) == expected
|
||||
|
||||
@@ -134,7 +134,7 @@ def test_stoploss_order_dry_run_kucoin(default_conf, mocker):
|
||||
|
||||
|
||||
def test_stoploss_adjust_kucoin(mocker, default_conf):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="kucoin")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="kucoin")
|
||||
order = {
|
||||
"type": "limit",
|
||||
"price": 1500,
|
||||
@@ -161,7 +161,7 @@ def test_kucoin_create_order(default_conf, mocker, side, ordertype, rate):
|
||||
default_conf["dry_run"] = False
|
||||
mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kucoin")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="kucoin")
|
||||
exchange._set_leverage = MagicMock()
|
||||
exchange.set_margin_mode = MagicMock()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
||||
|
||||
|
||||
def test_okx_ohlcv_candle_limit(default_conf, mocker):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
timeframes = ("1m", "5m", "1h")
|
||||
start_time = int(datetime(2021, 1, 1, tzinfo=timezone.utc).timestamp() * 1000)
|
||||
|
||||
@@ -188,7 +188,7 @@ def test_get_maintenance_ratio_and_amt_okx(
|
||||
}
|
||||
),
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
assert exchange.get_maintenance_ratio_and_amt("ETH/USDT:USDT", 2000) == (0.01, None)
|
||||
assert exchange.get_maintenance_ratio_and_amt("ETH/USDT:USDT", 2001) == (0.015, None)
|
||||
assert exchange.get_maintenance_ratio_and_amt("ETH/USDT:USDT", 4001) == (0.02, None)
|
||||
@@ -199,12 +199,12 @@ def test_get_maintenance_ratio_and_amt_okx(
|
||||
|
||||
|
||||
def test_get_max_pair_stake_amount_okx(default_conf, mocker, leverage_tiers):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
assert exchange.get_max_pair_stake_amount("BNB/BUSD", 1.0) == float("inf")
|
||||
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
exchange._leverage_tiers = leverage_tiers
|
||||
|
||||
assert exchange.get_max_pair_stake_amount("XRP/USDT:USDT", 1.0) == 30000000
|
||||
@@ -229,7 +229,7 @@ def test_get_max_pair_stake_amount_okx(default_conf, mocker, leverage_tiers):
|
||||
],
|
||||
)
|
||||
def test__get_posSide(default_conf, mocker, mode, side, reduceonly, result):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
exchange.net_only = mode == "net"
|
||||
assert exchange._get_posSide(side, reduceonly) == result
|
||||
|
||||
@@ -257,7 +257,7 @@ def test_additional_exchange_init_okx(default_conf, mocker):
|
||||
]
|
||||
)
|
||||
default_conf["dry_run"] = False
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx", api_mock=api_mock)
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx", api_mock=api_mock)
|
||||
assert api_mock.fetch_accounts.call_count == 0
|
||||
exchange.trading_mode = TradingMode.FUTURES
|
||||
# Default to netOnly
|
||||
@@ -438,7 +438,7 @@ def test_load_leverage_tiers_okx(default_conf, mocker, markets, tmp_path, caplog
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
default_conf["stake_currency"] = "USDT"
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
exchange.trading_mode = TradingMode.FUTURES
|
||||
exchange.margin_mode = MarginMode.ISOLATED
|
||||
exchange.markets = markets
|
||||
@@ -520,7 +520,7 @@ def test__set_leverage_okx(mocker, default_conf):
|
||||
default_conf["trading_mode"] = TradingMode.FUTURES
|
||||
default_conf["margin_mode"] = MarginMode.ISOLATED
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
exchange._lev_prep("BTC/USDT:USDT", 3.2, "buy")
|
||||
assert api_mock.set_leverage.call_count == 1
|
||||
# Leverage is rounded to 3.
|
||||
@@ -554,7 +554,7 @@ def test_fetch_stoploss_order_okx(default_conf, mocker):
|
||||
api_mock = MagicMock()
|
||||
api_mock.fetch_order = MagicMock()
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
|
||||
exchange.fetch_stoploss_order("1234", "ETH/BTC")
|
||||
assert api_mock.fetch_order.call_count == 1
|
||||
@@ -594,7 +594,7 @@ def test_fetch_stoploss_order_okx(default_conf, mocker):
|
||||
assert resp["type"] == "stoploss"
|
||||
|
||||
default_conf["dry_run"] = True
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
dro_mock = mocker.patch(f"{EXMS}.fetch_dry_run_order", MagicMock(return_value={"id": "123455"}))
|
||||
|
||||
api_mock.fetch_order.reset_mock()
|
||||
@@ -614,7 +614,7 @@ def test_fetch_stoploss_order_okx(default_conf, mocker):
|
||||
"sl1,sl2,sl3,side", [(1501, 1499, 1501, "sell"), (1499, 1501, 1499, "buy")]
|
||||
)
|
||||
def test_stoploss_adjust_okx(mocker, default_conf, sl1, sl2, sl3, side):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
order = {
|
||||
"type": "stoploss",
|
||||
"price": 1500,
|
||||
@@ -625,7 +625,7 @@ def test_stoploss_adjust_okx(mocker, default_conf, sl1, sl2, sl3, side):
|
||||
|
||||
|
||||
def test_stoploss_cancel_okx(mocker, default_conf):
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
|
||||
exchange.cancel_order = MagicMock()
|
||||
|
||||
@@ -639,7 +639,7 @@ def test_stoploss_cancel_okx(mocker, default_conf):
|
||||
def test__get_stop_params_okx(mocker, default_conf):
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, exchange="okx")
|
||||
params = exchange._get_stop_params("ETH/USDT:USDT", 1500, "sell")
|
||||
|
||||
assert params["tdMode"] == "isolated"
|
||||
@@ -660,13 +660,13 @@ def test_fetch_orders_okx(default_conf, mocker, limit_order):
|
||||
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
|
||||
start_time = datetime.now(timezone.utc) - timedelta(days=20)
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
# Not available in dry-run
|
||||
assert exchange.fetch_orders("mocked", start_time) == []
|
||||
assert api_mock.fetch_orders.call_count == 0
|
||||
default_conf["dry_run"] = False
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okx")
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="okx")
|
||||
|
||||
def has_resp(_, endpoint):
|
||||
if endpoint == "fetchOrders":
|
||||
|
||||
@@ -11,6 +11,8 @@ from tests.conftest import EXMS, get_default_conf_usdt
|
||||
|
||||
|
||||
EXCHANGE_FIXTURE_TYPE = Tuple[Exchange, str]
|
||||
EXCHANGE_WS_FIXTURE_TYPE = Tuple[Exchange, str, str]
|
||||
|
||||
|
||||
# Exchanges that should be tested online
|
||||
EXCHANGES = {
|
||||
@@ -360,6 +362,7 @@ def set_test_proxy(config: Config, use_proxy: bool) -> Config:
|
||||
config1 = deepcopy(config)
|
||||
config1["exchange"]["ccxt_config"] = {
|
||||
"httpsProxy": proxy,
|
||||
"wsProxy": proxy,
|
||||
}
|
||||
return config1
|
||||
|
||||
@@ -376,7 +379,7 @@ def get_exchange(exchange_name, exchange_conf):
|
||||
exchange_conf, validate=True, load_leverage_tiers=True
|
||||
)
|
||||
|
||||
yield exchange, exchange_name
|
||||
return exchange, exchange_name
|
||||
|
||||
|
||||
def get_futures_exchange(exchange_name, exchange_conf, class_mocker):
|
||||
@@ -398,15 +401,41 @@ def get_futures_exchange(exchange_name, exchange_conf, class_mocker):
|
||||
class_mocker.patch(f"{EXMS}.load_cached_leverage_tiers", return_value=None)
|
||||
class_mocker.patch(f"{EXMS}.cache_leverage_tiers")
|
||||
|
||||
yield from get_exchange(exchange_name, exchange_conf)
|
||||
return get_exchange(exchange_name, exchange_conf)
|
||||
|
||||
|
||||
@pytest.fixture(params=EXCHANGES, scope="class")
|
||||
def exchange(request, exchange_conf, class_mocker):
|
||||
class_mocker.patch("freqtrade.exchange.bybit.Bybit.additional_exchange_init")
|
||||
yield from get_exchange(request.param, exchange_conf)
|
||||
return get_exchange(request.param, exchange_conf)
|
||||
|
||||
|
||||
@pytest.fixture(params=EXCHANGES, scope="class")
|
||||
def exchange_futures(request, exchange_conf, class_mocker):
|
||||
yield from get_futures_exchange(request.param, exchange_conf, class_mocker)
|
||||
return get_futures_exchange(request.param, exchange_conf, class_mocker)
|
||||
|
||||
|
||||
@pytest.fixture(params=["spot", "futures"], scope="class")
|
||||
def exchange_mode(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=EXCHANGES, scope="class")
|
||||
def exchange_ws(request, exchange_conf, exchange_mode, class_mocker):
|
||||
class_mocker.patch("freqtrade.exchange.bybit.Bybit.additional_exchange_init")
|
||||
exchange_conf["exchange"]["enable_ws"] = True
|
||||
if exchange_mode == "spot":
|
||||
exchange, name = get_exchange(request.param, exchange_conf)
|
||||
pair = EXCHANGES[request.param]["pair"]
|
||||
elif EXCHANGES[request.param].get("futures"):
|
||||
exchange, name = get_futures_exchange(
|
||||
request.param, exchange_conf, class_mocker=class_mocker
|
||||
)
|
||||
pair = EXCHANGES[request.param]["futures_pair"]
|
||||
else:
|
||||
pytest.skip("Exchange does not support futures.")
|
||||
|
||||
if not exchange._has_watch_ohlcv:
|
||||
pytest.skip("Exchange does not support watch_ohlcv.")
|
||||
yield exchange, name, pair
|
||||
exchange.close()
|
||||
|
||||
64
tests/exchange_online/test_ccxt_ws_compat.py
Normal file
64
tests/exchange_online/test_ccxt_ws_compat.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
Tests in this file do NOT mock network calls, so they are expected to be fluky at times.
|
||||
|
||||
However, these tests aim to test ccxt compatibility, specifically regarding websockets.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from time import sleep
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exchange.exchange_utils import timeframe_to_prev_date
|
||||
from freqtrade.loggers.set_log_levels import set_loggers
|
||||
from freqtrade.util.datetime_helpers import dt_now
|
||||
from tests.conftest import log_has_re
|
||||
from tests.exchange_online.conftest import EXCHANGE_WS_FIXTURE_TYPE
|
||||
|
||||
|
||||
@pytest.mark.longrun
|
||||
@pytest.mark.timeout(3 * 60)
|
||||
class TestCCXTExchangeWs:
|
||||
def test_ccxt_watch_ohlcv(self, exchange_ws: EXCHANGE_WS_FIXTURE_TYPE, caplog, mocker):
|
||||
exch, _exchangename, pair = exchange_ws
|
||||
|
||||
assert exch._ws_async is not None
|
||||
timeframe = "1m"
|
||||
pair_tf = (pair, timeframe, CandleType.SPOT)
|
||||
m_hist = mocker.spy(exch, "_async_get_historic_ohlcv")
|
||||
m_cand = mocker.spy(exch, "_async_get_candle_history")
|
||||
|
||||
res = exch.refresh_latest_ohlcv([pair_tf])
|
||||
assert m_cand.call_count == 1
|
||||
|
||||
# Currently open candle
|
||||
next_candle = timeframe_to_prev_date(timeframe, dt_now())
|
||||
now = next_candle - timedelta(seconds=1)
|
||||
# Currently closed candle
|
||||
curr_candle = timeframe_to_prev_date(timeframe, now)
|
||||
|
||||
assert pair_tf in exch._exchange_ws._klines_watching
|
||||
assert pair_tf in exch._exchange_ws._klines_scheduled
|
||||
assert res[pair_tf] is not None
|
||||
df1 = res[pair_tf]
|
||||
caplog.set_level(logging.DEBUG)
|
||||
set_loggers(1)
|
||||
assert df1.iloc[-1]["date"] == curr_candle
|
||||
|
||||
# Wait until the next candle (might be up to 1 minute).
|
||||
while True:
|
||||
caplog.clear()
|
||||
res = exch.refresh_latest_ohlcv([pair_tf])
|
||||
df2 = res[pair_tf]
|
||||
assert df2 is not None
|
||||
if df2.iloc[-1]["date"] == next_candle:
|
||||
break
|
||||
assert df2.iloc[-1]["date"] == curr_candle
|
||||
sleep(1)
|
||||
|
||||
assert m_hist.call_count == 0
|
||||
# shouldn't have tried fetch_ohlcv a second time.
|
||||
assert m_cand.call_count == 1
|
||||
assert log_has_re(r"watch result.*", caplog)
|
||||
@@ -915,7 +915,7 @@ def test_execute_entry(
|
||||
default_conf_usdt["margin_mode"] = margin_mode
|
||||
mocker.patch("freqtrade.exchange.gate.Gate.validate_ordertypes")
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker, id=exchange_name)
|
||||
patch_exchange(mocker, exchange=exchange_name)
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=False)
|
||||
freqtrade.strategy.leverage = MagicMock(return_value=leverage)
|
||||
@@ -3810,6 +3810,9 @@ def test_get_real_amount_quote_dust(
|
||||
def test_get_real_amount_no_trade(default_conf_usdt, buy_order_fee, caplog, mocker, fee):
|
||||
mocker.patch(f"{EXMS}.get_trades_for_order", return_value=[])
|
||||
|
||||
# Invalid nested trade object
|
||||
buy_order_fee["trades"] = [{"amount": None, "cost": 22}]
|
||||
|
||||
amount = buy_order_fee["amount"]
|
||||
trade = Trade(
|
||||
pair="LTC/ETH",
|
||||
|
||||
@@ -4,7 +4,7 @@ from freqtrade.enums import CandleType
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input,expected",
|
||||
"candle_type,expected",
|
||||
[
|
||||
("", CandleType.SPOT),
|
||||
("spot", CandleType.SPOT),
|
||||
@@ -17,17 +17,17 @@ from freqtrade.enums import CandleType
|
||||
("premiumIndex", CandleType.PREMIUMINDEX),
|
||||
],
|
||||
)
|
||||
def test_CandleType_from_string(input, expected):
|
||||
assert CandleType.from_string(input) == expected
|
||||
def test_CandleType_from_string(candle_type, expected):
|
||||
assert CandleType.from_string(candle_type) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input,expected",
|
||||
"candle_type,expected",
|
||||
[
|
||||
("futures", CandleType.FUTURES),
|
||||
("spot", CandleType.SPOT),
|
||||
("margin", CandleType.SPOT),
|
||||
],
|
||||
)
|
||||
def test_CandleType_get_default(input, expected):
|
||||
assert CandleType.get_default(input) == expected
|
||||
def test_CandleType_get_default(candle_type, expected):
|
||||
assert CandleType.get_default(candle_type) == expected
|
||||
|
||||
@@ -429,7 +429,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) ->
|
||||
backtesting.start()
|
||||
|
||||
|
||||
def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) -> None:
|
||||
def test_backtesting_no_pair_left(default_conf, mocker) -> None:
|
||||
mocker.patch(f"{EXMS}.exchange_has", MagicMock(return_value=True))
|
||||
mocker.patch(
|
||||
"freqtrade.data.history.history_utils.load_pair_history",
|
||||
@@ -449,13 +449,6 @@ def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) ->
|
||||
with pytest.raises(OperationalException, match="No pair in whitelist."):
|
||||
Backtesting(default_conf)
|
||||
|
||||
default_conf["pairlists"] = [{"method": "VolumePairList", "number_assets": 5}]
|
||||
with pytest.raises(
|
||||
OperationalException,
|
||||
match=r"VolumePairList not allowed for backtesting\..*StaticPairList.*",
|
||||
):
|
||||
Backtesting(default_conf)
|
||||
|
||||
default_conf.update(
|
||||
{
|
||||
"pairlists": [{"method": "StaticPairList"}],
|
||||
@@ -469,7 +462,7 @@ def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) ->
|
||||
Backtesting(default_conf)
|
||||
|
||||
|
||||
def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, tickers) -> None:
|
||||
def test_backtesting_pairlist_list(default_conf, mocker, tickers) -> None:
|
||||
mocker.patch(f"{EXMS}.exchange_has", MagicMock(return_value=True))
|
||||
mocker.patch(f"{EXMS}.get_tickers", tickers)
|
||||
mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y: y)
|
||||
@@ -495,12 +488,6 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti
|
||||
):
|
||||
Backtesting(default_conf)
|
||||
|
||||
default_conf["pairlists"] = [{"method": "StaticPairList"}, {"method": "PerformanceFilter"}]
|
||||
with pytest.raises(
|
||||
OperationalException, match="PerformanceFilter not allowed for backtesting."
|
||||
):
|
||||
Backtesting(default_conf)
|
||||
|
||||
default_conf["pairlists"] = [
|
||||
{"method": "StaticPairList"},
|
||||
{"method": "PrecisionFilter"},
|
||||
|
||||
@@ -38,6 +38,7 @@ TESTABLE_PAIRLISTS = [p for p in AVAILABLE_PAIRLISTS if p not in ["RemotePairLis
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def whitelist_conf(default_conf):
|
||||
default_conf["runmode"] = "dry_run"
|
||||
default_conf["stake_currency"] = "BTC"
|
||||
default_conf["exchange"]["pair_whitelist"] = [
|
||||
"ETH/BTC",
|
||||
@@ -68,6 +69,7 @@ def whitelist_conf(default_conf):
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def whitelist_conf_2(default_conf):
|
||||
default_conf["runmode"] = "dry_run"
|
||||
default_conf["stake_currency"] = "BTC"
|
||||
default_conf["exchange"]["pair_whitelist"] = [
|
||||
"ETH/BTC",
|
||||
@@ -94,6 +96,7 @@ def whitelist_conf_2(default_conf):
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def whitelist_conf_agefilter(default_conf):
|
||||
default_conf["runmode"] = "dry_run"
|
||||
default_conf["stake_currency"] = "BTC"
|
||||
default_conf["exchange"]["pair_whitelist"] = [
|
||||
"ETH/BTC",
|
||||
@@ -773,7 +776,7 @@ def test_VolumePairList_whitelist_gen(
|
||||
whitelist_result,
|
||||
caplog,
|
||||
) -> None:
|
||||
whitelist_conf["runmode"] = "backtest"
|
||||
whitelist_conf["runmode"] = "util_exchange"
|
||||
whitelist_conf["pairlists"] = pairlists
|
||||
whitelist_conf["stake_currency"] = base_currency
|
||||
|
||||
@@ -2387,3 +2390,65 @@ def test_MarketCapPairList_exceptions(mocker, default_conf_usdt):
|
||||
OperationalException, match="This filter only support marketcap rank up to 250."
|
||||
):
|
||||
PairListManager(exchange, default_conf_usdt)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pairlists,expected_error,expected_warning",
|
||||
[
|
||||
(
|
||||
[{"method": "StaticPairList"}],
|
||||
None, # Error
|
||||
None, # Warning
|
||||
),
|
||||
(
|
||||
[{"method": "VolumePairList", "number_assets": 10}],
|
||||
"VolumePairList", # Error
|
||||
None, # Warning
|
||||
),
|
||||
(
|
||||
[{"method": "MarketCapPairList", "number_assets": 10}],
|
||||
None, # Error
|
||||
r"MarketCapPairList.*lookahead.*", # Warning
|
||||
),
|
||||
(
|
||||
[{"method": "StaticPairList"}, {"method": "FullTradesFilter"}],
|
||||
None, # Error
|
||||
r"FullTradesFilter do not generate.*", # Warning
|
||||
),
|
||||
( # combi, fails and warns
|
||||
[
|
||||
{"method": "VolumePairList", "number_assets": 10},
|
||||
{"method": "MarketCapPairList", "number_assets": 10},
|
||||
],
|
||||
"VolumePairList", # Error
|
||||
r"MarketCapPairList.*lookahead.*", # Warning
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_backtesting_modes(
|
||||
mocker, default_conf_usdt, pairlists, expected_error, expected_warning, caplog, markets, tickers
|
||||
):
|
||||
default_conf_usdt["runmode"] = "dry_run"
|
||||
default_conf_usdt["pairlists"] = pairlists
|
||||
|
||||
mocker.patch.multiple(
|
||||
EXMS,
|
||||
markets=PropertyMock(return_value=markets),
|
||||
exchange_has=MagicMock(return_value=True),
|
||||
get_tickers=tickers,
|
||||
)
|
||||
exchange = get_patched_exchange(mocker, default_conf_usdt)
|
||||
|
||||
# Dry run mode - works always
|
||||
PairListManager(exchange, default_conf_usdt)
|
||||
|
||||
default_conf_usdt["runmode"] = "backtest"
|
||||
if expected_error:
|
||||
with pytest.raises(OperationalException, match=f"Pairlist Handlers {expected_error}.*"):
|
||||
PairListManager(exchange, default_conf_usdt)
|
||||
|
||||
if not expected_error:
|
||||
PairListManager(exchange, default_conf_usdt)
|
||||
|
||||
if expected_warning:
|
||||
assert log_has_re(f"Pairlist Handlers {expected_warning}", caplog)
|
||||
|
||||
@@ -2154,6 +2154,7 @@ def test_api_exchanges(botclient):
|
||||
"valid": True,
|
||||
"supported": True,
|
||||
"comment": "",
|
||||
"dex": False,
|
||||
"trade_modes": [
|
||||
{"trading_mode": "spot", "margin_mode": ""},
|
||||
{"trading_mode": "futures", "margin_mode": "isolated"},
|
||||
@@ -2165,9 +2166,19 @@ def test_api_exchanges(botclient):
|
||||
"name": "mexc",
|
||||
"valid": True,
|
||||
"supported": False,
|
||||
"dex": False,
|
||||
"comment": "",
|
||||
"trade_modes": [{"trading_mode": "spot", "margin_mode": ""}],
|
||||
}
|
||||
waves = [x for x in response["exchanges"] if x["name"] == "wavesexchange"][0]
|
||||
assert waves == {
|
||||
"name": "wavesexchange",
|
||||
"valid": True,
|
||||
"supported": False,
|
||||
"dex": True,
|
||||
"comment": ANY,
|
||||
"trade_modes": [{"trading_mode": "spot", "margin_mode": ""}],
|
||||
}
|
||||
|
||||
|
||||
def test_api_freqaimodels(botclient, tmp_path, mocker):
|
||||
|
||||
Reference in New Issue
Block a user