diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index 0007b0f09..cfa590fae 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -1,6 +1,6 @@ """ Gate.io exchange subclass """ import logging -from typing import Dict, List, Tuple +from typing import Dict, List, Optional, Tuple from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import OperationalException @@ -31,7 +31,7 @@ class Gateio(Exchange): # TradingMode.SPOT always supported and not required in this list # (TradingMode.MARGIN, MarginMode.CROSS), # (TradingMode.FUTURES, MarginMode.CROSS), - # (TradingMode.FUTURES, MarginMode.ISOLATED) + (TradingMode.FUTURES, MarginMode.ISOLATED) ] def validate_ordertypes(self, order_types: Dict) -> None: @@ -40,3 +40,24 @@ class Gateio(Exchange): if any(v == 'market' for k, v in order_types.items()): raise OperationalException( f'Exchange {self.name} does not support market orders.') + + def get_maintenance_ratio_and_amt( + self, + pair: str, + nominal_value: Optional[float] = 0.0, + ) -> Tuple[float, Optional[float]]: + """ + :return: The maintenance margin ratio and maintenance amount + """ + info = self.markets[pair]['info'] + return (float(info['maintenance_rate']), None) + + def get_max_leverage(self, pair: str, stake_amount: Optional[float]) -> float: + """ + Returns the maximum leverage that a pair can be traded at + :param pair: The base/quote currency pair being traded + :param nominal_value: The total value of the trade in quote currency (margin_mode + debt) + """ + market = self.markets[pair] + if market['limits']['leverage']['max'] is not None: + return market['limits']['leverage']['max'] diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gateio.py index 6f7862909..209bf3577 100644 --- a/tests/exchange/test_gateio.py +++ b/tests/exchange/test_gateio.py @@ -1,8 +1,11 @@ +from unittest.mock import MagicMock, PropertyMock + import pytest from freqtrade.exceptions import OperationalException from freqtrade.exchange import Gateio from freqtrade.resolvers.exchange_resolver import ExchangeResolver +from tests.conftest import get_patched_exchange def test_validate_order_types_gateio(default_conf, mocker): @@ -26,3 +29,51 @@ def test_validate_order_types_gateio(default_conf, mocker): with pytest.raises(OperationalException, match=r'Exchange .* does not support market orders.'): ExchangeResolver.load_exchange('gateio', default_conf, True) + + +@pytest.mark.parametrize('pair,mm_ratio', [ + ("ETH/USDT:USDT", 0.005), + ("ADA/USDT:USDT", 0.003), +]) +def test_get_maintenance_ratio_and_amt_gateio(default_conf, mocker, pair, mm_ratio): + api_mock = MagicMock() + exchange = get_patched_exchange(mocker, default_conf, api_mock, id="gateio") + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock( + return_value={ + 'ETH/USDT:USDT': { + 'taker': 0.0000075, + 'maker': -0.0000025, + 'info': { + 'maintenance_rate': '0.005', + }, + 'id': 'ETH_USDT', + 'symbol': 'ETH/USDT:USDT', + }, + 'ADA/USDT:USDT': { + 'taker': 0.0000075, + 'maker': -0.0000025, + 'info': { + 'maintenance_rate': '0.003', + }, + 'id': 'ADA_USDT', + 'symbol': 'ADA/USDT:USDT', + }, + } + ) + ) + assert exchange.get_maintenance_ratio_and_amt(pair) == (mm_ratio, None) + + +@pytest.mark.parametrize('pair,nominal_value,max_lev', [ + ("ETH/BTC", 0.0, 2.0), + ("TKN/BTC", 100.0, 5.0), + ("BLK/BTC", 173.31, 3.0), + ("LTC/BTC", 0.0, 1.0), + ("TKN/USDT", 210.30, 1.0), +]) +def test_get_max_leverage_gateio(default_conf, mocker, pair, nominal_value, max_lev): + # Binance has a different method of getting the max leverage + exchange = get_patched_exchange(mocker, default_conf, id="kraken") + assert exchange.get_max_leverage(pair, nominal_value) == max_lev