50 lines
2.0 KiB
Python
50 lines
2.0 KiB
Python
import logging
|
|
from datetime import datetime, timedelta
|
|
|
|
from ccxt.base.errors import ExchangeNotAvailable
|
|
from vectorbtpro import pd, tp, vbt
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def find_earliest_date(symbol: str, exchange: str, **kwargs) -> tp.Optional[pd.Timestamp]:
|
|
"""Wrapper around CCXTData.find_earliest_date to handle ExchangeNotAvailable error with binary search
|
|
Args:
|
|
symbol: The trading symbol to query
|
|
exchange: The exchange to query
|
|
**kwargs: Additional arguments to pass to the find_earliest_date method
|
|
|
|
Returns:
|
|
tp.Optional[pd.Timestamp]: The earliest available date if found, otherwise None
|
|
"""
|
|
log.info("Searching for earliest date for %s", symbol)
|
|
start_date = pd.Timestamp(kwargs.pop("start", datetime(2010, 1, 1))).floor("D")
|
|
end_date = pd.Timestamp(kwargs.pop("end", datetime.now())).floor("D")
|
|
|
|
while start_date < end_date:
|
|
log.info("Trying %s to %s range", start_date, end_date)
|
|
mid_date = (start_date + (end_date - start_date) // 2).floor("D")
|
|
try:
|
|
found_date = vbt.CCXTData.find_earliest_date(
|
|
symbol, exchange=exchange, start=mid_date, end=end_date, limit=10, **kwargs
|
|
)
|
|
if found_date:
|
|
# Move the end date to mid_date to search the earlier half
|
|
end_date = mid_date
|
|
else:
|
|
# Move the start date to mid_date + 1 to search the later half
|
|
start_date = mid_date + timedelta(days=1)
|
|
except ExchangeNotAvailable:
|
|
# Move the start date to mid_date + 1 to search the later half
|
|
start_date = mid_date + timedelta(days=1)
|
|
|
|
# After the loop, start_date should be the earliest date with data
|
|
try:
|
|
found_date = vbt.CCXTData.find_earliest_date(
|
|
symbol, exchange=exchange, start=start_date, end=end_date, **kwargs
|
|
)
|
|
return found_date
|
|
except ExchangeNotAvailable as e:
|
|
log.error("ExchangeNotAvailable error encountered at final step... Error: %s", e)
|
|
return None
|