Merge pull request #623 from xmatthias/cxxt_obj_sellfix

[cxxt][1/2] fix fee calculation in binance
This commit is contained in:
Michael Egger
2018-04-26 19:58:24 +02:00
committed by GitHub
8 changed files with 402 additions and 31 deletions

View File

@@ -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
}

View File

@@ -9,8 +9,9 @@ import ccxt
import pytest
from freqtrade import OperationalException, DependencyException, NetworkException
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
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)
import freqtrade.exchange as exchange
from freqtrade.tests.conftest import log_has
@@ -499,3 +500,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

View File

@@ -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)

View File

@@ -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'