1. 为什么"个人做量化"这件事在AI时代突然变得可行了
三年前如果有人跟我说"你一个人也能搞出一套能跑的量化策略",我大概率会笑笑不说话。那时候做量化是什么门槛?你得有Wind或者聚宽的机构账号,得有人给你喂清洗过的行情数据,得懂C++写撮合回测引擎,还得有台像样的服务器跑参数扫描。光是数据这一项,就把99%的个人挡在门外了。
但现在情况完全变了。我最近半年陆陆续续用Python加AI辅助工具,从零搭了三套不同风格的策略,从数据获取、因子构造、回测验证到模拟盘跟踪,全流程一个人搞定。这不是我变强了,而是工具链的成熟把量化的门槛从"团队级"拉到了"个人级"。
具体来说,有三个变化是决定性的。第一,免费或低成本的行情数据源已经足够个人使用,日线级别的数据几乎不花钱,分钟级数据也有不少渠道能拿到。第二,回测框架像Backtrader、VectorBT、Qlib这些已经非常成熟,你不需要自己造轮子,专注在策略逻辑本身就行。第三,也是最关键的——AI辅助编码工具(比如Codex这类代码生成助手)让写策略代码这件事从"必须精通Python和金融工程"变成了"你能把逻辑讲清楚就行"。
我举个自己的真实例子。我想做一个基于动量+波动率过滤的轮动策略,以前我得自己查API文档、处理复权、对齐时间戳、写回测循环,一套下来两三天。现在我直接把逻辑用中文描述给AI助手,它给我生成骨架代码,我再针对数据接口和回测框架做适配,半天就能跑出第一版结果。省下来的时间全部花在策略逻辑的打磨上,这才是个人做量化真正的红利所在。
这篇文章我想把整个流程拆开讲清楚:一个人怎么从零开始,用Python和AI辅助工具,搭出一套适合自己的量化策略。不追求高频,不追求机构级精度,追求的是"能跑通、能验证、能迭代"的完整闭环。适合有一定编程基础但金融背景不深的个人开发者,也适合做过主观交易想转量化的朋友。
2. 个人量化的最小可行工具链怎么选
2.1 数据源:别一上来就追求"全"
我见过太多人卡在第一步——找数据。总觉得数据不够全、不够干净就没法开始。实际上个人量化起步阶段,你需要的只是日线级别的OHLCV数据,加上基本的复权处理就够了。
免费数据源里,A股可以用AkShare或者Tushare的免费额度,美股用yfinance,加密货币用ccxt对接交易所的公开接口。这些我都实际用过,AkShare的接口偶尔会变,但社区更新很快;yfinance胜在稳定,缺点是偶尔有数据缺失需要自己补;ccxt适合做币圈策略的朋友,接口统一度很高。
提示:数据源不要贪多,选一个主源用熟,再配一个备用源做交叉验证就够了。我一开始同时接了四个数据源,结果光是处理不同源之间的字段差异就花了一周,完全没必要。
这里有个容易被忽略的细节:复权方式的选择会直接影响回测结果。前复权适合做技术指标计算,因为价格连续;后复权适合做收益率计算,因为不会出现负价格。我一般是在数据加载阶段统一做前复权,然后在计算收益时用复权后的价格序列。这个细节如果搞错,回测出来的收益率可能差出好几个百分点。
2.2 回测框架:Backtrader还是自己写
这个问题我被问过无数次。我的答案是:如果你刚开始,用Backtrader;如果你想深入理解回测机制,自己写一个简化版。
Backtrader的好处是生态成熟,指标库丰富,多股回测、参数优化、绘图这些都有现成方案。它的Cerebro引擎设计得很优雅,策略类继承bt.Strategy之后,只需要实现next()方法就能跑。我最早做多股轮动回测就是用Backtrader,配合bt.analyzers做绩效统计,基本够用。
但Backtrader也有坑。它的默认撮合逻辑是"当前bar收盘价成交",这在日线级别回测里其实是有未来函数嫌疑的——你当天收盘才知道的信号,怎么可能当天收盘价成交?我的处理方式是改成次日开盘价成交,在next()里记录信号,在next_open()里执行。这个改动让我的回测结果和实盘偏差小了很多。
自己写回测引擎的好处是可控。我后来用Pandas+Numpy写了一个向量化回测框架,核心逻辑就是:信号矩阵和收益率矩阵做点积,加上手续费和滑点。代码量不到200行,但跑参数扫描的速度比Backtrader快一个数量级。缺点是只能做日线级别的简单策略,复杂的止损止盈逻辑处理起来麻烦。
| 对比维度 | Backtrader | 自写向量化回测 |
|---|---|---|
| 上手难度 | 低,文档全 | 中,需要理解回测原理 |
| 多股支持 | 原生支持 | 需要自己设计数据结构 |
| 参数扫描速度 | 慢,事件驱动 | 快,向量化计算 |
| 复杂逻辑 | 灵活 | 受限 |
| 适合场景 | 策略验证阶段 | 大规模参数搜索 |
2.3 AI辅助编码:把Codex当成你的"策略翻译官"
这是我觉得AI时代给个人量化带来的最大变量。以前你脑子里有个策略想法,得先翻译成代码,再调试,再验证。现在你可以直接把想法用自然语言描述出来,让AI助手生成第一版代码。
我常用的工作流是这样的:先用中文把策略逻辑写清楚,包括入场条件、出场条件、仓位管理、风控规则,然后让AI生成Python代码。生成之后我不会直接用,而是逐行检查——重点看三个地方:数据对齐有没有问题、有没有未来函数、边界条件处理对不对。
举个例子,我让AI生成一个"20日动量排名前5的股票等权持有,每周调仓"的策略。它生成的代码逻辑基本正确,但在计算动量时用了当天的收盘价,而调仓日也是当天,这就引入了未来函数。我改成用前一天的收盘价计算信号,当天开盘调仓,问题就解决了。
注意:AI生成的代码在金融场景下必须做未来函数检查。常见的问题包括:用当天收盘价计算当天信号、用未来数据做标准化、在回测中使用了实盘拿不到的数据。这些坑我几乎每个都踩过。
3. 从想法到策略:一套动量轮动策略的完整实现
3.1 策略逻辑的自然语言描述
我拿一个实际跑过的策略来拆解。这个策略的核心逻辑是动量轮动+波动率过滤,具体规则如下:
- 股票池:沪深300成分股(实际用ETF替代,避免个股停牌和退市问题)
- 动量计算:过去20个交易日的收益率
- 波动率计算:过去20个交易日收益率的标准差
- 筛选条件:动量排名前10,且波动率低于中位数
- 持仓数量:等权持有5只
- 调仓频率:每周一开盘调仓
- 风控:单只ETF最大回撤超过15%时清仓该标的
这个策略的逻辑基础是动量效应——过去涨得好的东西短期内倾向于继续涨。但纯动量策略在震荡市里回撤很大,所以加了波动率过滤,把那些涨得猛但波动也大的标的剔除掉。这个思路不是我原创的,很多学术论文都验证过,但个人做的好处是可以根据自己的风险偏好调整参数。
3.2 用AI生成策略骨架代码
把上面的逻辑整理成一段清晰的描述,丢给AI助手,它生成的代码大概长这样:
import pandas as pd import numpy as np class MomentumRotationStrategy: def __init__(self, data, lookback=20, top_n=10, hold_n=5, vol_filter=True, rebalance_freq='W-MON'): self.data = data # DataFrame, columns=标的, index=日期 self.lookback = lookback self.top_n = top_n self.hold_n = hold_n self.vol_filter = vol_filter self.rebalance_freq = rebalance_freq def calculate_signals(self): # 计算动量和波动率 returns = self.data.pct_change() momentum = self.data.pct_change(self.lookback) volatility = returns.rolling(self.lookback).std() # 生成调仓日期 rebalance_dates = pd.date_range( self.data.index[0], self.data.index[-1], freq=self.rebalance_freq ) signals = pd.DataFrame(0, index=self.data.index, columns=self.data.columns) for date in rebalance_dates: if date not in self.data.index: continue # 获取调仓日的动量和波动率 mom = momentum.loc[date].dropna() vol = volatility.loc[date].dropna() # 动量排名筛选 top_momentum = mom.nlargest(self.top_n).index # 波动率过滤 if self.vol_filter: vol_median = vol.median() selected = [s for s in top_momentum if vol[s] < vol_median] else: selected = list(top_momentum) # 等权持有 hold = selected[:self.hold_n] if len(hold) > 0: signals.loc[date, hold] = 1.0 / len(hold) return signals这段代码AI生成的部分大概占70%,我手动调整了调仓日期的处理逻辑和波动率过滤的细节。关键是要理解每一行在做什么,而不是直接跑。比如pct_change(self.lookback)这里,如果数据里有停牌导致的NaN,动量计算就会出问题,需要先做填充处理。
3.3 回测执行与绩效评估
有了信号矩阵,回测就简单了。我用的是自写的向量化回测:
def backtest(signals, prices, commission=0.0003, slippage=0.001): # 信号滞后一天,避免未来函数 signals_lagged = signals.shift(1).fillna(0) # 计算每日收益率 returns = prices.pct_change().fillna(0) # 策略收益 = 信号 * 收益率 strategy_returns = (signals_lagged * returns).sum(axis=1) # 扣除交易成本 turnover = signals_lagged.diff().abs().sum(axis=1) cost = turnover * (commission + slippage) strategy_returns = strategy_returns - cost # 计算净值曲线 nav = (1 + strategy_returns).cumprod() return nav, strategy_returns跑出来之后看几个核心指标:年化收益、最大回撤、夏普比率、胜率、盈亏比。我一般还会看分年度收益,如果某一年特别差,得搞清楚是策略逻辑的问题还是市场环境的问题。
我第一次跑这个策略的时候,年化收益看起来不错,但最大回撤到了35%,而且回撤集中在2018年和2022年。后来分析发现,这两年都是动量因子失效的年份,纯动量策略在这种环境下就是会亏。加了波动率过滤之后,回撤降到了22%,年化收益只损失了不到2个百分点,性价比很高。
4. 回测里那些"看起来很美"的陷阱
4.1 未来函数:最隐蔽也最致命
未来函数是回测里最常踩的坑,没有之一。它的表现形式很多,有些很明显,比如用了未来才知道的数据;有些很隐蔽,比如数据对齐时的时区问题。
我踩过的一个典型坑是财务数据的使用。我想做一个基于ROE的选股策略,直接用财报里的ROE数据做筛选。回测结果好得离谱,年化40%多。后来发现,财报的发布日期和报告期是两回事——你在一季度结束的时候,根本拿不到一季报的数据,通常要等一个月甚至更久。我改成用财报实际发布日期来对齐数据之后,年化收益直接掉到了15%。
另一个隐蔽的坑是指数成分股调整。如果你用当前的沪深300成分股去回测过去五年的数据,那就是典型的幸存者偏差——那些被调出的股票,往往是因为表现差才被调出的,你等于自动过滤掉了差股票。正确的做法是用历史成分股数据,或者干脆用ETF来规避这个问题。
提示:检查未来函数的一个笨办法是,把回测信号打印出来,随机挑几个调仓日,手动核对当天你能拿到的数据是否支持这个信号。如果发现某个信号依赖了当天收盘后才能知道的信息,那就是未来函数。
4.2 过拟合:参数越多,死得越快
个人做量化最容易犯的错就是过拟合。因为你有无限的时间去调参数,总能把回测曲线调得很漂亮。我见过有人用8个参数拟合三年的数据,回测夏普3.0,实盘三个月亏了20%。
我的经验是:策略的核心参数不要超过3个,而且每个参数都要有经济学逻辑支撑。比如动量回看期,20日、60日、120日分别对应短期、中期、长期动量效应,这是有学术研究支撑的。但如果你把回看期设成17日,那就纯粹是拟合了。
判断过拟合的一个实用方法是样本外测试。把数据分成两段,前70%做参数优化,后30%做验证。如果样本外表现和样本内差很多,那就是过拟合了。我一般还会做滚动窗口测试,用过去三年的数据优化参数,在接下来一年验证,然后滚动前进。这个方法更接近实盘的真实情况。
4.3 交易成本:被低估的收益杀手
很多人回测的时候不扣交易成本,或者只扣万分之三的佣金。实际上个人做量化的交易成本远不止这些。滑点、冲击成本、最小交易单位限制,这些都会吃掉收益。
我做过一个测算:一个每周调仓、持仓5只的策略,如果每次调仓换手率是50%,一年下来换手率大概25倍。按单边千分之一的综合成本算,一年光成本就吃掉2.5%的收益。如果你的策略年化收益是15%,成本就占了六分之一。
降低交易成本的方法有几个:降低调仓频率(从每周改成每两周)、增加持仓数量(从5只增加到10只,降低单只权重)、设置调仓阈值(信号变化超过一定幅度才调仓)。我现在的策略基本都改成了双周调仓,换手率降了一半,年化收益反而提高了,因为省下来的成本超过了信号衰减的损失。
5. 从回测到模拟盘:策略上线前的最后一道关
5.1 模拟盘跟踪的必要性
回测跑得再好,也不能直接上实盘。我自己的规矩是:任何策略必须经过至少3个月的模拟盘跟踪,才考虑投入真金白银。
模拟盘和回测的区别在于:回测是"事后诸葛亮",你知道当天收盘价是多少,信号计算和成交都在同一天完成;模拟盘是"实时决策",你需要在盘中或者收盘后计算信号,然后按第二天的价格成交。这个时间差会带来很多回测里看不到的问题。
我遇到过的情况包括:数据源在盘中更新延迟,导致信号计算用了过时的数据;调仓日遇到节假日,需要顺延处理;某些标的流动性不足,模拟盘按收盘价成交,实盘可能滑点很大。这些问题在回测里都不会暴露,只有模拟盘才能发现。
5.2 模拟盘的技术实现
模拟盘的技术架构比回测复杂一些,但也没那么难。我的方案是:用定时任务每天收盘后拉数据、算信号、生成调仓指令,第二天开盘手动或半自动执行。
具体来说,我用schedule库或者系统的crontab做定时任务,每天下午4点触发。脚本做三件事:拉取最新数据、计算策略信号、和当前持仓对比生成调仓列表。调仓列表输出到一个CSV文件,我第二天早上看一眼,确认没问题就手动执行。
import schedule import time from datetime import datetime def daily_task(): print(f"开始执行每日任务: {datetime.now()}") # 1. 拉取最新数据 data = fetch_latest_data() # 2. 计算信号 signals = strategy.calculate_signals(data) # 3. 生成调仓指令 current_positions = load_current_positions() target_positions = signals.iloc[-1] orders = generate_orders(current_positions, target_positions) # 4. 保存指令 orders.to_csv(f"orders_{datetime.now().strftime('%Y%m%d')}.csv") print(f"调仓指令已生成,共{len(orders)}条") # 每个交易日收盘后执行 schedule.every().monday.at("16:00").do(daily_task) schedule.every().tuesday.at("16:00").do(daily_task) # ... 其他交易日 while True: schedule.run_pending() time.sleep(60)这个方案的好处是简单可控,不需要对接券商API,避免了自动交易的风险。缺点是执行效率低,适合资金量不大、调仓频率不高的个人策略。
5.3 模拟盘和回测的偏差分析
模拟盘跑了一段时间之后,一定要做偏差归因分析。把模拟盘的实际收益和回测的理论收益做对比,看看差异来自哪里。
我自己的经验是,偏差主要来自三个地方:成交价格差异(回测用收盘价,模拟盘用次日开盘价)、数据差异(回测用的是清洗过的历史数据,模拟盘用的是实时数据,可能有缺失或错误)、执行延迟(回测是瞬时成交,模拟盘有手动操作的时间差)。
这些偏差加起来,通常会让模拟盘收益比回测低2-5个百分点。如果偏差超过这个范围,就要仔细检查是不是策略逻辑有问题,或者数据源有系统性误差。
6. 个人量化策略迭代的一些实战心得
6.1 策略不是越复杂越好
我刚开始做量化的时候,总想把各种因子都塞进去——动量、价值、质量、波动率、情绪,恨不得做一个全能策略。结果就是参数爆炸,过拟合严重,实盘表现一塌糊涂。
后来我慢慢想明白一个道理:个人量化的优势在于灵活和小众,不在于全面。你不需要打败所有机构,你只需要找到一两个有效的因子,把它做深做透。我现在的主力策略就两个因子:动量和波动率。逻辑简单,参数少,但实盘跑了两年多,表现一直很稳定。
6.2 持续跟踪比频繁优化更重要
很多人策略上线之后,一看回撤就慌,赶紧调参数。结果调来调去,把策略调废了。我的做法是:策略上线之后,除非逻辑本身出了问题,否则至少跟踪半年再考虑调整。
判断策略是否失效,不能看短期回撤,要看滚动夏普比率和因子IC值。如果滚动夏普持续低于0.5,或者因子IC连续三个月为负,那才说明策略可能真的失效了。短期的回撤,很多时候只是市场风格切换,策略本身没问题。
6.3 把AI当成助手而不是依赖
AI辅助编码确实能大幅提高效率,但策略的核心逻辑必须你自己想清楚。AI可以帮你写代码、查文档、优化性能,但它不知道你的风险偏好,不知道你对市场的理解,更不知道什么样的策略适合你。
我的工作流是:自己想清楚策略逻辑,用自然语言写下来,让AI生成代码骨架,自己逐行检查和调整,然后跑回测验证。AI负责"翻译"和"搬砖",我负责"决策"和"判断"。这个分工我觉得是最合理的。
注意:AI生成的代码在金融场景下一定要做安全审查。我遇到过AI生成的代码里直接用了
eval()函数处理用户输入,这在实盘环境里是绝对不能接受的。所有涉及资金操作的代码,必须经过人工审核。
6.4 记录每一次失败的尝试
我从开始做量化到现在,跑过不下50个策略,真正上实盘的只有3个。剩下的47个都失败了,但我把每一次失败的原因都记录下来了。这些记录比成功的经验更有价值。
比如我试过一个基于新闻情绪的择时策略,回测看起来不错,但实盘发现新闻数据的获取和处理延迟太大,等情绪信号出来,行情已经走完了。这个失败让我明白了一个道理:个人做量化,数据获取速度是硬约束,不要碰那些依赖实时数据的策略。
还有一个基于机器学习的选股策略,用随机森林预测下期收益,回测AUC有0.6多,看起来还行。但实盘发现模型对市场环境变化极其敏感,2021年训练的模型到2022年就完全失效了。这个失败让我对机器学习在个人量化中的应用变得非常谨慎——没有足够的数据和算力做持续训练,ML策略很难稳定。
6.5 资金管理和心态建设
最后说一个容易被忽略但极其重要的点:资金管理。个人做量化,最容易犯的错就是All in。我见过有人把全部积蓄投进一个回测年化50%的策略,结果实盘第一个月就回撤20%,心态直接崩了。
我的建议是:任何策略上线,初始资金不要超过总可投资金的20%。跑满一年,确认策略稳定之后,再逐步加仓。而且不同策略之间要分散,动量策略和均值回归策略搭配,股票策略和商品策略搭配,降低整体回撤。
心态方面,量化交易最大的挑战是在策略回撤的时候坚持执行。回测里看到的回撤是历史数据,实盘里的回撤是真金白银。我自己的做法是:把策略的预期最大回撤写下来,贴在电脑旁边。当实际回撤接近这个数字的时候,提醒自己这是策略的正常表现,不要轻易干预。
这套流程我跑了两年多,从最开始的手忙脚乱到现在基本半自动化,中间踩了无数的坑。但回头看,个人做量化这件事在AI时代确实变得可行了。你不需要机构级的资源,只需要一套合理的工具链、清晰的策略逻辑、严格的回测验证,以及最重要的——持续学习和迭代的耐心。