惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
V2EX - 技术
V2EX - 技术
The Last Watchdog
The Last Watchdog
宝玉的分享
宝玉的分享
T
Tenable Blog
WordPress大学
WordPress大学
K
Kaspersky official blog
Microsoft Security Blog
Microsoft Security Blog
大猫的无限游戏
大猫的无限游戏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Hacker News - Newest:
Hacker News - Newest: "LLM"
P
Palo Alto Networks Blog
Help Net Security
Help Net Security
V
Vulnerabilities – Threatpost
Know Your Adversary
Know Your Adversary
C
CXSECURITY Database RSS Feed - CXSecurity.com
A
Arctic Wolf
Forbes - Security
Forbes - Security
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Cloudflare Blog
Hugging Face - Blog
Hugging Face - Blog
H
Hacker News: Front Page
W
WeLiveSecurity
博客园 - 【当耐特】
G
Google Developers Blog
Martin Fowler
Martin Fowler
TaoSecurity Blog
TaoSecurity Blog
Hacker News: Ask HN
Hacker News: Ask HN
人人都是产品经理
人人都是产品经理
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
AI
AI
N
Netflix TechBlog - Medium
C
Cisco Blogs
I
Intezer
aimingoo的专栏
aimingoo的专栏
博客园 - 聂微东
G
GRAHAM CLULEY
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
小众软件
小众软件
Blog — PlanetScale
Blog — PlanetScale
MyScale Blog
MyScale Blog
L
Lohrmann on Cybersecurity
Engineering at Meta
Engineering at Meta

土法炼钢兴趣小组的算法知识备份

国密算法与国密 TLS 系列索引 【系统架构设计】架构质量属性:不只是"高可用高性能" 【系统架构设计百科】告警策略:如何避免"狼来了" 【系统架构设计】CQRS:读写分离的架构哲学 【系统架构设计】空间架构:极端扩展场景的解法 【系统架构设计】微服务架构深度审视:优势、代价与适用边界 【系统架构设计】扩展性原理:水平、垂直与对角扩展 【系统架构设计】无状态设计:扩展的第一步也是最难的一步 【系统架构设计】缓存架构:从本地到分布式的多级缓存体系 【系统架构设计】管道与过滤器:Unix 哲学的架构表达 【系统架构设计】复杂性管理:架构的核心战场 【系统架构设计】消息队列架构:异步解耦的设计与陷阱 【系统架构设计】CDN 架构:全球加速的设计原理 【系统架构设计】连接池设计:被忽视的性能杀手 【系统架构设计】弹性设计模式:熔断器、舱壁与超时 【系统架构设计】高可用设计模式:冗余、故障转移与仲裁 【系统架构设计】容量规划:从拍脑袋到数据驱动 【系统架构设计】数据库扩展:分库分表的工程实践与替代方案 【系统架构设计】SLO 工程:可靠性的量化管理 【系统架构设计】性能建模:用数学思维分析系统瓶颈 【系统架构设计】混沌工程:主动验证系统的韧性 【系统架构设计】零拷贝与内存映射:数据搬运的极致优化 【系统架构设计】线程模型:从 thread-per-request 到协程 【系统架构设计】容灾架构:多活与灾备设计 【系统架构设计】数据库性能模式:索引、查询与连接管理 【系统架构设计】数据建模:从关系范式到文档模型的真实权衡 【系统架构设计】吞吐量优化:批处理、流水线与并发模型 【系统架构设计】流处理架构:从批处理到实时的范式迁移 【系统架构设计】搜索引擎架构:倒排索引之上的系统设计 【系统架构设计】时序数据架构:监控与 IoT 的存储设计 【系统架构设计】数据迁移与版本化:在线不停机的数据演进 【系统架构设计】数据湖与数据仓库:分析架构的演进路线 【系统架构设计】API 网关设计:入口层的职责边界 【系统架构设计】应用层数据一致性模式:在正确性与性能之间走钢丝 【系统架构设计】多模数据库选型:Polyglot Persistence 的工程实践 【系统架构设计】服务发现与注册:动态拓扑的基础设施 【系统架构设计】配置管理架构:从配置文件到配置中心 【系统架构设计】全链路压测:大规模系统的性能验证 【系统架构设计】幂等性设计:分布式环境下的安全重试 【系统架构设计】契约测试与 Schema 演进:服务间的信任协议 【系统架构设计】长连接与推送架构:WebSocket、SSE 与 MQTT 【系统架构设计】延迟分析:从 P50 到 P999 的全链路追踪 【系统架构设计百科】DDD 战术模式:聚合、实体与值对象 【系统架构设计百科】防腐层与开放主机服务:系统集成的 DDD 方案 【系统架构设计百科】领域事件与事件风暴:从业务到架构的桥梁 【系统架构设计百科】CQRS + Event Sourcing 完整实战:从领域建模到部署 【系统架构设计百科】DDD 与微服务:用领域模型划分服务边界 【系统架构设计】DDD 战略设计:限界上下文与上下文映射 【系统架构设计百科】认证架构:从 Session 到 JWT 到 OIDC 【系统架构设计】API 设计哲学:REST vs GraphQL vs gRPC 的真实权衡 排序算法专题:从 TimSort 到并行排序 【密码学百科】国密算法体系:SM2/SM3/SM4/SM9 全景解读 【密码学百科】承诺方案:Pedersen 承诺、向量承诺与多项式承诺 【密码学百科】不经意传输与隐私信息检索:OT、OT 扩展与 PIR 【密码学百科】门限密码学:门限签名、门限解密与分布式密钥生成 完美哈希:从理论到 gperf 实践 【密码学百科】安全多方计算:从 Yao 的混淆电路到实用 MPC 【密码学百科】同态加密:从 Paillier 到全同态加密(FHE) 【密码学百科】零知识证明系统:zk-SNARKs、zk-STARKs 与 Bulletproofs 【密码学百科】概率论与密码分析:生日攻击、差分分析与线性分析 【密码学百科】计算复杂性与归约:密码安全性证明的基石 【密码学百科】秘密共享:Shamir 方案、VSS 与安全多方计算入口 【密码学百科】椭圆曲线代数:Weierstrass 方程、点群运算与曲线选择 【密码学百科】离散对数与配对密码学:从 DLP 到 BLS 签名 【密码学百科】格密码数学基础:SVP、LWE 与格基约化 【密码学百科】抽象代数:群、环、域的密码学视角 【密码学百科】有限域算术:GF(2^n) 运算与在 AES/ECC 中的应用 【密码学百科】数论进阶:二次剩余、椭圆曲线上的 Weil 配对 【密码学百科】密码学简史:从凯撒密码到量子时代 【密码学百科】威胁模型与安全目标:CIA 三要素之外 【密码学百科】Kerckhoffs 原则与现代密码设计哲学 【密码学百科】随机性:密码学的基石 【密码学百科】信息论入门:熵、完美保密与 Shannon 定理 【密码学百科】分组密码原理:Feistel 网络与 SPN 结构 【密码学百科】AES 逐步拆解:SubBytes 到 MixColumns 的数学 【密码学百科】分组密码工作模式全览:ECB/CBC/CTR/OFB/CFB 【密码学百科】流密码:RC4 的兴衰与 ChaCha20 的崛起 【密码学百科】密码学哈希函数:MD5→SHA-2→SHA-3 的进化之路 【密码学百科】MAC 与 HMAC:消息认证的正确姿势 【密码学百科】认证加密(AEAD):GCM、ChaCha20-Poly1305 与 OCB 【密码学百科】密钥派生函数:HKDF、PBKDF2、Argon2 与密码存储 【密码学百科】公钥密码的数论基础:模运算、群、原根 【密码学百科】RSA 从原理到攻击:教科书 RSA 为什么不安全 【密码学百科】Diffie-Hellman 密钥交换与离散对数问题 【密码学百科】椭圆曲线密码学(ECC):从几何直觉到点群运算 【密码学百科】数字签名:ECDSA、EdDSA 与 Schnorr 签名 【密码学百科】现代密钥交换:X25519、ECDHE 与前向保密 【密码学百科】混合加密与 KEM/DEM 范式:ECIES 与 HPKE 【密码学百科】填充方案:PKCS#1 v1.5、OAEP 与 PSS 【密码学百科】TLS 协议全解析:从握手到 0-RTT 【密码学百科】PKI 与数字证书:信任链的构建与崩塌 【密码学百科】密码认证协议:从 SRP 到 OPAQUE 【密码学百科】零知识证明入门:如何证明你知道而不泄露 【密码学百科】安全信道构造:Noise 协议框架与 Signal 协议 【密码学百科】密钥管理工程:HSM、KMS 与密钥生命周期 【密码学百科】侧信道攻击:从时序攻击到功耗分析 【密码学百科】密码学实现陷阱:三层漏洞分类、审计工具链与系统性预防 密码敏捷性:如何设计可升级的密码系统 【密码学百科】OpenSSL/BoringSSL 架构剖析:ENGINE、Provider 与 FIPS 模块 排序基准测试:用数据说话
【量化交易】量化交易全景:从信号到订单的工程链路
2026-05-01 · via 土法炼钢兴趣小组的算法知识备份

风险提示:本系列为工程参考,不构成投资建议。文中出现的策略骨架、因子、参数、阈值都是为了说明工程链路而保留的最小例子,不代表任何可直接上线的方法。

写过策略代码的人多半都遇到过这种场景:在 Jupyter 里跑出年化 35%、夏普 2.6、最大回撤 8%,曲线漂亮得不真实;接到模拟盘里第一个月就跌了 4%,再上实盘第一周直接被滑点和手续费吃掉一半收益。然后开始返工:是不是用了未来函数?是不是停牌没处理?是不是涨跌停日成交假设过乐观?是不是回测里没扣印花税?是不是复权方式搞错了?是不是把因子值用了今天才发布的财报?

这些问题不是策略写得不好,是工程链路没接好。量化交易的难点从来不是想到一个能赚钱的想法,而是把一个有效的想法在不被工程坑吃掉的前提下落到实盘。这条链路从一根 K 线进入数据库,到一笔订单从交易所成交回报回流,要走过至少八段,每一段都有自己的输入输出、失败模式与不变量。

这个系列的目标,是把这条链路上每一段的工程方法讲清楚。我们不讲”明天涨什么”,我们讲:

  • 一份行情数据从交易所发出来,怎么落到一张能被回测复用、又不引入未来函数的表里;
  • 一个因子从公式到能进入组合优化器,要经过哪些清洗、对齐、中性化、检验;
  • 一个回测引擎要做到什么程度,才能让模拟盘和实盘的偏差小于一个可解释的范围;
  • 一笔目标交易要被拆成多少子单、走哪些场所、用什么算法,才能让冲击成本不把 Alpha 吃掉;
  • 一套风控要在哪几个时间点拦在哪几条链路上,才能在策略失控的瞬间把钱守住。

这是【量化交易】系列的第 1 篇,承担两件事:第一,把整条链路的骨架画清楚,让后续 28 篇每篇都能挂回这张图;第二,给出一份”研究 → 上线”的流程清单,让读者在自己写第一条策略之前就知道每一步的卡点在哪。


一、什么是量化交易:从直觉到工程

1.1 一个不太严谨但够用的定义

量化交易(Quantitative Trading)这个词在工业界被用得很宽:它既包括”用 Python 跑回测、买基金”的散户量化,也包括”FPGA 解 ITCH 包做高频做市”的机构 HFT,中间还有股票多因子、CTA 趋势跟踪、统计套利、可转债套利、加密做市、跨期跨品种套利。这些事看起来差异很大,但都满足三个共同特征:

  1. 决策由可表达为代码的规则或模型驱动,而不是由交易员的主观判断驱动;
  2. 执行由系统自动完成,至少在”何时下单、下多少、撤不撤”这些动作上不依赖人;
  3. 效果可统计度量,能用收益、夏普、回撤、信息比率这些指标评价。

这三条同时成立的系统,就是量化系统。少一条都不算:

  • 只有规则、靠人下单,是”半自动交易”;
  • 有自动执行、但参数靠拍脑袋调,是”程序化交易”,不一定是量化;
  • 模型存在、但效果无法度量,是”调参玄学”。

主观投资(discretionary trading)与量化的边界并不在”用不用电脑”,而是在”决策是否可复现”。一位基金经理把所有买卖逻辑写在 Excel 里逐单录入,仍然是主观;一套基于神经网络的策略,如果同样的输入永远给出同样的输出,就是量化,不论里面藏着多少黑盒。

1.2 量化的四个层次

把量化系统拆成四个层次,对后续每一篇都有用:

层次 含义 输出物 典型角色
因子(Factor) 对某种市场异象的可计算度量 截面数列:每个标的每个时点一个数 研究员
信号(Signal) 把因子转换成”对未来收益的预测” 预期收益向量 + 不确定度 策略研究员
策略(Strategy) 信号 + 风险 + 执行约束 → 目标持仓 目标持仓与目标交易 策略工程师
系统(System) 把策略落地的全部基础设施 一条能稳定运转的流水线 量化工程师 / SRE

很多团队的事故都来自层次混淆。研究员认为”因子做得好就行了”,工程师认为”系统稳定就行了”,没人对”信号到策略到系统”那一段负责,于是因子在研究环境是有效的,进了实盘就失效。本系列在每一篇都会标注它在哪个层次:

  • 第 9–14 篇是因子层;
  • 第 12、13 篇与 ML 相关的部分跨到信号层;
  • 第 15–17 篇是策略层;
  • 第 23–28 篇是系统层。

1.3 量化能赚什么钱

工程文章不预测市场,但”系统设计为什么这么设”绕不开这个问题。市场里能被量化系统稳定收割的钱,大致来自下面几类:

  • 风险溢价:长期承担某种风险(市场风险、波动率风险、流动性风险)应得的补偿。指数增强、Smart Beta、风险平价大都吃这类钱;
  • 市场异象:投资者群体的认知偏差、行为偏差、机构约束(如指数调样、季末美化报表)造成的可预测偏离。多因子、动量、反转、分析师预期修正吃这类;
  • 微观结构:订单簿不平衡、盘口报价的短期回归、做市商库存调整带来的微观可预测性。HFT 与做市吃这类;
  • 结构性套利:同一现金流的多种表达之间的价差。期现套利、ETF 套利、跨期跨品种套利、可转债套利吃这类;
  • 信息差:基本面研究、另类数据挖掘、新闻舆情对市场未消化信息的提前解读。事件驱动与基本面量化吃这类。

不同钱对应不同的工程要求:HFT 拼时延,统计套利拼协整稳定性,基本面量化拼数据与因子库,做市拼库存控制与风控速度。后续每个具体策略类的篇章都会先回答”它在赚什么钱”,再讲怎么实现。

1.4 量化不能解决的事

工程方法不是万能。下面这些问题,再好的系统也解决不了:

  • 市场逻辑变化:政策变更、做空机制改变、注册制、股指期货受限、加密交易所被封禁,这些事件下历史规律会失效;
  • 容量边界:一个 5 亿规模可行的策略,做到 50 亿可能完全不行。任何回测在容量上都有上限,不靠工程突破;
  • 黑天鹅尾部:再好的风控也只能压住可统计的尾部,对真正的”未见过的事件”(2015 股灾、2020 原油负油价、2022 LME 镍逼空)都需要硬性熔断兜底;
  • 过度拟合:再大的模型也会在训练集上漂亮,事前检验它会不会失败,是研究问题,不是工程问题。

工程只能保证”如果策略在历史上是有效的,工程不会把它的有效性吃掉”。能不能找到一个真正有效的策略,是另一回事。


二、量化交易的工程链路

2.1 一张图:八段链路

把整个量化系统的数据流拆开,从左到右一定经过这八段:

数据 → 特征 → 因子 → 信号 → 组合 → 执行 → 风控 → 复盘
                                                     ↑
                                                     └── 反馈到数据/特征/信号

每一段都有清晰的输入输出,每一段都有自己的失败模式:

输入 输出 主要失败模式
数据 交易所原始行情、基本面、参考数据 干净、对齐、PIT 安全的表 时间错位、复权错、停牌缺失
特征 干净表 标的 × 时点的数值矩阵 未来函数、横截面泄漏
因子 特征矩阵 经过中性化、标准化的因子 极端值、行业暴露、风格暴露
信号 因子 + 模型 预期收益与不确定度 过拟合、时序泄漏、样本不平衡
组合 信号 + 风险模型 + 约束 目标持仓 协方差病态、约束不可行
执行 目标持仓 - 当前持仓 实际成交 滑点、冲击成本、未成交残单
风控 全链路状态 放行/限制/熔断 漏拦、误杀、规则缺口
复盘 实际成交、行情、信号 归因报表与反馈 归因方法错误、口径不一致

下面这张系统架构图把这八段画成层,并标出每段对应的本系列章节:

量化交易系统架构

图里有三种箭头:

  • 实线表示数据/指令的前向流动;
  • 红色虚线表示风控的控制流(前置/在途/事后三层),它不是数据流,是一票否决权;
  • 绿色虚线表示成交回报的回流,从交易所一路回到回测/复盘,是闭环的关键。

很多团队画系统图只画前向,会漏掉两件事:风控的控制流和成交回报的回流。只要有一处回流被切断,复盘就会和实盘对不上,时间一长策略就成了黑盒。

2.2 数据:能不能正确用昨天

数据这一段决定整条链路的下限。它的工作不是”把行情存进去”,而是回答一个问题:你能不能在 t 时刻只用 t-ε 之前真实可得的数据做决策。这个能力叫 PIT(point-in-time)安全。

一份不 PIT 安全的数据有很多种死法:

  • 用了财报数据,但用的是”事实发生时的财报值”而不是”在那个时点市场实际看到的财报值”。财报会被更正、被审计调整、被重述(restatement),如果数据库覆盖更新而不是版本化,回测会看到当时不可能看到的修正版数字;
  • 把分析师一致预期写在预测发布日,而实际上 Bloomberg、Wind 是按日发布、可被回填的,要拿”快照”而不是”现值”;
  • 复权用了未来除权信息:如果用前复权日线在某个 t 上算昨日收益,分母里嵌入了 t 之后的除权因子,等于偷看未来;
  • 上市日、退市日、停牌日没有专门的状态字段,回测里”停牌日成交”就发生了。

数据段的不变量大致有四条:

  1. 任意一个数据点必须有”被市场看到的时间戳”asof,与”事件发生时间戳”event_time 分开存;
  2. 同一字段被多次发布的,必须按版本保存,不能覆盖;
  3. 任何一个时点 t 的查询,等价于 WHERE asof <= t,不允许出现 WHERE event_time = t
  4. 复权因子要按时点存,回测查询时给复权因子绑定 asof,不能用”当前最新的复权”。

第 5、6、7 篇会把这四条不变量在工程上怎么做钉死。

2.3 特征与因子:把数据变成可比的数

特征是从数据里算出来的”中间变量”,因子是把特征变成”对截面有信息量的数列”。两者的边界没那么清晰,但工程上有个朴素的区分:

  • 特征:可以是任意尺度、任意分布、任意单位的数值,例如”过去 20 日成交量”、“市值”、“过去 60 日收益的偏度”;
  • 因子:经过横截面处理、能直接和别的因子加减比较的数列,通常做过去极值、标准化、行业中性化、市值中性化。

工程上有几个反复犯的错误:

  • 直接用原始市值做因子,结果整张表被几只权重股带着走,完全不是”小市值溢价”,是”按市值排序”;
  • 滚动统计窗口对停牌不处理,停牌日补 0 把波动率算崩;
  • 横截面排序用 rank 但没排除 NA,rank 方法不同结果差很大;
  • 因子之间高度相关却没去相关,多因子合成等于在一个方向上加了几次仓位。

第 7、9 篇专门讲因子工厂、第 8 篇讲另类数据特征,每一类问题都会给出代码级的处理方案。

2.4 信号与组合:从预测到目标

信号是把因子翻译成”预期收益”。最简单的是单因子线性映射,复杂的是 LightGBM 或 LSTM 给出条件分布。但不论模型多复杂,输出都要落到两个量上:

  • 每个标的的预期超额收益 alpha_i
  • 每个标的预期收益的不确定度 sigma_i,或更一般地,整张协方差矩阵 Sigma

组合优化的工作是把 alphaSigma 在一组约束下变成目标持仓 w*

maximize    w^T alpha - 0.5 * lambda * w^T Sigma w - cost(w, w_prev)
subject to  sum(w) = 1(或 0,市场中性)
            |w_i| <= w_max
            beta_exposure(w) ∈ [-b, b]
            industry_exposure(w) ∈ [-h, h]
            turnover(w, w_prev) <= T

这是教科书写法。工程上需要回答更朴素的问题:

  • Sigma 怎么估计才能不病态?历史协方差直接用,标的多了立马奇异;
  • 约束写错一个不等号,优化器会给出极端解,怎么发现?
  • 上一期目标持仓没有完全成交,新一期是否要把残单算进 w_prev
  • 优化器无解的时候降级到什么?回到上期持仓还是按比例缩放?

第 15、16、17 篇会给出具体的工程化方案,特别是 cost 函数的写法——它既要包含手续费、印花税,也要包含冲击成本的二次项,不然优化器会算出一份在”没有市场摩擦”假设下漂亮、在真实市场里瞬间被冲击吃掉的目标持仓。

2.5 执行:把目标持仓变成成交

执行是被低估得最厉害的一段。研究员写完信号交给”执行模块”的那一刻,往往觉得自己的工作做完了;但一份目标持仓和一份实际成交之间的差距,常常比信号本身的 Alpha 还大。

执行段要回答的问题:

  • 目标交易在多长的窗口内完成?秒级、分钟级、小时级、整日?
  • 拆成多少子单?每个子单挂哪个价位?挂多久?
  • 没成交的部分是追价、撤掉、还是等下一根 K 线?
  • 多场所怎么路由?暗池、做市商询价、限价簿、竞价撮合各占多少?

这些问题对应不同的执行算法:VWAP(成交量加权平均价)、TWAP(时间加权平均价)、POV(参与率)、IS(实施差额,Implementation Shortfall)、Adaptive。第 23、24 篇会讲执行算法与智能订单路由(SOR),并给出”执行成本怎么测、怎么归因”的方法。

执行段的不变量有两条最关键:

  1. 每一笔下单必须带一个全链路唯一的 client_order_id,与回报匹配;
  2. 一个交易意图在系统里只能对应一份”在途订单状态”,禁止重复下单。

这两条在第 27 篇 OMS/EMS 架构里展开。

2.6 风控:三层一票否决

风控分三层,对应三个不同的时间尺度:

  • 前置(Pre-trade):在订单发出去之前拦。检查单笔金额、单标的当日累计、自成交(self-trade)、涨跌停、流动性、可融券与否、限制名单。
  • 在途(At-trade):订单在外、还没全部成交时拦。实时持仓、实时盈亏、风险敞口、Beta、行业暴露、币种敞口。
  • 事后(Post-trade):成交回报回流后做合规复核。监管报送、账务勾稽、日终核对。

工程上最常见的风控故障:

  • 风控做在策略代码里而不是独立通道里,策略 bug 一并把风控绕过;
  • 实时持仓由本地状态估计,没用交易所回报兜底,断线后状态漂移;
  • 涨跌停判断只看价格不看状态,连续一字板时仍然挂单消耗席位;
  • 自成交检查只在同账户内做,没考虑同主体下多个账户。

第 16、19、25 篇会分别讲撮合层、组合层、做市层的风控做法。本系列的核心立场是:风控必须是独立通道,必须有”安全默认是拒绝”的能力,必须能在毫秒级熔断

2.7 复盘:闭环的最后一段

复盘的工作不是事后写报告,是把实盘结果反哺回研究流程。一份合格的复盘要回答:

  • 实盘收益与回测收益的差距来自哪里?滑点占多少?费率占多少?信号衰减占多少?容量边际占多少?
  • 哪些标的的成交价显著差于预期?是流动性问题还是模型问题?
  • 哪些信号在最近 N 天的 IC 显著下滑?是统计噪声还是结构性失效?

第 22 篇会给出一套”实盘 - 回测差异分解”的口径模板。这一段的工程要点是口径一致:复盘用的费率、滑点假设、撮合假设必须和回测引擎完全一致,否则你比的是两套系统而不是策略本身的有效性。


三、关键约束:时间正确性

3.1 量化系统里时间有几种

普通系统里的时间通常只有一种:墙上时钟。量化系统里至少有六种,必须分清:

时间名 含义 典型来源
事件时间(event_time) 事件在现实中发生的时间 交易所撮合时间、财报披露时间
采集时间(capture_time) 数据被你的系统首次采到的时间 行情接收器入队时间
可见时间(asof) 市场上一般参与者能看到该数据的时间 撮合时间 + 网络延迟
决策时间(decision_time) 策略基于已知数据做出决策的时间 信号生成时刻
下单时间(submit_time) 订单离开本系统的时间 网卡发出时间
成交时间(exec_time) 交易所撮合该订单的时间 成交回报中的时间字段

回测里只能用 asof <= decision_time,不能用 event_time <= decision_time。事件时间小于决策时间不代表那个时点你能看到,这是新手最常踩的坑。

3.2 未来函数:从公式到代码

未来函数(look-ahead bias)是指一个本应只能用 t 时刻及以前数据计算的量,事实上偷用了 t 之后的数据。常见形态:

  • 未对齐的滚动窗口pandas.rolling(20).mean() 默认右对齐,没问题;但 rolling(20, center=True) 就是中心对齐,会用到未来 10 个点;
  • 整体标准化:在整段历史上用 (x - x.mean()) / x.std() 做归一化,均值方差用了全样本,等于偷看未来;
  • 填充错误fillna(method='bfill') 用未来值回填;
  • 联表错误:把财报数据按 report_date 联到行情上,但市场看到财报要等 announce_date(通常晚 30–90 天);
  • 复权错误:用前复权日线计算昨日收益,分母嵌入了之后的除权因子。

工程上防止未来函数有三层:

  1. 数据层:所有事实表都带 asof,查询封装强制 asof <= t
  2. 特征层:滚动窗口默认右对齐,禁止 center=True,禁止整体标准化(用 expanding 或滚动窗口替代);
  3. 回测层:撮合假设必须延迟一根 bar,即 t 时刻信号只能用 t+1 的开盘价或 VWAP 成交。

3.3 复权与停牌:两种最常见的隐形未来

复权和停牌看起来是数据问题,本质是时间问题。

复权有三种:不复权(原始价)、前复权、后复权。前复权是最常用的,但它的复权因子依赖未来的所有除权除息事件。一个回测如果用”今天最新的前复权数据”在历史时点上做信号,整段历史的价格已经被未来事件污染了。

正确做法:保留原始价 + 一张 (asof, factor) 表,回测查询时按 asof 取当时已知的复权因子。等价的实现是后复权(以历史某点为基准向后累乘),它有一个好性质——历史值固定不变,后续除权事件只追加新数据,不修改老数据。

停牌带来的问题更隐蔽:

  • 停牌日不应该出现在样本里,但很多数据源会用前一日收盘价填补,pct_change 算出 0% 收益,假装连续;
  • 停牌期间发生的事件(增发、并购、退市预警)在复牌日一次性反映,回测里如果不识别”复牌跳空”就会把跳空算成正常收益;
  • 停牌日不能下单,但回测如果按”日线收盘价成交”会假装能成交。

第 6 篇会给出停牌处理的几条标准动作。

3.4 三套环境的时间语义

研究、回测、实盘三套环境对时间的处理是不同的,工程上必须对齐:

环境 时间推进方式 数据可见性 撮合假设
研究 事后批处理 全样本可见 不撮合
回测 按 bar 推进 asof <= t 模拟撮合(滑点/延迟模型)
实盘 真实墙上时钟 真实可见 真实撮合

研究阶段允许用全样本,但只能用于”探索”,不能用于评价策略表现;回测阶段必须严格按时间推进;实盘则没有”重来一次”的机会。

第 19 篇专门讲回测引擎的时间引擎怎么写,第 20 篇讲常见的时间相关坑(前视、生存者偏差、再平衡时机偏差)。


四、买方与卖方视角

4.1 角色差异

量化系统的设计思路在买方与卖方之间差异很大:

  • 买方(Buy-Side):基金、自营、对冲基金、量化私募。目标是用资金赚收益,关心 Alpha、风险、容量、Sharpe;
  • 卖方(Sell-Side):券商、做市商、经纪商、交易所、流动性提供者。目标是为客户提供流动性或工具,关心做市利差、佣金、滑点、库存。

简单粗暴的对照:

维度 买方 卖方
目标函数 风险调整后收益 流动性提供 + 价差 + 佣金
时延要求 多数策略秒级到日级,少数毫秒 几乎全部微秒级
持仓方向 主动选 Alpha 被动跟随客户/市场
风控重点 组合层风险 库存与单笔风险
系统重点 研究 → 回测 → 组合优化 → 执行 行情 → 撮合/做市 → 风控 → 清结算

4.2 系统设计差异

买方系统重在研究链路:数据平台、因子库、回测引擎、组合优化器、归因分析。执行通常用券商提供的算法或外部 EMS,不必自己造。

卖方系统重在低延迟链路:行情解码、撮合、做市报价、风控网关、订单路由、监管报送。研究在卖方更多体现为定价模型与做市参数调优,不是 Alpha 挖掘。

两者中间还有一类——量化做市与高频套利,介于买方与卖方之间,靠极低延迟在订单簿上做被动或半主动报价。第 25、26 篇会专门讲做市与 HFT 架构。

本系列以买方视角为主线(第 1–22 篇),同时覆盖做市/HFT 与系统工程(第 23–28 篇)。读者可以按自己角色选择重点。


五、市场覆盖:A 股、美股、期货、加密

5.1 市场结构差异速查表

下面这张表是多市场量化的”地理常识”,必须记住:

维度 A 股 港股 美股 国内期货 加密(中心化)
撮合机制 集合竞价 + 连续竞价 同左 连续竞价 + 收盘竞价 集合 + 连续 连续竞价(订单簿)
交易制度 T+1 现货 T+0 T+0 T+0 T+0
涨跌停 ±10%(创业板/科创板 ±20%,ST ±5%) 各品种不同 多数无
最小变动价位 0.01 元 0.001/0.005/0.01 等 0.01 美元(个别 0.0001) 各品种不同 各币对不同
卖空 融券受限,标的池小 可做空 可做空 可做空(双向) 可永续合约做空
交易费率 佣金(万 1–3)+ 印花税(卖出千 1)+ 过户费 印花税 + 佣金 + 交易征费 极低佣金 + SEC 费 万 0.5 左右 0.02%–0.1%
数据 Level 2 可买(券商/数据商) 可买 NASDAQ ITCH / NYSE Pillar 可买 API 公开
交易时间 9:30–11:30 / 13:00–15:00 9:30–12:00 / 13:00–16:00 9:30–16:00 ET 多时段含夜盘 7×24

每一栏背后都对应回测里的一行代码:

  • 涨跌停 → 回测里要加”涨停日不能买、跌停日不能卖”逻辑;
  • T+1 → 当日买入的股票当日不能卖,组合优化的 w_prev 要分”可卖部分”和”今日新买部分”;
  • 印花税单边 → 卖出成本明显高于买入,导致换手率敏感的策略偏好低换手;
  • 最小变动价位 → 滑点模型不能假设连续价格,必须按 tick 离散化。

5.2 A 股的几个特殊约束

A 股是国内量化的主战场,有几个其他市场少见的约束,单独列出:

  • T+1:买入当日不能卖,导致日内反转策略受限;
  • 涨跌停:连续涨停板期间订单簿极不平衡,挂单基本无法成交,回测必须把”一字板”识别出来;
  • 集合竞价:开盘前 9:15–9:25 的集合竞价规则与连续竞价不同,9:25 撮合的成交价是开盘价,回测里”按开盘价成交”必须区分”集合竞价撮合到的”和”开盘后第一笔连续撮合”;
  • 科创板/创业板涨跌停 20%:要按板块查涨跌停幅度;
  • 新股次新股:上市头几日无涨跌幅限制,波动极大;
  • 退市制度:ST、退市整理期标的的特殊规则。

第 2 篇会把这些约束铺开讲,并给出回测引擎里对应的开关。

5.3 加密的特殊性

加密市场的工程难点和传统市场不一样:

  • 7×24 无休市:没有日切,没有”昨日收盘”的天然对账锚点,要自己定义结算窗口;
  • 多场所流动性碎片化:同一币种在数十家交易所交易,价差与流动性差异巨大;
  • 现货/合约/永续/期权混合:永续合约的资金费率(funding rate)决定持仓成本,CEX 和 DEX 还要分开;
  • API 限速:交易所 REST/WebSocket 限速严格,下单链路要自己做速率控制;
  • 交易所风险:交易所本身可能跑路、被黑、暂停提现,工程上必须把”账户余额”和”链上余额”分开核对。

第 14 篇专门讲加密策略的工程化,包括跨所搬砖、资金费率套利、做市等。


六、研究流程:从想法到上线

6.1 一张图

研究流程图把”一个想法到一笔实盘订单”中间的所有关键卡点串起来:

量化研究流程

整个流程有 12 个步骤,6 道关键卡点(G1–G6)。每一道卡点都是一次”go / no-go” 决定,不通过就回到上一步或者放弃。

6.2 每一步的关键动作与卡点

1. 假设

  • 用一句话写出可证伪的假设。例如:“过去 20 日成交量加权动量在 A 股全市场截面上在未来 5 日有正向预测能力。”
  • 不允许写”我觉得动量有用”这种没法证伪的话。

2. 因子构造

  • 明确每个数据源的 asof 字段;
  • 处理停牌、复权、新股、退市;
  • 行业中性化(按申万一级)、市值中性化(对 log 市值回归取残差);
  • 极值处理:MAD 或分位数截断;
  • 标准化:z-score 或 rank。

卡点 G1:因子 PIT 校验通过。把因子计算往前挪一天,结果应该完全一致;如果不一致说明哪里偷看了未来。

3. 单因子检验

  • 计算 IC(信息系数)、Rank IC、IC_IR;
  • 分组:把因子值按截面排成 10 组,看分组收益是否单调;
  • 衰减:因子值在未来 1、5、10、20 日的预测能力衰减半衰期;
  • 行业/风格暴露:检查因子在哪些行业/风格上集中。

卡点 G2:Rank IC 显著(t > 2)、IC_IR > 0.5、衰减半衰期 ≥ 调仓周期。不通过则回到第 2 步调整因子定义。

4. 多因子合成

  • 因子之间的相关性矩阵,相关性 > 0.7 的因子做正交化或剔除;
  • 加权方法:等权、IC 加权、ICIR 加权、ML 合成;
  • 合成后的总因子重新做单因子检验,看 IC 是否提升。

5. 组合构建

  • 设定约束:换手率上限、单标的权重上限、行业偏离上限、风格偏离上限;
  • 优化目标:均值方差 / 风险预算 / 凯利近似;
  • 协方差矩阵估计:样本协方差 + Ledoit-Wolf 收缩,或多因子风险模型。

6. 回测

  • 撮合假设:t 信号 → t+1 开盘价或 VWAP 成交;
  • 滑点模型:固定滑点 / 比例滑点 / 平方根冲击模型;
  • 费率:佣金 + 印花税 + 过户费 + 平台费;
  • 样本切分:样本内训练,样本外验证,留一段不许碰的最终样本。

卡点 G3:扣除真实费率与冲击成本后,样本外 Sharpe 仍然显著为正、最大回撤可控、收益分布无极端尾部依赖。

7. Walk-forward 验证

  • 滚动训练:每隔 N 个月重新训练,前 K 个月做训练,后 1 个月做检验;
  • 参数稳健性:在合理参数邻域内表现是否稳定,曲面是否光滑;
  • 结构断点:把样本按时间切几段,每段表现是否一致。

8. 容量估计

  • 把目标交易量映射到日均成交量(ADV)的占比;
  • 估计冲击成本:常用平方根模型 impact ∝ σ * sqrt(Q/ADV)
  • 给出”在不同管理规模下的预期净 Alpha 曲线”。

9. 模拟盘

  • 使用真实行情、模拟下单、影子账户,跑 1–3 个月;
  • 关键指标:模拟盘日收益与回测日收益的 Pearson 相关、绝对差距、滑点偏差;
  • 不一致就回到第 6 步,检查回测假设。

卡点 G4:模拟盘与回测的日收益相关性 > 0.8,日均偏差 < 一定阈值,滑点偏差能解释清楚来源。

10. 灰度上线

  • 先用 1%–10% 的目标资金试运行;
  • 限速:单日最大下单笔数与金额;
  • 监控:滑点漂移、IC 衰减、持仓异常、交易所拒单率。

卡点 G5:灰度期内监控指标无系统性漂移,无非预期事件。

11. 全量上线

  • 资金分批上调;
  • 持续监控 + 日报 + 周报;
  • 异常熔断阈值预先定义。

12. 复盘归因

  • 实盘收益 = 信号收益 - 滑点 - 费率 + 残差;
  • 残差大的话定位到某几只标的或某几日;
  • 归因结果反馈到下一轮的假设。

卡点 G6:归因模型对实盘 - 回测差异的解释力 > 阈值,否则视为偶然或存在未识别风险。

6.3 每一步的常见卡点

步骤 常见卡点 处理
1 假设含混无法证伪 写一句话假设
2 因子值含未来数据 PIT 校验脚本
3 IC 显著但分组不单调 检查极值与行业暴露
4 多因子合成后 IC 反而下降 因子相关性筛选
5 优化器无解 / 极端解 约束放宽 + 协方差收缩
6 回测漂亮、滑点崩 加更激进的冲击模型
7 参数曲面陡 视为过拟合,丢弃
8 容量太小 直接放弃或按容量缩规模
9 模拟与回测偏差大 检查回测假设、对齐口径
10 灰度期 IC 衰减 暂停,研究是否结构性失效
11 实盘异常 熔断
12 归因解释力不足 视为偶然,暂停加仓

七、本系列的边界

7.1 我们讲什么

【量化交易】系列覆盖以下内容

  • 市场结构与微观结构(第 2、3、4 篇):交易制度、订单类型、订单簿动力学;
  • 数据工程(第 5、6、7、8 篇):行情管道、生存者偏差、特征存储、另类数据;
  • 因子与信号(第 9、10、11、12、13 篇):经典因子、统计套利、事件驱动、ML/DL;
  • 加密策略(第 14 篇);
  • 组合与风险(第 15、16、17 篇):组合构建、风险模型、仓位管理;
  • 执行成本(第 18 篇);
  • 回测(第 19、20、21、22 篇):引擎、坑、Walk-forward、绩效;
  • 执行算法(第 23、24 篇):VWAP/TWAP/IS、SOR;
  • 做市与 HFT(第 25、26 篇);
  • 系统架构(第 27 篇);
  • 运维与合规(第 28 篇)。

7.2 我们不讲什么

下面这些不在本系列覆盖范围:

  • 具体的可上线 Alpha:不公开任何”现在还能赚钱”的因子或参数;
  • 投资建议:本系列不给买卖建议,不预测市场,不评价具体标的;
  • 撮合引擎实现细节:撮合是交易所/经纪商侧的工作,已由 【金融科技工程】系列 第 16 篇覆盖;
  • 清算结算:见 【金融科技工程】系列 第 11、18 篇;
  • 监管细则:见 【金融科技工程】系列 第 21 篇;
  • 传统投研基本面分析:本系列只讲量化方法,不讲行业研究、估值模型、价值投资。

7.3 与其他系列的引用关系

【量化交易】与【金融科技工程】是互补的。简单划线:

  • 金融科技工程 关心”钱怎么不丢”——账务、清算、合规;
  • 量化交易工程 关心”钱怎么变多”——信号、组合、执行。

两套系统在交易所/经纪商侧汇合:撮合是金融科技的工作,发单与回报是量化交易的工作。

与【分布式系统】系列也有交叉:消息总线、时序数据库、共识算法,量化系统都用得上,但本系列不重复讲分布式基础,需要时引用 【分布式系统】系列


八、阅读路径

整个系列共 28 篇,不同读者可以按下面四条路径选读。

8.1 入门路径

目标:建立量化的世界观,能跑通第一个回测。

  1. 第 1 篇(本篇)
  2. 第 2 篇 市场结构
  3. 第 5 篇 数据管道
  4. 第 6 篇 生存者偏差
  5. 第 9 篇 因子库入门
  6. 第 19 篇 回测引擎
  7. 第 22 篇 绩效指标

读完这 7 篇能写出一个”不犯严重错误的回测”。

8.2 策略路径

目标:理解多种策略类型与适用边界。

  1. 第 9 篇 因子库
  2. 第 10 篇 统计套利
  3. 第 11 篇 事件驱动
  4. 第 12 篇 ML Alpha
  5. 第 13 篇 DL 时序
  6. 第 14 篇 加密
  7. 第 15 篇 组合构建
  8. 第 16 篇 风险模型

策略路径读完,对”市面上的量化策略大概在做什么”有结构性认知。

8.3 工程路径

目标:把策略变成稳定运行的系统。

  1. 第 5 篇 数据管道
  2. 第 7 篇 特征存储
  3. 第 19、20、21 篇 回测三连
  4. 第 23、24 篇 执行算法 + SOR
  5. 第 27 篇 系统架构
  6. 第 28 篇 运维合规

工程路径是给量化工程师准备的”系统书”。

8.4 HFT 路径

目标:进入低延迟领域。

  1. 第 3 篇 微观结构
  2. 第 4 篇 订单类型
  3. 第 16 篇 风险模型(实时风控相关)
  4. 第 25 篇 做市
  5. 第 26 篇 HFT 架构
  6. 第 27 篇 系统架构

HFT 路径要求对网络、内核、硬件加速有基础。


九、三段最小代码

文章末尾给三段最小可运行代码,分别覆盖数据加载、因子计算、回测骨架。它们的目的是让读者立刻有”代码触感”,后续每一篇都会在更具体的场景上扩展。

9.1 数据加载:PIT 安全的行情读取

下面这段用 polars 读一份本地 parquet 行情,强制按 asof 过滤。环境:Python 3.11、polars 1.x。

import polars as pl
from datetime import date

def load_pit_safe(
    path: str,
    decision_date: date,
    universe: list[str] | None = None,
) -> pl.DataFrame:
    """读取 PIT 安全的日频行情。

    要求 parquet 必须包含字段:
      - symbol: str
      - event_date: date     该 bar 对应的交易日
      - asof: datetime       数据被市场看到的时间
      - open / high / low / close / volume
      - adj_factor: float    截至 asof 已知的复权因子
    """
    df = (
        pl.scan_parquet(path)
        .filter(pl.col("asof") <= pl.lit(decision_date))
        .group_by(["symbol", "event_date"])
        .agg([
            pl.col("open").last(),
            pl.col("high").last(),
            pl.col("low").last(),
            pl.col("close").last(),
            pl.col("volume").last(),
            pl.col("adj_factor").last(),
            pl.col("asof").last(),
        ])
        .sort(["symbol", "event_date"])
    )
    if universe is not None:
        df = df.filter(pl.col("symbol").is_in(universe))
    return df.collect()

要点:

  1. 先按 asof <= decision_date 过滤,再按 (symbol, event_date) 取 last。这样保证拿到的是”在 decision_date 之前最新可见”的版本,不是事件时间为 decision_date 的最新值;
  2. adj_factor 跟着 asof 走,回测查询时直接用,不要拿”今天最新的复权因子”;
  3. universe 过滤放在最后,避免在 scan 阶段触发字段全表扫。

PIT 校验脚本可以这样写:把 decision_date 往前挪一天再跑一遍,结果应该是上一版的子集。如果出现”挪前一天反而多出一些行”,说明 asof 字段被弄脏了。

9.2 因子计算:行业中性化的横截面动量

下面是一个最简单的”过去 20 日动量、行业中性化、截面 z-score” 因子。环境:numpy 1.26、pandas 2.x、scipy 1.11。

import numpy as np
import pandas as pd

def neutralize_by_group(values: pd.Series, groups: pd.Series) -> pd.Series:
    """对每个组内做去均值。"""
    return values - values.groupby(groups).transform("mean")

def zscore_clip(s: pd.Series, n_std: float = 3.0) -> pd.Series:
    """先做 MAD 截尾,再 z-score。"""
    med = s.median()
    mad = (s - med).abs().median() * 1.4826
    if mad == 0 or np.isnan(mad):
        return pd.Series(np.zeros(len(s)), index=s.index)
    clipped = s.clip(med - n_std * mad, med + n_std * mad)
    return (clipped - clipped.mean()) / (clipped.std(ddof=0) + 1e-12)

def momentum_factor(
    px: pd.DataFrame,         # 行=日期, 列=symbol, 值=后复权收盘价
    industry: pd.Series,      # index=symbol, 值=行业代码
    lookback: int = 20,
) -> pd.DataFrame:
    """过去 lookback 日动量 + 行业中性 + z-score。"""
    # 关键:shift(1) 保证当日因子只用 t-1 及以前的价格
    ret = px.pct_change(lookback).shift(1)

    out = pd.DataFrame(index=ret.index, columns=ret.columns, dtype=float)
    for dt, row in ret.iterrows():
        valid = row.dropna()
        if len(valid) < 50:
            continue
        ind = industry.reindex(valid.index)
        neutralized = neutralize_by_group(valid, ind)
        out.loc[dt, valid.index] = zscore_clip(neutralized).values
    return out

要点:

  1. shift(1) 是防止信号偷看同一根 bar 的收盘——典型的未来函数;
  2. MAD 截尾对厚尾数据更稳健;如果改成 clip(quantile(0.01), quantile(0.99)) 也行;
  3. 行业中性化用”组内去均值”做最简单实现,更严格的做法是对行业哑变量做横截面 OLS 取残差;
  4. 当横截面有效样本太少时(< 50)跳过这一天,避免噪音放大。

9.3 回测骨架:向量化的最小回测

下面是一段向量化回测骨架。它做出三个关键工程决定:信号 t → 持仓 t+1、按 t+1 开盘价成交、滑点 + 比例费率扣除。环境:pandas 2.x、numpy 1.26。

import numpy as np
import pandas as pd

def vector_backtest(
    factor: pd.DataFrame,        # 因子 z-score
    open_px: pd.DataFrame,       # 开盘价
    close_px: pd.DataFrame,      # 收盘价
    top_pct: float = 0.1,        # 多头分位
    bot_pct: float = 0.1,        # 空头分位
    fee_bps: float = 3.0,        # 单边费率(基点)
    slip_bps: float = 5.0,       # 单边滑点(基点)
) -> dict:
    """多空对冲、等权、日频再平衡、市场中性。"""
    # 1) 由因子在 t 决定持仓,t+1 开盘成交 → 持仓在 t+1 开始生效
    rank = factor.rank(axis=1, pct=True)
    long_mask = rank >= (1 - top_pct)
    short_mask = rank <= bot_pct

    n_long = long_mask.sum(axis=1).replace(0, np.nan)
    n_short = short_mask.sum(axis=1).replace(0, np.nan)

    weight = pd.DataFrame(0.0, index=factor.index, columns=factor.columns)
    weight = weight.where(~long_mask, (1.0).__rdiv__(n_long), axis=0) \
        if False else weight  # 写法兼容,下面用更直接的方式

    weight[long_mask] = (long_mask.div(n_long, axis=0))[long_mask]
    weight[short_mask] = -(short_mask.div(n_short, axis=0))[short_mask]

    # 2) 信号在 t 形成,权重在 t+1 起效
    weight = weight.shift(1)

    # 3) t+1 收益 ≈ (close_{t+1} - open_{t+1}) / open_{t+1} 用于持有期内
    #    简化为 t+1 close 相对 t close 的收益,再扣除入场滑点
    ret_close = close_px.pct_change()
    gross = (weight * ret_close).sum(axis=1)

    # 4) 换手成本:|w_t - w_{t-1}| * (fee + slip) 单边
    turnover = (weight - weight.shift(1)).abs().sum(axis=1)
    cost = turnover * (fee_bps + slip_bps) / 1e4

    pnl = gross - cost

    # 5) 指标
    ann = pnl.mean() * 252
    vol = pnl.std() * np.sqrt(252)
    sharpe = ann / vol if vol > 0 else np.nan
    max_dd = (pnl.cumsum() - pnl.cumsum().cummax()).min()

    return {
        "pnl": pnl,
        "turnover": turnover,
        "ann_return": ann,
        "ann_vol": vol,
        "sharpe": sharpe,
        "max_drawdown": float(max_dd),
    }

要点:

  1. weight.shift(1) 是不可省略的一步——信号 t 形成、t+1 开始持有,回测里漏掉这一步等于用未来数据;
  2. 换手成本用 |w_t - w_{t-1}| 直接近似,单边费率与滑点合并到 bps;
  3. 这是”向量化回测”,速度快但表达力弱:它假设无限流动性、无冲击成本、按收盘成交。第 19 篇会给出”事件驱动 + 滑点模型 + 容量约束”的完整版本。

向量化回测的最大用途是因子早期筛选——从几千个候选因子里快速挑出几十个可能有效的,再交给事件驱动回测做精测。第 19、20 篇会讲两套引擎怎么配合。

9.4 一段 IC 计算:单因子检验的最小样例

光算因子还不够,必须配套一段 IC 计算来评价它。下面这段计算每日横截面 Spearman 相关,并给出 Rank IC 的均值、标准差、IC_IR、t 统计量与衰减曲线。

import numpy as np
import pandas as pd
from scipy.stats import spearmanr

def rank_ic(
    factor: pd.DataFrame,    # 行=日期, 列=symbol
    fwd_ret: pd.DataFrame,   # 同结构,前瞻收益(已对齐到因子日期)
) -> pd.Series:
    """每日横截面 Rank IC。"""
    out = {}
    for dt in factor.index:
        f = factor.loc[dt].dropna()
        r = fwd_ret.loc[dt].reindex(f.index).dropna()
        f = f.reindex(r.index)
        if len(f) < 50:
            continue
        rho, _ = spearmanr(f.values, r.values)
        out[dt] = rho
    return pd.Series(out).sort_index()

def ic_summary(ic: pd.Series) -> dict:
    n = ic.dropna().shape[0]
    mean = ic.mean()
    std = ic.std(ddof=1)
    return {
        "n_days": n,
        "ic_mean": mean,
        "ic_std": std,
        "ic_ir": mean / std if std > 0 else np.nan,
        "t_stat": mean / (std / np.sqrt(n)) if std > 0 else np.nan,
        "win_rate": (ic > 0).mean(),
    }

def ic_decay(
    factor: pd.DataFrame,
    px: pd.DataFrame,
    horizons: list[int] = [1, 5, 10, 20, 60],
) -> pd.DataFrame:
    """衰减曲线:不同前瞻天数下的 Rank IC 均值。"""
    rows = []
    for h in horizons:
        fwd = px.pct_change(h).shift(-h)
        ic = rank_ic(factor, fwd)
        s = ic_summary(ic)
        rows.append({"horizon": h, **s})
    return pd.DataFrame(rows)

判定准则(仅做参考,具体阈值与策略类型有关):

  • ic_mean 量级:日频股票多因子典型在 0.02–0.05 之间,超过 0.10 多半是数据问题;
  • ic_ir ≥ 0.5 通常被视为可考虑入库;
  • t_stat ≥ 2 视为统计显著;
  • 衰减曲线半衰期短于调仓周期,因子等于在错过;半衰期长说明信号缓慢,调仓频率可降低。

9.5 关于 numba 与 vectorbt

回测对性能敏感时,用 numba 加速核心循环、用 vectorbt 做大规模参数扫描是常见选择。两者的边界:

  • vectorbt:适合参数网格搜索、多策略并行、可视化分析,底层是 numba+numpy;
  • numba:适合自己写事件驱动撮合循环,单次回测的微秒级优化;
  • 纯 pandas/polars:适合早期向量化筛选,写得快但性能上限低。

第 19 篇会把三种方案在同一个策略上做基准对比,给出选择建议。



十、回测引擎选型:四类方案的工程取舍

回测引擎是所有量化系统的核心基础设施之一。市面上主流方案大致分四类,工程取舍不同。

10.1 向量化回测(Vectorized)

代表:自己写的 pandas/numpy/polars 流水线、vectorbt。

  • 优点:极快,一次回测可以在秒级完成;适合参数扫描、因子筛选;
  • 缺点:表达力弱——很难表达”订单挂在某价位 30 秒后未成交则撤”这类逻辑;难以处理冲击成本、跨日订单状态;
  • 适用:因子早期筛选、单一调仓频率的截面策略、资产配置类策略。

10.2 事件驱动回测(Event-Driven)

代表:zipline、backtrader、自研事件循环。

  • 优点:能精确表达订单生命周期、撮合假设、多场所、跨周期信号;
  • 缺点:慢,单次回测可能要几分钟到几小时;写起来比向量化复杂;
  • 适用:上线前精测、HFT/做市策略、跨期跨品种、复杂订单类型。

10.3 模拟撮合(Tick-level Simulation)

代表:自研 tick 级订单簿重建 + 撮合模拟器。

  • 优点:能在 tick 级别复盘,精确到撮合优先级与队列位置;
  • 缺点:极慢且贵,需要 tick 数据,存储与计算成本高;
  • 适用:HFT、做市、订单路由策略。

10.4 影子账户(Paper Trading)

代表:把信号接到真实行情、模拟下单、影子持仓核算。

  • 优点:完全消除回测假设偏差,最贴近实盘;
  • 缺点:需要时间——一个月就是一个月,无法加速;
  • 适用:上线前的最终验证。

四类方案在一个完整研究流水线里通常会组合使用:向量化做粗筛 → 事件驱动做精测 → 影子账户做最终验证。第 19 篇会给出三套环境如何对齐口径。


十一、生态与工具栈

下面这张表列出本系列默认假设的工具栈。读者用别的工具栈也行,关键是把每一类需求找到对应工具。

类别 默认工具 备选
数据处理(DataFrame) polars 1.x、pandas 2.x duckdb
数值计算 numpy 1.26 jax
加速 numba cython、rust pyo3
时序数据库 clickhouse、questdb influxdb、timescaledb
列存 parquet(zstd 压缩) orc
消息总线 redis stream、kafka nats、pulsar
回测向量化 vectorbt bt、backtesting.py
回测事件驱动 zipline-reloaded、backtrader 自研
组合优化 cvxpy + ECOS/Clarabel scipy.optimize、pyportfolioopt
ML 模型 lightgbm、xgboost、catboost sklearn
深度学习 pytorch tensorflow
行情接入 ctp(期货)、xtquant、ib_insync 直连交易所 SDK
可视化 plotly、altair matplotlib、seaborn
监控 prometheus + grafana datadog

后续每一篇都会标注它使用的工具版本。当某段代码依赖特定版本时(例如 polars 0.x 与 1.x 之间 API 变了),会显式声明。


十二、常见误区与反模式

工程链路上反复看到的几个反模式,列出来作为反例:

12.1 “回测漂亮就上线”

漂亮的回测有 N 种来源:未来函数、生存者偏差、过拟合、容量假设、滑点假设过乐观、费率忘记扣、训练样本与检验样本未隔离、参数在几百次试错后挑出来的。任何一种都能让回测看起来比实盘强 5–10 倍。

工程上的对策:每一份回测必须配套交付以下检查:

  • PIT 校验脚本(往前挪一天结果是子集);
  • 生存者偏差校验(对比”含已退市”和”不含已退市”的差异);
  • 容量校验(按 ADV 折算后的净 Alpha);
  • 样本外校验(最后一段不许碰的数据);
  • 参数稳健性(参数邻域内 Sharpe 标准差)。

12.2 “把研究脚本直连实盘”

最危险的反模式。研究环境通常没有风控、没有限速、没有幂等、没有状态恢复。直连实盘的后果是策略 bug 直接变成资金事故。

工程上的对策:研究环境永远不能拿到真实账户的下单凭证。下单链路必须经过 OMS/EMS,OMS/EMS 必须开启所有风控开关。第 27 篇会给出环境隔离的具体方案。

12.3 “风控写在策略代码里”

风控如果和策略写在一起,策略 bug 会一并把风控绕过。Knight Capital 2012 年的 4.4 亿美元事故就是典型——老代码模块被误激活,没有独立风控通道兜底。

工程上的对策:风控必须是独立通道,物理上独立的进程、独立的部署、独立的代码仓库(或至少独立的代码路径)。策略再怎么 bug 也不能污染风控状态。

12.4 “本地估算持仓”

很多新写的系统会把”持仓”算成本地状态:上次目标 + 上次成交 = 当前持仓。问题是网络抖动、回报丢失、撤单回报延迟都会让本地估算和交易所真实持仓漂移。漂移一旦发生,风控就会基于错误数据放行错误订单。

工程上的对策:本地状态只作为辅助,真实持仓以交易所回报为准,每分钟(或每次下单前)做一次对账,发现漂移就停止下单并告警。

12.5 “复盘换口径”

实盘表现不好,复盘时把回测的滑点假设调高一点、费率算少一点,让数据”对得上”。这是自欺。

工程上的对策:回测口径和复盘口径字段级一致,由同一份配置文件生成。任何口径修改必须同步两端,并对历史所有跑过的回测重跑一遍。第 22 篇会给出口径管理的工程做法。

12.6 “用平均数掩盖尾部”

夏普比率假设收益正态分布,对厚尾不敏感。一个策略 250 个交易日里 248 天小赚、2 天大亏 50%,年终统计看 Sharpe 仍然不错,但实盘上你扛不住那 2 天。

工程上的对策:评价策略至少看四个指标:Sharpe、最大回撤、Calmar(年化收益/最大回撤)、收益分布的偏度峰度。任何一个不达标都不上线。第 22 篇会展开指标体系。


十三、一份不变量清单

把整篇文章的工程要点压缩到一份清单,写在墙上每天看一遍,能避免 80% 的事故:

  • 数据:所有事实表带 asof,查询永远 WHERE asof <= t
  • 复权:保留原始价 + 按 asof 的复权因子表,禁止用”今日最新”复权数据回测;
  • 停牌:不参与因子计算、不参与撮合、不参与持仓估值;
  • 因子:所有滚动窗口右对齐,所有标准化用滚动或扩展窗口,禁止整体标准化;
  • PIT 校验:把 decision_date 往前挪一天,结果必须是子集;
  • 撮合:信号 t 形成、t+1 开盘价或 VWAP 成交,禁止当 bar 收盘成交;
  • 费率:佣金、印花税、过户费、滑点全扣,单边和双边分清楚;
  • 订单:每笔下单带全链路唯一 client_order_id,与回报匹配;
  • 风控:独立通道、安全默认拒绝、毫秒级熔断;
  • 状态:实时持仓以交易所回报为准,本地估计只能作为辅助;
  • 复盘:复盘口径与回测口径完全一致,否则不可比;
  • 环境隔离:研究/回测/实盘的代码、数据、时间引擎严格分离,禁止”研究脚本直连实盘账户”。

每一条都对应后续某一篇的工程方法。本系列的所有内容,本质上都是在帮你把这份清单从一行字落到一行代码。


十四、结语

量化交易的工程难度,不在任何一段单独的代码,而在八段链路必须同时正确。一根 K 线数据进来时不被时间错位污染、一个因子算出来时不偷看未来、一份目标持仓在执行时不被滑点吃掉、一笔成交回报回来时能精确匹配上原订单、一次崩盘时风控能在毫秒内把链路熔断——这些事任何一件单看都不难,难的是 365 天每天都对。

这个系列的目标,是让读者读完之后,对每一段链路都有”我知道哪里会出事、我知道怎么守住”的信心。后续 27 篇会把上面的每一条不变量从一句话展开到几千字 + 代码 + 实测。第 2 篇先从市场结构开始:A 股、美股、期货、加密各自的撮合机制、订单类型、交易制度,这是所有后续策略代码的底层假设。


参考文献

书籍

  • Marcos López de Prado. Advances in Financial Machine Learning. Wiley, 2018. 第 1–4 章关于数据结构、特征工程、生存者偏差的论述是本系列数据章节的主要参考。
  • Marcos López de Prado. Machine Learning for Asset Managers. Cambridge University Press, 2020. 协方差矩阵收缩、组合优化的稳定性方法。
  • Robert Kissell. The Science of Algorithmic Trading and Portfolio Management. Academic Press, 2013. 执行算法与冲击成本模型的工业级参考。
  • Rishi Narang. Inside the Black Box: A Simple Guide to Quantitative and High-Frequency Trading. Wiley, 2nd ed., 2013. 量化系统分层与买卖方分工的入门读物。
  • Maureen O’Hara. Market Microstructure Theory. Blackwell, 1995. 市场微观结构经典教材。
  • Larry Harris. Trading and Exchanges: Market Microstructure for Practitioners. Oxford University Press, 2003. 工业界视角的微观结构。
  • Ernest Chan. Algorithmic Trading: Winning Strategies and Their Rationale. Wiley, 2013. 统计套利、均值回归类策略的工程化处理。

论文

  • Eugene F. Fama, Kenneth R. French. “Common risk factors in the returns on stocks and bonds.” Journal of Financial Economics, 33(1), 1993. 多因子模型的原始论文。
  • Narasimhan Jegadeesh, Sheridan Titman. “Returns to Buying Winners and Selling Losers: Implications for Stock Market Efficiency.” Journal of Finance, 48(1), 1993. 动量异象的开山之作。
  • Olivier Ledoit, Michael Wolf. “Honey, I Shrunk the Sample Covariance Matrix.” Journal of Portfolio Management, 30(4), 2004. 协方差矩阵收缩。
  • Robert Almgren, Neil Chriss. “Optimal Execution of Portfolio Transactions.” Journal of Risk, 3, 2001. 最优执行的经典论文,IS 算法的理论基础。

规范与文档

  • FIX Protocol Specification, https://www.fixtrading.org。订单协议工业标准。
  • NASDAQ TotalView-ITCH 5.0 Specification。Level 3 行情协议参考。
  • 上海证券交易所交易规则(最新版)。A 股 T+1、涨跌停、集合竞价规则的权威文本。
  • 中国金融期货交易所交易规则(最新版)。股指期货交易制度。

工具与库


上一篇系列首页  下一篇02 市场结构

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-01 · quant

量化交易

从因子研究到生产执行的量化交易全栈工程。覆盖市场微结构、数据管线、因子构造、组合优化、回测方法论、执行算法、做市策略、高频架构到生产运维。面向策略研究员与工程师。

2026-05-01 · quant

【量化交易】回测引擎设计:事件驱动与向量化

把回测引擎当成一套工程系统讲清楚:事件驱动架构、撮合保真度、滑点嵌入、多频率多账户、并行加速、回放对账。给出可运行的最小事件驱动回测器与 vectorbt 向量化对照实现。

2026-05-01 · quant

【量化交易】回测陷阱:前视偏差、过拟合、数据窥视

回测引擎只能保证「语法对」,但真正杀死策略的是「逻辑错、数据脏、推断不严」三件事。本文系统拆解前视偏差(lookahead bias)、过拟合(overfitting)、数据窥视(data snooping)三大陷阱,介绍 Bonferroni、BH-FDR、Family-Wise Error 的多重检验修正,给出 Deflated Sharpe 与概率 Sharpe(PSR)的可运行 Python 实现,配一份 30 条上线前自检清单。