Implement get_pair_base_curr and get_pair_quote_curr

This commit is contained in:
Matthias 2020-02-24 21:50:27 +01:00
parent 3e4f663418
commit 61037ab7b8
6 changed files with 70 additions and 25 deletions

View File

@ -228,6 +228,18 @@ class Exchange:
markets = self.markets markets = self.markets
return sorted(set([x['quote'] for _, x in markets.items()])) 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: def klines(self, pair_interval: Tuple[str, str], copy: bool = True) -> DataFrame:
if pair_interval in self._klines: if pair_interval in self._klines:
return self._klines[pair_interval].copy() if copy else self._klines[pair_interval] return self._klines[pair_interval].copy() if copy else self._klines[pair_interval]

View File

@ -1125,12 +1125,13 @@ class FreqtradeBot:
if trade.fee_open == 0 or order['status'] == 'open': if trade.fee_open == 0 or order['status'] == 'open':
return order_amount return order_amount
trade_base_currency = self.exchange.get_pair_base_currency(trade.pair)
# use fee from order-dict if possible # use fee from order-dict if possible
if ('fee' in order and order['fee'] is not None and if ('fee' in order and order['fee'] is not None and
(order['fee'].keys() >= {'currency', 'cost'})): (order['fee'].keys() >= {'currency', 'cost'})):
if (order['fee']['currency'] is not None and if (order['fee']['currency'] is not None and
order['fee']['cost'] 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'] new_amount = order_amount - order['fee']['cost']
logger.info("Applying fee on amount for %s (from %s to %s) from Order", logger.info("Applying fee on amount for %s (from %s to %s) from Order",
trade, order['amount'], new_amount) trade, order['amount'], new_amount)
@ -1145,6 +1146,7 @@ class FreqtradeBot:
return order_amount return order_amount
amount = 0 amount = 0
fee_abs = 0 fee_abs = 0
trade_base_currency = self.exchange.get_pair_base_currency(trade.pair)
for exectrade in trades: for exectrade in trades:
amount += exectrade['amount'] amount += exectrade['amount']
if ("fee" in exectrade and exectrade['fee'] is not None and 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! # only applies if fee is in quote currency!
if (exectrade['fee']['currency'] is not None and if (exectrade['fee']['currency'] is not None and
exectrade['fee']['cost'] 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'] fee_abs += exectrade['fee']['cost']
if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC): if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC):

View File

@ -217,8 +217,9 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 9 active markets: " assert ("Exchange Bittrex has 10 active markets: "
"BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XLTCUSDT, XRP/BTC.\n" "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, NEO/BTC, "
"TKN/BTC, XLTCUSDT, XRP/BTC.\n"
in captured.out) in captured.out)
patch_exchange(mocker, api_mock=api_mock, id="binance") patch_exchange(mocker, api_mock=api_mock, id="binance")
@ -231,7 +232,7 @@ def test_list_markets(mocker, markets, capsys):
pargs['config'] = None pargs['config'] = None
start_list_markets(pargs, False) start_list_markets(pargs, False)
captured = capsys.readouterr() 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) captured.out)
patch_exchange(mocker, api_mock=api_mock, id="bittrex") 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) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 11 markets: " assert ("Exchange Bittrex has 12 markets: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, LTC/USDT, NEO/BTC, " "BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, LTC/USDT, NEO/BTC, "
"TKN/BTC, XLTCUSDT, XRP/BTC.\n" "TKN/BTC, XLTCUSDT, XRP/BTC.\n"
in captured.out) in captured.out)
@ -256,8 +257,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), True) start_list_markets(get_args(args), True)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 8 active pairs: " assert ("Exchange Bittrex has 9 active pairs: "
"BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n" "BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n"
in captured.out) in captured.out)
# Test list-pairs subcommand with --all: all pairs # 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) start_list_markets(get_args(args), True)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 10 pairs: " assert ("Exchange Bittrex has 11 pairs: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, LTC/USDT, NEO/BTC, " "BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, LTC/USDT, NEO/BTC, "
"TKN/BTC, XRP/BTC.\n" "TKN/BTC, XRP/BTC.\n"
in captured.out) in captured.out)
@ -282,8 +283,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 5 active markets with ETH, LTC as base currencies: " assert ("Exchange Bittrex has 6 active markets with ETH, LTC as base currencies: "
"ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, XLTCUSDT.\n" "ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, base=LTC # active markets, base=LTC
@ -295,8 +296,8 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 3 active markets with LTC as base currency: " assert ("Exchange Bittrex has 4 active markets with LTC as base currency: "
"LTC/BTC, LTC/USD, XLTCUSDT.\n" "LTC/BTC, LTC/ETH, LTC/USD, XLTCUSDT.\n"
in captured.out) in captured.out)
# active markets, quote=USDT, USD # active markets, quote=USDT, USD
@ -384,7 +385,7 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() captured = capsys.readouterr()
assert ("Exchange Bittrex has 9 active markets:\n" assert ("Exchange Bittrex has 10 active markets:\n"
in captured.out) in captured.out)
# Test tabular output, no markets found # Test tabular output, no markets found
@ -407,7 +408,7 @@ def test_list_markets(mocker, markets, capsys):
] ]
start_list_markets(get_args(args), False) start_list_markets(get_args(args), False)
captured = capsys.readouterr() 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"]' '"TKN/BTC","XLTCUSDT","XRP/BTC"]'
in captured.out) in captured.out)

View File

@ -575,7 +575,34 @@ def get_markets():
} }
}, },
'info': {}, '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
} }
},
},
} }

View File

@ -400,7 +400,7 @@ def test_validate_stake_currency_error(default_conf, mocker, caplog):
def test_get_quote_currencies(default_conf, mocker): def test_get_quote_currencies(default_conf, mocker):
ex = get_patched_exchange(mocker, default_conf) 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 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/BTC': 'active': True
# 'ETH/USDT': 'active': True # 'ETH/USDT': 'active': True
# 'LTC/BTC': 'active': False # 'LTC/BTC': 'active': False
# 'LTC/ETH': 'active': True
# 'LTC/USD': 'active': True # 'LTC/USD': 'active': True
# 'LTC/USDT': 'active': True # 'LTC/USDT': 'active': True
# 'NEO/BTC': 'active': False # 'NEO/BTC': 'active': False
@ -1870,26 +1871,26 @@ def test_get_valid_pair_combination(default_conf, mocker, markets):
# 'XRP/BTC': 'active': False # 'XRP/BTC': 'active': False
# all markets # all markets
([], [], False, False, ([], [], 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']), 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']),
# active markets # active markets
([], [], False, True, ([], [], 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']), 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']),
# all pairs # all pairs
([], [], True, False, ([], [], 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']), 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']),
# active pairs # active pairs
([], [], True, True, ([], [], 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']), 'TKN/BTC', 'XRP/BTC']),
# all markets, base=ETH, LTC # all markets, base=ETH, LTC
(['ETH', 'LTC'], [], False, False, (['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 # all markets, base=LTC
(['LTC'], [], False, False, (['LTC'], [], False, False,
['LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']), ['LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']),
# all markets, quote=USDT # all markets, quote=USDT
([], ['USDT'], False, False, ([], ['USDT'], False, False,
['ETH/USDT', 'LTC/USDT', 'XLTCUSDT']), ['ETH/USDT', 'LTC/USDT', 'XLTCUSDT']),

View File

@ -2192,6 +2192,7 @@ def test_handle_timedout_limit_buy(mocker, default_conf, limit_buy_order) -> Non
Trade.session = MagicMock() Trade.session = MagicMock()
trade = MagicMock() trade = MagicMock()
trade.pair = 'LTC/ETH'
limit_buy_order['remaining'] = limit_buy_order['amount'] limit_buy_order['remaining'] = limit_buy_order['amount']
assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order) assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order)
assert cancel_order_mock.call_count == 1 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.session = MagicMock()
trade = MagicMock() trade = MagicMock()
trade.pair = 'LTC/ETH'
limit_buy_order['remaining'] = limit_buy_order['amount'] limit_buy_order['remaining'] = limit_buy_order['amount']
assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order) assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order)
assert cancel_order_mock.call_count == 1 assert cancel_order_mock.call_count == 1