mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-09 14:00:55 +08:00
fix some comments and add docstring
This commit is contained in:
@@ -800,217 +800,3 @@ def fname_to_code(fname: str):
|
||||
if fname.startswith(prefix):
|
||||
fname = fname.lstrip(prefix)
|
||||
return fname
|
||||
|
||||
|
||||
########################## Sample ############################
|
||||
def sample_calendar_bac(calendar_raw, freq_raw, freq_sam):
|
||||
"""
|
||||
freq_raw : "min" or "day"
|
||||
"""
|
||||
freq_raw = "1" + freq_raw if re.match("^[0-9]", freq_raw) is None else freq_raw
|
||||
freq_sam = "1" + freq_sam if re.match("^[0-9]", freq_sam) is None else freq_sam
|
||||
|
||||
if freq_sam.endswith(("minute", "min")):
|
||||
|
||||
def cal_next_sam_minute(x, sam_minutes):
|
||||
hour = x.hour
|
||||
minute = x.minute
|
||||
if 9 <= hour <= 11:
|
||||
minute_index = (11 - hour) * 60 + 30 - minute + 120
|
||||
elif 13 <= hour <= 15:
|
||||
minute_index = (15 - hour) * 60 - minute
|
||||
else:
|
||||
raise ValueError("calendar hour must be in [9, 11] or [13, 15]")
|
||||
|
||||
minute_index = minute_index // sam_minutes * sam_minutes
|
||||
|
||||
if 0 <= minute_index < 120:
|
||||
return 15 - (minute_index + 59) // 60, (120 - minute_index) % 60
|
||||
elif 120 <= minute_index < 240:
|
||||
return 11 - (minute_index - 120 + 29) // 60, (240 - minute_index + 30) % 60
|
||||
else:
|
||||
raise ValueError("calendar minute_index error")
|
||||
|
||||
sam_minutes = int(freq_sam[:-3]) if freq_sam.endswith("min") else int(freq_sam[:-6])
|
||||
|
||||
if not freq_raw.endswith(("minute", "min")):
|
||||
raise ValueError("when sampling minute calendar, freq of raw calendar must be minute or min")
|
||||
else:
|
||||
raw_minutes = int(freq_raw[:-3]) if freq_raw.endswith("min") else int(freq_raw[:-6])
|
||||
if raw_minutes > sam_minutes:
|
||||
raise ValueError("raw freq must be higher than sample freq")
|
||||
|
||||
_calendar_minute = np.unique(
|
||||
list(
|
||||
map(
|
||||
lambda x: pd.Timestamp(x.year, x.month, x.day, *cal_next_sam_minute(x, sam_minutes), 59),
|
||||
calendar_raw,
|
||||
)
|
||||
)
|
||||
)
|
||||
return _calendar_minute
|
||||
else:
|
||||
|
||||
_calendar_day = np.unique(list(map(lambda x: pd.Timestamp(x.year, x.month, x.day, 23, 59, 59), calendar_raw)))
|
||||
if freq_sam.endswith(("day", "d")):
|
||||
sam_days = int(freq_sam[:-1]) if freq_sam.endswith("d") else int(freq_sam[:-3])
|
||||
return _calendar_day[(len(_calendar_day) + sam_days - 1) % sam_days :: sam_days]
|
||||
|
||||
elif freq_sam.endswith(("week", "w")):
|
||||
sam_weeks = int(freq_sam[:-1]) if freq_sam.endswith("w") else int(freq_sam[:-4])
|
||||
_day_in_week = np.array(list(map(lambda x: x.dayofweek, _calendar_day)))
|
||||
_calendar_week = _calendar_day[np.ediff1d(_day_in_week[::-1], to_begin=1)[::-1] > 0]
|
||||
return _calendar_week[(len(_calendar_week) + sam_weeks - 1) % sam_weeks :: sam_weeks]
|
||||
|
||||
elif freq_sam.endswith(("month", "m")):
|
||||
sam_months = int(freq_sam[:-1]) if freq_sam.endswith("m") else int(freq_sam[:-5])
|
||||
_day_in_month = np.array(list(map(lambda x: x.day, _calendar_day)))
|
||||
_calendar_month = _calendar_day[np.ediff1d(_day_in_month[::-1], to_begin=1)[::-1] > 0]
|
||||
return _calendar_month[(len(_calendar_month) + sam_months - 1) % sam_months :: sam_months]
|
||||
else:
|
||||
raise ValueError("sample freq must be xmin, xd, xw, xm")
|
||||
|
||||
|
||||
def parse_freq(freq):
|
||||
freq = freq.lower()
|
||||
search_obj = re.search("^([0-9]*)([a-z]+)", freq)
|
||||
if search_obj is None:
|
||||
raise ValueError("freq format is not supported")
|
||||
_count = int(search_obj.group(1) if search_obj.group(1) else "1")
|
||||
_freq = search_obj.group(2)
|
||||
_freq_format_dict = {
|
||||
"month": "month",
|
||||
"mon": "month",
|
||||
"week": "week",
|
||||
"w": "week",
|
||||
"day": "day",
|
||||
"d": "day",
|
||||
"minute": "minute",
|
||||
"min": "minute",
|
||||
}
|
||||
try:
|
||||
_freq = _freq_format_dict.get(_freq)
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
"freq format is not supported, the supported freq includes (x)month/m, (x)day/d, (x)minute/min"
|
||||
)
|
||||
return _count, _freq
|
||||
|
||||
|
||||
def sample_calendar(calendar_raw, freq_raw, freq_sam):
|
||||
"""
|
||||
freq_raw : "min" or "day"
|
||||
"""
|
||||
raw_count, freq_raw = parse_freq(freq_raw)
|
||||
sam_count, freq_sam = parse_freq(freq_sam)
|
||||
if not len(calendar_raw):
|
||||
return calendar_raw
|
||||
if freq_sam == "minute":
|
||||
|
||||
def cal_next_sam_minute(x, sam_minutes):
|
||||
hour = x.hour
|
||||
minute = x.minute
|
||||
if (hour == 9 and minute >= 30) or (9 < hour < 11) or (hour == 11 and minute < 30):
|
||||
minute_index = (hour - 9) * 60 + minute - 30
|
||||
elif 13 <= hour < 15:
|
||||
minute_index = (hour - 13) * 60 + minute + 120
|
||||
else:
|
||||
raise ValueError("calendar hour must be in [9, 11] or [13, 15]")
|
||||
|
||||
minute_index = minute_index // sam_minutes * sam_minutes
|
||||
|
||||
if 0 <= minute_index < 120:
|
||||
return 9 + (minute_index + 30) // 60, (minute_index + 30) % 60
|
||||
elif 120 <= minute_index < 240:
|
||||
return 13 + (minute_index - 120) // 60, (minute_index - 120) % 60
|
||||
else:
|
||||
raise ValueError("calendar minute_index error")
|
||||
|
||||
if req_raw != "minute":
|
||||
raise ValueError("when sampling minute calendar, freq of raw calendar must be minute or min")
|
||||
else:
|
||||
if raw_count > sam_count:
|
||||
raise ValueError("raw freq must be higher than sample freq")
|
||||
_calendar_minute = np.unique(
|
||||
list(
|
||||
map(lambda x: pd.Timestamp(x.year, x.month, x.day, *cal_next_sam_minute(x, sam_count), 0), calendar_raw)
|
||||
)
|
||||
)
|
||||
if calendar_raw[0] > _calendar_minute[0]:
|
||||
_calendar_minute[0] = calendar_raw[0]
|
||||
return _calendar_minute
|
||||
else:
|
||||
_calendar_day = np.unique(list(map(lambda x: pd.Timestamp(x.year, x.month, x.day, 0, 0, 0), calendar_raw)))
|
||||
if freq_sam == "day":
|
||||
return _calendar_day[::sam_count]
|
||||
|
||||
elif freq_sam == "week":
|
||||
_day_in_week = np.array(list(map(lambda x: x.dayofweek, _calendar_day)))
|
||||
_calendar_week = _calendar_day[np.ediff1d(_day_in_week, to_begin=-1) < 0]
|
||||
return _calendar_week[::sam_count]
|
||||
|
||||
elif freq_sam == "month":
|
||||
_day_in_month = np.array(list(map(lambda x: x.day, _calendar_day)))
|
||||
_calendar_month = _calendar_day[np.ediff1d(_day_in_month, to_begin=-1) < 0]
|
||||
return _calendar_month[::sam_count]
|
||||
else:
|
||||
raise ValueError("sample freq must be xmin, xd, xw, xm")
|
||||
|
||||
|
||||
def get_sample_freq_calendar(start_time=None, end_time=None, freq="day", **kwargs):
|
||||
_, norm_freq = parse_freq(freq)
|
||||
|
||||
from ..data.data import Cal
|
||||
|
||||
try:
|
||||
_calendar = Cal.calendar(start_time=start_time, end_time=end_time, freq=freq, **kwargs)
|
||||
freq, freq_sam = freq, None
|
||||
except ValueError:
|
||||
freq_sam = freq
|
||||
if norm_freq in ["month", "week", "day"]:
|
||||
try:
|
||||
_calendar = Cal.calendar(start_time=start_time, end_time=end_time, freq="day", freq_sam=freq, **kwargs)
|
||||
freq = "day"
|
||||
except ValueError:
|
||||
raise
|
||||
_calendar = Cal.calendar(start_time=start_time, end_time=end_time, freq="min", freq_sam=freq, **kwargs)
|
||||
freq = "min"
|
||||
elif norm_freq == "minute":
|
||||
_calendar = Cal.calendar(start_time=start_time, end_time=end_time, freq="min", freq_sam=freq, **kwargs)
|
||||
freq = "min"
|
||||
else:
|
||||
raise ValueError(f"freq {freq} is not supported")
|
||||
return _calendar, freq, freq_sam
|
||||
|
||||
|
||||
def sample_feature(feature, start_time=None, end_time=None, fields=None, method="last", method_kwargs={}):
|
||||
selector_datetime = slice(start_time, end_time)
|
||||
fields = fields if fields else slice(None)
|
||||
|
||||
from ..data.dataset.utils import get_level_index
|
||||
|
||||
datetime_level = get_level_index(feature, level="datetime") == 0
|
||||
if isinstance(feature, pd.Series):
|
||||
feature = feature.loc[selector_datetime] if datetime_level else feature.loc[(slice(None), selector_datetime)]
|
||||
elif isinstance(feature, pd.DataFrame):
|
||||
feature = (
|
||||
feature.loc[selector_datetime, fields]
|
||||
if datetime_level
|
||||
else feature.loc[(slice(None), selector_datetime), fields]
|
||||
)
|
||||
if feature.empty:
|
||||
return None
|
||||
if isinstance(feature.index, pd.MultiIndex):
|
||||
if callable(method):
|
||||
method_func = method
|
||||
return feature.groupby(level="instrument").apply(lambda x: method_func(x, **method_kwargs))
|
||||
elif isinstance(method, str):
|
||||
return getattr(feature.groupby(level="instrument"), method)(**method_kwargs)
|
||||
else:
|
||||
if callable(method):
|
||||
method_func = method
|
||||
return method_func(feature, **method_kwargs)
|
||||
elif isinstance(method, str):
|
||||
return getattr(feature, method)(**method_kwargs)
|
||||
|
||||
return feature
|
||||
|
||||
Reference in New Issue
Block a user