mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-16 17:12:20 +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
|
:param conf_path: A path to the qlib config in yml format
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with open(conf_path) as f:
|
if conf_path is None:
|
||||||
config = yaml.safe_load(f)
|
config = {}
|
||||||
|
else:
|
||||||
|
with open(conf_path) as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
config.update(kwargs)
|
config.update(kwargs)
|
||||||
default_conf = config.pop("default_conf", "client")
|
default_conf = config.pop("default_conf", "client")
|
||||||
init(default_conf, **config)
|
init(default_conf, **config)
|
||||||
@@ -216,7 +219,7 @@ def auto_init(**kwargs):
|
|||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
conf_type: ref
|
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
|
# following configs in `qlib_cfg_update` is project=specific
|
||||||
qlib_cfg_update:
|
qlib_cfg_update:
|
||||||
exp_manager:
|
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.
|
# - 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.
|
# - The shared configure may be updated later and you don't want to copy it.
|
||||||
# - You have some customized config.
|
# - You have some customized config.
|
||||||
qlib_conf_path = conf["qlib_cfg"]
|
qlib_conf_path = conf.get("qlib_cfg", None)
|
||||||
qlib_conf_update = conf.get("qlib_cfg_update")
|
qlib_conf_update = conf.get("qlib_cfg_update", {})
|
||||||
init_from_yaml_conf(qlib_conf_path, **qlib_conf_update, **kwargs)
|
init_from_yaml_conf(qlib_conf_path, **qlib_conf_update, **kwargs)
|
||||||
logger = get_module_logger("Initialization")
|
logger = get_module_logger("Initialization")
|
||||||
logger.info(f"Auto load project config: {conf_pp}")
|
logger.info(f"Auto load project config: {conf_pp}")
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ def handler_mod(task: dict, rolling_gen):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
# Maybe dataset do not have handler, then do nothing.
|
# Maybe dataset do not have handler, then do nothing.
|
||||||
pass
|
pass
|
||||||
|
except TypeError:
|
||||||
|
# May be the handler is a string. `"handler.pkl"["kwargs"]` will raise TypeError
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RollingGen(TaskGen):
|
class RollingGen(TaskGen):
|
||||||
@@ -259,3 +262,56 @@ class RollingGen(TaskGen):
|
|||||||
# Update the following rolling
|
# Update the following rolling
|
||||||
res.extend(self.gen_following_tasks(t, test_end))
|
res.extend(self.gen_following_tasks(t, test_end))
|
||||||
return res
|
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