1. 为什么我会去折腾一个在线量化平台
最早接触量化交易是在自己的笔记本上跑回测,数据要自己下,复权要自己算,回测框架还得自己搭。一套流程走下来,策略还没写几行,光是把环境跑通就耗掉了大半个周末。后来听圈子里的人聊起在线量化平台,说不用配环境、不用管数据源、浏览器打开就能写策略,我第一反应是"哪有这么省事的事"。直到有段时间手头的机器拿去修了,闲着也是闲着,就注册了一个叫 Quantopian 的在线量化平台试了试,结果一用就是小半年。
这篇东西不是平台说明书,也不是什么入门教程。我想聊的是:一个习惯了本地折腾的人,第一次把策略搬到在线平台上,到底会遇到哪些坑、哪些爽点,以及这套东西放到今天还值不值得参考。Quantopian 这个平台本身后来已经关停了,但它当年那套"在线研究 + 社区策略 + 实盘对接"的模式,几乎定义了后来一大批同类产品的形态。所以哪怕你现在用的是别的平台,这里面的经验大概率还是能对上号。
先说清楚它是什么。Quantopian 是一个基于浏览器的量化策略研究与回测平台,核心语言是 Python,内置了历史行情数据、财务数据和一些另类数据,你只需要写一个initialize加handle_data的函数结构,就能跑出一个完整的回测。它解决的核心问题是把量化研究的基础设施全部托管掉,让写策略的人只关心逻辑本身。适合谁?适合有一定 Python 基础、想快速验证想法、又不想在数据清洗和框架搭建上耗时间的人。如果你连 pandas 都没摸过,那上手会有点吃力,但也不是完全不行,平台自带的示例策略足够你照猫画虎。
我当时的动机很单纯:想验证一个基于动量反转的日频策略,本地跑一次回测要十几分钟,改个参数又得重跑,效率太低。在线平台的好处是算力在云端,提交完任务关掉浏览器都行,回来直接看结果。就冲这一点,值得试。
2. 平台整体设计与思路拆解
2.1 在线量化到底把什么托管了
要理解这类平台的价值,得先搞清楚本地量化的完整链路有多长。一个策略从想法到回测结果,中间至少要经过这些环节:数据获取、数据清洗、复权处理、因子计算、信号生成、仓位管理、手续费与滑点建模、绩效统计。本地做的话,每一环都得自己写代码,而且每一环都可能出错。比如复权没处理好,回测收益直接失真;滑点没建模,高频策略的收益全是幻觉。
Quantopian 的思路是把这条链路切成两半:数据、算力、撮合模拟、绩效统计这些"脏活"平台包了,策略逻辑留给你。你写的东西本质上就是"什么时候买、买多少、什么时候卖"这三件事。这个切分很聪明,因为它把量化里最没有创造性、最容易出错、又最耗时间的部分标准化了。
具体来说,平台托管了这些东西:
- 历史数据:美股日频和分钟频行情、财务数据、部分宏观数据,全部预加载好,直接调用 API 就能取。
- 回测引擎:你写的策略会被平台的事件驱动引擎逐根 K 线执行,自动处理订单撮合、手续费、滑点。
- 绩效分析:回测跑完自动生成收益曲线、夏普比率、最大回撤、换手率等一整套指标。
- 研究环境:一个叫 Research 的 Notebook 环境,可以像 Jupyter 一样做数据探索和因子分析。
这套设计的优势在于降低试错成本。本地改一个参数要重跑十几分钟,在线平台可能几十秒就出结果,而且可以并行提交多个回测。劣势也很明显:你被平台的数据和 API 绑死了,想用自定义数据源或者做平台不支持的策略类型(比如高频、期权组合),就会很别扭。
2.2 为什么是 Python 而不是别的语言
量化圈的语言选择一直有争论,C++ 快但开发慢,R 统计强但工程弱,Python 居中。Quantopian 选 Python 是必然的,因为它的目标用户是"会写点代码的研究员",不是"会做研究的工程师"。Python 的生态(numpy、pandas、scipy)让因子计算和统计分析变得极其顺手,而平台把性能敏感的部分(数据读取、撮合引擎)用底层语言实现了,你写的 Python 只是策略逻辑,不会成为瓶颈。
这里有个细节值得说:平台的回测引擎是事件驱动的,不是向量化回测。什么意思?向量化回测是一次性把整个时间序列算完,快但没法模拟"根据当前持仓决定下一步操作"这种逻辑;事件驱动是逐根 K 线推进,每根 K 线调用一次你的handle_data,更接近真实交易。代价是慢,但平台用云端算力把这个代价抹平了。这个取舍很关键,它决定了你能写什么样的策略——事件驱动能支持复杂的仓位管理和条件单,向量化不行。
2.3 社区策略这个设计是双刃剑
Quantopian 当年最出圈的功能是社区,任何人都能把自己的策略公开,别人可以看、可以评论、可以 fork 过来改。这个设计的好处是学习曲线被拉平了,新手可以直接读别人的策略代码,看别人怎么处理分红、怎么设止损。我早期就是靠读社区里的高分策略,才搞明白order_target_percent和order的区别。
但社区也是坑。公开的策略里,真正能赚钱的极少,大部分是过拟合的产物。你会看到很多策略回测曲线漂亮得不像话,夏普比率 3 以上,最大回撤个位数,但仔细一看,要么是用了未来数据,要么是在极小的样本上调参调出来的。新手如果直接拿这些策略去实盘,基本是送钱。所以社区的正确用法是"学写法",不是"抄策略"。
3. 核心细节解析与实操要点
3.1 策略的基本骨架长什么样
Quantopian 的策略结构非常固定,就两个必须实现的函数:
def initialize(context): # 只在回测开始时执行一次 # 用来设置标的、参数、调度任务 context.stock = sid(24) # 指定一只股票 schedule_function(rebalance, date_rule=date_rules.every_day()) def handle_data(context, data): # 每根 K 线执行一次 # 用来做交易决策 passinitialize是初始化,handle_data是主循环。这个结构和很多事件驱动框架(比如 backtrader)是相通的,理解了其中一个,其他的都能触类旁通。
我踩过的第一个坑是分不清context和data。context是一个贯穿整个回测的容器,你可以往里面塞任何东西,比如持仓状态、计数器、自定义参数;data是当前时刻的行情快照,只能读不能写。新手经常想在data里存东西,结果报错。记住一句话:要跨 K 线保存的状态放context,当前行情从data取。
3.2 下单 API 的选择有讲究
平台提供了好几个下单函数,用错了会导致回测结果和预期完全不符:
| 函数 | 作用 | 适用场景 |
|---|---|---|
order(asset, amount) | 按股数下单 | 需要精确控制股数时 |
order_value(asset, value) | 按金额下单 | 按资金比例分配时 |
order_target(asset, amount) | 调仓到目标股数 | 需要精确持仓时 |
order_target_percent(asset, pct) | 调仓到目标仓位比例 | 最常用,按比例配置 |
我一开始用的是order,结果每次调仓都要自己算当前持仓和目标持仓的差额,代码又长又容易错。后来换成order_target_percent,一行搞定,它会自动帮你算需要买卖多少。这个函数是回测里最实用的,没有之一。
但要注意一个细节:order_target_percent的目标比例是占整个组合价值的比例,不是占现金的比例。如果你同时持有三只股票,每只设 0.3,那总仓位就是 90%,剩下 10% 是现金。这个逻辑要搞清楚,否则仓位会算错。
3.3 手续费和滑点不能忽略
回测里最容易自欺欺人的地方就是手续费和滑点。平台默认会收手续费(每股 0.001 美元左右)和滑点(默认是固定值),但很多人为了"让回测好看",会手动把它们设成 0。这么做等于在骗自己。
我的做法是把滑点设得比默认值更高一点,比如默认 0.01,我设成 0.02。为什么?因为真实交易里,你的成交价往往比你想的差,尤其是流动性不好的标的。回测里把滑点设高,实盘时反而更接近预期。这个思路叫"保守建模",宁可回测难看一点,也别实盘打脸。
手续费的影响在高换手策略里尤其明显。一个日频调仓的策略,如果每天换手 50%,一年 250 个交易日,光手续费就能吃掉一大块收益。所以回测时一定要看换手率这个指标,换手率过高的策略,即使收益漂亮,实盘也很难复制。
3.4 避免未来数据是底线
未来数据(look-ahead bias)是回测里最隐蔽的杀手。什么叫未来数据?就是你在做决策时,用了当时还不可能知道的信息。比如:
- 用当天的收盘价决定当天开盘就买入(收盘价在开盘时还不知道)
- 用财报数据做决策,但财报的公布日期晚于你使用它的日期
- 用
data.current(asset, 'price')在handle_data里取"当前价格",但没意识到这个价格在实盘里可能拿不到
平台对这类问题有一些保护机制,比如财务数据会按公布日期对齐,但它保护不了你逻辑上的错误。我见过一个策略,回测年化 40%,仔细一看,它在handle_data里用了当天的最高价和最低价来判断买卖点——这在实盘里根本做不到,因为你不可能同时知道当天的最高和最低。
自查未来数据的方法很简单:把策略的决策逻辑用自然语言写一遍,然后问自己"这个信息在决策的那个时刻,我真的能拿到吗"。如果答案是"不确定",那就当它是未来数据,改掉。
4. 实操过程与核心环节实现
4.1 从零跑通第一个策略的完整流程
我拿一个最简单的双均线策略来演示整个流程。策略逻辑:当 5 日均线上穿 20 日均线时买入,下穿时卖出。
第一步,在initialize里设置参数和调度:
def initialize(context): context.asset = sid(24) # 选一只流动性好的标的 context.short_window = 5 context.long_window = 20 # 每天开盘前执行一次调仓判断 schedule_function(rebalance, date_rule=date_rules.every_day(), time_rule=time_rules.market_open())这里用schedule_function把调仓逻辑单独抽出来,而不是写在handle_data里,好处是执行时机可控。market_open()表示开盘时执行,这样避免用当天收盘价做决策。
第二步,写调仓函数:
def rebalance(context, data): # 取历史收盘价,注意这里取的是过去 N 天的数据 hist = data.history(context.asset, 'price', context.long_window + 1, '1d') short_ma = hist[-context.short_window:].mean() long_ma = hist[-context.long_window:].mean() if short_ma > long_ma: order_target_percent(context.asset, 1.0) else: order_target_percent(context.asset, 0.0)data.history是取历史数据的核心 API,参数分别是标的、字段、长度、频率。注意我取了long_window + 1天,因为要算均线,得保证有足够的数据点。
第三步,跑回测,看结果。平台会自动生成收益曲线和各项指标。我第一次跑出来的结果是年化 6%,最大回撤 15%,夏普 0.4。说实话不好看,但这是真实的结果,比那些"年化 50%"的社区策略靠谱多了。
4.2 参数怎么调才不算过拟合
调参是量化里最容易走火入魔的环节。我一开始也犯过这个错:把均线窗口从 5/20 试到 10/30、8/25、7/21……试了二十几组,挑出回测最好的那组。结果实盘一跑,完全不是那么回事。
后来我学乖了,调参要遵守几条规矩:
- 参数要有经济含义。5 日和 20 日代表一周和一个月,这是有交易逻辑支撑的;7 日和 23 日就没有,纯粹是数字游戏。
- 参数要在样本外验证。把历史数据切成两段,前一段调参,后一段验证。如果后一段表现崩了,说明过拟合。
- 参数敏感性要低。好的策略在参数小幅变动时,表现应该稳定。如果 5/20 年化 10%,6/20 年化 2%,那这个策略就是脆弱的。
我现在的习惯是只试有含义的参数组合,最多不超过 5 组,试完就定,不再纠结。纠结出来的最优参数,大概率是拟合噪声。
4.3 用 Research 环境做因子分析
平台的 Research 环境是我用得最多的功能之一。它本质上是一个 Jupyter Notebook,但预加载了平台的数据接口。你可以在这里做因子有效性检验,比如算某个因子的 IC(信息系数)、分层回测收益。
举个我实际做过的例子:验证"过去 20 日收益率"这个动量因子在标的池里的选股能力。步骤是:
- 取一个股票池,比如流动性前 500 的股票。
- 每个调仓日,算每只股票过去 20 日收益率。
- 按收益率排序,分成 5 组,看每组下一期的平均收益。
- 如果第 1 组和第 5 组的收益差显著,说明因子有效。
这个过程在本地做要写不少代码,在 Research 里因为数据现成,几十行就能跑完。因子分析是策略研究的地基,地基没打好,上面盖的都是空中楼阁。
4.4 回测到实盘的鸿沟
平台支持把策略对接实盘,但这一步的坑比回测多得多。回测里你的订单一定能成交,实盘里可能挂单半天不成交;回测里滑点是固定值,实盘里滑点随市场波动;回测里没有停牌、涨跌停的限制,实盘里这些都会影响成交。
我的建议是回测和实盘之间要有一段模拟盘过渡期。用平台的模拟交易功能跑一两个月,看看实际成交情况和回测差多少。如果模拟盘的表现和回测差太远,说明回测里有没考虑到的因素,得回去改。
还有一个容易被忽略的点:回测的起始资金和实盘资金要匹配。回测用 100 万,实盘用 10 万,很多策略在小资金下表现完全不同,因为小资金更容易被手续费和最小交易单位影响。
5. 常见问题与排查技巧实录
5.1 回测报错速查表
用这类平台,报错是家常便饭。我整理了一份自己常遇到的错误和排查思路:
| 报错现象 | 可能原因 | 排查方法 |
|---|---|---|
KeyError取不到数据 | 标的代码错误或该标的当时未上市 | 检查 sid 是否正确,确认回测区间内标的存在 |
| 回测结果全是 0 | 策略没触发交易 | 打印信号变量,确认条件是否满足 |
| 收益曲线异常平滑 | 用了未来数据或没扣手续费 | 检查决策逻辑,确认手续费滑点非零 |
| 回测跑得极慢 | 在handle_data里做了重计算 | 把计算移到initialize或减少数据请求频率 |
| 持仓和预期不符 | 下单函数用错或资金不足 | 检查order_target_percent的目标比例总和 |
这张表里的每一条,我都是真金白银踩出来的。尤其是"收益曲线异常平滑"这一条,新手看到漂亮曲线容易兴奋,老手看到第一反应是"哪里出错了"。
5.2 数据对齐的坑
平台的数据是按交易日对齐的,但不同数据源的对齐方式可能不同。比如行情数据是每个交易日都有,财务数据是每季度公布一次。如果你在handle_data里直接取财务数据,平台会自动帮你做前向填充(用最近一次公布的数据),但填充的时机很关键。
我遇到过一个坑:某公司的财报在 3 月 15 日公布,但平台的数据里,这个财报被对齐到了 3 月 31 日(季度末)。结果我的策略在 3 月 16 日到 3 月 30 日之间,用的还是上一季度的数据。这个偏差在回测里看不出来,但实盘时会让你慢半拍。
解决办法是用平台提供的get_fundamentals接口,并指定date参数,确保取到的是当时真正能拿到的数据。这个细节很隐蔽,但影响不小。
5.3 策略失效了怎么办
任何策略都有失效的时候。我那个双均线策略,在趋势行情里表现不错,一到震荡市就来回被打脸。这时候要做的不是急着改参数,而是先判断是策略逻辑失效,还是市场环境变了。
判断方法:把策略的收益拆解成 alpha 和 beta。如果策略的收益主要来自市场整体上涨(beta),那它在熊市里必然亏钱,这不是策略的问题,是仓位管理的问题。如果策略在扣除市场收益后还有稳定的超额收益(alpha),那说明逻辑还在,只是短期不适应。
我现在的做法是给策略加一个市场状态过滤器。比如用大盘指数的均线判断当前是趋势市还是震荡市,趋势市才开仓,震荡市空仓。这个过滤器本身不产生收益,但能避开策略最不适应的环境。
5.4 几个独家避坑心得
最后分享几个文档里不会写、但实际用起来很关键的点:
- 回测区间要包含至少一轮完整的牛熊。只测 2015 到 2017 这种单边行情,策略的鲁棒性根本测不出来。我一般会测 2008 到 2018 这十年,里面有金融危机、有慢牛、有震荡,各种环境都覆盖到。
- 不要迷信夏普比率。夏普高不代表策略好,有些策略夏普高是因为收益波动小,但绝对收益也低。我更喜欢看卡玛比率(年化收益除以最大回撤),它更能反映"赚的钱值不值得承担的风险"。
- 策略的容量要提前估算。一个策略在小资金下年化 20%,资金放大到 1000 万可能就变成 5% 了,因为你的交易会冲击市场价格。估算方法是看策略的日均成交额占标的日均成交额的比例,超过 1% 就要警惕。
- 定期重新验证策略。市场结构在变,三年前有效的因子今天可能就失效了。我每季度会把所有在用的策略重新跑一遍样本外测试,表现明显下滑的就下架。
Quantopian 这个平台虽然已经不在了,但它教会我的东西一直受用:量化的核心不是找到圣杯策略,而是建立一套可重复、可验证、可迭代的研究流程。平台只是工具,工具会换,流程和思维才是留下来的。我现在用的平台换了,但写策略的习惯、调参的纪律、排查问题的思路,都是从那段在线量化的经历里带出来的。如果你也在考虑要不要试试在线量化平台,我的建议是:先用它快速验证几个想法,感受一下"想法到结果"的反馈速度,再决定要不要深入。这个反馈速度本身,就是在线平台最大的价值。