From 61037ab7b8f3f2467555c1a2a767580ea25f43a6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 24 Feb 2020 21:50:27 +0100 Subject: [PATCH] Implement get_pair_base_curr and get_pair_quote_curr --- freqtrade/exchange/exchange.py | 12 ++++++++++++ freqtrade/freqtradebot.py | 6 ++++-- tests/commands/test_commands.py | 31 ++++++++++++++++--------------- tests/conftest.py | 29 ++++++++++++++++++++++++++++- tests/exchange/test_exchange.py | 15 ++++++++------- tests/test_freqtradebot.py | 2 ++ 6 files changed, 70 insertions(+), 25 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 8023417a3..0e0d2dabe 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -228,6 +228,18 @@ class Exchange: markets = self.markets return sorted(set([x['quote'] for _, x in markets.items()])) + def get_pair_quote_currency(self, pair: str) -> str: + """ + Return a pair's quote currency + """ + return self.markets[pair].get('quote') + + def get_pair_base_currency(self, pair: str) -> str: + """ + Return a pair's quote currency + """ + return self.markets[pair].get('base') + def klines(self, pair_interval: Tuple[str, str], copy: bool = True) -> DataFrame: if pair_interval in self._klines: return self._klines[pair_interval].copy() if copy else self._klines[pair_interval] diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 00d5c369a..38583b5ad 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1125,12 +1125,13 @@ class FreqtradeBot: if trade.fee_open == 0 or order['status'] == 'open': return order_amount + trade_base_currency = self.exchange.get_pair_base_currency(trade.pair) # use fee from order-dict if possible if ('fee' in order and order['fee'] is not None and (order['fee'].keys() >= {'currency', 'cost'})): if (order['fee']['currency'] is not None and order['fee']['cost'] is not None and - trade.pair.startswith(order['fee']['currency'])): + trade_base_currency == order['fee']['currency']): new_amount = order_amount - order['fee']['cost'] logger.info("Applying fee on amount for %s (from %s to %s) from Order", trade, order['amount'], new_amount) @@ -1145,6 +1146,7 @@ class FreqtradeBot: return order_amount amount = 0 fee_abs = 0 + trade_base_currency = self.exchange.get_pair_base_currency(trade.pair) for exectrade in trades: amount += exectrade['amount'] if ("fee" in exectrade and exectrade['fee'] is not None and @@ -1152,7 +1154,7 @@ class FreqtradeBot: # only applies if fee is in quote currency! if (exectrade['fee']['currency'] is not None and exectrade['fee']['cost'] is not None and - trade.pair.startswith(exectrade['fee']['currency'])): + trade_base_currency == exectrade['fee']['currency']): fee_abs += exectrade['fee']['cost'] if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC): diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index a9fe0f637..fd8df4b56 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -217,8 +217,9 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), False) captured = capsys.readouterr() - assert ("Exchange Bittrex has 9 active markets: " - "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XLTCUSDT, XRP/BTC.\n" + assert ("Exchange Bittrex has 10 active markets: " + "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, NEO/BTC, " + "TKN/BTC, XLTCUSDT, XRP/BTC.\n" in captured.out) patch_exchange(mocker, api_mock=api_mock, id="binance") @@ -231,7 +232,7 @@ def test_list_markets(mocker, markets, capsys): pargs['config'] = None start_list_markets(pargs, False) captured = capsys.readouterr() - assert re.match("\nExchange Binance has 9 active markets:\n", + assert re.match("\nExchange Binance has 10 active markets:\n", captured.out) patch_exchange(mocker, api_mock=api_mock, id="bittrex") @@ -243,8 +244,8 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), False) captured = capsys.readouterr() - assert ("Exchange Bittrex has 11 markets: " - "BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, LTC/USDT, NEO/BTC, " + assert ("Exchange Bittrex has 12 markets: " + "BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, LTC/USDT, NEO/BTC, " "TKN/BTC, XLTCUSDT, XRP/BTC.\n" in captured.out) @@ -256,8 +257,8 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), True) captured = capsys.readouterr() - assert ("Exchange Bittrex has 8 active pairs: " - "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n" + assert ("Exchange Bittrex has 9 active pairs: " + "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n" in captured.out) # Test list-pairs subcommand with --all: all pairs @@ -268,8 +269,8 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), True) captured = capsys.readouterr() - assert ("Exchange Bittrex has 10 pairs: " - "BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, LTC/USDT, NEO/BTC, " + assert ("Exchange Bittrex has 11 pairs: " + "BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, LTC/USDT, NEO/BTC, " "TKN/BTC, XRP/BTC.\n" in captured.out) @@ -282,8 +283,8 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), False) captured = capsys.readouterr() - assert ("Exchange Bittrex has 5 active markets with ETH, LTC as base currencies: " - "ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, XLTCUSDT.\n" + assert ("Exchange Bittrex has 6 active markets with ETH, LTC as base currencies: " + "ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, XLTCUSDT.\n" in captured.out) # active markets, base=LTC @@ -295,8 +296,8 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), False) captured = capsys.readouterr() - assert ("Exchange Bittrex has 3 active markets with LTC as base currency: " - "LTC/BTC, LTC/USD, XLTCUSDT.\n" + assert ("Exchange Bittrex has 4 active markets with LTC as base currency: " + "LTC/BTC, LTC/ETH, LTC/USD, XLTCUSDT.\n" in captured.out) # active markets, quote=USDT, USD @@ -384,7 +385,7 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), False) captured = capsys.readouterr() - assert ("Exchange Bittrex has 9 active markets:\n" + assert ("Exchange Bittrex has 10 active markets:\n" in captured.out) # Test tabular output, no markets found @@ -407,7 +408,7 @@ def test_list_markets(mocker, markets, capsys): ] start_list_markets(get_args(args), False) captured = capsys.readouterr() - assert ('["BLK/BTC","ETH/BTC","ETH/USDT","LTC/BTC","LTC/USD","NEO/BTC",' + assert ('["BLK/BTC","ETH/BTC","ETH/USDT","LTC/BTC","LTC/ETH","LTC/USD","NEO/BTC",' '"TKN/BTC","XLTCUSDT","XRP/BTC"]' in captured.out) diff --git a/tests/conftest.py b/tests/conftest.py index acb730330..000f62868 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -575,7 +575,34 @@ def get_markets(): } }, 'info': {}, - } + }, + 'LTC/ETH': { + 'id': 'LTCETH', + 'symbol': 'LTC/ETH', + 'base': 'LTC', + 'quote': 'ETH', + 'active': True, + 'precision': { + 'base': 8, + 'quote': 8, + 'amount': 3, + 'price': 5 + }, + 'limits': { + 'amount': { + 'min': 0.001, + 'max': 10000000.0 + }, + 'price': { + 'min': 1e-05, + 'max': 1000.0 + }, + 'cost': { + 'min': 0.01, + 'max': None + } + }, + }, } diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index d1c105591..98edd0dbb 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -400,7 +400,7 @@ def test_validate_stake_currency_error(default_conf, mocker, caplog): def test_get_quote_currencies(default_conf, mocker): ex = get_patched_exchange(mocker, default_conf) - assert set(ex.get_quote_currencies()) == set(['USD', 'BTC', 'USDT']) + assert set(ex.get_quote_currencies()) == set(['USD', 'ETH', 'BTC', 'USDT']) def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs directly @@ -1862,6 +1862,7 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): # 'ETH/BTC': 'active': True # 'ETH/USDT': 'active': True # 'LTC/BTC': 'active': False + # 'LTC/ETH': 'active': True # 'LTC/USD': 'active': True # 'LTC/USDT': 'active': True # 'NEO/BTC': 'active': False @@ -1870,26 +1871,26 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): # 'XRP/BTC': 'active': False # all markets ([], [], False, False, - ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', + ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']), # active markets ([], [], False, True, - ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'NEO/BTC', + ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']), # all pairs ([], [], True, False, - ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', + ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']), # active pairs ([], [], True, True, - ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'NEO/BTC', + ['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']), # all markets, base=ETH, LTC (['ETH', 'LTC'], [], False, False, - ['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), + ['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), # all markets, base=LTC (['LTC'], [], False, False, - ['LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), + ['LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), # all markets, quote=USDT ([], ['USDT'], False, False, ['ETH/USDT', 'LTC/USDT', 'XLTCUSDT']), diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 20db46fac..9a7816d35 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2192,6 +2192,7 @@ def test_handle_timedout_limit_buy(mocker, default_conf, limit_buy_order) -> Non Trade.session = MagicMock() trade = MagicMock() + trade.pair = 'LTC/ETH' limit_buy_order['remaining'] = limit_buy_order['amount'] assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order) assert cancel_order_mock.call_count == 1 @@ -2215,6 +2216,7 @@ def test_handle_timedout_limit_buy_corder_empty(mocker, default_conf, limit_buy_ Trade.session = MagicMock() trade = MagicMock() + trade.pair = 'LTC/ETH' limit_buy_order['remaining'] = limit_buy_order['amount'] assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order) assert cancel_order_mock.call_count == 1