1. 为什么写代码的人会去碰“管钱的事”前阵子跟几个老同事吃饭聊起一个挺有意思的现象以前组里写业务系统的、写中间件的、甚至写前端的最近陆陆续续都开始研究AI量化理财。有人自己写脚本盯盘有人用现成的量化框架跑策略回测还有人干脆把开源项目改了个底朝天。大家喝着酒聊K线、聊因子、聊回撤恍惚间以为自己在跟某个量化私募的人开会。这个现象其实一点都不意外。程序员接触量化理财几乎是顺理成章的事。写代码的人天生习惯用逻辑和系统去解决问题而量化交易本质上就是一个把投资逻辑变成代码、用数据验证、用系统执行的过程。说白了它就是一个软件开发项目——只不过交付物不是网站或App而是一套决策系统。我最早接触这个东西其实是被朋友拉下水的。当时他给我看了一套简单的双均线策略的回测曲线说年化收益看着还行。我第一反应是质疑这数据干净吗手续费算了吗有没有未来函数问完这几个问题我自己都笑了——这不就是平时做技术方案评审时的那套思路吗。从那一刻起我就知道这事儿我大概率会陷进去。这篇文章不聊具体买卖建议不聊怎么预测明天涨跌那些都是玄学。我想聊的是一个写代码的人如何用做工程的方式去碰管钱的事从数据获取、策略设计、回测验证到风险控制每一步会遇到什么坑以及我亲身踩过之后总结出来的经验。1.1 程序员做量化理财的天然优势先说说为什么程序员干这事儿有优势这不是自吹自擂而是技能树真的对得上。量化交易的核心链条是这样的数据 —— 信号 —— 执行 —— 风控。你看这四个环节每一个都是程序员日常工作的亲戚。数据处理是我见过最多程序员入坑的切入点。处理过日志、清洗过用户行为数据的同学面对行情数据的感受是就这。K线数据、分时数据、盘口数据无非就是时间序列、去重、对齐、缺失值处理这套东西在公司里早就玩熟了。我第一次写数据清洗脚本的时候一度怀疑自己是在处理某个业务的埋点日志。信号生成这块其实就是特征工程加模型推理。推荐系统里做的用户特征挖掘、排序模型训练搬到金融场景里面变成因子计算、模型预测涨跌概率。同一个套路换个数据集而已。我见过最夸张的同行直接把公司里的时序预测框架搬出来改巴改巴就上阵了。执行和风控就更熟了订单管理、状态机、熔断机制、重试策略——这不就是微服务架构里那套东西吗限流、降级、超时重试你在后端写过一遍在交易系统里再写一遍异常处理逻辑甚至有七成相似。所以你看不是程序员突然对金融感了兴趣而是金融这个领域突然对程序员敞开了大门。以前量化交易是名校金融数学专业毕业生的专属领地现在开源框架、免费数据源到处都是一个熟练的Python工程师完全可以自己攒一套。1.2 从写功能到写策略的思维转换不过技能迁移听着顺理成章真做起来还是有不小落差。最大的落差在于评判标准变了。写业务代码需求明确验收标准清晰——功能上线、不出Bug、性能达标这就行了。哪怕你代码写得丑一点只要测试通过没人会说你什么。量化策略不一样。策略没有正确的答案只有一个模糊的指标叫收益而这个收益是概率性的、有噪声的、会随时间变化的。我见过一个做后端的老哥写了一套非常漂亮的策略系统架构解耦、设计模式用得出神入化每一步都有日志和监控。结果跑了一年实盘收益还不如余额宝。问题出在哪出在他太关注系统怎么跑忽略了策略本身逻辑是否有效。换句话说他把量化当成一个纯工程问题来解但量化首先是一个投资逻辑问题工程只是载体。这个思维转变特别关键。写业务代码你追求确定性的正确写量化策略你得接受一切都是不确定的概率。同一个策略在某个市场环境下赚得盆满钵满换一个环境就亏得底朝天。这不是Bug这是常态。另一个转变是时间尺度不同。写业务代码你上线一个功能当天就知道效果如何量化策略不一样你调一个参数可能得等几个月才能验证这个改动到底有没有效果。这种延迟反馈特别磨人很多人就是熬不过这个阶段反复调整策略最终陷入过度优化的泥潭。2. 搭建一个能跑起来的量化系统聊完思维层面说点具体的。我把自己实际搭建量化系统的心得拆成几个模块逐个说说怎么落地。2.1 数据是地基但地基本身就不稳做量化系统第一步就是搞数据。你以为最简单的一步其实是最坑的一步。市面上免费的数据源不少但质量参差不齐。我一开始图省事用某个开源库直接拉日线数据回测跑得欢天喜地结果实盘一对照数据复权方式、停牌处理、涨跌停规则全对不上回测结果完全是空中楼阁。数据问题有几个典型坑第一个是复权问题。前复权和后复权的数据在回测中表现差异巨大尤其是拿长期数据做策略的时候。某只票价格因除权除息跳空如果你不做复权处理直接在这个跳空的位置产生不存在的涨跌幅策略信号会完全失真。所以我现在的做法是统一用后复权数据做回测因为后复权保留了完整的价格连续性算收益率最准确。第二个是停牌和涨跌停的处理。这个很多人一开始压根没想过。某只票连续涨停你的策略算出买入信号但实际你根本买不进去因为一字板封死了。回测里你毫不知情地买入了然后赚了一大笔虚拟利润实盘里你眼巴巴看着买不进。这就是典型的回测可以买但实盘买不到陷阱。第三个是数据对齐。不同来源的数据交易时间戳格式可能不一致有的用本地时间有的用UTC合并的时候稍不留神就错位了。我当时写了一个数据清洗模块专门做时间戳标准化、去重、按交易日重采样这一套下来才敢拿数据去喂策略。我的建议是一上来不要追求高精度分钟级数据先用干净的日线数据把流程跑通确认你的策略逻辑是有效的再考虑升级到更细粒度的数据。很多人一上来就要搞tick级高频结果数据量、存储、计算全成了瓶颈策略本身还没验证过纯属自己给自己挖坑。2.2 策略引擎的架构怎么组织说完了数据聊聊系统架构。我花了挺长时间才找到一套比较顺手的组织方式核心原则就是把策略逻辑和系统框架彻底解耦。为什么这么强调因为做策略的人和做系统的人有一个共同的经验一旦你要频繁修改策略逻辑却发现要动系统框架的代码那一切都完了。策略本身就是不断实验、不断推翻重来的如果每一次调整都要牵动系统底层你的迭代速度就慢得可怜。我最终采用的架构分四层第一层是数据服务层。统一封装数据获取、清洗、缓存对外提供干净的接口比如get_bars(symbol, start, end, period)。策略层完全不关心数据是从哪个源来的、有没有做复权处理直接调用接口拿数据就行。第二层是策略层。实现各种信号计算逻辑输入是一段历史数据输出是一系列目标持仓或者信号事件。策略逻辑应该做到纯函数化——同样的输入永远产生同样的输出不依赖外部状态这样便于回测和调试。第三层是执行模拟层。这层负责把策略产生的信号转换成模拟成交结果。需要考虑手续费、滑点、涨跌停限制、停牌等约束条件。这层越真实回测结果越有参考价值。第四层是回测引擎层。负责遍历历史数据、调度策略、记录账户权益曲线、计算各类绩效指标。我个人不太喜欢用现成的重量级回测框架更倾向于自己维护一套精简的引擎原因后面说。这四层各司其职我写策略的时候只碰第二层调数据的时候只碰第一层边界清晰调试起来非常舒服。2.3 现成框架和自研引擎的取舍说到回测框架很多人会问用现成的开源框架不香吗香但分阶段。如果你是新手我强烈建议先用现成的框架跑通一遍流程。主流的几个开源回测框架文档还算齐全社区也活跃你跟着教程走一遍能快速建立对回测怎么测的完整认知。而且现成框架的绩效计算模块做得比较完整夏普比率、最大回撤、收益曲线图都是现成的省很多事。但等你开始认真做策略研究你会发现现成框架的教学属性开始变成束缚。为了兼容各种场景框架往往做了很多抽象层你要改一个滑点模型可能要翻好几层代码。更重要的是框架的性能和你自己的性能预期差距可能很大——你要跑十年日线数据、几百只票的因子计算框架内部的循环处理方式可能慢得让你怀疑人生。我自己现在是混合模式用开源自研框架作为对照验证手段但主要回测流程跑在自己维护的精简引擎上。这个精简引擎满打满算不到一千行但每一个环节都是我自己控制的出了任何奇怪结果我能在十分钟内定位问题。这个取舍我认为是值得的。3. 核心策略的实现细节3.1 从最简单的策略开始双均线不管你在知乎、公众号上看到多少高大上的词——机器学习、深度学习、强化学习、高频因子——我心里的建议永远是从最简单的策略开始。双均线策略就是量化界的Hello World。双均线逻辑很简单短期均线上穿长期均线产生买入信号下穿产生卖出信号。代码实现不超过二十行import pandas as pd def moving_average_crossover(df, short_window20, long_window60): df[short_ma] df[close].rolling(windowshort_window).mean() df[long_ma] df[close].rolling(windowlong_window).mean() df[signal] 0 df.loc[df[short_ma] df[long_ma], signal] 1 df.loc[df[short_ma] df[long_ma], signal] -1 # 取信号变化点避免连续重复信号 df[position] df[signal].diff() return df这段代码看起来简单但里面已经包含了一个关键细节用diff()只取信号变化点避免每个交易日在同一个方向上重复产生开仓信号。我第一次跑这个策略的时候看着回测曲线直乐呵这也能赚钱但冷静下来一算账不对因为没算交易成本。双均线策略是出了名的震荡市绞肉机趋势行情里赚得痛快震荡行情里频繁开平仓手续费和滑点能把你之前赚的全吐回去甚至倒亏。这个例子特别适合拿来理解交易成本在策略研究中的地位。我后来在回测引擎里做了手续费和滑点模拟同样的双均线策略夏普比率几乎腰斩。很多人说程序员的量化策略都在回测里赚钱实盘全亏很大一部分原因就是回测里没认真模拟交易成本。3.2 引入机器学习模型从规则到预测当你对规则策略有了感觉可以开始碰更复杂的机器学习模型。但这里的坑比规则策略多得多。先说一个最常见的误区把机器学习当成水晶球觉得自己能预测明天涨跌。实际上金融时序的预测难度极高大部分成熟的做法是预测概率或者方向然后根据预测结果做仓位调整而不是全仓梭哈。我当时做的一个相对靠谱的方案是构造一系列技术指标作为特征过去N日的收益率、波动率、成交量变化率、RSI、布林带位置等预测未来N日上涨概率。如果概率高于阈值增加仓位低于阈值减少仓位。模型选的是梯度提升树而非神经网络原因是金融数据样本量相对有限树模型在小样本上更不容易过拟合而且特征重要性可解释性更好。代码框架大致是from sklearn.ensemble import GradientBoostingClassifier def prepare_features(df, lookback20): features pd.DataFrame(indexdf.index) features[ret_1] df[close].pct_change(1) features[ret_5] df[close].pct_change(5) features[ret_20] df[close].pct_change(20) features[vol_20] df[close].pct_change().rolling(20).std() features[volume_ratio] df[volume] / df[volume].rolling(20).mean() # 更多特征... return features.dropna() def train_model(): features prepare_features(historical_data) labels (future_return 0).astype(int) # 未来N日上涨为1 model GradientBoostingClassifier(n_estimators200, max_depth3) model.fit(features, labels) # 用时间序列交叉验证评估而不是随机划分这里有一个极其容易踩的坑样本划分方式。传统机器学习做随机划分训练集和测试集时间序列数据绝对不能这么干因为金融数据有时间相关性随机划分等于把未来信息泄露给了训练集回测结果虚高得离谱。必须用前N年训练、后N年测试的时间序列交叉验证方式。3.3 那些让人欲哭无泪的坑过拟合和前视偏差机器学习策略最大的敌人有两个一个是过拟合一个是前视偏差。这两个坑我算是拿真金白银买过教训。过拟合的表现是训练数据上表现完美但测试数据上崩塌且换一段全新的市场数据也一塌糊涂。树模型尤其容易过拟合层数越深、树越多、特征越多越容易把噪声也学进去。我第一次调参的时候训练集年化收益漂亮得宛如股神附体测试集直接亏到怀疑人生。后来习惯了任何策略如果它在训练集上的表现好得不像话那大概率是过拟合了不是你的策略牛逼。防过拟合的手段很多常规的有简化模型、增加正则项、早停法、滚动窗口训练。但我个人认为最有效的还是增加样本多样性——在多个相关性低的资产上同时验证策略而不是只在一只票上反复折腾。如果你的策略在股票、期货、宽基指数上都能跑出类似的逻辑效果那才敢说策略逻辑本身是有效的。前视偏差则是另一个隐蔽的坑。它的本质是用到了当下时点还不该知道的信息。举一个典型的例子你想用当天的收盘价来产生买入信号然后在当天开盘时执行买入——这就有问题了因为开盘时你根本不知道收盘价是多少。解决方法是信号的生成和使用必须严格基于当时可得数据计算特征时必须做shift把当期的值移动到下一期才能用。我把这套逻辑总结成一句话策略的每一个输入都必须是这个时刻真实世界能拿到的东西。这句话看着简单但落实起来需要你在写代码的时刻处处设防。4. 风控量化系统中最容易被忽视的一环4.1 仓位管理的数学基础很多程序员做量化理财一门心思扑在怎么选标的、怎么算信号上对仓位管理完全没概念。这是大忌。实际上对长期收益影响最大的往往不是选了什么票而是投了多少仓位。仓位管理有个经典公式——凯利公式。公式长这样f* (bp - q) / b其中f*是最优下注比例b是赔率盈利时的收益/亏损时的亏损p是胜率q 1 - p是败率。举个例子某个策略胜率55%盈利时平均赚10%亏损时平均亏10%那么f* (1*0.55 - 0.45) / 1 0.1也就是单次最多投入10%的仓位。但凯利公式在实际使用中有一个致命问题它假设你对胜率和赔率有精确估计而现实中这两个数本身就是带噪声的估计值。所以实践中有个经验做法用半凯利甚至四分之一凯利也就是把公式算出的比例再打个对折为估计误差留足安全边际。我自己的风控参数经过几轮调整固定用0.25倍凯利虽然单笔收益没那么刺激但净值曲线的平滑度大幅提升。4.2 回撤控制的两种思路回撤控制是量化系统的生命线。我自己踩过一个大坑策略连续盈利三个月我开始觉得这次不一样了手动加了两倍杠杆结果一周之内回撤吃掉前三个月的全部利润。后来我学乖了回撤控制用两种方式并行。第一种是硬性限额。设置一个绝对值的单日止损和阶段回撤限额。比如单日亏损超过总资金的3%强制清仓账户从峰值回撤超过15%资产减半运作。这些规则是写死的哪怕系统信号说要买入一旦触发风控限额直接停止新建仓。这种机械式的冷酷是必要的——因为人在亏损时的判断力会严重下降你觉得自己在做理智决策实际上只是想要回本。第二种是波动率目标调整。计算近期市场的实际波动率如果波动率上升主动降低仓位如果波动率下降适当提高仓位。这个思路本质上是动态风险预算让策略在不同市场环境下承受大致相当的风险水平。2018年那种单边阴跌的市场里波动率高的阶段我的系统自动把仓位压到很低的水平虽然少赚了一些反弹的利润但确实躲过了好几次大的回撤。4.3 实盘和回测的差距到底有多大聊一个绕不开的话题为什么回测曲线那么漂亮实盘全变味最大的差距来自理想化的假设。回测框架里你的订单按收盘价成交真实世界里你按收盘价委托可能根本排不上队。回测框架里滑点是个固定参数真实世界里大单进场直接就把价格推远了。回测框架里你瞬间完成换仓真实世界里你可能要花上好几分钟分批成交这期间价格已经变了。我自己的经验是用保守化验证来弥合这个差距。具体做法是回测的时候成交价在信号价格的基础上再让出一到两个点的偏差当作滑点手续费按你实际使用券商费率的两倍去估算。这样跑出来的结果如果还能盈利那实盘才有信心上。如果回测这个保守版的策略都不赚钱那就别想着实盘会更好实盘永远更糟。另一个实盘特有的问题是延迟和中断。你的交易客户端可能因为网络抖动断线、券商接口可能因为系统升级不可用、你的云服务器可能半夜自动重启——每一个在软件开发中稀松平常的小问题放到交易场景里都可能变成真实亏损。所以实盘系统必须做过硬的容错设计断线自动重连、下单失败自动重试、重试失败告警通知每一项都要测试到位。5. 常见问题与排查技巧实录5.1 策略信号对不上我遇到最多的一个问题是回测里的信号和实盘里的信号对不上。明明用的同一套策略、同一种数据源结果一个说买一个说卖。排查了三个小时终于找到了元凶数据时间戳的时区问题。行情数据用的是交易所本地时间而我本机跑策略用的都是北京时间看似一样但遇到某些数据源用UTC时间戳两个时间之间差了8小时——计算当日收盘均线的时候昨日和今日的数据边界就错位了。解决方案在数据服务层统一做时区标准化所有数据入库前强制转成同一时区的datetime格式策略层永远从统一接口取数据。宁可在这个环节多花点功夫后续的调试成本能省一大半。5.2 回测速度慢到怀疑人生另一个高频问题是回测性能。一开始我用纯Python写回测循环跑一支股票十年日线数据一次回测要跑好几分钟。再叠加十几个参数组合的网格搜索一个晚上都跑不完。程序员对这种重复劳动的容忍度极低所以我做了两件事第一把数据预计算提取出来。所有需要滚动窗口计算的特征提前一次性算好存下来回测循环里只做信号判断和成交模拟不做任何特征计算。第二能向量化就向量化。用numpy和pandas的向量化操作替代显式循环性能提升是几十倍级别的。比如计算某技术指标时大多数人会用for循环逐行计算但实际上用rolling().apply()或者直接矩阵运算就能完成速度快得惊人。优化完之后同一个回测从几分钟降到几秒钟。这个优化过程本身就是程序员的舒适区——说白了就是做性能优化嘛。5.3 策略突然失效了怎么办最后聊一个每个做量化的人都会遇到的情况策略在某个时间突然开始亏钱回撤持续扩大曾经有效的逻辑不再灵验。首先需要区分两种情况是正常波动还是策略失效。判断方法很简单打开策略收益走势图观察当前的净值回撤幅度和历史上最大回撤的对比。如果回撤已经超过了历史最大回撤多大概率不是正常波动而是策略逻辑不再适应当前市场环境。标准的应对方式是降仓观察。不要立刻推翻策略也不要硬扛着满仓运行。先把仓位降到正常水平的一半甚至四分之一给策略一段观察期。如果降仓后仍然持续亏损那就停下来进入策略诊断流程重新看策略依赖的核心假设是什么当前市场环境是否已经发生了结构性变化。我自己的经验是很多看似失效的策略其实只是市场风格切换导致的阶段性失灵。比如一个基于动量效应的策略在趋势行情里赚得盆满钵满但到了2021年那种大小盘分化震荡的行情里就会持续打脸。这种时候如果你能识别出当前市场环境不匹配甚至可以主动暂停策略等市场风格回归再启动。6. 写在最后一些属于程序员的特别提醒我做了这些年量化理财的系统有个特别深的感觉这套东西本质上做的还是工程不是魔法。数据清洗、架构设计、模型验证、容错处理、性能优化——这些技能你早就会了你只是把它们用到了一个新的场景。而你最大的优势恰恰是你能用搞工程的态度去对待管钱这件事——你会在系统里写日志会在关键节点设告警会在每次改动后留backup会有一套自己的测试用例。这些东西在很多老派投资者眼里是不存在的概念但在量化系统里就是黄金。最后说三个不算成熟的建议第一有一个自己的研究笔记本。我会把每次策略迭代的理由、预期效果、实际结果都记录下来。量化研究最怕的就是改了参数忘了为什么改有了记录你能在将来复盘的时候看清自己的思维脉络。第二别把所有钱都放在量化系统里。即使系统跑得再顺也要留足生活备用金和情绪安抚金。因为量化系统一定会遇到连续回撤的阶段如果你把钱全部压在里面大概率会在最不该停的时候心态失衡手动干预然后做错。我见过太多人死在这一步。第三对收益率保持敬畏。一个年化20%的量化策略听起来不刺激但如果你能坚持五年、十年让复利慢慢滚这才是可怕的力量。更多人追求的是一年翻倍的爽感结果两年内亏掉六成本金。慢就是快这句话在普通人能接触到的投资领域里从来都是成立的。写代码的人去碰管钱的事这件事的优势不是更聪明而是更系统、更自律、更经得起复盘。把这些做扎实了剩下的就交给时间去验证。