diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index 23174bcd6..656a1e30f 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -1,6 +1,7 @@ """ Gate.io exchange subclass """ import logging -from typing import Dict, List, Tuple +from datetime import datetime +from typing import Dict, List, Optional, Tuple from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import OperationalException @@ -46,25 +47,29 @@ class Gateio(Exchange): raise OperationalException( f'Exchange {self.name} does not support market orders.') - def fetch_order(self, order_id: str, pair: str, params={}) -> Dict: - order = super().fetch_order(order_id, pair, params) + def get_trades_for_order(self, order_id: str, pair: str, since: datetime, + params: Optional[Dict] = None) -> List: + trades = super().get_trades_for_order(order_id, pair, since, params) - if self.trading_mode == TradingMode.FUTURES and order.get('fee') is None: + if self.trading_mode == TradingMode.FUTURES: # Futures usually don't contain fees in the response. # As such, futures orders on gateio will not contain a fee, which causes # a repeated "update fee" cycle and wrong calculations. # Therefore we patch the response with fees if it's not available. # An alternative also contianing fees would be # privateFuturesGetSettleAccountBook({"settle": "usdt"}) - pair_fees = self._trading_fees.get(pair, {}) - if pair_fees and pair_fees['taker'] is not None: - order['fee'] = { - 'currency': self.get_pair_quote_currency(pair), - 'cost': abs(order['cost']) * pair_fees['taker'], - 'rate': pair_fees['taker'], - } - return order + if pair_fees: + for idx, trade in enumerate(trades): + if trade.get('fee', {}).get('cost') is None: + takerOrMaker = trade.get('takerOrMaker', 'taker') + if pair_fees.get(takerOrMaker) is not None: + trades[idx]['fee'] = { + 'currency': self.get_pair_quote_currency(pair), + 'cost': abs(trade['cost']) * pair_fees[takerOrMaker], + 'rate': pair_fees[takerOrMaker], + } + return trades def fetch_stoploss_order(self, order_id: str, pair: str, params={}) -> Dict: return self.fetch_order( diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gateio.py index 9102d6704..c718c3838 100644 --- a/tests/exchange/test_gateio.py +++ b/tests/exchange/test_gateio.py @@ -1,3 +1,4 @@ +from datetime import datetime, timezone from unittest.mock import MagicMock import pytest @@ -72,8 +73,13 @@ def test_stoploss_adjust_gateio(mocker, default_conf, sl1, sl2, sl3, side): assert exchange.stoploss_adjust(sl1, order, side) assert not exchange.stoploss_adjust(sl2, order, side) +@pytest.mark.parametrize('takerormaker,rate,cost', [ + ('taker', 0.0005, 0.0001554325), + ('maker', 0.0, 0.0), -def test_fetch_order_gateio(mocker, default_conf): +]) +def test_fetch_my_trades_gateio(mocker, default_conf, takerormaker, rate, cost): + mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True) tick = {'ETH/USDT:USDT': { 'info': {'user_id': '', 'taker_fee': '0.0018', @@ -94,17 +100,19 @@ def test_fetch_order_gateio(mocker, default_conf): default_conf['margin_mode'] = MarginMode.ISOLATED api_mock = MagicMock() - api_mock.fetch_order = MagicMock(return_value={ - 'fee': None, + api_mock.fetch_my_trades = MagicMock(return_value=[{ + 'fee': {'cost': None}, 'price': 3108.65, 'cost': 0.310865, + 'order': '22255', + 'takerOrMaker': takerormaker, 'amount': 1, # 1 contract - }) + }]) exchange = get_patched_exchange(mocker, default_conf, api_mock=api_mock, id='gateio') exchange._trading_fees = tick - order = exchange.fetch_order('22255', 'ETH/USDT:USDT') - - assert order['fee'] - assert order['fee']['rate'] == 0.0005 - assert order['fee']['currency'] == 'USDT' - assert order['fee']['cost'] == 0.0001554325 + trades = exchange.get_trades_for_order('22255', 'ETH/USDT:USDT', datetime.now(timezone.utc)) + trade = trades[0] + assert trade['fee'] + assert trade['fee']['rate'] == rate + assert trade['fee']['currency'] == 'USDT' + assert trade['fee']['cost'] == cost