mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-06 04:20:57 +08:00
Add multi horizon task generator
This commit is contained in:
@@ -152,8 +152,11 @@ def init_from_yaml_conf(conf_path, **kwargs):
|
||||
:param conf_path: A path to the qlib config in yml format
|
||||
"""
|
||||
|
||||
with open(conf_path) as f:
|
||||
config = yaml.safe_load(f)
|
||||
if conf_path is None:
|
||||
config = {}
|
||||
else:
|
||||
with open(conf_path) as f:
|
||||
config = yaml.safe_load(f)
|
||||
config.update(kwargs)
|
||||
default_conf = config.pop("default_conf", "client")
|
||||
init(default_conf, **config)
|
||||
@@ -216,7 +219,7 @@ def auto_init(**kwargs):
|
||||
.. code-block:: yaml
|
||||
|
||||
conf_type: ref
|
||||
qlib_cfg: '<shared_yaml_config_path>'
|
||||
qlib_cfg: '<shared_yaml_config_path>' # this could be null reference no config from other files
|
||||
# following configs in `qlib_cfg_update` is project=specific
|
||||
qlib_cfg_update:
|
||||
exp_manager:
|
||||
@@ -259,8 +262,8 @@ def auto_init(**kwargs):
|
||||
# - There is a shared configure file and you don't want to edit it inplace.
|
||||
# - The shared configure may be updated later and you don't want to copy it.
|
||||
# - You have some customized config.
|
||||
qlib_conf_path = conf["qlib_cfg"]
|
||||
qlib_conf_update = conf.get("qlib_cfg_update")
|
||||
qlib_conf_path = conf.get("qlib_cfg", None)
|
||||
qlib_conf_update = conf.get("qlib_cfg_update", {})
|
||||
init_from_yaml_conf(qlib_conf_path, **qlib_conf_update, **kwargs)
|
||||
logger = get_module_logger("Initialization")
|
||||
logger.info(f"Auto load project config: {conf_pp}")
|
||||
|
||||
@@ -112,6 +112,9 @@ def handler_mod(task: dict, rolling_gen):
|
||||
except KeyError:
|
||||
# Maybe dataset do not have handler, then do nothing.
|
||||
pass
|
||||
except TypeError:
|
||||
# May be the handler is a string. `"handler.pkl"["kwargs"]` will raise TypeError
|
||||
pass
|
||||
|
||||
|
||||
class RollingGen(TaskGen):
|
||||
@@ -259,3 +262,56 @@ class RollingGen(TaskGen):
|
||||
# Update the following rolling
|
||||
res.extend(self.gen_following_tasks(t, test_end))
|
||||
return res
|
||||
|
||||
|
||||
class MultiHorizonGenBase(TaskGen):
|
||||
def __init__(self, horizon: List[int] = [5], label_leak_n=2):
|
||||
"""
|
||||
This task generator tries to genrate tasks for different horizons based on an existing task
|
||||
|
||||
Parameters
|
||||
----------
|
||||
horizon : List[int]
|
||||
the possible horizons of the tasks
|
||||
label_leak_n : int
|
||||
How many future days it will take to get complete label after the day making prediction
|
||||
For example:
|
||||
- User make prediction on day `T`(after getting the close price on `T`)
|
||||
- The label is the return of buying stock on `T + 1` and selling it on `T + 2`
|
||||
- the `label_leak_n` will be 2 (e.g. two days of information is leaked to leverage this sample)
|
||||
"""
|
||||
self.horizon = list(horizon)
|
||||
self.label_leak_n = label_leak_n
|
||||
self.ta = TimeAdjuster()
|
||||
self.test_key = "test"
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_horizon(self, task: dict, hr: int):
|
||||
"""
|
||||
This method is designed to change the task **in place**
|
||||
|
||||
Parameters
|
||||
----------
|
||||
task : dict
|
||||
Qlib's task
|
||||
hr : int
|
||||
the horizon of task
|
||||
"""
|
||||
|
||||
def generate(self, task: dict):
|
||||
res = []
|
||||
for hr in self.horizon:
|
||||
|
||||
# Add horizon
|
||||
t = copy.deepcopy(task)
|
||||
self.set_horizon(t, hr)
|
||||
|
||||
# adjust segment
|
||||
segments = self.ta.align_seg(t["dataset"]["kwargs"]["segments"])
|
||||
test_start = min(t for t in segments[self.test_key] if t is not None)
|
||||
for k in list(segments.keys()):
|
||||
if k != self.test_key:
|
||||
segments[k] = self.ta.truncate(segments[k], test_start, hr + self.label_leak_n)
|
||||
t["dataset"]["kwargs"]["segments"] = segments
|
||||
res.append(t)
|
||||
return res
|
||||
|
||||
Reference in New Issue
Block a user