2026/10/13 23:58:14

Python量化交易入门:数据获取、策略回测与实盘实践

Python量化交易入门:数据获取、策略回测与实盘实践 这两年问“Python能不能做量化”的人越来越多而且问题通常会延伸成“我又不是专业量化研究员Python到底对我有什么用”。我一般只回答一句量化本质上不是高频跑得快而是把你的交易思路变成一套可以被验证、可回溯、可反复打磨的规则Python只是这条链路里最顺手的那块拼图。它能把行情数据拉取、指标计算、策略回测、模拟执行、甚至自动下单串成一条流水线。适合两类人一类是有成熟的交易想法、却被手工复盘拖垮效率的投资者另一类是初学数据分析、想用真实市场数据练手的新手。即使你不做自动交易只是用Python整理行情、生成复盘报告也已经值回票价。1. 内容整体设计与思路拆解1.1 为什么最终选了Python做量化如果让我用一句话说清“为什么是Python”我会说因为它把时间从写代码上抢了回来留给你去想策略。量化交易的本质不是写代码而是反复迭代。今天你觉得双均线参数可行明天把周期拉长又要重新验证一遍。Excel也能做但当你处理一年甚至三年的分钟级数据打开文件就要等半分钟计算指标更是卡到怀疑人生。C性能确实好但普通研究阶段去写C光编译和内存管理就够你喝一壶更别说每次改一次参数都要重新编译。Python的优势在于读和写都像说话一样自然而且几乎所有的数据处理、统计分析和可视化工作都有现成的高质量库兜底。pandas处理表格数据numpy做数值运算matplotlib和plotly画图requests拉网页接口这些都是经过大量项目验证的工具不需要从零造轮子。更重要的是Python的动态特性让人能把精力集中在策略逻辑上而不是底层实现。说实话我见过不少策略想法很好的人最后不是败给市场而是败给工具链太复杂、坚持不下去。还有一个很实际的理由回测的可复现性。做量化必须反复问自己一个问题——同样的参数、同样的数据半年后再跑一遍能不能得到一样的结果Python脚本天然具备这种可复现能力只要固定好数据版本和环境依赖任何时候重跑都能还原当时的结论。这件事Excel很难做到因为手工操作、版本覆盖太容易发生。1.2 量化系统应该拆成哪几层我自己的经验是量化项目能不能长期维护关键看一开始怎么拆层。很多人一上来就写一堆脚本把数据获取、策略逻辑、回测指标全堆在一个文件里改到第五天就开始痛苦。我习惯把系统分成四层数据层、策略层、回测层、执行与风控层。数据层负责一切输入K线、成交明细、财务数据、公告数据同时做清洗、复权、对齐。策略层做的事情很简单根据数据层输出的干净数据产出一组买卖信号。回测层负责把信号放到历史上模拟执行计算收益、回撤、换手、胜率等指标。执行与风控层只有在实盘阶段才会激活它接收策略信号根据当前持仓和资金做仓位检查再生成实际委托。这个分层顺序不是随意的。数据层做得越干净策略层的bug越少策略层只输出信号不关心买什么价格、手续费多少后面换一个回测引擎都不用改策略。反过来看很多人回测结果不理想往往不是策略问题而是数据层包含了脏数据或者执行层没有真实成本导致最终失真。把这四层在脑子里先立起来后面每一个环节出了问题你都知道该去哪一层排查。1.3 策略类型怎么选从趋势跟踪开始常见的量化策略大致可以分成四类趋势跟踪、均值回归、统计套利、因子选股。每类策略对数据频率、计算复杂度和实盘工程的要求都不一样。策略类型常见持仓周期核心逻辑适合人群趋势跟踪/动量几天到几周价格沿趋势运动跟随方向新手最适合入门均值回归几天价格偏离均值后会回归适合震荡市研究统计套利几秒到几天多标的价差回归需要一定工程基础因子选股几周到几个月按特征排序选组合适合做组合研究作为入门我强烈建议从单标的的趋势跟踪开始比如双均线、突破类策略。原因有几点逻辑简单容易解释行情数据只要一根日线就够不用处理复杂的多标的组合参数少便于做稳健性分析。很多人一上来就想做高频先不说硬件和数据成本高频对延迟和券商户头的要求就不是新手能轻易搞定的。先在一个标的、一个简单逻辑上跑通全流程比一开始就追求复杂策略重要得多。2. 核心细节解析与实操要点数据获取与预处理2.1 先搞清楚两类数据别只盯着K线量化系统的地基是数据这一层我花的时间比写策略还多。数据分两类行情数据和基本面数据。行情数据是指每个交易时点上的开盘、最高、最低、收盘、成交量、成交额这是绝大多数策略的原料。基本面数据则包括财务报表指标、估值、股东结构、行业分类、事件公告等做多因子和选股策略时常用量价策略不一定需要。很多新手容易犯一个错误只盯着“拿到数据”却不关心字段口径。比如同一个“收盘价”有的接口给的是不复权收盘价有的给的是前复权收盘价同一个“成交量”有的是股数有的是手数。这些字段如果不统一后面所有计算结果都会错得莫名其妙。我自己的做法是拿到任何数据源之后先打印出最近几行和最早几行人工核对一遍交易日期、价格上下界和量纲再进入策略环节。这个习惯看起来笨但能省下后面大量排查时间。还有一点要搞清楚“日线”到底代表哪个时区的时间。A股还好如果你做港股、美股或商品期货时区和交易时段不同日期标签很容易错位。一个稳健的做法是统一把时间列转换成UTC标准格式落地再在业务层按实际交易所时区转换。2.2 数据源选型免费、付费和自己抓怎么权衡我常用的数据源大致有三类先说结论研究阶段可以先用免费开源接口一旦确认策略要认真投入或进入实盘准备就换可靠的付费数据源并且至少找两个来源做交叉验证。第一类是免费开源接口库适合快速验证想法。它的优点是零成本、社区大、更新活跃缺点也明显数据完整性和稳定性参差不齐分钟级数据经常缺失部分字段是多方拼接出来的只能用于研究不能直接接到实盘。第二类是付费数据服务商字段清晰、更新及时一般会提供SDK适合有一定预算的个人或小团队。第三类是自己写爬虫去网页抓取这个我不推荐上来就做网页结构经常变还要处理反爬和断线重试维护成本很高。选型时有一个关键判断标准未来你的策略如果不赚钱你应该能归因到“策略本身不行”而不是“数据源坑了你”。如果数据源字段不齐、复权错误、时序断裂你根本没法得出这个结论。所以我建议在研究初期就把原始数据以标准化格式落盘存档每次回测都基于同一份本地数据快照而不是每次现拉现用。这样数据源即使后面数据有变动你依然能追溯当时的回测结论是怎么来的。2.3 预处理里最容易忽略的四个细节预处理决定回测的下限我踩过不少坑下面四个细节是最容易犯的。第一个是复权。股票会分红除权价格会跳空。如果你直接用不复权价格算均线策略会在除权日莫名触发买卖信号如果你用前复权价格做历史回测那历史价格会不断被最新价格修正相当于用了未来的复权因子产生轻微的未来函数。我的做法是策略回测统一用后复权价格实盘信号再结合最新价计算或者至少保证整个研究期内只用同一套复权规则不要中途切换。第二个是停牌和涨跌停。很多数据接口会把停牌日省略掉而不是留下一行NaN。如果你不做处理直接按连续日期计算收益率停牌后的第一根K线收益率会被错误地当作一个完整交易日的收益导致累计收益严重失真。同样的涨停板当天卖出和跌停板当天买入都可能无法成交回测必须加入涨跌停过滤否则你会高估策略的可执行性。第三个是时间索引一致。多个数据源合并时天然日、自然日、节假日经常打架。交易日历必须用交易所的官方日历不能用自然日直接推断。我的习惯是数据落地时先设置好时间索引并重新采样到策略需要的频率宁可冗余也不能缺失。第四个是数据落地格式。分钟级数据动辄上千万行每次都从接口现拉不现实最好一次性拉到本地存成Parquet或HDF5这类二进制格式读取速度和磁盘占用都比CSV好得多。同时对内存做优化收盘价、成交量这类数值列用float32而不是float64能省出一半内存。3. 核心细节解析与实操要点策略编写与回测3.1 用pandas写一个最简单的双均线策略有了干净数据就可以写策略了。我把双均线策略当作“数据加工”的一个典型示范先用rolling计算短周期和长周期均线再做信号判断最后平移到持仓状态。import pandas as pd import numpy as np def dual_ma_strategy(df, short5, long20): data df.copy() data[ma_short] data[close].rolling(short).mean() data[ma_long] data[close].rolling(long).mean() # 1表示持有多头仓位0表示空仓 data[signal] np.where(data[ma_short] data[ma_long], 1, 0) # 关键信号必须推迟一天避免使用未来信息 data[position] data[signal].shift(1) data[ret] data[close].pct_change() data[strategy_ret] data[position] * data[ret] data[strategy_cum] (1 data[strategy_ret]).cumprod() data[benchmark_cum] (1 data[ret]).cumprod() return data这里最容易被忽略的是shift(1)。很多人第一次写策略直接用当天的信号计算当天的收益回测结果异常漂亮。原因是你等于用当天收盘后才知道的信号去赚当天白天的涨幅这在现实中是做不到的。真实交易中就算你在收盘前几分钟确认金叉成立也很难保证在收盘价全部成交。所以更稳妥的做法是用今天的数据得出信号明天开盘再执行回测里用“次日开盘价”成交。position和signal还有一个区别signal可以随时变化但position只有经过价格变化后才变成收益。pct_change()之后用position去乘表示这段持仓期赚到的收益。空仓期没有持仓收益如果不想让资金闲置可以给空仓资金记上无风险收益不过对入门策略来说可以先忽略。如果要更接近真实交易还需要加入手续费和滑点。双均线策略不是高频策略交易频率不高但每次交易成本依然会挤掉一部分利润。手续费按万分之二点五计算加上滑点按万分之五计算你就会发现收益表没那么好看了。这部分切身体会等你做完第一版回测后会特别深。3.2 回测指标怎么看才不容易被骗回测跑完一堆数字跳出来最容易犯的毛病是只盯总收益率。总收益率高不代表策略好背后可能是极端行情驱动也可能是过拟合堆出来的。我一般会先看下面这几个指标缺一不可。指标含义我的使用建议累计收益率整体赚了多少只是起点不能作为决策依据年化收益率折算到一年的复利收益用来和其他策略、基准比较最大回撤从峰值跌到谷底的最大幅度我最关注的指标决定策略能不能拿得住夏普比率每承受一单位波动的超额收益大于1算不错大于2要小心过拟合胜率盈利交易次数占比单独看没用要结合盈亏比盈亏比平均盈利和平均亏损的比例和胜率组合起来看效果最大回撤比收益率重要得多。一个年化收益30%但最大回撤40%的策略普通人根本拿不住很可能在最低点割肉离场最终亏损收场。我见过不少策略单看夏普很漂亮但回撤期长达一年实盘根本无法坚持。所以回测报告里我会把资金曲线和基准放在一起画肉眼观察一年以上的回撤走势这比任何数值都直观。还有一点要提醒回测是在历史数据上的一次模拟样本量很小。如果一段回测只有十几笔交易无论如何都不具备统计意义。我个人认为至少需要上百次完整交易、覆盖两三轮完整的市场涨跌周期结论才勉强值得信任。3.3 防止过拟合少调参、多验证过拟合是量化回测最容易踩的坑本质是策略把历史数据里的噪声当成了规律。比如你拿着双均线策略把短期参数从3调到60把长期参数从20调到120在历史数据上总能找到一组看起来非常赚钱的参数。这不是因为策略有多厉害而是你试了几百组参数随机噪声里总有一组表现突出。这就像让一百个人猜硬币总有人连续猜中十次但你不会因此认为他有预测能力。避开的办法有几条都很朴素。第一条是控制参数数量参数越多过拟合空间越大。第二条是把数据切三段训练期、验证期、盲测期。在训练期调参在验证期确认参数依然有效最后在盲测期用从未碰过的数据做一次最终评估。第三条是做参数热力图如果最优参数附近有一片连续稳定区域策略可信度更高如果只有孤零零一个最优点旁边参数表现都很差那大概率是过拟合。再一个容易被忽略的点是交易成本敏感性。把手续费和滑点调高一倍再回测如果策略的夏普比率没有明显恶化说明策略对执行成本不敏感实盘更可靠。如果收益减半甚至变负那就要小心回测里看起来很美的利润实盘很可能被摩擦成本吃掉。4. 实操过程与核心环节实现从策略到可运行系统4.1 搭一个可复现的量化实验环境开始写代码之前先花五分钟把环境建好这一点很多新手会跳过后果是三个月后自己都复现不了当初的结果。我建议的流程是这样的。python -m venv quant_env source quant_env/bin/activate pip install pandas numpy matplotlib jupyter statsmodels pip freeze requirements.txt依赖版本一定要固化。pandas这类库的版本升级经常会导致rolling窗口行为、日期解析规则发生变化同一条回测脚本换一个版本跑出来的结果可能就不一样。所以每一次确认有意义的回测结果我都会记录对应的数据快照时间和requirements.txt保证后续任何时间可以还原。目录结构我也固定成五块data放原始数据和预处理后的数据strategies放策略代码backtest放回测引擎和指标计算results放回测报告和图表config放参数配置。配置统一放在配置文件里策略代码不硬编码参数这样切换不同的标的、时间段、成本参数都方便。4.2 拿下面这个案例走一遍完整回测我以某只宽基指数ETF为例用日线数据做双均线回测。数据周期是过去五年参数设为短期5天、长期20天。初始资金10万元佣金按成交金额的万分之二点五计算滑点按万分之五计算。这里是核心步骤。第一步取数据并做预处理补全缺失交易日期统一复权规则计算每日收益率。第二步按上一节的dual_ma_strategy函数生成持仓状态和策略收益。第三步把手续费和滑点扣进去生成最终资金曲线。第四步计算指标并与“买入并持有”基准做对比。我做了几组参数后得到一份典型结果如下数字我做了一些模糊处理但趋势代表了常见情况。指标双均线策略买入持有基准年化收益率8.6%10.3%最大回撤16.2%29.8%夏普比率0.870.58交易次数461这份结果传达的信息很重要双均线策略在年化收益上并不一定跑赢买入持有但它的回撤显著缩小夏普比率更高。也就是说这个策略的价值在于“平滑资金曲线”而不是翻倍暴富。如果你拿这个结果去期望年化50%那方向就错了。我也做过另一组参数年化更高但回撤超过40%这种策略在实盘里几乎无法坚持。回测完成后我会顺手画几张图资金曲线对比、持仓状态时序、每笔交易的盈亏分布。资金曲线图能看出策略在哪个阶段吃到了利润、哪个阶段持续回撤盈亏分布图能看出是否存在少数几笔交易贡献大部分收益的情况。如果盈利只靠两三笔交易撑起来那这个策略的可复制性就很差。4.3 从回测到实盘中间的衔接步骤不能省很多人回测看着不错立刻就想接实盘自动交易这个跳跃太大容易摔得很惨。我建议按三步走。第一步是模拟盘验证。用真实行情接口实时接收行情同时继续用历史回测框架跑策略但把信号输出到日志。这个阶段不追求执行速度重点是确认策略在真实行情下能够稳定产生信号数据接口不会时不时断流。第二步是信号提醒。把策略信号通过消息推送到微信或者邮件由人工判断是否下单。这一步能帮你及时发现信号与行情的偏差还能避免全自动出金风险。第三步才是半自动或全自动下单而且下单前必须有仓位检查、止损检查、当日剩余可买资金检查这三道安全网。我特别建议把“信号”和“订单”分开。策略层只管生成信号执行层负责把信号翻译成订单。这样可以防止策略里一个毫秒级的重复触发导致执行层重复下单。实盘环境的成交回报、撤单、超时、网络重连都需要单独设计状态机不要把逻辑全部塞进策略里。刚开始做半自动时宁可慢一点也要确保每一笔委托都能记录到日志里出问题随时可追溯。5. 常见问题与排查技巧实录5.1 回测收益漂亮、实盘却亏损先查未来函数未来函数是回测失真最大的元凶。特征很典型回测曲线极其顺滑胜率高得离谱几乎没有回撤。出现这种情况第一个要查的就是是否无意中用到了未来数据。常见的未来函数有几种用当天收盘后才确定的指标去生成了当天开盘的交易信号用前复权价格做历史回测导致历史价格被未来分红数据修正公司财报发布前就把财报数据填充到回测里实际上是用了未来才公开的信息选取指数成分股时用当前成分股名单回测历史忽略了当时成分股已经变化这是典型的幸存者偏差。检查方式也简单随机抽取几笔盈利交易打印出信号的日期和对应的执行价仔细对照看信号出现时是否能真实知道这些信息。另一招是把策略脚本里面的所有shift(0)都过一遍凡是当天数据同时用于当天信号和当天成交就要打问号。交易里最保守的假设就是所有信号都只能次日执行如果你都要怀疑到底用没用到未来数据那句直接改成次日开盘价成交准没错。5.2 数据失真、幸存者偏差和流动性幻觉回测好、实盘差除了未来函数和过拟合另外两个大坑是数据失真和幸存者偏差。数据失真最典型的是复权问题。用前复权数据算历史均线看起来信号很多实际上每条历史K线都被人为调整过回测的反映只是一个虚拟价格形态。另一个是除权跳空当天成交现实中你要么在除权前卖要么在除权后买回测却可能在同一根K线上既持有又计算收益凭空多出一段利润。幸存者偏差在选股类策略里尤其明显。如果你只用“现在还活着”的股票去回测历史就等于自动剔除了那些退市暴跌的股票收益自然好看。即便你不是主动挑选很多数据接口默认就只保留了当前仍上市的公司这个坑非常隐蔽。处理办法是用“当时实际存在的股票池”来跑回测至少也要保留退市标记把退市股票纳入结果。流动性幻觉则出现在小市值标的上。回测里你按收盘价买入5万元可能没问题但实盘如果资金量变大一个买卖指令就能把价格推高成交成本远超回测假设。所以回测时一定要看策略涉及标的的日均成交额规则是单笔委托金额不超过当日成交额的很小一个比例比如千分之一到千分之五否则回测结果基本失真。5.3 运行环境里的典型故障与日志的重要性量化系统跑久了你会发现自己不是在研究策略而是在处理工程问题。我遇到的运行环境故障里有几类特别典型。第一类是数据接口限流或Key失效。免费接口尤其容易遇到前期用的好好的某一天开始频繁报错或返回空数据。对策是本地数据快照 定时增量更新不要每次策略运行都打一次接口。第二类是交易所节假日日历不一致导致策略在非交易日产生错误信号或者错过节后开盘的第一根K线。对策是维护一份交易所官方日历而不是用自然日推。第三类是pandas版本变更导致rolling结果变化这类问题最隐蔽症状是“代码没改换个环境结果就不同了”。对策就是固定依赖版本严重时干脆用Docker打包环境。日志比任何调试工具都重要。我之前调试一个“偶发重复下单”的问题全靠日志发现是网络重连后状态没有重置重复收到了同一个信号。回测和实盘系统都应该记录三个最基本的信息策略信号产生的时间、订单发送的内容和对象、成交回报的结果。遇到异常先看日志再谈修复这条习惯能帮你省下大量时间。5.4 上线前两张“保护性检查清单”最后放两张我一直在用的检查清单一张给回测阶段一张给实盘前。回测前检查是否用后复权价格是否用交易日历对全日期是否有停牌和涨跌停处理信号是否至少推迟一个周期手续费和滑点是否已计入结果的稳定性是否经过参数邻域验证。实盘前额外检查数据源是否独立交叉验证信号与订单是否分离是否有重复下单防护是否有最大仓位限制是否有单日最大亏损熔断成交回报是否完整落日志网络异常和断线重连是否有状态机处理。最后再说一个我特别推荐的小习惯把每次回测的交易明细导到表格里随机抽查几十笔交易人工对着K线图看一遍。这个习惯看起来原始但它能发现回测引擎里最诡异的偏差。我就曾经通过这个办法发现某一段回测里策略总是在跌停日“神奇地”买到货原因是数据源把跌停日的卖一价当作收盘价成交现实中根本不可能成交。数据、代码、工具都可能是错的但一笔一笔人工核对永远是你最后一道照妖镜。