Source code for koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader
import numpy as np
import pandas as pd
from exchange_calendars import get_calendar
from tqdm import tqdm
from ..store import SQLiteStore
from .KrxHistoricalDailyPriceDataLoader import KrxHistoricalDailyPriceDataLoader
[docs]class KrxHistoricalDailyPriceDataForBacktestLoader:
def __init__(self, filename, library=None):
self._loader = KrxHistoricalDailyPriceDataLoader(filename)
self._store = SQLiteStore(filename)
self._calendar = get_calendar("XKRX")
if library is None:
library = "XKRX-ALL-BACKTEST"
self._library = self._store.get_or_create_library(library)
@classmethod
[docs] def get_adjust_ratios(cls, data, sort=True):
if sort:
data = data.sort_index(ascending=False)
adjust_ratios = []
last_close = data["Close"].iloc[0]
last_adjust_ratio = 1.0
adjust_ratios.append(last_adjust_ratio)
eleven_days = pd.Timedelta(11, unit="D")
for i in range(data.shape[0] - 1):
if data.index[i] - data.index[i + 1] > eleven_days:
last_close = data["Close"].iloc[i + 1]
last_adjust_ratio = 1.0
else:
last_close = last_close - data["Change"].iloc[i] * last_adjust_ratio
last_adjust_ratio = last_close / data["Close"].iloc[i + 1]
adjust_ratios.append(last_adjust_ratio)
adjust_ratios = np.array(adjust_ratios)
return adjust_ratios
@classmethod
[docs] def adjust_data(cls, data, sort=True):
if sort:
data = data.sort_index(ascending=False)
adjust_ratios = cls.get_adjust_ratios(data, sort=False)
data["Open"] = data["Open"] * adjust_ratios
data["High"] = data["High"] * adjust_ratios
data["Low"] = data["Low"] * adjust_ratios
data["Close"] = data["Close"] * adjust_ratios
data["Volume"] = data["Volume"] / adjust_ratios
return data
[docs] def get_symbols(self):
return self._library.list_symbols()
[docs] def update(self, download=False, 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._loader.symbols:
symbols_with_delisted.setdefault(symbol, False)
for symbol in self._loader.symbols_delisted:
symbols_with_delisted.setdefault(symbol, True)
entire_index = pd.DatetimeIndex([], name="Date")
entire_data = {}
entire_data_converted = {}
progress = tqdm(symbols_with_delisted.items(), disable=not progress_bar)
for symbol, is_delisted in progress:
progress.set_description("Loading Symbol [%s]" % symbol)
if download:
versioned_item = self._loader.load_or_download(
symbol, is_delisted=is_delisted, end_date=end_date
)
else:
versioned_item = self._loader.load_from_database(
symbol, is_delisted=is_delisted
)
if versioned_item is not None:
entire_data[symbol] = versioned_item.data
progress = tqdm(entire_data.items(), disable=not progress_bar)
for symbol, data in progress:
progress.set_description("Adjusting Symbol [%s]" % symbol)
entire_index = entire_index.union(data.index)
data = data[data["Close"] > 0]
if data.shape[0] > 0:
data = self.adjust_data(data)
data = data.sort_index()
columns = [
"Open",
"High",
"Low",
"Close",
"Volume",
"Amount",
"MarCap",
"Shares",
]
data = data[columns]
entire_data_converted[symbol] = data
progress = tqdm(entire_data_converted.items(), disable=not progress_bar)
for symbol, data in progress:
progress.set_description("Saving Symbol [%s]" % symbol)
data = data.reindex(entire_index)
data = data.fillna(0)
self._library.write(symbol, data)
[docs] def load(self, symbol, start_time=None, end_time=None):
if self._library.has_symbol(symbol):
versioned_item = self._library.read(
symbol, start_time=start_time, end_time=end_time
)
if (
versioned_item is not None
and versioned_item.data is not None
and versioned_item.data.shape[0] > 0
):
return versioned_item.data
[docs] def load_as_cursor(self, symbol, start_time=None, end_time=None):
if self._library.has_symbol(symbol):
versioned_item = self._library.read_as_cursor(
symbol, start_time=start_time, end_time=end_time
)
if versioned_item is not None and versioned_item.data is not None:
return versioned_item.data