refactor get_real_amount
This commit is contained in:
parent
f6ecd8e514
commit
9c2115c917
@ -367,16 +367,13 @@ class FreqtradeBot(object):
|
|||||||
order = exchange.get_order(trade.open_order_id, trade.pair)
|
order = exchange.get_order(trade.open_order_id, trade.pair)
|
||||||
# Try update amount (binance-fix)
|
# Try update amount (binance-fix)
|
||||||
try:
|
try:
|
||||||
# Only run for closed orders
|
new_amount = self.get_real_amount(trade, order)
|
||||||
if trade.fee_open != 0 and not (order['status'] == 'open'):
|
if order['amount'] != new_amount:
|
||||||
new_amount = self.get_real_amount(trade)
|
logger.info("Applying fee to amount for Trade {} from {} to {} ".format(
|
||||||
# This may break if a exchange applies no fee (which appears highly unlikely)
|
trade, order['amount'], new_amount))
|
||||||
if order['amount'] != new_amount:
|
order['amount'] = new_amount
|
||||||
logger.info("Applying fee to amount for Trade {} from {} to {} ".format(
|
# Fee was applied, so set to 0
|
||||||
trade, order['amount'], new_amount))
|
trade.fee_open = 0
|
||||||
order['amount'] = new_amount
|
|
||||||
# Fee was applied, so set to 0
|
|
||||||
trade.fee_open = 0
|
|
||||||
|
|
||||||
except OperationalException as exception:
|
except OperationalException as exception:
|
||||||
logger.warning("could not update trade amount: %s", exception)
|
logger.warning("could not update trade amount: %s", exception)
|
||||||
@ -388,30 +385,46 @@ class FreqtradeBot(object):
|
|||||||
return self.handle_trade(trade)
|
return self.handle_trade(trade)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_real_amount(self, order: Trade) -> float:
|
def get_real_amount(self, trade: Trade, order: Dict) -> float:
|
||||||
"""
|
"""
|
||||||
Get real amount for the trade
|
Get real amount for the trade
|
||||||
This is needed for exchanges which charge fees in target currency (e.g. binance)
|
Necessary for exchanges which charge fees in base currency (e.g. binance)
|
||||||
"""
|
"""
|
||||||
|
order_amount = order['amount']
|
||||||
|
# Only run for closed orders
|
||||||
|
if trade.fee_open == 0 or not order['status'] == 'open':
|
||||||
|
return order_amount
|
||||||
|
|
||||||
trades = exchange.get_trades_for_order(
|
# use fee from order-dict if possible
|
||||||
order.open_order_id, order.pair, order.open_date)
|
if order['fee']:
|
||||||
|
if trade.pair.startswith(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)
|
||||||
|
return new_amount
|
||||||
|
|
||||||
|
# Fallback to Trades
|
||||||
|
trades = exchange.get_trades_for_order(trade.open_order_id, trade.pair, trade.open_date)
|
||||||
|
|
||||||
if len(trades) == 0:
|
if len(trades) == 0:
|
||||||
raise OperationalException("get_real_amount: no trade found")
|
logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade)
|
||||||
|
return order_amount
|
||||||
amount = 0
|
amount = 0
|
||||||
fee_abs = 0
|
fee_abs = 0
|
||||||
for trade in trades:
|
for exectrade in trades:
|
||||||
amount += trade["amount"]
|
amount += exectrade['amount']
|
||||||
if "fee" in trade:
|
if "fee" in exectrade:
|
||||||
# only applies if fee is in quote currency!
|
# only applies if fee is in quote currency!
|
||||||
if order.pair.startswith(trade["fee"]["currency"]):
|
if trade.pair.startswith(exectrade['fee']['currency']):
|
||||||
fee_abs += trade["fee"]["cost"]
|
fee_abs += exectrade['fee']['cost']
|
||||||
|
|
||||||
if amount != order.amount:
|
if amount != order_amount:
|
||||||
logger.warning("amount {} does not match amount {}".format(amount, order.amount))
|
logger.warning("amount {} does not match amount {}".format(amount, trade.amount))
|
||||||
raise OperationalException("Half bought? Amounts don't match")
|
raise OperationalException("Half bought? Amounts don't match")
|
||||||
real_amount = amount - fee_abs
|
real_amount = amount - fee_abs
|
||||||
|
if fee_abs != 0:
|
||||||
|
logger.info("Applying fee on amount for {} (from {} to {}) from Trades".format(
|
||||||
|
trade, order['amount'], real_amount))
|
||||||
return real_amount
|
return real_amount
|
||||||
|
|
||||||
def handle_trade(self, trade: Trade) -> bool:
|
def handle_trade(self, trade: Trade) -> bool:
|
||||||
|
@ -585,14 +585,12 @@ def test_process_maybe_execute_sell(mocker, default_conf, limit_buy_order, caplo
|
|||||||
trade.open_fee = 0.001
|
trade.open_fee = 0.001
|
||||||
assert not freqtrade.process_maybe_execute_sell(trade)
|
assert not freqtrade.process_maybe_execute_sell(trade)
|
||||||
# Test amount not modified by fee-logic
|
# Test amount not modified by fee-logic
|
||||||
assert not log_has('Updating amount for Trade {} from 90.99181073 to 90.81'.format(trade),
|
assert not log_has('Applying fee to amount for Trade {} from 90.99181073 to 90.81'.format(
|
||||||
caplog.record_tuples)
|
trade), caplog.record_tuples)
|
||||||
|
|
||||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81)
|
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81)
|
||||||
# test amount modified by fee-logic
|
# test amount modified by fee-logic
|
||||||
assert not freqtrade.process_maybe_execute_sell(trade)
|
assert not freqtrade.process_maybe_execute_sell(trade)
|
||||||
assert log_has('Updating amount for Trade {} from 90.99181073 to 90.81'.format(trade),
|
|
||||||
caplog.record_tuples)
|
|
||||||
|
|
||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
@ -1319,7 +1317,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke
|
|||||||
assert freqtrade.handle_trade(trade) is True
|
assert freqtrade.handle_trade(trade) is True
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_quote(default_conf, trades_for_order, mocker):
|
def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
|
||||||
"""
|
"""
|
||||||
Test get_real_amount - fee in quote currency
|
Test get_real_amount - fee in quote currency
|
||||||
"""
|
"""
|
||||||
@ -1335,14 +1333,18 @@ def test_get_real_amount_quote(default_conf, trades_for_order, mocker):
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
# Amount is reduced by "fee"
|
# Amount is reduced by "fee"
|
||||||
assert freqtrade.get_real_amount(trade) == amount - (amount * 0.001)
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001)
|
||||||
|
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||||
|
'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992) from Trades',
|
||||||
|
caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_stake(default_conf, trades_for_order, mocker):
|
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
|
||||||
"""
|
"""
|
||||||
Test get_real_amount - fees in Stake currency
|
Test get_real_amount - fees in Stake currency
|
||||||
"""
|
"""
|
||||||
@ -1358,14 +1360,15 @@ def test_get_real_amount_stake(default_conf, trades_for_order, mocker):
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
# Amount does not change
|
# Amount does not change
|
||||||
assert freqtrade.get_real_amount(trade) == amount
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_BNB(default_conf, trades_for_order, mocker):
|
def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mocker):
|
||||||
"""
|
"""
|
||||||
Test get_real_amount - Fees in BNB
|
Test get_real_amount - Fees in BNB
|
||||||
"""
|
"""
|
||||||
@ -1383,14 +1386,15 @@ def test_get_real_amount_BNB(default_conf, trades_for_order, mocker):
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
# Amount does not change
|
# Amount does not change
|
||||||
assert freqtrade.get_real_amount(trade) == amount
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_multi(default_conf, trades_for_order2, mocker):
|
def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, mocker):
|
||||||
"""
|
"""
|
||||||
Test get_real_amount with split trades (multiple trades for this order)
|
Test get_real_amount with split trades (multiple trades for this order)
|
||||||
"""
|
"""
|
||||||
@ -1405,8 +1409,40 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, mocker):
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
# Amount is reduced by "fee"
|
# Amount is reduced by "fee"
|
||||||
assert freqtrade.get_real_amount(trade) == amount - (amount * 0.001)
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001)
|
||||||
|
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||||
|
'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992) from Trades',
|
||||||
|
caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
|
||||||
|
"""
|
||||||
|
Test get_real_amount with split trades (multiple trades for this order)
|
||||||
|
"""
|
||||||
|
limit_buy_order = deepcopy(buy_order_fee)
|
||||||
|
limit_buy_order['fee'] = {'cost': 0.004, 'currency': 'LTC'}
|
||||||
|
|
||||||
|
patch_get_signal(mocker)
|
||||||
|
patch_RPCManager(mocker)
|
||||||
|
patch_coinmarketcap(mocker)
|
||||||
|
mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True))
|
||||||
|
mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=trades_for_order)
|
||||||
|
amount = float(sum(x['amount'] for x in trades_for_order))
|
||||||
|
trade = Trade(
|
||||||
|
pair='LTC/ETH',
|
||||||
|
amount=amount,
|
||||||
|
exchange='binance',
|
||||||
|
open_rate=0.245441,
|
||||||
|
open_order_id="123456"
|
||||||
|
)
|
||||||
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
|
# Amount is reduced by "fee"
|
||||||
|
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount - 0.004
|
||||||
|
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||||
|
'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996) from Order',
|
||||||
|
caplog.record_tuples)
|
||||||
|
Loading…
Reference in New Issue
Block a user