diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 02d22a6dc..6d158deb0 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -362,6 +362,53 @@ class FreqtradeBot(object): return self.handle_trade(trade) return False + def get_real_amount(self, order: Trade) -> float: + """ + Get real amount for the trade + This is needed for exchanges which charge fees in target currency (binance) + """ + + trades = exchange.get_trades_for_order( + order.open_order_id, order.pair, order.open_date) + + if len(trades) == 0: + raise OperationalException("get_real_amount: no trade found") + amount = 0 + fee = 0 + for trade in trades: + amount += trade["amount"] + if "fee" in trade: + if order.pair.startswith(trade["fee"]["currency"]): + fee += trade["fee"]["cost"] + + # TODO: create order using amount_lots would be better + if amount != order.amount: + self.logger.warning("amount {} does not match amount {}".format(amount, order.amount)) + raise OperationalException("Half bought? Amounts don't match") + real_amount = amount - fee + return real_amount + + def maybe_update_real_amount(self, trade: Trade) -> bool: + """ + Updates trade-amount with real amount + :return: True if real-amount has been changed. + """ + if trade.is_open and trade.open_order_id is None: + # Trade is not open anymore + self.logger.warning("could not open trade amount - Trade is not open anymore") + return False + try: + new_amount = self.get_real_amount(trade) + except OperationalException as exception: + self.logger.warning("could not update trade amount: %s", exception) + return False + # updating amount + self.logger.info("Updating amount for Trade {} from {} to {}".format( + trade, trade.amount, new_amount)) + trade.amount = new_amount + Trade.session.flush() + return True + def handle_trade(self, trade: Trade) -> bool: """ Sells the current pair if the threshold is reached and updates the trade record. diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 8f727838e..cc306f11d 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1281,3 +1281,196 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, mocker) -> trade.update(limit_buy_order) patch_get_signal(mocker, value=(False, True)) assert freqtrade.handle_trade(trade) is True + + +def test_get_real_amount_quote(default_conf, trades_for_order, mocker): + """ + Test get_real_amount + """ + + rv = [{'info': {'id': 34567, + 'orderId': 123456, + 'price': '0.24544100', + 'qty': '8.00000000', + 'commission': '0.00800000', + 'commissionAsset': 'LTC', + 'time': 1521663363189, + 'isBuyer': True, + 'isMaker': False, + 'isBestMatch': True}, + 'timestamp': 1521663363189, + 'datetime': '2018-03-21T20:16:03.189Z', + 'symbol': 'LTC/ETH', + 'id': '34567', + 'order': '123456', + 'type': None, + 'side': 'buy', + 'price': 0.245441, + 'cost': 1.963528, + 'amount': 8.0, + 'fee': {'cost': 0.008, 'currency': 'LTC'}}] + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=rv) + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + trade = Trade( + pair='LTC/ETH', + amount=8, + exchange='binance', + open_order_id="123456" + ) + freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://')) + # Amount - cost + assert freqtrade.get_real_amount(trade) == 7.992 + + +def test_get_real_amount_stake(default_conf, mocker): + """ + Test get_real_amount + """ + + rv = [{'info': {'id': 34567, + 'orderId': 123456, + 'price': '0.24544100', + 'qty': '8.00000000', + 'commission': '0.00800000', + 'commissionAsset': 'LTC', + 'time': 1521663363189, + 'isBuyer': True, + 'isMaker': False, + 'isBestMatch': True}, + 'timestamp': 1521663363189, + 'datetime': '2018-03-21T20:16:03.189Z', + 'symbol': 'LTC/ETH', + 'id': '34567', + 'order': '123456', + 'type': None, + 'side': 'buy', + 'price': 0.245441, + 'cost': 1.963528, + 'amount': 8.0, + 'fee': {'cost': 0.008, 'currency': 'ETH'}}] + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=rv) + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + trade = Trade( + pair='IOTA/ETH', + amount=8, + exchange='binance', + open_order_id="123456" + ) + freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://')) + # Amount - cost + assert freqtrade.get_real_amount(trade) == 8 + + +def test_get_real_amount_BNB(default_conf, mocker): + """ + Test get_real_amount + """ + + rv = [{'info': {'id': 34567, + 'orderId': 123456, + 'price': '0.24544100', + 'qty': '8.00000000', + 'commission': '0.00800000', + 'commissionAsset': 'LTC', + 'time': 1521663363189, + 'isBuyer': True, + 'isMaker': False, + 'isBestMatch': True}, + 'timestamp': 1521663363189, + 'datetime': '2018-03-21T20:16:03.189Z', + 'symbol': 'LTC/ETH', + 'id': '34567', + 'order': '123456', + 'type': None, + 'side': 'buy', + 'price': 0.245441, + 'cost': 1.963528, + 'amount': 8.0, + 'fee': {'cost': 0.00094518, 'currency': 'BNB'}}] + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=rv) + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + trade = Trade( + pair='IOTA/ETH', + amount=8, + exchange='binance', + open_order_id="123456" + ) + freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://')) + # Amount - cost + assert freqtrade.get_real_amount(trade) == 8 + + +def test_get_real_amount_multi(default_conf, mocker): + """ + Test get_real_amount + """ + + rv = [{'info': {'id': 34567, + 'orderId': 123456, + 'price': '0.24544100', + 'qty': '8.00000000', + 'commission': '0.00800000', + 'commissionAsset': 'LTC', + 'time': 1521663363189, + 'isBuyer': True, + 'isMaker': False, + 'isBestMatch': True}, + 'timestamp': 1521663363189, + 'datetime': '2018-03-21T20:16:03.189Z', + 'symbol': 'LTC/ETH', + 'id': '34567', + 'order': '123456', + 'type': None, + 'side': 'buy', + 'price': 0.245441, + 'cost': 1.963528, + 'amount': 4.0, + 'fee': {'cost': 0.004, 'currency': 'LTC'}}, + {'info': {'id': 34567, + 'orderId': 123456, + 'price': '0.24544100', + 'qty': '8.00000000', + 'commission': '0.00800000', + 'commissionAsset': 'LTC', + 'time': 1521663363189, + 'isBuyer': True, + 'isMaker': False, + 'isBestMatch': True}, + 'timestamp': 1521663363189, + 'datetime': '2018-03-21T20:16:03.189Z', + 'symbol': 'LTC/ETH', + 'id': '34567', + 'order': '123456', + 'type': None, + 'side': 'buy', + 'price': 0.245441, + 'cost': 1.963528, + 'amount': 4.0, + 'fee': {'cost': 0.004, 'currency': 'LTC'}}] + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=rv) + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + trade = Trade( + pair='LTC/ETH', + amount=8, + exchange='binance', + open_order_id="123456" + ) + freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://')) + # Amount - cost + assert freqtrade.get_real_amount(trade) == 7.992