找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3123

积分

0

好友

418

主题
发表于 1 小时前 | 查看: 5| 回复: 0

“QLib 量化投资平台的实战系列,参考官方代码,设计新的应用场景,手把手带你玩转Qlib”

Qlib 量化平台logo

本文将通过一个完整的案例,演示如何使用 Qlib 平台构建并回测一个港股市场的 AI 选股策略。大纲如下:

  1. 环境和安装
  2. 数据准备
  3. 日频量价因子生成
  4. 绩效分析

🔧 Qlib安装与环境配置

Qlib的安装可能是新手遇到的第一个“坑”。官方教程有时会绕过一些实际部署中的细节。以下步骤基于实操经验,建议初学者按顺序执行。

  • 安装 Microsoft C++ 生成工具(必装!)
    如果你已经安装了完整版的 Microsoft Visual Studio,可以跳过此步。否则,你必须安装 Microsoft C++ 生成工具 或完整版 Visual Studio,以解决 Qlib 的底层运行依赖。

    Visual Studio 生成工具安装界面

  • 安装Qlib

    1. 克隆仓库:在你打算存放源码的目录下,打开 Git 或命令行,执行以下命令:
      git clone https://github.com/microsoft/qlib.git && cd qlib

      Git克隆Qlib仓库

    2. 创建并激活Conda环境:在 Qlib 根目录下,执行:
      #创建名为Qlib的虚拟环境
      conda create -n Qlib python=3.8 -y
      #环境创建成功后激活
      conda activate Qlib
      #安装基础依赖
      pip install numpy
      pip install --upgrade cython
    3. 安装Qlib包:在激活的 Qlib 环境下,执行安装。对于开发或学习,推荐使用开发模式:
      pip install -e .
      # `pip install -e .[dev]` 用于开发,详情见文档

📊 数据准备:自定义港股数据

Qlib 支持官方测试数据和用户自定义数据。为了贴近实战,我们使用自定义的港股日频数据。核心步骤是将 CSV 格式的原始数据,通过 dump_all 指令转换为 Qlib 内部的二进制格式。

为何选择港股通标的? 港股市场结构集中,头部公司主导,且存在大量低流动性“仙股”。港股通标的覆盖了总市值约85%、成交额超90%的公司,代表性更强,数据质量也相对更好。

提示:港股通标的名单会定期调整,最新列表需从港交所官网获取。

步骤 1:准备 CSV 数据格式

你需要为每只股票准备一个独立的 CSV 文件。将所有文件放入一个文件夹,例如命名为 hk_data。文件名应为股票代码,例如 HK00700.csv(腾讯控股)。

港股数据CSV文件列表

每个 CSV 文件必须包含以下字段:

字段名称 说明 注意事项
stock_code 股票代码(与文件名一致) 示例:"HK00700"
date 日频日期 格式:"2020-01-02"
open/high/low/close 复权价格 必须使用复权价(推荐后复权)
volume 成交量 单位:股
money 成交额 单位:港元
factor 复权因子 无复权时填 1.0
vwap 复权均价 计算公式:(成交额 / 成交量)
change 涨跌幅(%) 相对于前一交易日

特别注意两个“坑”:

  1. 必须使用复权价格:否则回测时的收益计算会严重失准。
  2. 必须有 factorchange 字段:否则策略净值可能出现异常(官方文档未明确说明,实操中遇到的坑)。

数据示例如下(Excel视图):

港股股票数据Excel表示例

步骤 2:数据清洗(可选但推荐)

如果你的数据源非常可靠,此步骤可以忽略。但对于来自网络或API的数据,清洗至关重要。Qlib为A股提供了标准的清洗脚本,对于港股,我们可以借鉴其思路编写自定义脚本。

一个完善的清洗流程应包括:基于指数数据生成交易日历、缺失值填充、异常值修正(如价格跳变)、以及最终的数据完整性校验。这能有效解决原始数据中“错、漏、杂”的问题。

例如,以下是一个清洗脚本运行后生成的质检报告摘要:

港股数据清洗质量报告

步骤 3:使用 dump_all 转换数据格式

运行以下命令,将 hk_data 文件夹中的 CSV 数据转换为 Qlib 的二进制格式。

python scripts/dump_bin.py dump_all \
--data_path ./qlib/data/csv_data/hk_data \  # 你的CSV数据路径
--qlib_dir ./qlib/data/hk_data \            # 转换后的数据保存路径
--symbol_field_name stock_code \            # CSV中股票代码的列名
--date_field_name date \                    # CSV中日期的列名
--include_fields open,high,low,close,volume,money,factor,vwap,change  # 包含的字段(逗号后无空格!)

转换成功后,目标目录(本例中为 ./qlib/data/hk_data)下会生成三个子文件夹:

  • calendar/day.txt:港股交易日历。
  • features/:二进制格式的行情数据(例如 open.day.bin)。
  • instruments/all.txt:所有股票代码列表。

步骤 4:数据健康度检查

在投入实战前,强烈建议进行数据健康度检查。

python scripts/check_data_health.py check_data --qlib_dir ./qlib/qlib/data/hk_data

检查报告可能会提示缺失值或数据跳变。这通常是正常现象。例如,缺失值很可能是由于股票停牌;价格跳变则可能源于除权除息或重大市场事件。

数据健康度检查报告显示缺失值

以报告提示有2行数据缺失的 HK00017 为例,查询港交所公告可以发现,该股票在相应时间段内确实有过停牌记录。因此,这类缺失属于正常情况。关键在于,在后续构建策略时,要合理利用 Qlib 提供的缺失值处理机制,最大限度地降低其对模型的干扰。

⚡ 港股日频量价因子AI策略实战

下面这个完整的脚本,清晰地展示了 Qlib 量化研究的标准流程:从数据准备、模型配置、训练到回测与绩效分析。每一个环节都紧密相连。

策略核心配置:

  • 因子模型:Alpha158(提供158个量价因子)
  • 预测模型LightGBM
  • 交易策略:TopK Dropout(每日持有 top K 只股票,并淘汰最差的 N 只)
  • 初始资金:200,000 HKD
  • 回测周期:2024-01-01 至 2025-09-29
  • 基准指数:恒生指数 (HSI)
"""
港股Alpha158因子策略测试脚本
本脚本实现了一个完整的量化交易策略测试流程:
1. 数据准备:使用Alpha158因子处理港股数据
2. 模型训练:使用LightGBM模型进行因子预测
3. 回测执行:使用TopKDropout策略进行投资组合回测
4. 绩效分析:计算并展示策略的绩效指标
注意:需要提前准备好港股数据文件
"""
import qlib
import pandas as pd
from qlib.data import D
from qlib.contrib.data.handler import Alpha158
import time
from qlib.utils import init_instance_by_config
from qlib.workflow import R
from qlib.contrib.evaluate import risk_analysis
from qlib.workflow.record_temp import SignalRecord, PortAnaRecord
from qlib.contrib.report import analysis_position
import os
import webbrowser
from plotly.offline import plot

# 初始化港股数据环境
qlib.init(provider_uri="D:/DM_Project/DM_QuantBox_V3.0_Qlib/qlib/qlib/data/cleaned_hk_data")

# 生成股票池
instruments = D.instruments(market="all")

if __name__ == '__main__':
    # ==================== 第一阶段:数据准备 ====================
    # 配置Alpha158因子处理器参数
    data_handler_config = {
        "instruments": instruments,      # 股票池:港股通标的
        "start_time": "2017-01-01",      # 数据开始时间
        "end_time": "2025-09-30",        # 数据结束时间
        "fit_start_time": "2017-01-01",  # 模型训练数据开始时间
        "fit_end_time": "2021-01-31"     # 模型训练数据结束时间
    }
    # 初始化Alpha158因子处理器
    h = Alpha158(**data_handler_config)

    # 提取因子特征和标签数据
    factors = h.fetch(col_set="feature")  # 158个Alpha因子特征
    labels = h.fetch(col_set="label")      # 标签:t+2日收益率(t日发信号,t+1开仓,t+2平仓)

    # ==================== 第二阶段:模型配置 ====================
    # 配置LightGBM模型和数据集
    task = {
        "model": {
            "class": "LGBModel",            # 使用LightGBM模型
            "module_path": "qlib.contrib.model.gbdt",
            "kwargs": {
                "loss": "mse",                 # 均方误差损失函数
                "colsample_bytree": 0.8879,    # 特征采样比例
                "learning_rate": 0.0421,       # 学习率
                "subsample": 0.8789,           # 样本采样比例
                "lambda_l1": 205.6999,         # L1正则化系数
                "lambda_l2": 580.9768,         # L2正则化系数
                "max_depth": 8,                # 树的最大深度
                "num_leaves": 210,             # 叶子节点数量
                "num_threads": 20              # 并行线程数
            }
        },
        "dataset": {
            "class": "DatasetH",
            "module_path": "qlib.data.dataset",
            "kwargs": {
                "handler": h,  # 使用Alpha158因子处理器
                "segments": {
                    "train": ("2017-01-01", "2021-01-31"),  # 训练集:2017-2021年
                    "valid": ("2021-02-01", "2023-12-31"),  # 验证集:2021-2023年
                    "test": ("2024-01-01", "2025-09-30")    # 测试集:2024-2025年9月
                }
            }
        }
    }
    # 初始化模型和数据集实例
    model = init_instance_by_config(task["model"])
    dataset = init_instance_by_config(task["dataset"])

    # ==================== 第三阶段:模型训练 ====================
    # 记录训练开始时间
    t_start = time.time()

    # 启动实验记录器
    with R.start(experiment_name="hk_lgb_strategy"):
        # 训练模型
        model.fit(dataset)
        # 保存训练好的模型
        R.save_objects(model=model)
        # 获取实验ID用于后续回测
        exp_id = R.get_recorder().id

    # ==================== 第四阶段:回测配置 ====================
    # 配置投资组合分析参数
    port_analysis_config = {
        "strategy": {
            "class": "TopkDropoutStrategy",      # 使用TopK淘汰策略
            "module_path": "qlib.contrib.strategy.signal_strategy",
            "kwargs": {
                "signal": "<PRED>",  # 使用模型预测信号
                "topk": 5,          # 每日持仓5只股票
                "n_drop": 2          # 每日淘汰2只表现最差的股票
            }
        },
        "backtest": {
            "start_time": "2024-01-01",      # 回测开始时间:测试集开始
            "end_time": "2025-09-29",        # 回测结束时间:提前一天避免索引越界
            "account": 200000,               # 初始资金:20W港元
            "benchmark": "HSI",              # 基准指数:恒生指数
            "exchange_kwargs": {
                "limit_threshold": None,      # 港股无涨跌停限制
                "deal_price": "close",        # 以收盘价成交
                "open_cost": 0.0015,          # 开仓手续费率:0.15%
                "close_cost": 0.0015,         # 平仓手续费率:0.15%
                "min_cost": 20                # 最低交易费用:20港元
            }
        }
    }

    # ==================== 第五阶段:信号生成和回测 ====================
    # 获取实验记录器
    recorder = R.get_recorder(experiment_name="hk_lgb_strategy")
    # 生成交易信号
    sr = SignalRecord(model, dataset, recorder)
    sr.generate()
    # 加载预测结果并更新策略配置
    pred = recorder.load_object("pred.pkl")
    port_analysis_config["strategy"]["kwargs"]["signal"] = pred

    # 执行回测并生成绩效分析
    par = PortAnaRecord(recorder, config=port_analysis_config)
    par.generate()

    # ==================== 第六阶段:结果展示 ====================
    # 加载并展示回测绩效报告
    report = recorder.load_object("portfolio_analysis/report_normal_1day.pkl")
    print("=" * 60)
    print("港股Alpha158因子策略回测结果(2024.01-2025.09)")
    print("=" * 60)
    print(risk_analysis(report))
    print("=" * 60)

    # 绘制IC/Rank IC图
    label = dataset.prepare("test", col_set="label")
    label.columns = ["label"]
    pred_label = pd.concat([label, pred], axis=1, sort=True).reindex(label.index)

    # 生成IC图表并保存
    ic_fig = analysis_position.score_ic_graph(pred_label, show_notebook=False)[0]
    ic_html_path = os.path.abspath("ic_graph.html")
    plot(ic_fig, filename=ic_html_path, auto_open=False)
    print(f"IC图表已保存至: {ic_html_path}")

    # 生成报告图表并保存
    report_fig = analysis_position.report_graph(report, show_notebook=False)[0]
    report_html_path = os.path.abspath("report_graph.html")
    plot(report_fig, filename=report_html_path, auto_open=False)
    print(f"报告图表已保存至: {report_html_path}")

    # 在默认浏览器中打开图表
    webbrowser.open(f"file://{report_html_path}")
    webbrowser.open(f"file://{ic_html_path}")

    # 计算并显示总运行时间
    t_end = time.time()
    print(f"总运行时间: {t_end - t_start:.2f} 秒")

说明:以上为完整代码。原文中提到“代码只能显示为一行”,此处已正确格式化为多行代码块,便于阅读和复制。

📊 结果可视化与绩效分析

脚本运行完毕后,会自动在浏览器中打开两份图表:report_graph.html(综合绩效报告)和 ic_graph.html(IC分析图)。

1. 综合绩效报告
这份报告包含多组子图,是评估策略的核心:

  • 累计收益率曲线:策略净值 vs 基准净值。
  • 滚动最大回撤曲线:展示历史上任一时刻开始可能发生的最大亏损。
  • 超额收益率曲线:策略收益超越基准的部分。
  • 换手率序列:反映策略的交易频率。
  • 超额收益回撤曲线:专门观察超额收益的回落情况。

在本案例的回测周期(2024/01/01 ~ 2025/09/29)内,该策略的累计收益率达到了约81%。图中可以清晰看到,最大回撤发生在2025年4月初,这与当时市场的特定事件相吻合。

2. IC (Information Coefficient) 分析图
IC值衡量了模型预测(因子)与未来实际收益率之间的相关性,是判断因子预测能力的关键指标。

Score IC 分析图表

参考标准:IC均值大于0.05通常认为因子具有预测能力。本例中,IC均值约为0.08,Rank IC均值约为0.09,表明所使用的Alpha158因子在港股测试集上具有一定的选股能力。

📚 总结与思考

本次实战演示了从零开始,利用 Qlib 平台构建一个港股AI选股策略的全过程。其中,数据准备是基石,特别是数据格式、复权处理和清洗校验;模型与回测配置是核心,需要根据市场特点(如港股无涨跌停)调整参数。

一个有趣的发现是:本策略使用2017年至2021年的数据训练,却在2024年至2025年的测试集上取得了不错的效果。这或许暗示着这两个时间段的市场逻辑存在某种相似性,例如可能都处于由估值修复、资金流向驱动的市场阶段。

当然,任何量化模型都是对历史规律的总结。市场风格会切换,消息面冲击无法预测。因此,这个策略案例更重要的价值在于提供了一套可复现、可迭代的研究框架。你可以尝试更换因子集、调整模型参数、或者引入新的数据处理方法,在 云栈社区 与更多开发者交流想法,不断优化属于你自己的量化策略。

记住,回测表现不代表未来收益,实战中务必谨慎,做好风险控制。

喜財恭發梗图




上一篇:《集异壁》解构:哥德尔定理如何串联巴赫音乐与艾舍尔画作的递归宇宙
下一篇:Stagewise:基于浏览器的前端AI开发助手,实现可视化智能修改
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-11 10:06 , Processed in 0.597510 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表