• 拆解qlib的dataset,使用代码方式加载数据集


    "qlib ailabx量化投资平台" 建设第 16 篇。

    这是100天小目标中的第16天。

    今天的主题是手动特征工程,qlib的特征工程是基于表达式的,不像传统策略使用pandas的dataframe里的计算函数,或者Ta-lib来计算——传统方式适合因子数比较少,比如一个策略不会超过3-5个因子,而AI量化动辄上百个因子,如果一个个写那维护成本太高了(qlib自身就内置了两个handler, 一个158个因子,另一个360个因子)。

    01 dataset数据集的加载方式拆解

    config = {
        "class": "DatasetH",
        "module_path": "qlib.data.dataset",
        "kwargs": {
            "handler": {
                "class": "Alpha158",
                "module_path": "qlib.contrib.data.handler",
                "kwargs": data_handler_config,
            },
            "segments": {
                "train": ("2008-01-01", "2014-12-31"),
                "valid": ("2015-01-01", "2016-12-31"),
                "test": ("2017-01-01", "2020-08-01"),
            },
        },
    }
    ds = init_instance_by_config(config)

    官方的例子使用了大量的init_instance_by_config,我们可以跟进代码看看细节。

    主要我们需要把handler变成我们自己的。 

    DatasetH(带Handler的Dataset)的初始化函数如下:

    def __init__(
        self, handler: Union[Dict, DataHandler], segments: Dict[Text, Tuple], fetch_kwargs: Dict = {}, **kwargs
    ):

    参数handler, segments,fetch_kwargs以及**kwargs。

    一般我们只管前两个参数:handler和segments。

    我们可以把handler由dict变成DataHandler来加载:

    def load_dataset(data_handler):
        ds = DatasetH(data_handler, segments={"train": ('20180101', '20181231'), "valid": ('20190101', '20191231')})
        return ds

    02 Handler的加载方式

    data_handler_config = {
        "start_time": "2008-01-01",
        "end_time": "2020-08-01",
        "fit_start_time": "2008-01-01",
        "fit_end_time": "2014-12-31",
        "instruments": self.market,
    

    }

    {
                "class": "Alpha158",
                "module_path": "qlib.contrib.data.handler",
                "kwargs": data_handler_config,
            }

    在路径qlib.contrib.data.handler下的Alpha158类,参数kwargs是一个dict。

    Alpha158继承自DataHandlerLP(带处理器的Handler的意思)

    class Alpha158(DataHandlerLP):
        def __init__(
            self,
            instruments="csi500",
            start_time=None,
            end_time=None,
            freq="day",
            infer_processors=[],
            learn_processors=_DEFAULT_LEARN_PROCESSORS,
            fit_start_time=None,
            fit_end_time=None,
            process_type=DataHandlerLP.PTYPE_A,
            filter_pipe=None,
            inst_processor=None,
            **kwargs,
        ):

    在初始化的函数里,一是训练和推理的预处理器, 二是初始化了一个QlibDataLoader,传给

    infer_processors = check_transform_proc(infer_processors, fit_start_time, fit_end_time)
    learn_processors = check_transform_proc(learn_processors, fit_start_time, fit_end_time)
    
    data_loader = {
        "class": "QlibDataLoader",
        "kwargs": {
            "config": {
                "feature": self.get_feature_config(),
                "label": kwargs.get("label", self.get_label_config()),
            },
            "filter_pipe": filter_pipe,
            "freq": freq,
            "inst_processor": inst_processor,
        },
    }
    super().__init__(
        instruments=instruments,
        start_time=start_time,
        end_time=end_time,
        data_loader=data_loader,
        infer_processors=infer_processors,
        learn_processors=learn_processors,
        process_type=process_type,
    )

    我们简化为直接调用基类是可以的:

    这段是初始化data_loader的参数:

    03 QlibDataLoader的初始化

    外部传入的参数如下:

    04 总体代码:

    加载dataset数据集是分层独立的

    dataloader加载数据,并负责特征与标注。

    datahandler加上了预处理,比如数据标准化,填充不存在的值之类的。dataset用于数据集划分,比如训练集,测试集,回测集等。

    05 预处理器

    顾名思义,infer=推理, learn=训练。都是处理器,但使用的阶段不同而已。

    MinMax正则,这是机器学习里常用的数据预处理,简单理解就是数据“归一化”,(X-Xmin) /(Xmax -Xmin),这里就与量纲无关了。

    两上小问题:

    为何训练阶段与测试阶段使用的处理器不同?

    在官方示例里的alpha158里,默认的处理器如下:

    为何正则化需要fit_start_time给定日期范围?

    小结:

    今天我们主要关注的是dataset如何构建,在官方完全一个config配置之余,通过代码去看背后具体发生了什么,以及这些参数的意义。

    在一开始学习及后续使用,不建议用alpha158或者alpha360。

    初学用这个计算量太大,太慢;

    后续实战重点就是建立自己的alpha因子。

    这两者作为一个benchmark是可以的。

    明天要使用bigquant里的特征来建立策略。

  • 相关阅读:
    【数组及指针经典笔试题解析】
    Go开始:Go基本元素介绍
    【爬虫--必须要了解的请求头 user-agent】
    电脑自动开机win11设置教程
    源码 编译 安装 openssl libssl-dev
    【面试:并发篇31:多线程:cas】无锁实现并发
    Java_继承
    6.30模拟赛总结
    微信小程序实现上拉加载更多
    8年测试老鸟,性能测试-数据库连接池问题定位/分析,一篇打通...
  • 原文地址:https://blog.csdn.net/weixin_38175458/article/details/126366244