Qlib 高频交易(High-Frequency Trading)嵌套决策执行框架:从日频组合到分钟级下单的联合回测设计
【免费下载链接】qlibQlib is an AI-oriented Quant investment platform that aims to use AI tech to empower Quant Research, from exploring ideas to implementing productions. Qlib supports diverse ML modeling paradigms, including supervised learning, market dynamics modeling, and RL, and is now equipped with https://github.com/microsoft/RD-Agent to automate R&D process.项目地址: https://gitcode.com/GitHub_Trending/qli/qlib
本文面向量化开发与研究工程师,系统讲解 Qlib 中用于支持多层级(Multi-Level)联合交易回测的嵌套决策执行(Nested Decision Execution)框架。文章以 docs/component/highfreq.rst 为主线,结合 examples/nested_decision_execution/workflow.py 与 executor 源码 展开:读完后你将理解"日频组合管理 + 日内订单执行"为何必须在一个框架内联合建模、框架的Trading Agent/Execution Env分层抽象如何落地,并能基于仓库自带的workflow.py复现 day → 30min → 5min 三级嵌套回测、理解全部关键配置参数。
1 背景:日频与日内交易为何需要联合回测
传统的量化研究中,日频交易(例如组合管理、调仓)与日内交易(例如订单执行、算法交易)通常被当作两个独立课题分别研究。但在真实投资链路中,两者的收益是耦合的:
- 日频调仓的"下单"最终要在日内完成,日内执行质量(滑点、冲击成本)会反作用于组合层面的真实收益;
- 不同层级策略的最优化并不是独立的:例如当订单执行策略被改进后,高换手率的组合策略可能反而成为更优选择(docs/component/highfreq.rst 原文论证)。
要得到"日频 + 日内"的联合交易绩效,就必须让两层策略互相交互并联合回测(Joint Backtest);而当时公开的高频回测框架均不支持多层级联合交易,导致上述回测并不准确。为此 Qlib 设计了一套考虑层间交互的嵌套决策执行框架:它既支撑不同频率策略在同一回测中嵌套运行,也天然为跨层级联合优化(例如用强化学习同时优化组合与执行策略)提供统一环境。
2 框架总览:Trading Agent 与 Execution Env 的分层嵌套
框架的总体设计如下(黄色中间部分即嵌套决策执行框架本体):
每一层都由一个Trading Agent(交易代理)与一个Execution Env(执行环境)构成(见 docs/component/highfreq.rst 的设计说明):
- Trading Agent自带三个模块:
- Information Extractor:数据/信息处理模块,负责从行情、因子、事件等原始数据中抽取特征;
- Forecast Model:预测模块,输出价格趋势、收益等预测信号;
- Decision Generator:决策生成器,基于预测信号产生交易决策(订单、调仓目标等)。
- Execution Env:接收交易算法(Trading Algorithm)产出的决策,返回执行结果(成交价格、成交量、费用等)。
该框架强调三个维度的可定制性:交易算法的频率(日内 / 日频 / 周频)、决策内容、以及执行环境均可由用户自定义。关键之处在于:执行环境内部可以再嵌套更细粒度的交易算法与执行环境(即图例中的 sub-workflow / 子流程)——例如把日频订单通过日内切分转化为更细粒度的决策。这种嵌套灵活性使研究者能够直接探索"不同层级交易策略组合"的效果,打破各层级交易算法之间被割裂的优化边界。
框架整体的联合优化可由QlibRL支持(docs/component/rl/overall.rst),相关 API 可参考 docs/reference/api.rst。仓库 examples/nested_decision_execution/workflow.py 提供了完整的可运行示例(运行方式见后文第 5 节)。
3 源码级拆解:Executor 的分层执行机制
3.1 三层执行器体系:BaseExecutor / NestedExecutor / SimulatorExecutor
在 Qlib 回测体系中,"执行环境"的具体承载者是位于 qlib/backtest/executor.py 的执行器(Executor),其继承结构为:
BaseExecutor:所有执行器的基类。它按time_per_step粒度生成交易日历(TradeCalendarManager),管理交易账户trade_account,并负责在每步结束后更新组合指标(update_bar_end)与推进日历(trade_calendar.step())。NestedExecutor(BaseExecutor):嵌套执行器,是本框架的核心实现。当它被调用执行一个trade_decision时,会调用内层的inner_strategy与inner_executor,在更高频率的环境中对上层决策进行再执行。SimulatorExecutor(BaseExecutor):最底层的"原子"模拟器,直接对订单列表向Exchange撮合成交(deal_order),支持serial/parallel两种撮合顺序(见 qlib/backtest/executor.py 的TT_SERIAL/TT_PARAL定义)。
每个执行器的"一步"有多大,完全由time_per_step(如"day"、"30min"、"5min")决定;不同频率的数据则由CommonInfrastructure/LevelInfrastructure中的多频率日历与行情(Exchange)提供。
3.2 NestedExecutor 的核心执行循环
NestedExecutor._collect_data(qlib/backtest/executor.py)实现了层间交互的核心逻辑,流程可概括为:
- 初始化子交易:
_init_sub_trading把内层执行器重置到"外层当前这一步"的时间窗口内(inner_executor.reset(start_time, end_time)),并把当前层级的 LevelInfra 下传给内层策略。 - 子级循环:在
while not self.inner_executor.finished()中反复:- 更新上层决策(
trade_decision.update(...),外层策略有机会逐步更新决策); - 让内层策略
inner_strategy.generate_trade_decision(...)生成更细粒度的子决策; - 把子决策交给
inner_executor.collect_data(...)执行,并累加execute_result与内层订单指标(inner_order_indicators)。
- 更新上层决策(
- 收尾钩子:内层循环结束后调用
inner_strategy.post_upper_level_exe_step()与post_exe_step(...),让内层策略感知外层执行完成,便于维护跨层状态。
两个对使用很关键的布尔参数(构造参数见 executor.py 中NestedExecutor.__init__):
skip_empty_decision=True:当上层决策为空时跳过内层循环;但当"决策会被逐步更新"或"内层执行器可能不跟随外层决策"时须置为False。align_range_limit=True:强制对齐trade_range决策的时间窗(range_limit由外层策略给出),跳过窗口外的子步骤。
跨层级账户的处理有一个精妙设计(executor.py 源码注释):内层执行器通过copy_trade_account=True浅拷贝共享外层账户——持仓(positions)在各层间共享,而组合指标与交易指标(portfolio & trading metrics)各层独立记账,从而能同时得到 day/30min/5min 三个频率各自的绩效报表(这正是示例能输出三套分析结果的原因)。此外NestedExecutor.get_all_executors()会递归收集自身及所有内层执行器,供统一管理与指标输出。
3.3 决策与订单的数据结构
决策链路的下游是 qlib/backtest/decision.py 中定义的Order数据类与OrderDir枚举(OrderDir.SELL/OrderDir.BUY)。Order记录标的stock_id、数量amount、买卖方向direction、订单区间start_time/end_time,成交后由回测系统回填deal_amount与factor(无法成交时deal_amount == 0且factor is None,例如停牌导致整单失败)。amount_delta/deal_amount_delta/sign属性统一了买卖的方向语义,供上层策略与账户结算复用。
4 关键配套策略:TWAP 与 SBB(规则型日内执行)
在嵌套框架里,"把上层订单转成细粒度执行决策"的任务落在各类策略上(策略基类为 qlib/strategy/base.py 的BaseStrategy)。高频/执行场景常用到 qlib/contrib/strategy/rule_strategy.py 中的两个规则型策略:
- TWAPStrategy:时间加权平均价格策略,把外层订单
order.amount在决策允许的trade_len个交易步内均匀切分成交(amount_expect = order.amount / trade_len * (rel_trade_step + 1)),并按交易单位(trade_unit,A 股为 100 股/手)取整、在最后一步把余量全部出清;同时会跳过停牌标的、依据execute_result回填已成交量,避免重复下单。 - SBBStrategyEMA:
(S)elect the (B)etter one among every two adjacent trading (B)ars,即基于EMA 信号在相邻两根交易 bar 中"挑更好的一根"执行,用于日内择时。其信号为EMA($close,10) - EMA($close,20),构造参数freq指定信号的取样频率(默认"day",可与执行器的time_per_step不同),instruments限定信号覆盖的标的池(如"csi300")。
另外,日频调仓层的典型外层策略是 qlib/contrib/strategy/signal_strategy.py 中的TopkDropoutStrategy,它按模型预测信号维持一个 Top-K 股票池并定期调出掉队标的——在示例中它负责"日频组合生成"这一层。
5 实战示例:日频组合 + 分钟级执行的联合回测
5.1 三段式执行链:day → 30min → 5min
仓库自带示例 examples/nested_decision_execution/workflow.py(类NestedDecisionExecutionWorkflow)演示了完整用法:外层用TopkDropoutStrategy在日频生成组合调仓决策,然后经由三段嵌套执行器把订单拆解到30 分钟直至5 分钟级别撮合:
| 层级 | 执行器(time_per_step) | 内层策略(inner_strategy) | 职责 |
|---|---|---|---|
| 外层 | NestedExecutor(day) | SBBStrategyEMA(freq="1min") | 日频调仓决策在盘内按 1min 级信号择时执行 |
| 中层 | NestedExecutor(30min) | TWAPStrategy | 把 30min 粒度的订单按时间均匀拆分 |
| 内层 | SimulatorExecutor(5min) | —— | 最细粒度撮合、生成组合与交易指标 |
示例完整的执行器/回测配置如下(节选自 workflow.py 的port_analysis_config):
port_analysis_config = { "executor": { "class": "NestedExecutor", "module_path": "qlib.backtest.executor", "kwargs": { "time_per_step": "day", # 外层每步 = 1 个交易日 "inner_executor": { "class": "NestedExecutor", "module_path": "qlib.backtest.executor", "kwargs": { "time_per_step": "30min", # 中层每步 = 30 分钟 "inner_executor": { "class": "SimulatorExecutor", # 内层原子撮合器 "module_path": "qlib.backtest.executor", "kwargs": { "time_per_step": "5min", # 最细执行粒度 = 5 分钟 "generate_portfolio_metrics": True, "verbose": True, "indicator_config": {"show_indicator": True}, }, }, "inner_strategy": { # 中层把订单均分到 5min "class": "TWAPStrategy", "module_path": "qlib.contrib.strategy.rule_strategy", }, "generate_portfolio_metrics": True, "indicator_config": {"show_indicator": True}, }, }, "inner_strategy": { # 日频层做日内择时 "class": "SBBStrategyEMA", "module_path": "qlib.contrib.strategy.rule_strategy", "kwargs": {"instruments": "csi300", "freq": "1min"}, }, "track_data": True, # 收集逐笔决策,供 RL 训练使用 "generate_portfolio_metrics": True, "indicator_config": {"show_indicator": True}, }, }, "backtest": { "start_time": "2020-09-20", "end_time": "2021-05-20", "account": 100000000, # 初始资金 1 亿元 "exchange_kwargs": { "freq": "1min", # 行情数据频率 "limit_threshold": 0.095, # 涨跌停阈值(A 股约 ±9.5% 留缓冲) "deal_price": "close", "open_cost": 0.0005, # 开仓成本(双边费率习惯性拆分) "close_cost": 0.0015, "min_cost": 5, # 单笔最低佣金 }, }, }外层策略(训练好的模型 + 数据集作为信号)在backtest()方法中注入:
strategy_config = { "class": "TopkDropoutStrategy", "module_path": "qlib.contrib.strategy.signal_strategy", "kwargs": {"signal": (model, dataset), "topk": 50, "n_drop": 5}, } self.port_analysis_config["strategy"] = strategy_config self.port_analysis_config["backtest"]["benchmark"] = "SH000300" # 沪深300模型侧复用 Qlib 的标准训练链路:数据集使用Alpha158因子 +DatasetH,模型使用LGBModel(qlib.contrib.model.gbdt,配置见 workflow.py 中 task 定义),时间分段为 train(2007-01-01 至 2014-12-31)/valid(2015-2016)/test(2020-01-01 至 2021-05-31),并用SignalRecord生成预测、PortAnaRecord生成组合绩效分析(qlib.workflow.record_temp)。
5.2 多频率数据初始化(provider_uri 按频率映射)
由于联合回测同时需要日频与分钟频数据,示例的_init_qlib()做了两件关键事情(可对照 qlib/config.py 的HIGH_FREQ_CONFIG理解):
provider_uri_day = "~/.qlib/qlib_data/cn_data" # 日频数据 GetData().qlib_data(target_dir=provider_uri_day, region=REG_CN, version="v2", exists_skip=True) provider_uri_1min = HIGH_FREQ_CONFIG.get("provider_uri") # "~/.qlib/qlib_data/cn_data_1min" 分钟频数据 GetData().qlib_data(target_dir=provider_uri_1min, interval="1min", region=REG_CN, version="v2", exists_skip=True) provider_uri_map = {"1min": provider_uri_1min, "day": provider_uri_day} qlib.init(provider_uri=provider_uri_map, dataset_cache=None, expression_cache=None)即qlib.init的provider_uri支持传入{频率: 数据目录}字典,让不同频率的数据与交易日历按需加载。HIGH_FREQ_CONFIG(qlib/config.py)给出了分钟频数据目录与DiskExpressionCache缓存的推荐默认值。
5.3 运行方式
进入示例目录后直接执行(示例 README):
python workflow.py backtest # 启动联合回测并输出 1day/30minute/5minute 三级绩效 python workflow.py collect_data # 按步收集 trade_decision(供 RL 训练等下游使用)执行后,PortAnaRecord会在 Qlib 的 MLflow 记录器(Experiment 2)中分别保存port_analysis_1day.pkl、port_analysis_30minute.pkl、port_analysis_5minute.pkl与indicator_analysis_*.pkl三组工件。示例源码 docstring 记录了某次历史运行的输出(当前版本数据/模型下数值可能有差异,仅作结果形态示意):
| 频率 | benchmark 年化收益 | benchmark 信息比率 | 超额年化(含费) | 超额信息比率(含费) |
|---|---|---|---|---|
| 1day | 0.154967 | 0.805422 | 0.264280 | 2.261392 |
| 30minute | 0.148787 | 0.935252 | 0.294536 | 2.018860 |
| 5minute | 0.172170 | 1.103439 | 0.281536 | 1.866091 |
同时输出各层的交易指标(ffr 成交满足率 / pa 价格优势 / pos 交易正向率)。在示例的历史输出中,1day 的ffr≈0.946、30minute≈0.983、5minute≈0.991——执行粒度越细、成交满足率越高,直观体现了日内拆单对执行效果的改善。另外workflow.py还提供了两个内部校验方法:check_diff_freq()把 30minute/5minute 的账户净值重采样到日频后与 1day 层对齐断言(多级间资金核算一致性校验),backtest_only_daily()运行纯日频单层回测用于对比嵌套与单层执行是否有严重偏差。
5.4 执行指标(indicator_config)配置说明
示例在所有层级都开启了show_indicator=True,其定义与可选参数见 BaseExecutor 构造文档:
show_indicator:是否输出指标,指标包括pa(价格优势,成交价相对基准价更优的程度)、pos(正向率)、ffr(成交满足率)。pa_config.base_price:价格优势的基准价,"twap"(时间加权均价,默认)或"vwap"(成交量加权均价)。pa_config.weight_method与ffr_config.weight_method:多订单聚合加权方式,"mean"(默认)/"amount_weighted"(按数量加权)/"value_weighted"(按成交额加权)。
{ "show_indicator": True, "pa_config": {"agg": "twap", "price": "$close"}, "ffr_config": {"weight_method": "value_weighted"}, }5.5 track_data 与强化学习联动
注意示例在日频层执行器设置了track_data: True。这在 executor.py 的collect_data实现中体现为:当track_data为真时,执行器每步会yield trade_decision,使外部驱动方(如 RL 训练循环)能拿到逐决策数据;执行器还返回每步的decision_list与inner_order_indicators。同时,源码针对 RL 场景做了专门适配:通常"Qlib 策略 ↔ Qlib 执行器"的嵌套循环可以切换为"RL Policy ↔ RL Env[内嵌 Qlib Executor]"的写法,即内层策略作为代理策略通过yield from把控制权交给 RL Env 等待策略动作——这让嵌套执行框架能够直接对接强化学习联合优化(源码注释见 executor.pyNestedExecutor._collect_data,入门资料见 docs/component/rl/quickstart.rst)。
6 仓库内的高频量化配套资源
除了嵌套决策执行,当前仓库还沉淀了一批高频相关模块与示例,可与此框架组合使用:
- 高频数据预测基准:
examples/highfreq/目录提供基于 1 分钟数据的预测工作流(workflow.py、highfreq_handler.py、highfreq_processor.py、highfreq_ops.py)及配置文件workflow_config_High_Freq_Tree_Alpha158.yaml;其底层处理器HighFreqHandler/HighFreqBacktestHandler与高性能算子位于 qlib/contrib/data/highfreq_handler.py、qlib/contrib/ops/high_freq.py。它使用的HIGH_FREQ_CONFIG与本文示例同源。 - 无固定频率的特征抽取:
examples/orderbook_data/提供从盘口/订单簿数据中按事件(而非固定频率)抽取特征的方法(见 README)。 - 基于强化学习的高频订单执行:
examples/rl_order_execution/提供基于 RL 的订单执行示例(train_ppo.yml、backtest_ppo.yml等配置与数据生成脚本,见 README),与本文框架的 RL 集成点一脉相承。 - RL 框架文档:整体方案与 API 详见 docs/component/rl/overall.rst、docs/component/rl/framework.rst。
7 小结
Qlib 的嵌套决策执行框架把"日频组合决策"与"日内订单执行"放进同一个可递归嵌套的执行器体系中:每层由Trading Agent(信息抽取、预测、决策)与Execution Env(执行器 + 内层策略)组成,通过NestedExecutor的递归循环把上层订单逐级拆解到更细的时间粒度,并以"共享持仓、分层记账"的方式输出各频率独立的绩效与交易指标。相比"日频、日内分开回测"的传统做法,该设计能更真实地评估多层级策略的联合表现,并为基于强化学习的跨层级联合优化提供了统一、可控的训练环境。想要快速上手,可直接阅读并运行 examples/nested_decision_execution/workflow.py;想深入源码,则建议从 qlib/backtest/executor.py 中NestedExecutor的_collect_data循环读起,再对照 docs/component/highfreq.rst 的框架图理解层级语义。
【免费下载链接】qlibQlib is an AI-oriented Quant investment platform that aims to use AI tech to empower Quant Research, from exploring ideas to implementing productions. Qlib supports diverse ML modeling paradigms, including supervised learning, market dynamics modeling, and RL, and is now equipped with https://github.com/microsoft/RD-Agent to automate R&D process.项目地址: https://gitcode.com/GitHub_Trending/qli/qlib
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考