Implement fee rate calculation
This commit is contained in:
parent
45c97fde2d
commit
59bafc8d02
@ -22,7 +22,7 @@ from freqtrade.data.converter import ohlcv_to_dataframe
|
||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
||||
OperationalException, TemporaryError)
|
||||
from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async
|
||||
from freqtrade.misc import deep_merge_dicts
|
||||
from freqtrade.misc import deep_merge_dicts, safe_value_fallback
|
||||
|
||||
|
||||
CcxtModuleType = Any
|
||||
@ -1084,8 +1084,33 @@ class Exchange:
|
||||
and order['fee']['cost'] is not None
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_cost_curr_rate(order: Dict) -> Tuple[float, str, Optional[float]]:
|
||||
def calculate_fee_rate(self, order: Dict) -> Optional[float]:
|
||||
"""
|
||||
Calculate fee rate if it's not given by the exchange.
|
||||
:param order: Order or trade (one trade) dict
|
||||
"""
|
||||
if order['fee'].get('rate') is not None:
|
||||
return order['fee'].get('rate')
|
||||
fee_curr = order['fee']['currency']
|
||||
# Calculate fee based on order details
|
||||
if fee_curr in self.get_pair_base_currency(order['symbol']):
|
||||
# Base currency - divide by amount
|
||||
return round(order['fee']['cost'] / order['amount'], 8)
|
||||
elif fee_curr in self.get_pair_quote_currency(order['symbol']):
|
||||
# Quote currency - divide by cost
|
||||
return round(order['fee']['cost'] / order['cost'], 8)
|
||||
else:
|
||||
# If Fee currency is a different currency
|
||||
try:
|
||||
comb = self.get_valid_pair_combination(fee_curr, self._config['stake_currency'])
|
||||
tick = self.fetch_ticker(comb)
|
||||
|
||||
fee_to_quote_rate = safe_value_fallback(tick, tick, 'last', 'ask')
|
||||
return round((order['fee']['cost'] * fee_to_quote_rate) / order['cost'], 8)
|
||||
except DependencyException:
|
||||
return None
|
||||
|
||||
def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]:
|
||||
"""
|
||||
Extract tuple of cost, currency, rate.
|
||||
Requires order_has_fee to run first!
|
||||
@ -1094,7 +1119,7 @@ class Exchange:
|
||||
"""
|
||||
return (order['fee']['cost'],
|
||||
order['fee']['currency'],
|
||||
order['fee'].get('rate', None))
|
||||
self.calculate_fee_rate(order))
|
||||
# calculate rate ? (order['fee']['cost'] / (order['amount'] * order['price']))
|
||||
|
||||
|
||||
|
@ -2159,9 +2159,44 @@ def test_order_has_fee(order, expected) -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize("order,expected", [
|
||||
({'fee': {'currency': 'ETH/BTC', 'cost': 0.43}}, (0.43, 'ETH/BTC', None)),
|
||||
({'fee': {'currency': 'ETH/USDT', 'cost': 0.01}}, (0.01, 'ETH/USDT', None)),
|
||||
({'fee': {'currency': 'ETH/USDT', 'cost': 0.34, 'rate': 0.01}}, (0.34, 'ETH/USDT', 0.01)),
|
||||
({'symbol': 'ETH/BTC', 'fee': {'currency': 'ETH', 'cost': 0.43}},
|
||||
(0.43, 'ETH', 0.01)),
|
||||
({'symbol': 'ETH/USDT', 'fee': {'currency': 'USDT', 'cost': 0.01}},
|
||||
(0.01, 'USDT', 0.01)),
|
||||
({'symbol': 'BTC/USDT', 'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.01}},
|
||||
(0.34, 'USDT', 0.01)),
|
||||
])
|
||||
def test_extract_cost_curr_rate(order, expected) -> None:
|
||||
assert Exchange.extract_cost_curr_rate(order) == expected
|
||||
def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None:
|
||||
mocker.patch('freqtrade.exchange.Exchange.calculate_fee_rate', MagicMock(return_value=0.01))
|
||||
ex = get_patched_exchange(mocker, default_conf)
|
||||
assert ex.extract_cost_curr_rate(order) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("order,expected", [
|
||||
# Using base-currency
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
||||
'fee': {'currency': 'ETH', 'cost': 0.004, 'rate': None}}, 0.1),
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.05, 'cost': 0.05,
|
||||
'fee': {'currency': 'ETH', 'cost': 0.004, 'rate': None}}, 0.08),
|
||||
# Using quote currency
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
||||
'fee': {'currency': 'BTC', 'cost': 0.005}}, 0.1),
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
||||
'fee': {'currency': 'BTC', 'cost': 0.002, 'rate': None}}, 0.04),
|
||||
# Using foreign currency
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
||||
'fee': {'currency': 'NEO', 'cost': 0.0012}}, 0.001944),
|
||||
({'symbol': 'ETH/BTC', 'amount': 2.21, 'cost': 0.02992561,
|
||||
'fee': {'currency': 'NEO', 'cost': 0.00027452}}, 0.00074305),
|
||||
# TODO: More tests here!
|
||||
# Rate included in return - return as is
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
||||
'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.01}}, 0.01),
|
||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
||||
'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.005}}, 0.005),
|
||||
])
|
||||
def test_calculate_fee_rate(mocker, default_conf, order, expected) -> None:
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'last': 0.081})
|
||||
|
||||
ex = get_patched_exchange(mocker, default_conf)
|
||||
assert ex.calculate_fee_rate(order) == expected
|
||||
|
Loading…
Reference in New Issue
Block a user