Skip to content

Commit db56f9f

Browse files
committed
Refactor caching
1 parent ffaf382 commit db56f9f

File tree

1 file changed

+66
-48
lines changed

1 file changed

+66
-48
lines changed

Trading/live/caching/caching.py

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -39,56 +39,74 @@ def get_last_n_candles_from_date(from_date: datetime, instrument: Instrument, da
3939
'''
4040
Gets last n candles from date, including date
4141
'''
42+
if from_date > datetime.now():
43+
raise ValueError("from_date cannot be in the future.")
4244

4345
caching = get_caching_file_rw(instrument, data_source)
44-
data = caching.read()
45-
if not data:
46-
LOGGER.info("No data in caching")
47-
# get_last_n_candles_history only returns the last n candles starting with today, so we need to get more data
48-
# calculate how many candles we need to include from today until the from_date
49-
now = datetime.now()
50-
if from_date < now:
51-
from_today = now - from_date
52-
LOGGER.info(f"From today: {from_today}")
53-
new_n = n
54-
if instrument.timeframe.period == TIMEFRARME_ENUM.ONE_MONTH.value:
55-
new_n = new_n + math.ceil(from_today.days/29)
56-
57-
history = _get_last_n_from_client(instrument, new_n)
46+
LOGGER.info(f"Fetching last {n} candles from {from_date} for {instrument.symbol} {instrument.timeframe} file: {caching.file_name}...")
47+
cached_data = caching.read()
5848

49+
if not cached_data:
50+
LOGGER.info("No data in cache, fetching initial data...")
51+
return _fetch_and_cache_initial_data(from_date, instrument, n, caching)
52+
53+
history = History(**cached_data)
54+
55+
if from_date in history.date:
56+
return _handle_from_date_in_history(history, from_date, n, instrument, caching)
57+
58+
if from_date > history.date[-1]:
59+
LOGGER.info("Fetching data for date greater than cached data's newest date...")
60+
return _fetch_and_extend_history(from_date, history, n, instrument, caching, after_cache=True)
61+
62+
if from_date < history.date[0]:
63+
LOGGER.info("Fetching data for date earlier than cached data's oldest date...")
64+
return _fetch_and_extend_history(from_date, history, n, instrument, caching, after_cache=False)
65+
return history.slice_n_candles_before_date(from_date, n)
66+
67+
def _fetch_and_cache_initial_data(from_date: datetime, instrument: Instrument, n: int, caching):
68+
now = datetime.now()
69+
candles_needed = n
70+
71+
if instrument.timeframe.period == TIMEFRARME_ENUM.ONE_MONTH.value and from_date < now:
72+
days_diff = (now - from_date).days
73+
candles_needed += math.ceil(days_diff / 29)
74+
elif instrument.timeframe.period == TIMEFRARME_ENUM.ONE_DAY.value and from_date < now:
75+
candles_needed += (now - from_date).days
76+
77+
new_history = _get_last_n_from_client(instrument, candles_needed)
78+
caching.write(new_history.__dict__)
79+
LOGGER.info("Initial data written to cache.")
80+
return new_history.slice_n_candles_before_date(from_date, n)
81+
82+
def _handle_from_date_in_history(history: History, from_date: datetime, n: int, instrument: Instrument, caching):
83+
index = history.date.index(from_date)
84+
if index - n < 0:
85+
# Need more candles to satisfy the request
86+
LOGGER.info("Fetching more data to cover from_date...")
87+
additional_candles = len(history) + n - index
88+
new_history = _get_last_n_from_client(instrument, additional_candles)
89+
history.extend(new_history)
5990
caching.write(history.__dict__)
60-
LOGGER.info("Data written to caching")
61-
return history.slice_n_candles_before_date(from_date, n)
91+
return history.slice_n_candles_before_date(from_date, n)
92+
93+
def _fetch_and_extend_history(from_date: datetime, history: History, n: int, instrument: Instrument, caching, after_cache: bool):
94+
if after_cache:
95+
date_diff = (from_date - history.date[-1]).days
6296
else:
63-
history = History(**data)
64-
history_oldest_date = history.date[0]
65-
history_newest_date = history.date[-1]
66-
67-
if from_date in history.date:
68-
index = history.date.index(from_date)
69-
if index - n < 0:
70-
# fetch new data
71-
new_n = len(history) + n - index
72-
LOGGER.info("Fetching new data for from_date in history")
73-
new_history = _get_last_n_from_client(instrument, new_n)
74-
history.extend(new_history)
75-
caching.write(history.__dict__)
76-
elif from_date > history_newest_date:
77-
diff = from_date - history_newest_date
78-
if instrument.timeframe.period == TIMEFRARME_ENUM.ONE_MONTH.value:
79-
new_n = len(history) + math.ceil(diff.days/29) + 1
80-
LOGGER.info("Fetching new data for from_date > history_newest_date")
81-
new_history = _get_last_n_from_client(instrument, new_n)
82-
history.extend(new_history)
83-
caching.write(history.__dict__)
84-
LOGGER.info("Data written to caching")
85-
elif from_date < history_oldest_date:
86-
diff = history_oldest_date - from_date
87-
if instrument.timeframe.period == TIMEFRARME_ENUM.ONE_MONTH.value:
88-
new_n = len(history) + math.ceil(diff.days/29) + 1
89-
LOGGER.info("Fetching new data for from_date < history_oldest_date")
90-
new_history = _get_last_n_from_client(instrument, new_n)
91-
history.extend(new_history)
92-
caching.write(history.__dict__)
93-
LOGGER.info("Data written to caching")
94-
return history.slice_n_candles_before_date(from_date, n)
97+
date_diff = (history.date[0] - from_date).days
98+
99+
candles_needed = n + math.ceil(date_diff / 29) if instrument.timeframe.period == TIMEFRARME_ENUM.ONE_MONTH.value else n
100+
new_history = _get_last_n_from_client(instrument, candles_needed)
101+
history.extend(new_history)
102+
caching.write(history.__dict__)
103+
LOGGER.info("Extended data written to cache.")
104+
return history.slice_n_candles_before_date(from_date, n)
105+
106+
if __name__ == '__main__':
107+
instrument = Instrument("EURUSD", Timeframe("1D"))
108+
from_date = datetime(2020, 2, 23, 1, 0)
109+
n = 5
110+
data_source = DataSourceEnum.XTB
111+
last_n = get_last_n_candles_from_date(from_date, instrument, data_source, n)
112+
print(last_n.date)

0 commit comments

Comments
 (0)