parent
24f480b4ce
commit
11c76c3c89
@ -9,7 +9,7 @@ import logging
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Coroutine, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import ccxt
|
import ccxt
|
||||||
@ -1371,6 +1371,22 @@ class Exchange:
|
|||||||
data = sorted(data, key=lambda x: x[0])
|
data = sorted(data, key=lambda x: x[0])
|
||||||
return pair, timeframe, data
|
return pair, timeframe, data
|
||||||
|
|
||||||
|
def _build_coroutine(self, pair: str, timeframe: str, since_ms: Optional[int]) -> Coroutine:
|
||||||
|
if not since_ms and self.required_candle_call_count > 1:
|
||||||
|
# Multiple calls for one pair - to get more history
|
||||||
|
one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe)
|
||||||
|
move_to = one_call * self.required_candle_call_count
|
||||||
|
now = timeframe_to_next_date(timeframe)
|
||||||
|
since_ms = int((now - timedelta(seconds=move_to // 1000)).timestamp() * 1000)
|
||||||
|
|
||||||
|
if since_ms:
|
||||||
|
return self._async_get_historic_ohlcv(
|
||||||
|
pair, timeframe, since_ms=since_ms, raise_=True)
|
||||||
|
else:
|
||||||
|
# One call ... "regular" refresh
|
||||||
|
return self._async_get_candle_history(
|
||||||
|
pair, timeframe, since_ms=since_ms)
|
||||||
|
|
||||||
def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes, *,
|
def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes, *,
|
||||||
since_ms: Optional[int] = None, cache: bool = True
|
since_ms: Optional[int] = None, cache: bool = True
|
||||||
) -> Dict[Tuple[str, str], DataFrame]:
|
) -> Dict[Tuple[str, str], DataFrame]:
|
||||||
@ -1389,22 +1405,15 @@ class Exchange:
|
|||||||
cached_pairs = []
|
cached_pairs = []
|
||||||
# Gather coroutines to run
|
# Gather coroutines to run
|
||||||
for pair, timeframe in set(pair_list):
|
for pair, timeframe in set(pair_list):
|
||||||
|
if timeframe not in self.timeframes:
|
||||||
|
logger.warning(
|
||||||
|
f"Cannot download ({pair}, {timeframe}) combination as this timeframe is "
|
||||||
|
f"not available on {self.name}. Available timeframes are "
|
||||||
|
f"{', '.join(self.timeframes)}.")
|
||||||
|
continue
|
||||||
if ((pair, timeframe) not in self._klines or not cache
|
if ((pair, timeframe) not in self._klines or not cache
|
||||||
or self._now_is_time_to_refresh(pair, timeframe)):
|
or self._now_is_time_to_refresh(pair, timeframe)):
|
||||||
if not since_ms and self.required_candle_call_count > 1:
|
input_coroutines.append(self._build_coroutine(pair, timeframe, since_ms))
|
||||||
# Multiple calls for one pair - to get more history
|
|
||||||
one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe)
|
|
||||||
move_to = one_call * self.required_candle_call_count
|
|
||||||
now = timeframe_to_next_date(timeframe)
|
|
||||||
since_ms = int((now - timedelta(seconds=move_to // 1000)).timestamp() * 1000)
|
|
||||||
|
|
||||||
if since_ms:
|
|
||||||
input_coroutines.append(self._async_get_historic_ohlcv(
|
|
||||||
pair, timeframe, since_ms=since_ms, raise_=True))
|
|
||||||
else:
|
|
||||||
# One call ... "regular" refresh
|
|
||||||
input_coroutines.append(self._async_get_candle_history(
|
|
||||||
pair, timeframe, since_ms=since_ms))
|
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Using cached candle (OHLCV) data for pair %s, timeframe %s ...",
|
"Using cached candle (OHLCV) data for pair %s, timeframe %s ...",
|
||||||
|
@ -107,6 +107,8 @@ def patch_exchange(mocker, api_mock=None, id='binance', mock_markets=True) -> No
|
|||||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||||
else:
|
else:
|
||||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock())
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock())
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.timeframes', PropertyMock(
|
||||||
|
return_value=['5m', '15m', '1h', '1d']))
|
||||||
|
|
||||||
|
|
||||||
def get_patched_exchange(mocker, config, api_mock=None, id='binance',
|
def get_patched_exchange(mocker, config, api_mock=None, id='binance',
|
||||||
|
@ -1692,6 +1692,13 @@ def test_refresh_latest_ohlcv(mocker, default_conf, caplog) -> None:
|
|||||||
cache=False)
|
cache=False)
|
||||||
assert len(res) == 3
|
assert len(res) == 3
|
||||||
assert exchange._api_async.fetch_ohlcv.call_count == 3
|
assert exchange._api_async.fetch_ohlcv.call_count == 3
|
||||||
|
exchange._api_async.fetch_ohlcv.reset_mock()
|
||||||
|
caplog.clear()
|
||||||
|
# Call with invalid timeframe
|
||||||
|
res = exchange.refresh_latest_ohlcv([('IOTA/ETH', '3m')],cache=False)
|
||||||
|
assert not res
|
||||||
|
assert len(res) == 0
|
||||||
|
assert log_has_re(r'Cannot download \(IOTA\/ETH, 3m\).*', caplog)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
Loading…
Reference in New Issue
Block a user