首页
/ Qlib Online 模块详解:模拟真实账户的每日订单生成、执行与组合更新实战

Qlib Online 模块详解:模拟真实账户的每日订单生成、执行与组合更新实战

2026-09-05 11:09:27作者:卓艾滢Kingsley

本篇指南围绕 Qlib 的 Online 模块(对应文档 docs/hidden/online.rst)展开:它把"训练好的模型 + 交易策略"放进一个持久化的模拟账户里,按真实交易的节奏——前一交易日收盘后出预测、下一交易日执行订单、收盘后更新账户——逐日推进。读完后,你将能够编写 Online 配置文件、使用 online simulate / generate / execute / update / show / add_user / remove_user 命令完成从区间回放到逐日实盘模拟的完整流程,并理解账户文件夹中每个文件(pickle 模型、订单 JSON、持仓报表)的来龙去脉。

Online 模拟的是什么:一个真实交易账户的生命周期

Online 模块的核心目标是:模拟"如果我们真的用模型和策略去实盘交易,会发生什么"。与 Qlib 其他模块一致,它通过配置文件确定模型与策略参数,并把账户保存在一个文件夹中;之后每个交易日,模块都用最新信息为你的账户执行交易,性能可以随时通过 API 查看。

每个账户会经历以下三个过程。其中 pred_date 是你预测目标持仓的日期(使用截至该日收盘的数据),trade_date 是你实际下单交易的日期,两者相差一个交易日:

  1. 生成订单列表(Generate the order list,在 pred_date 进行);
  2. 执行订单列表(Execute the order list,在 trade_date 进行);
  3. 更新账户(Update account,在 trade_date 进行)。

除此之外,你也可以直接创建一个账户,用该模块测试它在一段区间内的表现,即一次性的 Simulate(start_date, end_date)

这个"前一日预测、当日交易"的时间语义在源码中有直接体现。qlib/contrib/online/operator.pyOperator.init 会校验 trade_date 是否为可交易日期,然后调用 get_pre_trading_date(trade_date, future=True) 求出预测日:

trade_date = pd.Timestamp(date)
if not is_tradable_date(trade_date):
    raise ValueError("trade date is not tradable date".format(trade_date.date()))
pred_date = get_pre_trading_date(trade_date, future=True)

而区间模拟 simulate 的 docstring 明确描述了循环内容(见 qlib/contrib/online/operator.py):

Run the ( generate_trade_decision -> execute_order_list -> update_account ) process everyday from start date to end date.

其内部实现将日期序列错位一位(for pred_date, trade_date in zip(dates[:-2], dates[1:-1])),即每天先取 pred_date 的数据算分数、更新策略、生成并落盘订单列表,再由 SimulatorExecutortrade_date 执行订单、最后 update_account 推进账户状态——与文档描述的三步流程一一对应。

账户的持久化方式:模型与策略保存为 pickle 文件,持仓(position)与报表(report)保存为 Excel/CSV,具体目录结构见下文"账户数据结构"。

账户数据结构:每个用户一个文件夹

文档约定:Online 需要把账户保存在一个文件夹中(下文以 user_data 指代根目录),多账户按 user_id 分目录存放。完整的文件结构如下(加粗表示文件夹):

{user_folder}
│   users.csv: (每个用户的初始日期)
│
└───{user_id1}:(用户子文件夹,保存其数据)
    │   position.xlsx
    │   report.csv
    │   model_{user_id1}.pickle
    │   strategy_{user_id1}.pickle
    │
    └───score
    │   └───{YYYY}
    │       └───{MM}
    │           │   score_{YYYY-MM-DD}.csv
    │
    └───trade
        └───{YYYY}
            └───{MM}
                │   orderlist_{YYYY-MM-DD}.json
                │   transaction_{YYYY-MM-DD}.csv
│
└───{user_id2}
    │   position.xlsx
    │   report.csv
    │   model_{user_id2}.pickle
    │   strategy_{user_id2}.pickle
    │
    └───score
    └───trade
    ...

这套结构在源码中可以得到逐项印证(qlib/contrib/online/manager.pyqlib/contrib/online/utils.py):

  • users.csv:由 create_user_folder 创建,列为 user_id, add_dateutils.py);UserManager 以它为索引 load_usersmanager.py)。
  • model_{user_id}.pickle / strategy_{user_id}.pickleUserManager.add_user 通过 save_instance 分别落盘(manager.py);加载时使用受限的 restricted_pickle_loadutils.py)。
  • position.xlsx / report.csv:由账户对象 Account.save_account(...) 写出,见 UserManager.save_user_datamanager.py)。
  • score/trade/ 子目录:分别存放预测分数与订单/成交文件,由分数与订单的读写工具维护(save_score_seriessave_order_list 等,由 operator.py 引入)。

每个账户在内存中的抽象是 User,它持有 account / strategy / model 三件套,并能在每个交易日开始 init_state、随时用 showReport 对照基准(默认 SH000905)输出超额收益分析,见 qlib/contrib/online/user.py

配置文件:模型、策略与初始资金

Online 的配置文件必须包含模型策略两部分信息,再加上账户初始资金。文档给出的原始示例如下:

strategy:
    class: TopkAmountStrategy
    module_path: qlib.contrib.strategy
    args:
        market: csi500
        trade_freq: 5

model:
    class: ScoreFileModel
    module_path: qlib.contrib.online.online_model
    args:
        loss: mse
        model_path: ./model.bin

init_cash: 1000000000

UserManager.add_user 会解析这份 YAML:用 init_instance_by_config(config["model"]) 构建模型、用 init_instance_by_config(config["strategy"]) 构建策略,调用 strategy.get_init_args_from_model(model, add_date) 完成策略与模型的对接,最后以 config["init_cash"] 初始化 Accountmanager.py)。

关于模型(model)

model 字段决定在预测日生成分数(score)时使用什么模型。文档给出了两种 ScoreFileModel 配置示例:一种是携带模型参数直接打分(旧版写法,loss: mse 等),另一种是读取现成的分数文件:

model:
    class: ScoreFileModel
    module_path: qlib.contrib.online.online_model
    args:
        score_path: <your score path>

对照当前仓库的实现(qlib/contrib/online/online_model.py),ScoreFileModel 现在的构造函数只接受 score_path:它把分数 CSV 读入内存(索引为 (stock_id, datetime) 的多级索引,含 score 列),get_data_with_date(date) 取出该日分数序列,predict 原样返回——即"给定预测日,返回当日全市场分数"。

如果你的模型不属于上述类型,需要自行实现。从源码结构看,Online 对模型的最小契约写在 qlib/contrib/online/init.py 的 TODO 说明中:模型必须实现 get_data_with_date(self, date, **kwargs),返回"用于预测 date 日分数(label)的输入数据",配合 predict 完成打分。

关于策略(strategy)

strategy 字段定义在预测日生成订单列表所用策略。文档示例为 Topk 类策略:

strategy:
    class: TopkDropoutStrategy
    module_path: qlib.contrib.strategy.strategy
    args:
        topk: 100
        n_drop: 10

需要注意版本差异:TopkDropoutStrategy 在当前仓库位于 qlib/contrib/strategy/signal_strategy.py,因此 module_path 应写为 qlib.contrib.strategy.signal_strategy;其完整参数为 topk(组合股票数)、n_drop(每个交易日替换的股票数)、method_sell(默认 "bottom")、method_buy(默认 "top")、hold_thresh(默认 1)、only_tradable(默认 False)、forbid_all_trade_at_limit(默认 True)。而示例开头的 TopkAmountStrategy(market, trade_freq) 属于旧版写法,当前源码中未提供该类——若要在当前版本跑通配置,建议改用上面的 TopkDropoutStrategy

结合当前仓库的完整配置

综合以上修正,一份贴近当前仓库实现的配置可以写成:

strategy:
    class: TopkDropoutStrategy
    module_path: qlib.contrib.strategy.signal_strategy
    args:
        topk: 100
        n_drop: 10

model:
    class: ScoreFileModel
    module_path: qlib.contrib.online.online_model
    args:
        score_path: ./score.csv

init_cash: 1000000000

一键体验:simulate 区间模拟

在写好配置文件后,可以用一条命令创建账户文件夹,并从 2017-01-01 模拟交易到 2018-08-01:

online simulate -id v-test -config ./config/config.yaml -exchange_config ./config/exchange.yaml -start 2017-01-01 -end 2018-08-01 -path ./user_data/

日期语义(文档原文语义):

  • start date(2017-01-01) 是用户的添加日期(add date),同时也是第一个预测日期;
  • end date(2018-08-01) 是最后一个交易日期;
  • 区间结束后,可用 online generate -date 2018-08-02 ... 在下一个交易日继续生成订单列表。

从源码看(qlib/contrib/online/operator.py),simulate 的完整动作是:清空同名旧账户并 add_user,然后对区间内每个 (pred_date, trade_date) 依次执行——① 取数并保存分数序列;② user.strategy.update(score_series, pred_date, trade_date) 更新策略(与模型联动);③ 生成并保存订单列表;④ 由 SimulatorExecutor 自动执行订单并保存成交文件;⑤ update_account 推进账户状态。循环结束后汇总组合指标并调用 show 输出。

exchange.yaml:交易所撮合参数

-exchange_config 指定撮合行为。文档给出的简版示例:

open_cost: 0.003
close_cost: 0.003
limit_threshold: 0.095
deal_price: vwap

这些参数最终透传给 Exchange 构造(qlib/contrib/online/utils.pyprepare 读取 YAML 后执行 Exchange(trade_dates=dates, **exchange_paras))。对照 qlib/backtest/exchange.py 中的定义,各参数含义与默认值为:

  • open_cost:开仓成本费率,默认 0.0015;
  • close_cost:平仓成本费率(含卖出税费),默认 0.0025;
  • min_cost:最小佣金,默认 5.0;
  • deal_price:成交价取值方式,如 vwap(文档示例),也可配置买/卖分别取价;
  • limit_threshold:涨跌停限制阈值(如 0.095 对应约 ±9.5%);
  • impact_cost:市场冲击成本(滑点)费率。

文档中的 0.003/0.003/0.095/vwap 组合更贴近 A 股双边佣金约 0.3%、涨跌停约 10% 的设定,适合配合 csi500 这类市场使用。

online show:对照基准查看绩效

若账户保存在 ./user_data/,可以用下面的命令查看相对基准的绩效(SH000905 代表 csi500,SH000300 代表 csi300):

online show -id v-test -path ./user_data/ -bench SH000905

文档示例的输出:

Result of porfolio:
                                                      risk
excess_return_without_cost mean               0.000605
                           std                0.005481
                           annualized_return  0.152373
                           information_ratio  1.751319
                           max_drawdown      -0.059055
excess_return_with_cost    mean               0.000410
                           std                0.005478
                           annualized_return  0.103265
                           information_ratio  1.187411
                           max_drawdown      -0.075024

该结果对应 Operator.show 的实现(operator.py):取基准标的的 $change 序列作为 bench,分别对"组合收益 − 基准"与"组合收益 − 基准 − 交易成本"调用 risk_analysis(来自 qlib/contrib/evaluate.py),输出 mean、std、annualized_return、information_ratio、max_drawdown 五项风险指标。

日常操作:账户管理与逐日交易

除了 simulate,文档定义了完整的账户管理命令集(全部基于 qlib/contrib/online/operator.pyOperator 类,通过 fire 生成 CLI,见 operator.py):

命令 作用 源码位置
online add_user -id {user_id} -config {config_file} -path {folder_path} -date {add_date} 在 folder 中新增账户(add_date 会取不晚于该日的最近可交易日) operator.py
online remove_user -id {user_id} -path {folder_path} 删除账户(删除 {user_id} 子目录并更新 users.csv) operator.py
online show -id {user_id} -path {folder_path} -bench {benchmark} 展示相对基准的绩效 operator.py
online generate -date {date} -path {folder_path} 在交易日的预测日生成订单列表 operator.py
online execute -date {date} -exchange_config {exchange_config_path} -path {folder_path} 执行订单列表并产出成交结果 operator.py
online update -date {date} -path {folder_path} 根据成交结果更新账户 operator.py

例如:

>> online add_user -id v-test -config config.yaml -path ./user_data/ -date 2019-10-15
>> online remove_user -id v-test -path ./user_data/
>> online show -id v-test -path ./user_data/ -bench SH000905
>> online generate -date 2019-10-16 -path ./user_data/
>> online execute -date 2019-10-16 -exchange_config ./config/exchange.yaml -path ./user_data/
>> online update -date 2019-10-16 -path ./user_data/

使用规则与注意事项:

  • date 参数默认是交易日期(若今天是交易日且 qlib 数据已更新,即"今天");
  • generateupdate 会校验输入日期是否合法(非可交易日期直接抛 ValueError);上述三个过程应当在每一个交易日依次调用一次,顺序为 generate → execute → update;
  • execute 会检查账户数据新鲜度:若账户最后一次交易日晚于本次指定的预测日,会抛出 "The account data is not newest!"(operator.py),update 同样有类似的滞后检查(operator.py)。这意味着逐日流程不能跳日、不能乱序;
  • updatetype 参数指定订单由哪种执行器执行,当前仅支持 'SIM'(SimulatorExecutor),传其他值会报 "not found executor"(operator.py)。

生成的文件与订单列表格式

online generate 命令会在 {folder_path}/{user_id}/temp/ 下创建订单列表文件 orderlist_{YYYY-MM-DD}.json,其中 YYYY-MM-DD 是这些订单将要被执行的日期。文档描述的 JSON 格式为:

{
    'sell': {
            {'$stock_id1': '$amount1'},
            {'$stock_id2': '$amount2'}, ...
            },
    'buy': {
            {'$stock_id1': '$amount1'},
            {'$stock_id2': '$amount2'}, ...
            }
}

即分 sell / buy 两个方向,每个方向内是"股票代码 → 数量"的条目列表。订单执行后(无论通过 online execute 还是其他执行器),成交文件同样生成在 {folder_path}/{user_id}/temp/transaction_{YYYY-MM-DD}.csv),随后由 update 读入并推进账户。

与当前 Online Serving 框架的关系

需要说明版本背景:本页描述的 online 命令行模块属于 Qlib 早期的在线模拟实现,其代码主体是 qlib/contrib/online/ 下的 Operator / UserManager / User。当前仓库持续维护的在线化能力是 Online Serving 框架(文档见 docs/component/online.rst),它包含 Online Manager、Online Strategy、Online Tool 与 Updater 四类组件,配套可运行的示例位于 examples/online_srv/(如 online_management_simulate.pyrolling_online_management.pyupdate_online_pred.py),并基于任务管理(Task Management)中的 TrainerRMCollector 等组件实现模型滚动更新与在线推理。

Qlib Online Serving 框架结构图

从源码结构看,还有一个值得注意的现状:当前快照中 operator.py 引用的订单/分数读写与 SimulatorExecutor 封装(from .executor import ...)所在模块未包含在 qlib/contrib/online 目录内,说明该旧版 CLI 处于维护过渡状态。因此在当前仓库中复现"在线模拟",推荐路径是:先用本文的 online 概念模型(pred_date/trade_date、generate/execute/update 三步骤、账户文件夹结构)理解设计,再参照 examples/online_srv/qlib/workflow/online/ 中维护中的 Online Manager / OnlineStrategy / Updater 落地实际流程;同时注意 Online Serving 要求数据源保持更新(例如用仓库 scripts/data_collector/ 中的脚本滚动更新日线数据)。

小结

  • 核心流程:pred_date 预测 → trade_date 生成订单 → 执行 → 更新账户;区间模式 online simulate 一次跑完,逐日模式按 generate / execute / update 顺序每天调用。
  • 配置三要素strategy(如 TopkDropoutStrategy)、model(如 ScoreFileModel + score_path)、init_cash;撮合行为由 exchange.yamlopen_cost / close_cost / limit_threshold / deal_price 等)控制。
  • 账户即文件夹users.csv + 每用户一个子目录(pickle 模型/策略、position.xlsxreport.csvscore/trade/),可直接被 online show 汇总为相对基准(SH000905/SH000300)的五项风险指标。
  • 版本提示:旧版 online CLI 与当前维护中的 Online Serving(qlib/workflow/online/examples/online_srv/)概念一致、实现分属两代,实践时以后者为准。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384