这两年只要行情稍微活跃一点“量化交易”这四个字就会往你手机上挤。有人把它当成稳赚的印钞机有人把它当成机构割韭菜的屠刀但以我在A股折腾了这么多年的经验来看量化交易既没有前者那么神也没有后者那么可怕。它本质上是一套把投资逻辑变成可验证、可重复、可执行流程的方法。这篇内容我想用道、法、术、器、势这五个字把量化交易完整拆一遍结合A股的实际规则、Python代码和一些踩坑记录给想系统入门的读者一套能直接照着做的实战框架。如果你正准备学量化、写过几行策略代码但跑不通或者已经在回测平台上试水但总感觉差点意思这篇文章应该能帮你把零散的知识串成一条线。我不打算给你讲玄学也不会画一张包赚的大饼。我会从底层信念一直讲到工具选型最后落到A股特有的规则上尽量每一段都配一点能直接用的东西。1. 道——捅破那层窗户纸量化交易的底层信念1.1 量化不是圣杯而是把“赌”变成“Bet”很多人对量化交易的第一印象是“程序自动买卖躺着赚钱”。这个误解害人不浅。我在刚接触量化的时候也天真地以为只要写出一套信号让程序按信号执行就能从市场里稳定提款。结果自然是交了学费。后来我才想明白一个很朴素的道量化交易从来不能预测未来它只是让你在信息不完全、结果不确定的情况下做出大概率占优的决策。市场短期是投票机长期是称重机这句话放在量化语境里可以换个说法——你的策略不需要每一笔都对只要在统计意义上正期望并且波动可控迭代足够多次之后盈亏自然会向概率均值收敛。类比一下你就懂了。赌场里的庄家永远不会保证自己每一把都赢但每一把牌都设了微小的赔率优势加上大数定律只要玩的局数足够多庄家迟早赚钱。量化交易者做的事情本质上就是找到属于自己的那个微小优势然后用纪律把优势兑现出来。至于这个优势是大是小、能持续多久那是后面“法”“势”这些层要解决的问题。先把“道”想明白你不是在找圣杯你是在建立一套带概率优势的下注系统。1.2 纪律与逻辑才是普通人最缺的两样散户做A股普遍的问题不是信息不够而是决策太受情绪影响。涨了觉得还能涨跌了觉得会反弹来回几次本金就磨掉了。量化交易最大的价值不是“自动化”本身而是把决策权从情绪手里拿回来。举个例子。某个交易日你持仓的一只票突然放量拉升盘中一度涨停。人的第一反应是“明天还能涨先别卖”结果尾盘炸板第二天继续低开。这就是典型的情绪决策。如果换成量化系统你的卖出条件早就写在策略里了触发就走。它不会害怕错失利润也不会在回撤时死扛。还有一层是逻辑一致性。手工交易者很容易看涨了就用技术面理由说服自己看跌了又转头找基本面理由。量化策略要求你把逻辑写成一个可验证的规则比如“20日均线上穿60日均线买入反之卖出”。这个规则可能赚不到钱但它能被回测能被检验能被优化。手工交易的逻辑漏洞是模糊的量化交易的逻辑漏洞是明确的——这本身就是巨大的优势。1.3 道的落地期望值、盈亏比与“活得久”道听起来虚但我可以立刻给你一个能用公式落地的部分——资金管理与期望值。你可以暂时不纠结选什么因子先想清楚每个决策的数学期望[ E P(win) \times AvgWin - P(lose) \times AvgLoss ]如果E不为正策略再花哨也是慢性失血。一个很常见的误区是只看胜率有些人追求80%胜率结果每次赚1%就跑了每亏一次亏10%长期下来照样亏。A股日内波动大好的盈亏比往往比高的胜率更重要。我个人的习惯是回测中盈亏比低于1.5的策略直接不碰除非胜率高到离谱。另一个必须刻在脑子里的数字是回撤的“不对称性”。先看一组数据资金回撤幅度回到初始本金需要上涨10%11.1%20%25%30%42.9%50%100%60%150%这就是为什么我一直强调在A股做量化控制回撤的优先级永远高于追求更高的收益。很多人问“你的策略年化能到多少”我的回答通常是“你先告诉我最大回撤打算控制在多少我们再来谈收益。”把一个策略从年化30%、回撤40%改成年化20%、回撤15%我一定是选后者。因为只有回撤可控你才拿得住才谈得上复利。2. 法——把策略体系搭起来从单因子到多因子2.1 策略体系的三个层次“道”解决的是信仰和心态“法”解决的是方法论。我把一套完整策略拆成三个层次择时Timing、选股Selection、风控Risk Control。择时决定你什么时候进场、什么时候离场或者说仓位该加到几成。选股决定在确认进场的前提下具体买什么标的。风控决定单笔亏损上限、总仓位上限、板块集中度等硬约束。这三个层次不能混着做。最常见的问题是在选股层面加入择时逻辑比如“这只股票最近涨得好所以买入”这实际上是让动量因子去扮演择时角色逻辑会乱。一个成熟的策略框架是先用环境信号判断要不要做再用因子模型选出候选最后用风控规则过滤掉高危标的。我自己刚开始做的时候特别容易把注意力全放在“选股”上觉得只要选得准其他都不重要。后来发现A股市场风格切换极快选股再准在系统性下跌面前也是溃败。后来我把三层分开建模比如用“指数20日均线”做大盘环境判断用“小市值低换手动量”做选股再用“单票仓位上限5%”做风控整个策略的稳定性一下就上来了。2.2 三因子策略是怎么构建出来的网上经常能看到“三因子策略示例”最常见的组合是市值因子、价值因子、动量因子。这里我摊开讲一下如何构建一个属于自己的三因子逻辑。先明确一个原则因子不是越多越好而是每加一个因子都要有清晰的经济逻辑。你不应该只是因为某个指标在回测里表现好就塞进去那是数据挖掘不是策略开发。以我最常用的一套三因子组合为例市值因子A股历史上有很长一段时间存在明显的“小市值溢价”但这几年风格切换得非常剧烈。市值因子在A股不能直接照搬至少要和流动性、退市风险结合起来考虑。动量因子又称趋势因子过去20个交易日的累计收益排在前面的股票在一段时间内倾向于延续表现。A股的动量效应不如美股稳定但有的时候确实有效。换手率因子换手率过高的股票通常说明投机气氛浓后续波动加大低换手率股票的持续性相对好一点。换手率因子本质上是对交易拥挤度的一种逆向表达。构建三因子策略的流程是固定的先定义因子再做因子处理和标准化最后加权打分排序选出得分最高的N只股票。这在后面“术”的部分我会给出完整可跑的代码这里先强调两个容易踩坑的细节。第一因子计算之前先要统一数据口径。比如动量因子如果混用了前复权和不复权的价格计算结果会有显著偏差因为除权除息会扭曲价格序列。第二因子值必须做去极值和标准化。极端值会直接主导打分结果导致组合过度集中到某一只股票上失去了分散的意义。2.3 方法论层面最容易踩的三个坑这段话我建议你直接复制到自己的策略笔记里因为几乎每个量化新手都会在这三个坑里摔一遍。第一个坑是未来函数。我用最简单的例子说明如果策略里用了“当天收盘后才知道的成交额”去计算当天开盘时就应该产生的买入信号这就是未来函数。回测里它会给你一份漂亮的曲线实盘里它连第一笔单都成不了。第二个坑是过拟合。一个策略如果在历史数据上参数被优化到极致它很可能只是在记忆那段历史而不是在学习规律。判断过拟合的简单办法是把你的参数从最优值稍微偏离看看绩效是不是断崖式下跌。如果最优参数的邻域表现都很差说明策略很脆。第三个坑是忽略交易成本。A股的成本包括佣金、印花税和滑点。高频调仓策略看起来年化收益高一旦加上千分之几的成本可能直接从盈利变成亏损。我习惯在回测中主动设置比实际更高的成本率留出安全边际。3. 术——把想法变成能跑的Python代码3.1 数据准备和因子计算前面说了那么多理论现在进入实操。我用Python和Pandas构建一个简化的三因子策略。为了方便读者在没有数据接口的环境里也能跑起来这份代码用随机生成的数据模拟行情你只需要理解流程然后把数据源替换成自己抓取的日线数据即可。代码里用到的数据结构很简单按日期排列的收盘价表行是股票代码列是交易日期。另外还需要成交量和流通股本的数据用来计算换手率和市值。因子定义如下市值因子收盘价乘以流通股本。为了演示这里用随机数模拟流通股本。动量因子过去20个交易日的累计涨幅直接用close / close.shift(20) - 1计算。换手率因子成交量除以流通股本。成交量也用随机数模拟。真实环境下你可以通过数据接口获取这些字段。在演示代码中使用np.random.lognormal生成模拟数据是为了保证代码在任何环境下都能直接运行。等你跑通了整个流程再替换成真数据就知道每一步数据长什么样了。3.2 一个完整可运行的三因子回测脚本下面这份代码我尽量控制在90行以内包含了从数据模拟、因子计算、标准化、月度调仓到回测统计的完整流程。你可以复制到本地直接运行。建议先原样跑一遍再尝试修改参数这是最有效的学习方式。import numpy as np import pandas as pd # 固定随机种子保证结果可复现 np.random.seed(2024) # 1. 模拟数据300只股票252个交易日 dates pd.bdate_range(2023-01-02, periods252) codes [f{i:06d} for i in range(300)] close pd.DataFrame( np.random.lognormal(0, 0.03, (len(codes), len(dates))), indexcodes, columnsdates ) volume pd.DataFrame( np.random.lognormal(13, 0.5, (len(codes), len(dates))), indexcodes, columnsdates ) # 模拟流通股本行是股票代码保持相对稳定 float_shares pd.Series( np.random.lognormal(16, 0.6, len(codes)), indexcodes ) float_shares pd.DataFrame( np.tile(float_shares.values[:, None], (1, len(dates))), indexcodes, columnsdates ) # 2. 因子计算 # 市值因子价格 * 流通股本 mktcap close * float_shares # 动量因子20日累计收益 momentum close / close.shift(20, axis1) - 1 # 换手率因子成交量 / 流通股本用价格近似单股价格 turnover volume / (float_shares * close) # 3. 因子预处理去极值 标准化 def winsorize_series(s, limit3): med s.median() mad (s - med).abs().median() upper med limit * mad lower med - limit * mad return s.clip(lower, upper) def standardize_series(s): return (s - s.mean()) / s.std() # 4. 月度调仓回测 # 每个月最后一个交易日调仓按三个因子打分并等权持有得分最高的20只股票 def factor_score(sub_close, sub_mktcap, sub_momentum, sub_turnover): score pd.DataFrame(indexsub_close.columns) # 每个股票在每个调仓日是单独的截面 score[mktcap] winsorize_series(sub_mktcap.iloc[-1]) score[momentum] winsorize_series(sub_momentum.iloc[-1]) score[turnover] winsorize_series(sub_turnover.iloc[-1]) for col in [mktcap, momentum, turnover]: score[col] standardize_series(score[col]) # 等权合成市值小加分、动量强加分、换手率低加分 # 注意方向市值因子我们希望小市值所以取负 score[total] -score[mktcap] score[momentum] - score[turnover] return score[total].sort_values(ascendingFalse) # 记录每次调仓的持仓和下一区间收益 positions [] portfolio_ret [] # 每个月最后一个交易日作为调仓日 trade_dates dates[20:] # 动量需要前20个数据 month_end_dates pd.Series(trade_dates).groupby(trade_dates.to_period(M)).max().tolist() for i in range(len(month_end_dates) - 1): rebalance_date month_end_dates[i] next_date month_end_dates[i 1] if i 1 len(month_end_dates) else dates[-1] sub_close close.loc[:, dates[dates rebalance_date]] sub_mktcap mktcap.loc[:, dates[dates rebalance_date]] sub_momentum momentum.loc[:, dates[dates rebalance_date]] sub_turnover turnover.loc[:, dates[dates rebalance_date]] # 排除因子缺失的股票 valid sub_momentum.iloc[-1].notna() sub_mktcap.iloc[-1].notna() sub_close sub_close.loc[:, valid] sub_mktcap sub_mktcap.loc[:, valid] sub_momentum sub_momentum.loc[:, valid] sub_turnover sub_turnover.loc[:, valid] score_series factor_score(sub_close, sub_mktcap, sub_momentum, sub_turnover) selected score_series.head(20).index.tolist() # 计算持仓期间收益从rebalance_date下一天到next_date start_idx dates.get_loc(rebalance_date) 1 end_idx dates.get_loc(next_date) period_returns (close.loc[selected, dates[end_idx]] / close.loc[selected, dates[start_idx - 1]] - 1).mean() portfolio_ret.append(period_returns) # 5. 回测统计 cum_ret pd.Series(portfolio_ret).fillna(0) total_return (cum_ret 1).prod() - 1 max_drawdown (cum_ret.cumsum().cummax() - cum_ret.cumsum()).max() print(f总收益: {total_return:.2%}) print(f最大回撤: {max_drawdown:.2%}) print(f每月调仓次数: {len(portfolio_ret)})这段代码的核心思想是每个月的最后一个交易日在全市场范围内计算三个因子标准化后加权打分取前20只股票等权持有直到下个月调仓。你跑完后会得到一组模拟数据的收益统计数字本身没有意义但流程很有参考价值。我在实际写策略的时候还会在这个框架上加三个东西排除ST和退市风险股、排除上市不满60个交易日的次新股、单票持仓比例上限。这些过滤条件看起来简单却能避开A股里相当大一部分雷。3.3 回测指标怎么读收益、回撤和夏普有了回测结果下一步是怎么判断策略质量。除了代码里已经打印的总收益和最大回撤我建议你至少再关注两个指标夏普比率和胜率。夏普比率的标准公式是策略年化收益 - 无风险利率 / 年化波动率。实际使用中直接用策略日收益的均值 / 策略日收益的标准差再乘以sqrt(252)也可以得到一个合理估算。一般来说夏普大于1算合格大于2算优秀。A股波动大很多看起来赚大钱的策略夏普可能只有0.5意思是它赚钱主要靠运气加持。还有一个经常被忽略的指标是“收益来源的稳定性”。我习惯把每笔调仓的收益画出来然后看它是不是均匀分布。如果总收益完全来自某一年或某几次极端行情说明策略有严重的风格暴露不是稳健的alpha。判断方法是把每个月调仓收益列出来看看亏损月份的数量和亏损幅度。如果连续亏损超过半年再好的总曲线也要警惕。回测中出现这三类问题的概率最高信号频繁失效说明因子逻辑和市场环境不匹配需要回到“法”的层面重新审视。最大回撤集中在某一时间段大概率是遭遇了系统性风险需要考虑在“势”的层面加入择时或仓位控制。持仓过于集中打分排序选出来的20只股票经常集中到同一个行业说明因子缺少行业中性化处理。4. 器——工具选型与数据安全开源框架怎么挑4.1 平台与框架对比先想清楚你要做什么“器”这个字很直白就是工具。量化交易的工具链可以分成三类在线回测平台、开源回测框架、本地数据系统。工具之间没有绝对的好坏只有适不适合你当前所处的阶段。在线平台适合入门和快速验证想法。同花顺Supermind、聚宽、米筐这几家在国内比较常见。它们的优势是内置了数据、榜单、回测环境你几乎不用处理数据对齐的问题能很快把策略逻辑跑通。我自己早期很多策略雏形就是在这些平台上验证的效率确实高。开源框架适合做深度研究。Backtrader、Qlib、vn.py是三个主要方向。Backtrader最轻回测框架核心概念简单适合学习Qlib是微软开源的AI量化平台内置了机器学习建模流程适合有深度学习基础的进阶玩家vn.py则更偏实盘交易系统可以对接券商柜台开发门槛相对高。数据存储方面规模小的可以直接用SQLite数据量大了再考虑ClickHouse或者PostgreSQL加时序插件。在“器”这一层最容易犯的错误是一开始就上重武器本地数据库、分布式框架搞得很大结果策略连回测都还没跑通。4.2 开源框架推荐与避坑如果你决定走开源路线我按推荐程度给三类读者一点参考。第一类是完全没接触过回测框架的读者闭眼选Backtrader。它虽然是老框架但生态环境成熟网上资料多遇到问题容易搜到解决方案。一个重要提醒是Backtrader的官方维护在2023年后基本处于停滞状态所以不要指望它会有太多新功能更新你只需要使用它成熟稳定的回测部分。第二类是研究机器学习因子和AI选股的读者直接看Qlib。它把因子数据处理、模型训练、回测评估串成一个完整平台尤其适合做横截面选股任务。代价是学习曲线陡峭很多概念需要时间消化。第三类是有实盘开发需求的读者建议了解vn.py。它的交易接口、事件引擎、风控模块都做得比较系统但我不建议新手一上来就碰因为它把下单、撤单、报单回报这些细节全部暴露给你初学者很容易被这些和策略无关的复杂度吓退。开源方案里最坑的地方是数据对齐。不同数据源的历史价格复权方式可能不一样前复权、后复权、不复权适用场景不同。千万不要在自己代码里混用不同复权方式的数据这会造成因子计算和回测绩效的巨大偏差。我的习惯是在进入回测流程之前先统一做一次数据质量检查比如抽查某只股票在除权除息日附近的收益率是否异常。4.3 数据访问、存储与加密的落地设计很多人在学习量化时不太重视数据管理但随着策略数量增多、历史数据积累会发现数据访问乱成一个毛线团。这里分享一套我用了很久的简单方案兼顾轻量和安全。数据访问层我建议在代码和原始数据之间加一个统一的访问入口比如一个封装好的DataLoader类。不要直接在策略代码里散落地写pd.read_csv(某个路径)因为多个策略复用时路径和字段一变排查成本会高到崩溃。统一封装的好处是你只需要改一处数据路径所有策略都会跟着更新。存储层本地文件如果只做研究CSV和Parquet都够。但涉及账户信息、密钥、个人持仓等敏感字段时我建议做两层处理字段加密和访问控制。字段加密可以使用cryptography库对敏感列做AES加密密钥单独放在环境变量或密钥管理文件里不要把密钥硬编码到策略代码中。访问控制上给不同脚本分配不同权限策略脚本只读行情数据交易脚本才能访问账户数据。传输层尽量使用HTTPS和SSH隧道避免网络抓包泄露数据。我见过很多人在本地数据库里裸存券商账户的token这是非常危险的习惯。一旦代码传到公开仓库token就等于公开了。建议所有密钥都通过环境变量或配置文件注入并且把配置文件列入.gitignore。5. 势——读懂A股大环境规则、周期和仓位5.1 同一套策略为什么今年赚明年亏“势”是五个字里最容易被忽略、但决定生死的一个。量化策略不是活在真空里的市场环境一变同一套逻辑的收益可能直接从天上掉到地下。最典型的例子就是风格切换。2017年的蓝筹行情、2019到2020年的核心资产抱团、2021年的小票活跃、2022年的泥沙俱下、2023到2024年的高频轮动每种行情适合的策略逻辑完全不同。动量类策略在趋势市中如鱼得水在震荡市中却会被来回打脸小市值因子在流动性充裕的时候表现出色但在退市制度趋严的背景下因子暴露度需要大幅下调。所以我把“势”理解成两个层次一是大的市场环境牛熊状态、流动性情况二是风格周期大盘价值强还是小盘成长强。量化的“势”不是用来预测市场而是用来识别当前环境是否适合你的策略继续运行。一个简单的做法是给策略设置“开关”条件比如指数200日均线以下时自动降低仓位到五成以下。这种方法不能抓住所有机会但能让你的策略避开最糟糕的那段下跌。5.2 A股交易规则对策略的四个硬约束如果说美股量化策略像是在标准泳池里比赛A股量化就是在有暗流的河道里游泳。下面这四条规则每条都会直接影响策略设计和回测结果。第一是T1制度。当天买入的股票当天不能卖出。回测中如果按T0逻辑调仓比如当天卖出再买入实盘根本做不到。你在写回测代码时每一次卖出信号必须假定持有至少一个交易日。第二是涨跌停限制。主板涨跌停10%创业板和科创板20%。这会导致即使你的策略发出了买入或卖出信号也可能因为涨跌停而无法成交。回测里如果不考虑这个约束会明显高估策略收益尤其是在连续涨停板的行情里。第三是最小交易单位。A股买入必须以100股为单位的整数倍卖出时不足100股的部分可以一次性卖出。对小资金账户而言100股的门槛会影响持仓权重的精确执行尤其在想买高价股时。第四是停牌和ST制度。停牌股票的流动性突然消失如果策略持有停牌股资金就被锁死。ST股和退市风险股的波动机制也更特殊有严格的5%涨跌幅限制和交易权限要求。我现在所有策略都会在选股前过滤掉连续亏损和带帽的标的。5.3 顺势而为的仓位管理一个简单可用的信号关于“势”我想给你一套立刻能落地的仓位管理方法不用写复杂模型只需要一个简单的环境信号。我在策略里经常用“指数20日均线 60日均线”的关系来判断当前市场是否值得高仓位持仓。具体规则是当20日均线在60日均线上方时可以认为是偏多环境维持正常基准仓位比如70%当20日均线在60日均线下方时视为偏空环境把仓位压到基准仓位的一半以下当指数跌破某个关键支撑时我甚至会把仓位直接降到两成以下。这套方法的哲学很简单不要预测趋势只跟随趋势。它不保证你卖在最高点也不保证你能买在最低点但能让你减少在系统性下跌中的暴露。另一个我觉得特别重要的“势”是赚钱效应。A股市场经常出现“指数不涨但个股普涨”“指数涨但你手里的股票不涨”的结构分化。与其天天盯指数不如看整个市场的上涨家数占比。如果市场上涨家数占比持续低于40%不管你的策略回测多漂亮都建议降低交易频率。6. 常见问题与排查技巧实录6.1 数据接口老断、复权不一怎么排查数据是策略的地基地基歪了楼就歪了。我整理了一张问题排查表都是我自己实际操作中踩过的真实问题。现象常见原因排查方向接口频繁报错、拉不到全量历史数据服务限流将大批量请求拆成小批次增加随机延时和重试机制某只股票突然出现巨大收益率异常除权除息导致价格跳空检查是否使用复权数据统一使用前复权新上市股票被策略选中上市初期波动异常且无历史数据过滤上市不满60个交易日的股票同一策略在不同平台回测结果差异巨大数据复权、成本设置、调仓时点不一致核对数据版本、统一成交假设和费率参数6.2 回测绩效与实盘差距大的六个原因回测漂亮、实盘掉链子是几乎所有量化交易者都经历过的尴尬。原因通常集中在以下几个方面我按出现频率排序第一没有把滑点算进去。A股流动性不够的股票在回测里按收盘价成交实盘却要在买一卖一价甚至更差的价位才能成交。第二手续费参数设置偏低。股票交易的佣金是按成交金额计算的频繁调仓的手续费累积非常惊人。第三未来函数残留比如回测中用到了调仓日收盘后才知道的数据来做当天信号。第四幸存者偏差。很多免费的历史数据只包含现在还存活的股票那些已经退市的股票不在数据集里回测结果天然偏高。第五持仓周期与调仓时机不一致。第六策略过拟合参数对历史数据过度优化。我的经验是实盘前先对回测收益打一个七折再问自己能不能接受这个打折后的收益。如果答案是不能就别上真金白银。6.3 从“十行代码”到生产级策略的进阶路线很多入门者被“十行代码玩转量化交易”吸引这个切入点没问题。在线回测平台上写十行策略逻辑确实能快速建立起信号、回测、收益曲线的第一印象。但我想提醒你那十行代码只是种子不是庄稼。从“十行代码”走到能长期稳定运行的生产级策略我建议按这个顺序进阶第一步搞懂数据。把自己常用因子需要的数据字段、复权方式、口径统一搞清楚。第二步理解回测框架的运行机制尤其搞清楚成交假设在系统里是怎么撮合的。第三步建立自己的因子库和策略模板不再写一次性脚本。第四步接入实盘前手动模拟盘跟踪至少一个月记录信号和成交的差异。第五步上实盘时用小资金跑三到六个月验证滑点和执行细节。我自己在这个漫长过程中最大的体会是量化交易真正的门槛不是编程也不是数学而是你能不能建立起一套完整的“假设—回测—验证—修正”闭环。市场永远在变策略的寿命短则几个月、长则几年只有不断迭代修正的系统才有生命力。如果让我再给一个建议那就是从简单到极致的策略开始。很多高手用了多年最后还是在一个双均线系统或者一个单因子策略上赚到钱。不要害怕策略简单简单才意味着少出错少出错才可能活得久。把上面那些流程全部跑通之后你会发现量化交易其实不是一种击败市场的方式而是一种诚实面对自己和市场的方式。