Source code for koapy.utils.data.KrxHistoricalDailyPriceDataLoader
import pandas as pd
from exchange_calendars import get_calendar
from tqdm import tqdm
from ..store import SQLiteStore
from .KrxHistoricalDailyPriceDataDownloader import KrxHistoricalDailyPriceDataDownloader
[docs]class KrxHistoricalDailyPriceDataLoader:
def __init__(self, filename, library=None, library_delisted=None):
self._downloader = KrxHistoricalDailyPriceDataDownloader()
self._store = SQLiteStore(filename)
self._calendar = get_calendar("XKRX")
if library is None:
library = "XKRX"
if library_delisted is None:
library_delisted = "XKRX-DELISTED"
self._library = self._store.get_or_create_library(library)
self._library_delisted = self._store.get_or_create_library(library_delisted)
@property
[docs] def symbols(self):
return self._downloader.stocks.index
@property
[docs] def symbols_delisted(self):
return self._downloader.stocks_delisted.index
[docs] def load_from_database(self, symbol, is_delisted=None):
if is_delisted is None:
is_delisted = symbol not in self.symbols
library = self._library if not is_delisted else self._library_delisted
if library.has_symbol(symbol):
versioned_item = library.read(symbol)
if versioned_item.data is not None and versioned_item.data.shape[0] > 0:
return versioned_item
[docs] def load_or_download(
self, symbol, is_delisted=None, start_date=None, end_date=None
):
if is_delisted is None:
is_delisted = symbol not in self.symbols
library = self._library
now = pd.Timestamp.now(self._calendar.tz)
if is_delisted:
library = self._library_delisted
if library.has_symbol(symbol):
versioned_item = self.load_from_database(symbol, is_delisted=is_delisted)
if not is_delisted and versioned_item is not None:
if start_date is None:
start_date = (
versioned_item.data.index.max().tz_localize(self._calendar.tz)
+ self._calendar.day
)
if end_date is None:
end_date = (
self._calendar.previous_close(now)
.astimezone(self._calendar.tz)
.normalize()
)
if start_date <= end_date:
recent_data = self._downloader.download(
symbol, start_date=start_date
)
if recent_data is not None and recent_data.shape[0] > 0:
data = versioned_item.data
data = data.combine_first(recent_data)[data.columns]
data = data.convert_dtypes(convert_floating=False)
data = data.sort_index()
versioned_item = library.write(symbol, data)
return versioned_item
else:
data = self._downloader.download(
symbol, start_date=start_date, end_date=end_date
)
if data is not None and data.shape[0] > 0:
data = data.convert_dtypes(convert_floating=False)
data = data.sort_index()
versioned_item = library.write(symbol, data)
return versioned_item
[docs] def load(
self, symbol, is_delisted=None, start_date=None, end_date=None, download=True
):
if download:
return self.load_or_download(
symbol,
is_delisted=is_delisted,
start_date=start_date,
end_date=end_date,
)
else:
return self.load_from_database(symbol, is_delisted=is_delisted)
[docs] def update(self, progress_bar=False):
now = pd.Timestamp.now(self._calendar.tz)
end_date = (
self._calendar.previous_close(now).astimezone(self._calendar.tz).normalize()
)
symbols_with_delisted = {}
for symbol in self.symbols:
symbols_with_delisted.setdefault(symbol, False)
for symbol in self.symbols_delisted:
symbols_with_delisted.setdefault(symbol, True)
progress = tqdm(symbols_with_delisted.items(), disable=not progress_bar)
for symbol, is_delisted in progress:
progress.set_description("Updating Symbol [%s]" % symbol)
_versioned_item = self.load_or_download(
symbol, is_delisted=is_delisted, end_date=end_date
)