mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-12-16 12:51:14 +00:00
Emulate fetch_orders if it ain't supported natively
This commit is contained in:
@@ -1439,11 +1439,29 @@ class Exchange:
|
|||||||
:param pair: Pair for the query
|
:param pair: Pair for the query
|
||||||
:param since: Starting time for the query
|
:param since: Starting time for the query
|
||||||
"""
|
"""
|
||||||
if self._config['dry_run'] or not self.exchange_has('fetchOrders'):
|
if self._config['dry_run']:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def fetch_orders_emulate() -> List[Dict]:
|
||||||
|
orders = []
|
||||||
|
if self.exchange_has('fetchClosedOrders'):
|
||||||
|
orders = self._api.fetch_closed_orders(pair, since=since_ms)
|
||||||
|
if self.exchange_has('fetchOpenOrders'):
|
||||||
|
orders_open = self._api.fetch_open_orders(pair, since=since_ms)
|
||||||
|
orders.extend(orders_open)
|
||||||
|
return orders
|
||||||
|
|
||||||
try:
|
try:
|
||||||
since_ms = int((since.timestamp() - 10) * 1000)
|
since_ms = int((since.timestamp() - 10) * 1000)
|
||||||
|
if self.exchange_has('fetchOrders'):
|
||||||
|
try:
|
||||||
orders: List[Dict] = self._api.fetch_orders(pair, since=since_ms)
|
orders: List[Dict] = self._api.fetch_orders(pair, since=since_ms)
|
||||||
|
except ccxt.NotSupported:
|
||||||
|
# Some exchanges don't support fetchOrders
|
||||||
|
# attempt to fetch open and closed orders separately
|
||||||
|
orders = fetch_orders_emulate()
|
||||||
|
else:
|
||||||
|
orders = fetch_orders_emulate()
|
||||||
self._log_exchange_response('fetch_orders', orders)
|
self._log_exchange_response('fetch_orders', orders)
|
||||||
orders = [self._order_contracts_to_amount(o) for o in orders]
|
orders = [self._order_contracts_to_amount(o) for o in orders]
|
||||||
return orders
|
return orders
|
||||||
|
|||||||
@@ -1781,23 +1781,62 @@ def test_fetch_orders(default_conf, mocker, exchange_name, limit_order):
|
|||||||
limit_order['buy'],
|
limit_order['buy'],
|
||||||
limit_order['sell'],
|
limit_order['sell'],
|
||||||
])
|
])
|
||||||
|
api_mock.fetch_open_orders = MagicMock(return_value=[limit_order['buy']])
|
||||||
|
api_mock.fetch_closed_orders = MagicMock(return_value=[limit_order['buy']])
|
||||||
|
|
||||||
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
||||||
start_time = datetime.now(timezone.utc) - timedelta(days=5)
|
start_time = datetime.now(timezone.utc) - timedelta(days=5)
|
||||||
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
# Not available in dry-run
|
# Not available in dry-run
|
||||||
assert exchange.fetch_orders('mocked', start_time) == []
|
assert exchange.fetch_orders('mocked', start_time) == []
|
||||||
|
assert api_mock.fetch_orders.call_count == 0
|
||||||
default_conf['dry_run'] = False
|
default_conf['dry_run'] = False
|
||||||
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
res = exchange.fetch_orders('mocked', start_time)
|
res = exchange.fetch_orders('mocked', start_time)
|
||||||
|
assert api_mock.fetch_orders.call_count == 1
|
||||||
|
assert api_mock.fetch_open_orders.call_count == 0
|
||||||
|
assert api_mock.fetch_closed_orders.call_count == 0
|
||||||
assert len(res) == 2
|
assert len(res) == 2
|
||||||
|
|
||||||
|
res = exchange.fetch_orders('mocked', start_time)
|
||||||
|
|
||||||
|
api_mock.fetch_orders.reset_mock()
|
||||||
|
|
||||||
|
def has_resp(_, endpoint):
|
||||||
|
if endpoint == 'fetchOrders':
|
||||||
|
return False
|
||||||
|
if endpoint == 'fetchClosedOrders':
|
||||||
|
return True
|
||||||
|
if endpoint == 'fetchOpenOrders':
|
||||||
|
return True
|
||||||
|
|
||||||
|
mocker.patch(f'{EXMS}.exchange_has', has_resp)
|
||||||
|
|
||||||
|
# happy path without fetchOrders
|
||||||
|
res = exchange.fetch_orders('mocked', start_time)
|
||||||
|
assert api_mock.fetch_orders.call_count == 0
|
||||||
|
assert api_mock.fetch_open_orders.call_count == 1
|
||||||
|
assert api_mock.fetch_closed_orders.call_count == 1
|
||||||
|
|
||||||
|
mocker.patch(f'{EXMS}.exchange_has', return_value=True)
|
||||||
|
|
||||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
||||||
"fetch_orders", "fetch_orders", retries=1,
|
"fetch_orders", "fetch_orders", retries=1,
|
||||||
pair='mocked', since=start_time)
|
pair='mocked', since=start_time)
|
||||||
|
|
||||||
|
# Unhappy path - first fetch-orders call fails.
|
||||||
|
api_mock.fetch_orders = MagicMock(side_effect=ccxt.NotSupported())
|
||||||
|
api_mock.fetch_open_orders.reset_mock()
|
||||||
|
api_mock.fetch_closed_orders.reset_mock()
|
||||||
|
|
||||||
|
res = exchange.fetch_orders('mocked', start_time)
|
||||||
|
|
||||||
|
assert api_mock.fetch_orders.call_count == 1
|
||||||
|
assert api_mock.fetch_open_orders.call_count == 1
|
||||||
|
assert api_mock.fetch_closed_orders.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_trading_fees(default_conf, mocker):
|
def test_fetch_trading_fees(default_conf, mocker):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
|
|||||||
Reference in New Issue
Block a user