diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 940b0312b..45d66db06 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1960,12 +1960,14 @@ class Exchange: 'Looped through all tiers without finding a max leverage. Should never be reached' ) - else: # Search markets.limits for max lev + elif self.trading_mode == TradingMode.MARGIN: # Search markets.limits for max lev market = self.markets[pair] if market['limits']['leverage']['max'] is not None: return market['limits']['leverage']['max'] else: return 1.0 # Default if max leverage cannot be found + else: + return 1.0 @retrier def _set_leverage( diff --git a/tests/conftest.py b/tests/conftest.py index 2b0480da8..b22e45526 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -960,21 +960,40 @@ def get_markets(): 'symbol': 'NEO/USDT', 'base': 'NEO', 'quote': 'USDT', - 'active': True, - 'spot': True, - 'swap': False, - 'linear': None, + 'settle': '', + 'baseId': 'NEO', + 'quoteId': 'USDT', + 'settleId': '', 'type': 'spot', + 'spot': True, + 'margin': True, + 'swap': False, + 'futures': False, + 'option': False, + 'active': True, + 'contract': False, + 'linear': None, + 'inverse': None, 'taker': 0.0006, 'maker': 0.0002, + 'contractSize': None, + 'expiry': None, + 'expiryDatetime': None, + 'strike': None, + 'optionType': None, + 'tierBased': None, + 'percentage': None, + 'lot': 0.00000001, 'precision': { 'price': 8, 'amount': 8, 'cost': 8, }, - 'lot': 0.00000001, - 'contractSize': None, 'limits': { + "leverage": { + 'min': 1, + 'max': 10 + }, 'amount': { 'min': 0.01, 'max': 1000, @@ -1071,10 +1090,10 @@ def get_markets(): 'quote': 'USDT', 'active': True, 'spot': False, - 'swap': True, - 'linear': True, 'type': 'swap', 'contractSize': 0.01, + 'swap': False, + 'linear': False, 'taker': 0.0006, 'maker': 0.0002, 'precision': { @@ -1162,7 +1181,6 @@ def get_markets(): 'taker': 0.0006, 'maker': 0.0002, 'contractSize': 10, - 'maintenanceMarginRate': 0.02, 'active': True, 'expiry': None, 'expiryDatetime': None, @@ -1191,6 +1209,83 @@ def get_markets(): 'amount': 1 }, 'info': {} + }, + 'ADA/USDT:USDT': { + 'limits': { + 'leverage': { + 'min': 1, + 'max': 20, + }, + 'amount': { + 'min': 1, + 'max': 1000000, + }, + 'price': { + 'min': 0.52981, + 'max': 1.58943, + }, + 'cost': { + 'min': None, + 'max': None, + } + }, + 'precision': { + 'amount': 1, + 'price': 0.00001 + }, + 'tierBased': True, + 'percentage': True, + 'taker': 0.0000075, + 'maker': -0.0000025, + 'feeSide': 'get', + 'tiers': { + 'maker': [ + [0, 0.002], [1.5, 0.00185], + [3, 0.00175], [6, 0.00165], + [12.5, 0.00155], [25, 0.00145], + [75, 0.00135], [200, 0.00125], + [500, 0.00115], [1250, 0.00105], + [2500, 0.00095], [3000, 0.00085], + [6000, 0.00075], [11000, 0.00065], + [20000, 0.00055], [40000, 0.00055], + [75000, 0.00055] + ], + 'taker': [ + [0, 0.002], [1.5, 0.00195], + [3, 0.00185], [6, 0.00175], + [12.5, 0.00165], [25, 0.00155], + [75, 0.00145], [200, 0.00135], + [500, 0.00125], [1250, 0.00115], + [2500, 0.00105], [3000, 0.00095], + [6000, 0.00085], [11000, 0.00075], + [20000, 0.00065], [40000, 0.00065], + [75000, 0.00065] + ] + }, + 'id': 'ADA_USDT', + 'symbol': 'ADA/USDT:USDT', + 'base': 'ADA', + 'quote': 'USDT', + 'settle': 'USDT', + 'baseId': 'ADA', + 'quoteId': 'USDT', + 'settleId': 'usdt', + 'type': 'swap', + 'spot': False, + 'margin': False, + 'swap': True, + 'future': False, + 'option': False, + 'active': True, + 'contract': True, + 'linear': True, + 'inverse': False, + 'contractSize': 0.01, + 'expiry': None, + 'expiryDatetime': None, + 'strike': None, + 'optionType': None, + 'info': {} } } diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index cfe3cde89..30ffeeae0 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -171,36 +171,6 @@ def test_stoploss_adjust_binance( assert not exchange.stoploss_adjust(sl3, order, side=side) -def test_get_max_leverage_binance(default_conf, mocker, leverage_tiers): - - # Test Spot - exchange = get_patched_exchange(mocker, default_conf, id="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._leverage_tiers = leverage_tiers - - assert exchange.get_max_leverage("BNB/BUSD", 1.0) == 20.0 - assert exchange.get_max_leverage("BNB/USDT", 100.0) == 75.0 - assert exchange.get_max_leverage("BTC/USDT", 170.30) == 125.0 - assert isclose(exchange.get_max_leverage("BNB/BUSD", 99999.9), 5.000005) - assert isclose(exchange.get_max_leverage("BNB/USDT", 1500), 33.333333333333333) - assert exchange.get_max_leverage("BTC/USDT", 300000000) == 2.0 - assert exchange.get_max_leverage("BTC/USDT", 600000000) == 1.0 # Last tier - - assert exchange.get_max_leverage("SPONGE/USDT", 200) == 1.0 # Pair not in leverage_tiers - assert exchange.get_max_leverage("BTC/USDT", 0.0) == 125.0 # No stake amount - with pytest.raises( - InvalidOrderException, - match=r'Amount 1000000000.01 too high for BTC/USDT' - ): - exchange.get_max_leverage("BTC/USDT", 1000000000.01) - - def test_fill_leverage_tiers_binance(default_conf, mocker): api_mock = MagicMock() api_mock.fetch_leverage_tiers = MagicMock(return_value={ diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 30ba061fa..73af6af3e 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -341,7 +341,7 @@ class TestCCXTExchange(): def test_get_max_leverage_futures(self, exchange_futures): futures, futures_name = exchange_futures - # TODO-lev: binance, gateio, and okex test + # TODO-lev: binance, gateio, and okx test if futures: leverage_in_market_futures = EXCHANGES[futures_name]['leverage_in_market']['futures'] if leverage_in_market_futures: diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 211f15d0a..032473062 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1207,9 +1207,20 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice, assert exchange._set_leverage.call_count == 0 assert exchange.set_margin_mode.call_count == 0 + api_mock.create_order = MagicMock(return_value={ + 'id': order_id, + 'info': { + 'foo': 'bar' + }, + 'symbol': 'ADA/USDT:USDT', + 'amount': 1 + }) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) exchange.trading_mode = TradingMode.FUTURES + exchange._set_leverage = MagicMock() + exchange.set_margin_mode = MagicMock() order = exchange.create_order( - pair='XLTCUSDT', + pair='ADA/USDT:USDT', ordertype=ordertype, side=side, amount=1, @@ -2998,7 +3009,7 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): # all markets, only spot pairs ([], [], False, False, True, False, ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', - 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']), + 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']), # active markets ([], [], False, True, False, False, ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'NEO/BTC', @@ -3006,11 +3017,11 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): # all pairs ([], [], True, False, False, False, ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', - 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']), + 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']), # active pairs ([], [], True, True, False, False, ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'NEO/BTC', - 'TKN/BTC', 'XRP/BTC']), + 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']), # all markets, base=ETH, LTC (['ETH', 'LTC'], [], False, False, False, False, ['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), @@ -3019,7 +3030,7 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): ['LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), # spot markets, base=LTC (['LTC'], [], False, False, True, False, - ['LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT']), + ['LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), # all markets, quote=USDT ([], ['USDT'], False, False, False, False, ['ETH/USDT', 'LTC/USDT', 'XLTCUSDT']), @@ -3031,13 +3042,13 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): ['ETH/USDT', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), # spot markets, quote=USDT, USD ([], ['USDT', 'USD'], False, False, True, False, - ['ETH/USDT', 'LTC/USD', 'LTC/USDT']), + ['ETH/USDT', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), # all markets, base=LTC, quote=USDT (['LTC'], ['USDT'], False, False, False, False, ['LTC/USDT', 'XLTCUSDT']), # all pairs, base=LTC, quote=USDT (['LTC'], ['USDT'], True, False, False, False, - ['LTC/USDT']), + ['LTC/USDT', 'XLTCUSDT']), # all markets, base=LTC, quote=USDT, NONEXISTENT (['LTC'], ['USDT', 'NONEXISTENT'], False, False, False, False, ['LTC/USDT', 'XLTCUSDT']), @@ -3486,7 +3497,7 @@ def test_set_margin_mode(mocker, default_conf, margin_mode): ("binance", TradingMode.FUTURES, MarginMode.ISOLATED, False), ("gateio", TradingMode.FUTURES, MarginMode.ISOLATED, False), - ("okex", TradingMode.FUTURES, MarginMode.ISOLATED, False), + ("okx", TradingMode.FUTURES, MarginMode.ISOLATED, False), # * Remove once implemented ("binance", TradingMode.MARGIN, MarginMode.CROSS, True), @@ -3560,8 +3571,8 @@ def test__ccxt_config( ("LTC/BTC", 0.0, 1.0), ("TKN/USDT", 210.30, 1.0), ]) -def test_get_max_leverage_from_markets(default_conf, mocker, pair, nominal_value, max_lev): - default_conf['trading_mode'] = 'futures' +def test_get_max_leverage_from_margin(default_conf, mocker, pair, nominal_value, max_lev): + default_conf['trading_mode'] = 'margin' default_conf['margin_mode'] = 'isolated' api_mock = MagicMock() type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': False}) @@ -3836,13 +3847,13 @@ def test__fetch_and_calculate_funding_fees_datetime_called( ('XLTCUSDT', 1, 'spot'), ('LTC/USD', 1, 'futures'), ('XLTCUSDT', 0.01, 'futures'), - ('LTC/ETH', 1, 'futures'), ('ETH/USDT:USDT', 10, 'futures') ]) def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_mode): api_mock = MagicMock() default_conf['trading_mode'] = trading_mode default_conf['margin_mode'] = 'isolated' + exchange = get_patched_exchange(mocker, default_conf, api_mock) mocker.patch('freqtrade.exchange.Exchange.markets', { 'LTC/USD': { 'symbol': 'LTC/USD', @@ -3852,15 +3863,11 @@ def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_m 'symbol': 'XLTCUSDT', 'contractSize': '0.01', }, - 'LTC/ETH': { - 'symbol': 'LTC/ETH', - }, 'ETH/USDT:USDT': { 'symbol': 'ETH/USDT:USDT', 'contractSize': '10', } }) - exchange = get_patched_exchange(mocker, default_conf, api_mock) size = exchange._get_contract_size(pair) assert expected_size == size @@ -3868,7 +3875,7 @@ def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_m @pytest.mark.parametrize('pair,contract_size,trading_mode', [ ('XLTCUSDT', 1, 'spot'), ('LTC/USD', 1, 'futures'), - ('XLTCUSDT', 0.01, 'futures'), + ('ADA/USDT:USDT', 0.01, 'futures'), ('LTC/ETH', 1, 'futures'), ('ETH/USDT:USDT', 10, 'futures'), ]) @@ -3952,7 +3959,7 @@ def test__order_contracts_to_amount( @pytest.mark.parametrize('pair,contract_size,trading_mode', [ ('XLTCUSDT', 1, 'spot'), ('LTC/USD', 1, 'futures'), - ('XLTCUSDT', 0.01, 'futures'), + ('ADA/USDT:USDT', 0.01, 'futures'), ('LTC/ETH', 1, 'futures'), ('ETH/USDT:USDT', 10, 'futures'), ]) @@ -3987,7 +3994,7 @@ def test__trades_contracts_to_amount( @pytest.mark.parametrize('pair,param_amount,param_size', [ - ('XLTCUSDT', 40, 4000), + ('ADA/USDT:USDT', 40, 4000), ('LTC/ETH', 30, 30), ('LTC/USD', 30, 30), ('ETH/USDT:USDT', 10, 1), @@ -4003,6 +4010,7 @@ def test__amount_to_contracts( api_mock = MagicMock() default_conf['trading_mode'] = 'spot' default_conf['margin_mode'] = 'isolated' + exchange = get_patched_exchange(mocker, default_conf, api_mock) mocker.patch('freqtrade.exchange.Exchange.markets', { 'LTC/USD': { 'symbol': 'LTC/USD', @@ -4020,7 +4028,6 @@ def test__amount_to_contracts( 'contractSize': '10', } }) - exchange = get_patched_exchange(mocker, default_conf, api_mock) result_size = exchange._amount_to_contracts(pair, param_amount) assert result_size == param_amount result_amount = exchange._contracts_to_amount(pair, param_size) @@ -4342,3 +4349,33 @@ def test_get_maintenance_ratio_and_amt( default_conf['margin_mode'] = 'isolated' exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.get_maintenance_ratio_and_amt(pair, value) == (mmr, maintAmt) + + +def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers): + + # Test Spot + exchange = get_patched_exchange(mocker, default_conf, id="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._leverage_tiers = leverage_tiers + + assert exchange.get_max_leverage("BNB/BUSD", 1.0) == 20.0 + assert exchange.get_max_leverage("BNB/USDT", 100.0) == 75.0 + assert exchange.get_max_leverage("BTC/USDT", 170.30) == 125.0 + assert isclose(exchange.get_max_leverage("BNB/BUSD", 99999.9), 5.000005) + assert isclose(exchange.get_max_leverage("BNB/USDT", 1500), 33.333333333333333) + assert exchange.get_max_leverage("BTC/USDT", 300000000) == 2.0 + assert exchange.get_max_leverage("BTC/USDT", 600000000) == 1.0 # Last tier + + assert exchange.get_max_leverage("SPONGE/USDT", 200) == 1.0 # Pair not in leverage_tiers + assert exchange.get_max_leverage("BTC/USDT", 0.0) == 125.0 # No stake amount + with pytest.raises( + InvalidOrderException, + match=r'Amount 1000000000.01 too high for BTC/USDT' + ): + exchange.get_max_leverage("BTC/USDT", 1000000000.01) diff --git a/tests/exchange/test_okex.py b/tests/exchange/test_okex.py index affb2a28d..a9f7b8099 100644 --- a/tests/exchange/test_okex.py +++ b/tests/exchange/test_okex.py @@ -3,7 +3,7 @@ from unittest.mock import MagicMock # , PropertyMock from tests.conftest import get_patched_exchange -def test_get_maintenance_ratio_and_amt_okex( +def test_get_maintenance_ratio_and_amt_okx( default_conf, mocker, ): @@ -11,150 +11,153 @@ def test_get_maintenance_ratio_and_amt_okex( default_conf['trading_mode'] = 'futures' default_conf['margin_mode'] = 'isolated' default_conf['dry_run'] = False - api_mock.fetch_leverage_tiers = MagicMock(return_value={ - 'ETH/USDT:USDT': [ - { - 'tier': 1, - 'notionalFloor': 0, - 'notionalCap': 2000, - 'maintenanceMarginRatio': 0.01, - 'maxLeverage': 75, - 'info': { - 'baseMaxLoan': '', - 'imr': '0.013', - 'instId': '', - 'maxLever': '75', - 'maxSz': '2000', - 'minSz': '0', - 'mmr': '0.01', - 'optMgnFactor': '0', - 'quoteMaxLoan': '', - 'tier': '1', - 'uly': 'ETH-USDT' - } - }, - { - 'tier': 2, - 'notionalFloor': 2001, - 'notionalCap': 4000, - 'maintenanceMarginRatio': 0.015, - 'maxLeverage': 50, - 'info': { - 'baseMaxLoan': '', - 'imr': '0.02', - 'instId': '', - 'maxLever': '50', - 'maxSz': '4000', - 'minSz': '2001', - 'mmr': '0.015', - 'optMgnFactor': '0', - 'quoteMaxLoan': '', - 'tier': '2', - 'uly': 'ETH-USDT' - } - }, - { - 'tier': 3, - 'notionalFloor': 4001, - 'notionalCap': 8000, - 'maintenanceMarginRatio': 0.02, - 'maxLeverage': 20, - 'info': { - 'baseMaxLoan': '', - 'imr': '0.05', - 'instId': '', - 'maxLever': '20', - 'maxSz': '8000', - 'minSz': '4001', - 'mmr': '0.02', - 'optMgnFactor': '0', - 'quoteMaxLoan': '', - 'tier': '3', - 'uly': 'ETH-USDT' - } - }, - ], - 'XLTCUSDT': [ - { - 'tier': 1, - 'notionalFloor': 0, - 'notionalCap': 500, - 'maintenanceMarginRatio': 0.02, - 'maxLeverage': 75, - 'info': { - 'baseMaxLoan': '', - 'imr': '0.013', - 'instId': '', - 'maxLever': '75', - 'maxSz': '500', - 'minSz': '0', - 'mmr': '0.01', - 'optMgnFactor': '0', - 'quoteMaxLoan': '', - 'tier': '1', - 'uly': 'BTC-USDT' - } - }, - { - 'tier': 2, - 'notionalFloor': 501, - 'notionalCap': 1000, - 'maintenanceMarginRatio': 0.025, - 'maxLeverage': 50, - 'info': { - 'baseMaxLoan': '', - 'imr': '0.02', - 'instId': '', - 'maxLever': '50', - 'maxSz': '1000', - 'minSz': '501', - 'mmr': '0.015', - 'optMgnFactor': '0', - 'quoteMaxLoan': '', - 'tier': '2', - 'uly': 'BTC-USDT' - } - }, - { - 'tier': 3, - 'notionalFloor': 1001, - 'notionalCap': 2000, - 'maintenanceMarginRatio': 0.03, - 'maxLeverage': 20, - 'info': { - 'baseMaxLoan': '', - 'imr': '0.05', - 'instId': '', - 'maxLever': '20', - 'maxSz': '2000', - 'minSz': '1001', - 'mmr': '0.02', - 'optMgnFactor': '0', - 'quoteMaxLoan': '', - 'tier': '3', - 'uly': 'BTC-USDT' - } - }, - ] - }) - exchange = get_patched_exchange(mocker, default_conf, api_mock, id="okex") + mocker.patch.multiple( + 'freqtrade.exchange.Okx', + load_leverage_tiers=MagicMock(return_value={ + 'ETH/USDT:USDT': [ + { + 'tier': 1, + 'notionalFloor': 0, + 'notionalCap': 2000, + 'maintenanceMarginRatio': 0.01, + 'maxLeverage': 75, + 'info': { + 'baseMaxLoan': '', + 'imr': '0.013', + 'instId': '', + 'maxLever': '75', + 'maxSz': '2000', + 'minSz': '0', + 'mmr': '0.01', + 'optMgnFactor': '0', + 'quoteMaxLoan': '', + 'tier': '1', + 'uly': 'ETH-USDT' + } + }, + { + 'tier': 2, + 'notionalFloor': 2001, + 'notionalCap': 4000, + 'maintenanceMarginRatio': 0.015, + 'maxLeverage': 50, + 'info': { + 'baseMaxLoan': '', + 'imr': '0.02', + 'instId': '', + 'maxLever': '50', + 'maxSz': '4000', + 'minSz': '2001', + 'mmr': '0.015', + 'optMgnFactor': '0', + 'quoteMaxLoan': '', + 'tier': '2', + 'uly': 'ETH-USDT' + } + }, + { + 'tier': 3, + 'notionalFloor': 4001, + 'notionalCap': 8000, + 'maintenanceMarginRatio': 0.02, + 'maxLeverage': 20, + 'info': { + 'baseMaxLoan': '', + 'imr': '0.05', + 'instId': '', + 'maxLever': '20', + 'maxSz': '8000', + 'minSz': '4001', + 'mmr': '0.02', + 'optMgnFactor': '0', + 'quoteMaxLoan': '', + 'tier': '3', + 'uly': 'ETH-USDT' + } + }, + ], + 'ADA/USDT:USDT': [ + { + 'tier': 1, + 'notionalFloor': 0, + 'notionalCap': 500, + 'maintenanceMarginRatio': 0.02, + 'maxLeverage': 75, + 'info': { + 'baseMaxLoan': '', + 'imr': '0.013', + 'instId': '', + 'maxLever': '75', + 'maxSz': '500', + 'minSz': '0', + 'mmr': '0.01', + 'optMgnFactor': '0', + 'quoteMaxLoan': '', + 'tier': '1', + 'uly': 'ADA-USDT' + } + }, + { + 'tier': 2, + 'notionalFloor': 501, + 'notionalCap': 1000, + 'maintenanceMarginRatio': 0.025, + 'maxLeverage': 50, + 'info': { + 'baseMaxLoan': '', + 'imr': '0.02', + 'instId': '', + 'maxLever': '50', + 'maxSz': '1000', + 'minSz': '501', + 'mmr': '0.015', + 'optMgnFactor': '0', + 'quoteMaxLoan': '', + 'tier': '2', + 'uly': 'ADA-USDT' + } + }, + { + 'tier': 3, + 'notionalFloor': 1001, + 'notionalCap': 2000, + 'maintenanceMarginRatio': 0.03, + 'maxLeverage': 20, + 'info': { + 'baseMaxLoan': '', + 'imr': '0.05', + 'instId': '', + 'maxLever': '20', + 'maxSz': '2000', + 'minSz': '1001', + 'mmr': '0.02', + 'optMgnFactor': '0', + 'quoteMaxLoan': '', + 'tier': '3', + 'uly': 'ADA-USDT' + } + }, + ] + }) + ) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id="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) assert exchange.get_maintenance_ratio_and_amt('ETH/USDT:USDT', 8000) == (0.02, None) - assert exchange.get_maintenance_ratio_and_amt('XLTCUSDT', 1) == (0.02, None) - assert exchange.get_maintenance_ratio_and_amt('XLTCUSDT', 2000) == (0.03, None) + assert exchange.get_maintenance_ratio_and_amt('ADA/USDT:USDT', 1) == (0.02, None) + assert exchange.get_maintenance_ratio_and_amt('ADA/USDT:USDT', 2000) == (0.03, None) -def test_get_max_pair_stake_amount_okex(default_conf, mocker, leverage_tiers): +def test_get_max_pair_stake_amount_okx(default_conf, mocker, leverage_tiers): - exchange = get_patched_exchange(mocker, default_conf, id="okex") + exchange = get_patched_exchange(mocker, default_conf, id="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="okex") + exchange = get_patched_exchange(mocker, default_conf, id="okx") exchange._leverage_tiers = leverage_tiers assert exchange.get_max_pair_stake_amount('BNB/BUSD', 1.0) == 30000000 @@ -163,3 +166,135 @@ def test_get_max_pair_stake_amount_okex(default_conf, mocker, leverage_tiers): assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0, 10.0) == 100000000 assert exchange.get_max_pair_stake_amount('TTT/USDT', 1.0) == float('inf') # Not in tiers + + +# def test_load_leverage_tiers_okx(default_conf, mocker): +# mocker.patch.multiple( +# 'freqtrade.exchange.okx', +# load_leverage_tiers=MagicMock(return_value={ +# 'ETH/USDT:USDT': [ +# { +# 'tier': 1, +# 'notionalFloor': 0, +# 'notionalCap': 2000, +# 'maintenanceMarginRatio': 0.01, +# 'maxLeverage': 75, +# 'info': { +# 'baseMaxLoan': '', +# 'imr': '0.013', +# 'instId': '', +# 'maxLever': '75', +# 'maxSz': '2000', +# 'minSz': '0', +# 'mmr': '0.01', +# 'optMgnFactor': '0', +# 'quoteMaxLoan': '', +# 'tier': '1', +# 'uly': 'ETH-USDT' +# } +# }, +# { +# 'tier': 2, +# 'notionalFloor': 2001, +# 'notionalCap': 4000, +# 'maintenanceMarginRatio': 0.015, +# 'maxLeverage': 50, +# 'info': { +# 'baseMaxLoan': '', +# 'imr': '0.02', +# 'instId': '', +# 'maxLever': '50', +# 'maxSz': '4000', +# 'minSz': '2001', +# 'mmr': '0.015', +# 'optMgnFactor': '0', +# 'quoteMaxLoan': '', +# 'tier': '2', +# 'uly': 'ETH-USDT' +# } +# }, +# { +# 'tier': 3, +# 'notionalFloor': 4001, +# 'notionalCap': 8000, +# 'maintenanceMarginRatio': 0.02, +# 'maxLeverage': 20, +# 'info': { +# 'baseMaxLoan': '', +# 'imr': '0.05', +# 'instId': '', +# 'maxLever': '20', +# 'maxSz': '8000', +# 'minSz': '4001', +# 'mmr': '0.02', +# 'optMgnFactor': '0', +# 'quoteMaxLoan': '', +# 'tier': '3', +# 'uly': 'ETH-USDT' +# } +# }, +# ], +# 'ADA/USDT:USDT': [ +# { +# 'tier': 1, +# 'notionalFloor': 0, +# 'notionalCap': 500, +# 'maintenanceMarginRatio': 0.02, +# 'maxLeverage': 75, +# 'info': { +# 'baseMaxLoan': '', +# 'imr': '0.013', +# 'instId': '', +# 'maxLever': '75', +# 'maxSz': '500', +# 'minSz': '0', +# 'mmr': '0.01', +# 'optMgnFactor': '0', +# 'quoteMaxLoan': '', +# 'tier': '1', +# 'uly': 'ADA-USDT' +# } +# }, +# { +# 'tier': 2, +# 'notionalFloor': 501, +# 'notionalCap': 1000, +# 'maintenanceMarginRatio': 0.025, +# 'maxLeverage': 50, +# 'info': { +# 'baseMaxLoan': '', +# 'imr': '0.02', +# 'instId': '', +# 'maxLever': '50', +# 'maxSz': '1000', +# 'minSz': '501', +# 'mmr': '0.015', +# 'optMgnFactor': '0', +# 'quoteMaxLoan': '', +# 'tier': '2', +# 'uly': 'ADA-USDT' +# } +# }, +# { +# 'tier': 3, +# 'notionalFloor': 1001, +# 'notionalCap': 2000, +# 'maintenanceMarginRatio': 0.03, +# 'maxLeverage': 20, +# 'info': { +# 'baseMaxLoan': '', +# 'imr': '0.05', +# 'instId': '', +# 'maxLever': '20', +# 'maxSz': '2000', +# 'minSz': '1001', +# 'mmr': '0.02', +# 'optMgnFactor': '0', +# 'quoteMaxLoan': '', +# 'tier': '3', +# 'uly': 'ADA-USDT' +# } +# }, +# ] +# }) +# ) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0cb2d46f5..f9e75bb05 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -722,8 +722,8 @@ def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker) (False, 'futures', 'binance', 'isolated', 0.05, 8.167171717171717), (True, 'futures', 'gateio', 'isolated', 0.05, 11.7804274688304), (False, 'futures', 'gateio', 'isolated', 0.05, 8.181423084697796), - (True, 'futures', 'okex', 'isolated', 11.87413417771621), - (False, 'futures', 'okex', 'isolated', 8.085708510208207), + (True, 'futures', 'okex', 'isolated', 0.0, 11.87413417771621), + (False, 'futures', 'okex', 'isolated', 0.0, 8.085708510208207), ]) def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, limit_order_open, is_short, trading_mode,