Add tests for fill methods

This commit is contained in:
Matthias 2021-06-04 06:44:51 +02:00
parent 1e988c97ad
commit db03a24109
3 changed files with 106 additions and 6 deletions

View File

@ -608,22 +608,24 @@ class Exchange:
""" """
if self.exchange_has('fetchL2OrderBook'): if self.exchange_has('fetchL2OrderBook'):
ob = self.fetch_l2_order_book(pair, 20) ob = self.fetch_l2_order_book(pair, 20)
book_entry_type = 'asks' if side == 'buy' else 'bids' ob_type = 'asks' if side == 'buy' else 'bids'
remaining_amount = amount remaining_amount = amount
filled_amount = 0 filled_amount = 0
for book_entry in ob[book_entry_type]: for book_entry in ob[ob_type]:
book_entry_price = book_entry[0] book_entry_price = book_entry[0]
book_entry_coin_volume = book_entry[1] book_entry_coin_volume = book_entry[1]
book_entry_ref_currency_volume = book_entry_price * book_entry_coin_volume
if remaining_amount > 0: if remaining_amount > 0:
if remaining_amount < book_entry_ref_currency_volume: if remaining_amount < book_entry_coin_volume:
filled_amount += remaining_amount * book_entry_price filled_amount += remaining_amount * book_entry_price
else: else:
filled_amount += book_entry_ref_currency_volume * book_entry_price filled_amount += book_entry_coin_volume * book_entry_price
remaining_amount -= book_entry_ref_currency_volume remaining_amount -= book_entry_coin_volume
else: else:
break break
else:
# If remaining_amount wasn't consumed completely (break was not called)
filled_amount += remaining_amount * book_entry_price
forecast_avg_filled_price = filled_amount / amount forecast_avg_filled_price = filled_amount / amount
return self.price_to_precision(pair, forecast_avg_filled_price) return self.price_to_precision(pair, forecast_avg_filled_price)

View File

@ -1087,6 +1087,40 @@ def order_book_l2():
}) })
@pytest.fixture
def order_book_l2_usd():
return MagicMock(return_value={
'symbol': 'LTC/USDT',
'bids': [
[25.563, 49.269],
[25.562, 83.0],
[25.56, 106.0],
[25.559, 15.381],
[25.558, 29.299],
[25.557, 34.624],
[25.556, 10.0],
[25.555, 14.684],
[25.554, 45.91],
[25.553, 50.0]
],
'asks': [
[25.566, 14.27],
[25.567, 48.484],
[25.568, 92.349],
[25.572, 31.48],
[25.573, 23.0],
[25.574, 20.0],
[25.575, 89.606],
[25.576, 262.016],
[25.577, 178.557],
[25.578, 78.614]
],
'timestamp': None,
'datetime': None,
'nonce': 2372149736
})
@pytest.fixture @pytest.fixture
def ohlcv_history_list(): def ohlcv_history_list():
return [ return [

View File

@ -947,6 +947,70 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name):
assert order["symbol"] == "ETH/BTC" assert order["symbol"] == "ETH/BTC"
@pytest.mark.parametrize("side,startprice,endprice", [
("buy", 25.563, 25.566),
("sell", 25.566, 25.563)
])
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_create_dry_run_order_limit_fill(default_conf, mocker, side, startprice, endprice,
exchange_name, order_book_l2_usd):
default_conf['dry_run'] = True
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
mocker.patch.multiple('freqtrade.exchange.Exchange',
exchange_has=MagicMock(return_value=True),
fetch_l2_order_book=order_book_l2_usd,
)
order = exchange.create_dry_run_order(
pair='LTC/USDT', ordertype='limit', side=side, amount=1, rate=startprice)
assert 'id' in order
assert f'dry_run_{side}_' in order["id"]
assert order["side"] == side
assert order["type"] == "limit"
assert order["symbol"] == "LTC/USDT"
order_closed = exchange.fetch_dry_run_order(order['id'])
assert order_book_l2_usd.call_count == 1
assert order_closed['status'] == 'open'
assert not order['fee']
order_book_l2_usd.reset_mock()
order_closed['price'] = endprice
order_closed = exchange.fetch_dry_run_order(order['id'])
assert order_closed['status'] == 'closed'
assert order['fee']
@pytest.mark.parametrize("side,amount,endprice", [
("buy", 1, 25.566),
("buy", 100, 25.5672), # Requires interpolation
("buy", 1000, 25.575), # More than orderbook return
("sell", 1, 25.563),
("sell", 100, 25.5625), # Requires interpolation
("sell", 1000, 25.5555), # More than orderbook return
])
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_create_dry_run_order_market_fill(default_conf, mocker, side, amount, endprice,
exchange_name, order_book_l2_usd):
default_conf['dry_run'] = True
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
mocker.patch.multiple('freqtrade.exchange.Exchange',
exchange_has=MagicMock(return_value=True),
fetch_l2_order_book=order_book_l2_usd,
)
order = exchange.create_dry_run_order(
pair='LTC/USDT', ordertype='market', side=side, amount=amount, rate=25.5)
assert 'id' in order
assert f'dry_run_{side}_' in order["id"]
assert order["side"] == side
assert order["type"] == "market"
assert order["symbol"] == "LTC/USDT"
assert order['status'] == 'closed'
assert round(order["average"], 4) == round(endprice, 4)
@pytest.mark.parametrize("side", [ @pytest.mark.parametrize("side", [
("buy"), ("buy"),
("sell") ("sell")