拓冰建站拓冰建站
首页 / 资讯中心 / 正文

期货量化系统v3.0:从预测到风控的工程化重构

在期货量化这条路上摸爬滚炮了十多年我越来越确信一件事真正难的不是模型而是把一个预测系统从研究台上能用推到实盘环境能扛。QuantVortex这个项目从v1.0的雏形走到今天v3.0中间经历了两次几乎推翻重建的迭代。这一版的核心变化可以概括成一句话从预测涨跌转向管理预测的不确定性。这篇文章会完整拆解v3.0的架构设计、特征体系、预测引擎、风控与回测仿真逻辑以及上线后我实际踩到的坑。如果你是做量化开发、期货分析系统或者正打算把自己手里的预测代码工程化这篇应该能帮你省掉不少弯路。1. v3.0重写的直接原因v2时代困扰我的六个问题1.1 模块耦合从数据到信号一锅炖v2时期为了快速验证策略我把数据预处理、特征计算、信号生成、仓位建议全部写在一个大流程里。单看每个函数都很清晰运行起来也能出结果但一旦想替换某个环节就得动主流程。比如我想把信号生成从阈值判断换成机器学习概率输出这个看似简单的改动牵扯出了数据对齐、特征缓存、回测循环三个文件的修改。更麻烦的是v2里特征计算依赖了当时的全局状态——历史K线窗口、品种保证金率、手续费参数散落在各个.py文件里每次加载数据都伴随着各种隐藏依赖。v3.0重写时我定了两条硬规矩模块之间只通过标准数据结构通信不允许直接访问其他模块的全局状态每个模块必须有独立的输入输出测试样本。这两条规矩实施起来前期慢但后期改东西是真的快。1.2 样本内外表现差距大v2的模型在训练集上表现很好测试集也还行但一跑样本外就失效。当时我用的特征里有不少是事后才能知道的未来函数——比如用当天收盘后的统计量预测当天的涨跌方向这在回测里完全合理但实盘中等信号生成的时候那个统计量还没计算完。这类问题在回测里极容易被忽略就算你做了防泄漏处理某些全局标准化、滑动窗口中心化同样会引入未来信息。v3.0里我加强了对时间序列泄漏的检查后面特征工程部分我会细说。1.3 手续费与滑点预判的粗放处理v2时代的手续费参数是一个固定值滑点则在回测结束时统一扣减。听起来问题不大但实际交易中手续费对高频、中低频策略的影响差异很大滑点在趋势启动和震荡行情中的分布也完全不一样。用固定值回测出来的绩效遇到盘中极端行情实盘结果会和回测差一大截。v3.0将滑点建模和行情波动率挂钩手续费按具体合约参数的档位计算。虽然这会拖慢回测速度但换来的实盘可信度是值得的。1.4 为什么缝缝补补不如推倒重来v2后期我尝试过在原有代码上打补丁但每次修改都会引入新的bug。最后算了一笔账修补的工时成本加损失的机会成本已经超过了重写的工作量。所以v3.0的重写原则很明确不兼容旧代码但保留v2中验证有效的策略逻辑和核心算法思路。重写不是否定过去而是把那些散落的经验沉淀到统一的框架里让它变成一个可以长期演进的工程而不是一堆脚本的集合。2. 系统架构的重新划分预测、决策、执行三层解耦2.1 总览三层架构与数据流v3.0整体采用采集层、逻辑层、应用层的分层思想逻辑层内部再拆成三个相对独立的子模块信号预测模块负责读取标准化行情数据输出未来N周期的目标变量概率或期望幅度。这是一个纯计算组件不关心仓位。决策管理模块接收预测信号结合当前持仓、账户权益、风险限额输出目标仓位和可执行指令。这里包含了风控逻辑。执行与反馈模块负责把决策指令下推到模拟交易/实盘接口同时接收成交回报更新持仓状态。数据流方向是单向的——预测模块不感知决策结果决策模块不直接接触行情源执行模块只处理指令和回报。这样的单向依赖让调试和故障定位清晰很多。2.2 事件总线模块间通信的关键设计模块解耦只是第一步模块之间如何通信才是核心。v3.0引入了一个轻量级的事件总线Event Bus用Python标准库的queue和threading实现没有引入复杂的消息队列组件。核心事件类型包括MarketDataEvent行情数据到达由采集层写入总线FeatureEvent特征计算完成携带特征快照和对应的时间戳SignalEvent预测模块产出的信号包含目标方向、置信度、有效周期OrderEvent决策模块产生的目标委托包含合约代码、方向、数量、期望价格类型FillEvent模拟或实盘成交回报包含实际成交价格与数量整个系统跑起来后我经常在事件总线上挂一个录播器把每一条事件的产生时间和内容记录下来。这个设计在后期排查信号延迟错误成交时帮了我大忙——问题出现时直接回放事件流而不是靠日志打印去猜。2.3 技术选型与取舍技术栈整体如下语言Python 3.11核心计算用NumPy和Pandas模型训练用LightGBM数据存储K线数据和特征数据存Parquet文件按合约名和日期分区交易记录存SQLite回测引擎自研的事件驱动回测支持Tick级和分钟级模拟实盘对接通过CTP兼容接口连接期货公司柜台但v3.0默认使用模拟交易通道验证为什么没有上分布式、没有用专门的时序数据库因为现阶段系统的数据规模和计算频率还不至于需要那套基础设施。引入过多的组件只会增加运维负担这在个人维护的项目里是致命的。3. 特征工程模块清理K线与构建真正可用的特征集3.1 数据清洗的细节跳空、交割日与复权期货数据比股票数据麻烦得多。主力合约会换月、合约有到期日、不同品种的连续合约拼接方式不同而这些都会直接影响特征计算的连续性。v3.0的数据清洗模块做了这样几件事第一处理复权。期货连续合约的后复权算法核心是保证拼接点前后的价格序列不产生人为跳变。我用的是复权因子累乘法即以持仓量为权重把换月前的K线按比例换算到当前主力合约的价位水平。第二剔除交割日异常数据。临近交割的合约会出现流动性骤降和价格毛刺如果不处理特征计算会被这些极端值污染。清洗策略是距离交割日小于3天的K线不参与训练只保留在实时预测时作为参考。第三统一时间戳。期货夜盘交易时间跨天不同交易所的收盘时间点不同。如果直接把时间戳扔给模型它会学出晚上11点必涨这类无意义的规律。v3.0把所有K线统一映射到交易时段时间轴上即用交易日内的第几根K线作为序号特征。3.2 特征集的三层结构v3.0的特征集分为三层按计算复杂度和更新频率划分特征层级示例更新频率用途基础层OHLC、成交量、持仓量、成交额每根K线更新描述市场状态衍生层均线差、布林带位置、RSI、ATR随基础层更新捕捉动量和波动特征微观层主动买卖比、盘口撮合强度、主力资金流向估算分钟级更新刻画资金行为实际效果里微观层特征对期货中短周期的预测增益最大。比如主动买卖比即该K线内按主动买价成交的量与主动卖价成交的量的比值在关键价位附近对方向的区分度明显好于均线类指标。不过微观层数据的获取对数据源要求较高不是所有行情源都提供逐笔委托和成交明细。如果拿不到可以用大单占比这种基于分钟级成交拆分计算的近似指标替代。3.3 避免未来函数和特征泄漏的检查方法这是整个v3.0里我认为最有价值的部分。很多量化系统的预测结果虚高不是因为模型不行而是因为特征泄漏。常见的泄漏途径有三类标准化泄漏在全样本上计算z-score的均值和标准差再用这个均值去切分训练集。正确做法是用训练集的统计量去标准化验证集和测试集。标签对齐偏移预测第t1根K线的方向特征却用到了第t1根K线的收盘数据。这种情况在写代码时很容易出现特别是当特征窗口和标签窗口的索引没有严格区分时。信息渗入用了未来才会发布的库存数据、基差数据却假设这些数据在预测时刻已经可得。我在v3.0里写了一个泄漏检查器对每个特征列做滞后排列重要性分析——把该特征的时间戳随机打乱如果模型表现没有明显下降说明这个特征可能根本没用到时序信息或者本身就是噪音如果大幅下降则说明该特征和时序强相关需要再确认它的时序方向是否正确。3.4 特征重要性与实际取舍经过清洗和泄漏检查后我在螺纹钢和甲醇两个品种上做了特征重要性排序排名靠前的不是那些复杂的指标反而是一些基础的量价关系长周期动量过去20根K线的累计收益率方向持仓量变化率增仓还是减仓当前价格在近N日波动区间中的分位数成交量与持仓量的比值变化这些特征的共性是对市场状态反应迅速且没有复杂计算过拟合风险也低。反观那些加了大量参数的自定义指标往往换一个时间段就失效因为参数本身就是在拟合历史。4. 预测引擎从单一模型吃遍天到模型集成4.1 为什么从RNN切到LightGBMv2时期我主力用的是LSTM当时觉得深度学习做时间序列预测必然是趋势但实际样本外效果并没有比传统的梯度提升树好多少反而在训练时间和调参成本上高出好几倍。期货行情数据的信噪比非常低LSTM这类模型擅长捕捉的是高维复杂模式但在这种信号微弱决策边界明显的场景里树模型往往更稳。v3.0最终选了LightGBM作为主模型原因有三对特征尺度不敏感不需要精细归一化自带处理缺失值的能力实盘数据中断补全时更鲁棒训练速度快滚动重训练的成本低4.2 预测目标与模型集成策略预测目标我设计成了三分类概率未来N根K线的收益率大于正阈值为多小于负阈值为空中间为盘整。相比直接回归预测收益率数值分类任务的稳定性更强也方便后面接风控和仓位决策。模型集成上v3.0没有走复杂的Stacking而是采用**多窗口多特征子集的投票策略**用三组不同回看窗口如5根、10根、20根K线分别构建特征分别训练三个LightGBM分类器最终预测概率取三个模型输出的加权平均权重由近期样本外的AUC动态调整这样做的好处是单个模型如果过拟合到某个周期的波动另外两个模型可以中和掉偏差。实测下来集成后的预测AUC比单模型高出3到5个百分点更重要的是预测概率分布的稳定性明显提升。4.3 跨品种迁移与重训练节奏期货品种之间具有明显的联动性比如螺纹和热卷但直接把A品种训练的模型搬到B品种上效果通常不佳。v3.0采用的做法是全局预训练品种微调用所有流动性较好的品种数据训练一个基础模型针对每个目标品种用该品种近一年的数据对基础模型做增量训练每个品种保留自己的模型拷贝不共享参数重训练节奏上我最初每周末重训练一次后来发现周一到周五的盘面特征差异比想象中大现在改成每日收盘后增量训练用当天新数据更新模型每周做一次全量重训练。这样既能捕捉近期变化又不至于被短期噪音带偏。4.4 信号生成与置信度过滤模型输出的是三类概率多/空/盘整但真正下单不能只看概率大小还要看概率差。我定义了一个信号强度指标signal_strength max(p_long, p_short) - p_neutral只有当signal_strength超过某个阈值才产生交易信号。阈值设多少太保守或太激进都不好我用滚动三个月的历史信号强度分布来动态校准把阈值设在分布70到80分位之间保证每天平均只产生1到3次信号。5. 风控模块仓位管理才是真正赚钱的部分5.1 从预测收益到管理风险的思路转变很多做量化的人把精力全花在预测模型上但真正决定账户生死的是仓位管理。v3.0的风控模块遵循一个基本原则单次风险预算固定方向对了才加仓错了就止损。以10万元账户为例单笔交易最大亏损设定为账户权益的1%1000元那么开仓数量由以下公式决定开仓手数 (账户权益 × 1%) / (开仓价与止损价的价差 × 合约乘数)举例螺纹钢合约乘数10假设开仓价4000元/吨止损价3970元/吨价差30点。那么手数 (100000 × 0.01) / (30 × 10) 1000 / 300 ≈ 3手这样设置的好处是亏钱的单子永远只亏固定比例的钱不会因为情绪或行情剧烈波动突破风险预算。5.2 波动率过滤与市场状态识别v3.0加入了波动率状态识别模块根据ATR平均真实波幅的百分位把市场划分为四种状态低波动、正常波动、高波动、极端波动。不同状态下系统的处理逻辑不同市场状态ATR百分位系统行为低波动 20%正常出信号仓位乘数0.5正常波动20%-70%正常仓位高波动70%-90%仓位乘数0.5扩大止损距离极端波动 90%暂停开仓只处理已有持仓的风控光设阈值还不够。高波动和极端波动状态下价格可能在几秒内打到止损价这时候市价单的滑点会非常大。v3.0在高波动状态下会把止损单改成限价单追踪保护的结合方式避免在流动性瞬间枯竭的时候被扫损。5.3 模型退化检测与自动熔断预测模型在实盘环境中会悄悄退化——市场行为模式可能发生突变旧的规律不再适用。如果系统没有感知策略会连续亏损。v3.0设了三层熔断机制滚动胜率监控每50笔交易统计一次胜率和盈亏比如果滚动胜率低于模型预测概率对应的理论下限系统自动暂停新开仓。预测分布漂移检测对比近期模型输出的概率分布和历史训练集的概率分布用KL散度衡量。如果漂移超过阈值触发重训练。当日亏损熔断单日亏损达到账户权益的3%当天不再开新仓达到5%本周停止交易。熔断机制不是为了阻止亏损而是为了在不确定性升高的时候强制系统退后一步重新评估环境。这在实盘中救过我好几次。6. 回测与实盘的差距v3.0如何压低这一层水分6.1 回测结果为什么容易虚胖回测是量化系统最基础的可信度检验但大部分回测框架在细节上偏乐观。v3.0回测模块的改进集中在三个方面委托粒度、成交价格模拟、资金占用精度。委托粒度上v3.0支持市价单、限价单、止损单三种类型每种类型在撮合时的行为不同。限价单如果当根K线没有触及价位就挂在订单薄里等后续K线市价单按下一根K线的开盘价成交并且加入滑点偏移。成交价格模拟上我引入了盘口深度因子——当委托量超过当前盘口一档挂单量的30%时假设剩余部分以二档价格成交。这个设计对大委托的影响很大能更真实地反映冲击成本。6.2 滑点、手续费、保证金与强平的仿真期货交易成本里滑点往往是最大的一部分。v3.0的滑点模型采用固定跳数波动率复合的方式模拟滑点 基础滑点跳数 ATR × 滑点系数基础滑点跳数按品种流动性设定螺纹钢1跳甲醇1跳流动性差的品种2到3跳滑点系数取0.05左右意味着波动率越大模拟滑点越高。手续费方面v3.0按交易所真实费率分合约设置开仓和平仓费率分开平今和平昨也区分。这看起来是小事但对高频策略影响很大。保证金强平模拟也不能省。回测里如果浮亏导致保证金不足系统必须触发强平而不是假装交易还在继续。我见过不少回测系统在这个环节漏了导致回测绩效梦幻般地好。6.3 识别过拟合回测的几个信号回测结果好不代表策略好。我在v3.0里总结出几个判断回测是否过拟合的信号第一参数变化后绩效大起大落。如果一个参数从20变动到25年化收益从15%变成45%说明策略对参数极其敏感过拟合概率大。稳健的策略参数变化应该导致绩效小幅波动而非剧烈跳变。第二单笔交易最大盈利贡献过高。如果整个回测周期里前5笔最大盈利交易的合计贡献超过总盈利的60%说明策略在靠运气而不是靠概率优势。第三样本外测试的衰减幅度。把最近一年的数据作为样本外测试如果年化收益衰减超过50%说明模型学到的是历史模式而不是可迁移的规律。这些信号不能单看一个要结合起来评判。7. v3.0上线后遇到的真实问题与修复记录7.1 数据断流与程序状态恢复上线初期系统在一次盘中数据断流后出现了严重的仓位错乱。排查后发现断流期间行情时间戳没有更新但程序时钟还在走导致部分特征按零值参与计算模型的输出全部变成盘整而决策模块在盘整状态下应该保持不动但因为一个状态变量没有更新实际执行了错误的平仓指令。修复方案是加了一个行情心跳看门狗如果超过10秒没有收到行情推送系统自动进入持仓冻结状态所有新开仓指令不再执行已挂出的委托单全部撤销等行情恢复并确认特征缓存有效后再解除冻结。7.2 模型静默退化的应对另一个让我头疼的问题是模型退化不是突然发生的而是静默的。第一周一切正常第二周开始胜率缓慢下降等到触发熔断机制时已经连续回撤了好几天。后来我加了一个每日盘前自检流程每天早上加载最新模型输入最近5个交易日的行情数据生成预测和实际行情做对比输出预测精度快报。如果连续3天精度低于阈值就强制触发重训练而不是等亏损累积到熔断线再处理。这个改动让我从被动等回撤变成了主动识别漂移心态上踏实了很多。7.3 回测与实盘差异的最终收敛v3.0实盘运行三个月后我做了一次回测与实盘的全量对比。扣掉手续费和滑点之后实盘净值和回测净值的偏差控制在6%以内。余下的偏差主要来自盘中冲击成本比回测模拟还要高一点因为实盘市场深度在快速波动时比静态记录薄个别止损单在快速行情中的成交价差于模型假设整体来看v3.0的仿真精度已经达到了可信决策依据的水平。至少我不会再因为回测和实盘差太多而失眠了。7.4 还没解决的问题v3.0仍有两个待改进的方向。第一日线级别信号的研究深度不足。目前的预测引擎主要面向中短周期日线模型尝试过几次但效果不稳定还要继续打磨。第二多品种组合层面的风险聚合。现在每个品种都有自己的独立风控但组合层面的波动率预测还不够精细暂时用简单的固定比例分配替代。下一步想把组合优化模块补上。8. 实盘之外QuantVortex的工程化沉淀v3.0从0到1重新写代码工程上的沉淀比策略本身更有价值。配置管理所有品种参数、费率、止损逻辑、模型超参数都放在YAML配置文件中不写死在代码里。每次修改参数不用动代码系统热加载回测和实盘共用同一套配置。日志审计每个交易决策都会记录决策快照包括当时的预测概率、信号强度、持仓状况、可用资金、风险预算。这个快照是后期复盘的核心线索——为什么当时做出了这个决策而不是事后靠记忆猜。模块自检三个核心模块各有一个内置自检脚本每次系统启动时运行。如果特征数量不对、模型输出不在合理范围、账户权益与本地状态不一致系统拒绝启动或进入降级模式。这些工程化的投入看似不直接产生收益但在系统异常时能节省大量排查时间。对一个单人维护的系统来说时间就是最大的成本。根据我个人近一年的实盘运行经验期货智能分析系统的核心不在于预测多准而在于每个环节的不可靠性是否可控、可测量、可应对。QuantVortex v3.0目前已经形成了一套从特征到信号到风控到回测的完整闭环剩下的路还很长但至少每一段都踩实了。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门