diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index f2c08ff7d..8ac60d3de 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -3,6 +3,7 @@ import logging from random import randint from typing import List, Dict, Any, Optional +from datetime import datetime import ccxt import arrow @@ -134,7 +135,8 @@ def buy(pair: str, rate: float, amount: float) -> Dict: 'side': 'buy', 'remaining': 0.0, 'datetime': arrow.utcnow().isoformat(), - 'status': 'closed' + 'status': 'closed', + 'fee': None } return {'id': order_id} @@ -324,6 +326,25 @@ def get_order(order_id: str, pair: str) -> Dict: @retrier +def get_trades_for_order(order_id: str, pair: str, since: datetime) -> List: + if _CONF['dry_run']: + return [] + if not exchange_has('fetchMyTrades'): + return [] + try: + my_trades = _API.fetch_my_trades(pair, since.timestamp()) + matched_trades = [trade for trade in my_trades if trade['order'] == order_id] + + return matched_trades + + except ccxt.NetworkError as e: + raise TemporaryError( + 'Could not get trades due to networking error. Message: {}'.format(e) + ) + except ccxt.BaseError as e: + raise OperationalException(e) + + def get_pair_detail_url(pair: str) -> str: try: url_base = _API.urls.get('www') @@ -371,3 +392,13 @@ def get_fee(symbol='ETH/BTC', type='', side='', amount=1, e.__class__.__name__, e)) except ccxt.BaseError as e: raise OperationalException(e) + + +def get_amount_lots(pair: str, amount: float) -> float: + """ + get buyable amount rounding, .. + """ + # validate that markets are loaded before trying to get fee + if not _API.markets: + _API.load_markets() + return _API.amount_to_lots(pair, amount) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 298f03164..f0bf3fa4d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -287,7 +287,7 @@ class FreqtradeBot(object): if not whitelist: raise DependencyException('No currency pairs in whitelist') - # Pick pair based on StochRSI buy signals + # Pick pair based on buy signals for _pair in whitelist: (buy, sell) = self.analyze.get_signal(_pair, interval) if buy and not sell: @@ -323,11 +323,13 @@ class FreqtradeBot(object): ) ) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL + fee = exchange.get_fee(symbol=pair, taker_or_maker='maker') trade = Trade( pair=pair, stake_amount=stake_amount, amount=amount, - fee=exchange.get_fee(taker_or_maker='maker'), + fee_open=fee, + fee_close=fee, open_rate=buy_limit, open_date=datetime.utcnow(), exchange=exchange.get_id(), @@ -363,7 +365,19 @@ class FreqtradeBot(object): if trade.open_order_id: # Update trade with order values logger.info('Found open order for %s', trade) - trade.update(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: + new_amount = self.get_real_amount(trade, order) + if order['amount'] != new_amount: + order['amount'] = new_amount + # Fee was applied, so set to 0 + trade.fee_open = 0 + + except OperationalException as exception: + logger.warning("could not update trade amount: %s", exception) + + trade.update(order) if trade.is_open and trade.open_order_id is None: # Check if we can sell our current pair @@ -372,6 +386,48 @@ class FreqtradeBot(object): logger.warning('Unable to sell trade: %s', exception) return False + def get_real_amount(self, trade: Trade, order: Dict) -> float: + """ + Get real amount for the trade + 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 order['status'] == 'open': + return order_amount + + # use fee from order-dict if possible + if 'fee' in order and 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: + logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade) + return order_amount + amount = 0 + fee_abs = 0 + for exectrade in trades: + amount += exectrade['amount'] + if "fee" in exectrade: + # only applies if fee is in quote currency! + if trade.pair.startswith(exectrade['fee']['currency']): + fee_abs += exectrade['fee']['cost'] + + if amount != order_amount: + logger.warning("amount {} does not match amount {}".format(amount, trade.amount)) + raise OperationalException("Half bought? Amounts don't match") + 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 + 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/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 1bd091155..6df4a99fa 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -113,12 +113,14 @@ class Backtesting(object): stake_amount = args['stake_amount'] max_open_trades = args.get('max_open_trades', 0) + fee = exchange.get_fee() trade = Trade( open_rate=buy_row.close, open_date=buy_row.date, stake_amount=stake_amount, amount=stake_amount / buy_row.open, - fee=exchange.get_fee() + fee_open=fee, + fee_close=fee ) # calculate win/lose forwards from buy point diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 55f53329a..ed81ad2ec 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -85,7 +85,8 @@ class Trade(_DECL_BASE): exchange = Column(String, nullable=False) pair = Column(String, nullable=False) is_open = Column(Boolean, nullable=False, default=True) - fee = Column(Float, nullable=False, default=0.0) + fee_open = Column(Float, nullable=False, default=0.0) + fee_close = Column(Float, nullable=False, default=0.0) open_rate = Column(Float) close_rate = Column(Float) close_profit = Column(Float) @@ -156,7 +157,7 @@ class Trade(_DECL_BASE): getcontext().prec = 8 buy_trade = (Decimal(self.amount) * Decimal(self.open_rate)) - fees = buy_trade * Decimal(fee or self.fee) + fees = buy_trade * Decimal(fee or self.fee_open) return float(buy_trade + fees) def calc_close_trade_price( @@ -177,7 +178,7 @@ class Trade(_DECL_BASE): return 0.0 sell_trade = (Decimal(self.amount) * Decimal(rate or self.close_rate)) - fees = sell_trade * Decimal(fee or self.fee) + fees = sell_trade * Decimal(fee or self.fee_close) return float(sell_trade - fees) def calc_profit( @@ -195,7 +196,7 @@ class Trade(_DECL_BASE): open_trade_price = self.calc_open_trade_price() close_trade_price = self.calc_close_trade_price( rate=(rate or self.close_rate), - fee=(fee or self.fee) + fee=(fee or self.fee_close) ) return float("{0:.8f}".format(close_trade_price - open_trade_price)) @@ -215,7 +216,7 @@ class Trade(_DECL_BASE): open_trade_price = self.calc_open_trade_price() close_trade_price = self.calc_close_trade_price( rate=(rate or self.close_rate), - fee=(fee or self.fee) + fee=(fee or self.fee_close) ) return float("{0:.8f}".format((close_trade_price / open_trade_price) - 1)) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 648480bea..85ce3b35d 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -208,7 +208,7 @@ def markets_empty(): return MagicMock(return_value=[]) -@pytest.fixture +@pytest.fixture(scope='function') def limit_buy_order(): return { 'id': 'mocked_limit_buy', @@ -499,3 +499,90 @@ def result(): # that inserts a trade of some type and open-status # return the open-order-id # See tests in rpc/main that could use this + + +@pytest.fixture(scope="function") +def trades_for_order(): + return [{'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'}}] + + +@pytest.fixture(scope="function") +def trades_for_order2(): + return [{'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'}}] + + +@pytest.fixture +def buy_order_fee(): + return { + 'id': 'mocked_limit_buy_old', + 'type': 'limit', + 'side': 'buy', + 'pair': 'mocked', + 'datetime': str(arrow.utcnow().shift(minutes=-601).datetime), + 'price': 0.245441, + 'amount': 8.0, + 'remaining': 90.99181073, + 'status': 'closed', + 'fee': None + } diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index d626340a3..006f6188d 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -4,14 +4,15 @@ import logging from copy import deepcopy from random import randint from unittest.mock import MagicMock, PropertyMock -import ccxt +import ccxt import pytest -from freqtrade import OperationalException, DependencyException, TemporaryError -from freqtrade.exchange import init, validate_pairs, buy, sell, get_balance, get_balances, \ - get_ticker, get_ticker_history, cancel_order, get_name, get_fee, get_id, get_pair_detail_url import freqtrade.exchange as exchange +from freqtrade import OperationalException, DependencyException, TemporaryError +from freqtrade.exchange import (init, validate_pairs, buy, sell, get_balance, get_balances, + get_ticker, get_ticker_history, cancel_order, get_name, get_fee, + get_id, get_pair_detail_url, get_amount_lots) from freqtrade.tests.conftest import log_has API_INIT = False @@ -507,3 +508,10 @@ def test_get_fee(default_conf, mocker): }) mocker.patch('freqtrade.exchange._API', api_mock) assert get_fee() == 0.025 + + +def test_get_amount_lots(default_conf, mocker): + api_mock = MagicMock() + api_mock.amount_to_lots = MagicMock(return_value=1.0) + mocker.patch('freqtrade.exchange._API', api_mock) + assert get_amount_lots('LTC/BTC', 1.54) == 1 diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 217bf82e6..ead796aca 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -568,18 +568,30 @@ def test_process_maybe_execute_buy_exception(mocker, default_conf, caplog) -> No log_has('Unable to create trade:', caplog.record_tuples) -def test_process_maybe_execute_sell(mocker, default_conf) -> None: +def test_process_maybe_execute_sell(mocker, default_conf, limit_buy_order, caplog) -> None: """ Test process_maybe_execute_sell() method """ freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) - mocker.patch('freqtrade.freqtradebot.exchange.get_order', return_value=1) + mocker.patch('freqtrade.freqtradebot.exchange.get_order', return_value=limit_buy_order) + mocker.patch('freqtrade.freqtradebot.exchange.get_trades_for_order', return_value=[]) + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', + return_value=limit_buy_order['amount']) trade = MagicMock() trade.open_order_id = '123' + trade.open_fee = 0.001 assert not freqtrade.process_maybe_execute_sell(trade) + # Test amount not modified by fee-logic + assert not log_has('Applying fee to amount for Trade {} from 90.99181073 to 90.81'.format( + trade), caplog.record_tuples) + + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81) + # test amount modified by fee-logic + assert not freqtrade.process_maybe_execute_sell(trade) + trade.is_open = True trade.open_order_id = None # Assert we call handle_trade() if trade is feasible for execution @@ -812,7 +824,8 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, fe exchange='bittrex', open_order_id='123456789', amount=90.99181073, - fee=0.0, + fee_open=0.0, + fee_close=0.0, stake_amount=1, open_date=arrow.utcnow().shift(minutes=-601).datetime, is_open=True @@ -851,7 +864,8 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old, exchange='bittrex', open_order_id='123456789', amount=90.99181073, - fee=0.0, + fee_open=0.0, + fee_close=0.0, stake_amount=1, open_date=arrow.utcnow().shift(hours=-5).datetime, close_date=arrow.utcnow().shift(minutes=-601).datetime, @@ -890,7 +904,8 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old exchange='bittrex', open_order_id='123456789', amount=90.99181073, - fee=0.0, + fee_open=0.0, + fee_close=0.0, stake_amount=1, open_date=arrow.utcnow().shift(minutes=-601).datetime, is_open=True @@ -937,7 +952,8 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) - exchange='bittrex', open_order_id='123456789', amount=90.99181073, - fee=0.0, + fee_open=0.0, + fee_close=0.0, stake_amount=1, open_date=arrow.utcnow().shift(minutes=-601).datetime, is_open=True @@ -1299,3 +1315,161 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke 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, buy_order_fee, caplog, mocker): + """ + Test get_real_amount - fee in quote currency + """ + + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=trades_for_order) + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + amount = 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, 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_no_trade(default_conf, buy_order_fee, caplog, mocker): + """ + Test get_real_amount - fee in quote currency + """ + + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=[]) + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + amount = buy_order_fee['amount'] + 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, buy_order_fee) == amount + assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' + 'open_rate=0.24544100, open_since=closed) failed: myTrade-Dict empty found', + caplog.record_tuples) + + +def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, caplog, mocker): + """ + Test get_real_amount - fees in Stake currency + """ + trades_for_order[0]['fee']['currency'] = 'ETH' + + 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 = 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 does not change + assert freqtrade.get_real_amount(trade, buy_order_fee) == amount + + +def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mocker): + """ + Test get_real_amount - Fees in BNB + """ + + trades_for_order[0]['fee']['currency'] = 'BNB' + trades_for_order[0]['fee']['cost'] = 0.00094518 + + 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 = 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 does not change + assert freqtrade.get_real_amount(trade, buy_order_fee) == amount + + +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) + """ + + 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_order2) + amount = float(sum(x['amount'] for x in trades_for_order2)) + 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, 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) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index fa6e15f57..db8a5e9bd 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -126,7 +126,8 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) assert trade.open_order_id is None @@ -154,7 +155,8 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) @@ -177,7 +179,8 @@ def test_calc_close_trade_price_exception(limit_buy_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) @@ -191,7 +194,8 @@ def test_update_open_order(limit_buy_order): trade = Trade( pair='ETH/BTC', stake_amount=1.00, - fee=0.1, + fee_open=0.1, + fee_close=0.1, exchange='bittrex', ) @@ -214,7 +218,8 @@ def test_update_invalid_order(limit_buy_order): trade = Trade( pair='ETH/BTC', stake_amount=1.00, - fee=0.1, + fee_open=0.1, + fee_close=0.1, exchange='bittrex', ) limit_buy_order['type'] = 'invalid' @@ -227,7 +232,8 @@ def test_calc_open_trade_price(limit_buy_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'open_trade' @@ -245,7 +251,8 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'close_trade' @@ -267,7 +274,8 @@ def test_calc_profit(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'profit_percent' @@ -298,7 +306,8 @@ def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'profit_percent' @@ -326,7 +335,8 @@ def test_clean_dry_run_db(default_conf, fee): pair='ETH/BTC', stake_amount=0.001, amount=123.0, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='dry_run_buy_12345' @@ -337,7 +347,8 @@ def test_clean_dry_run_db(default_conf, fee): pair='ETC/BTC', stake_amount=0.001, amount=123.0, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='dry_run_sell_12345' @@ -349,7 +360,8 @@ def test_clean_dry_run_db(default_conf, fee): pair='ETC/BTC', stake_amount=0.001, amount=123.0, - fee=fee.return_value, + fee_open=fee.return_value, + fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='prod_buy_12345'