量化百科

从Python到C++,对量化回测的一点思考

由polll创建,最终由polll 被浏览 151 用户

写在前面:

说实话,关于量化方面在网上的资料确实挺少的。感觉很多做量化的人都惜字如金,但其实这只能怪行业的特殊性,就像套利一样,一旦策略趋同,那利润也就越摊越薄。但我觉得这其实是一个悖论。除非是完全被知道了核心机密,其他部分即使互相知道了大致策略,具体参数如果不清楚,复现出来的也不一样。而就算知道了策略参数,如果数据清洗步骤不一样,回测逻辑计算不一样,实盘订单提交逻辑不一样,那最终结果也不太一样。这一步步都是环环相扣,不可分割的。而就算全部都一样,对方也要有足够影响市场的资金量,才能够侵蚀你的利润。当然我不是鼓励探讨策略,策略核心还是要保密的,只是其他方面互相分享分享,探讨交流,问题也不大。这一点要向无私的vn.py作者 @用Python的交易员 看齐。

人之患在好为人师,而我也只是在逐步学习中,实在也没有什么资格能指点江山。只想借助本文,再次稍微记录下自己的微小经验和学习过程,和喜爱量化的你一起交流探讨。

目录:

1. 最近自己又迭代了什么新功能?

2. 为什么实盘和回测结果不一样?

3. 为什么一定要用tick级别做回测?

4. 为什么要拥抱C++?

5. 从Python到C++的感受?

6. C++学习记录分享

7. 后记


最近主要又迭代了什么新功能?

首先声明,回测框架的核心逻辑都已包含在最新版本的OnePy 2.1中,读懂了源码后应该已经足够能自己写出自己的框架了,所以不出意外今后应该不会更新。而自从上次更新之后,我自己又线下更新了许多新功能。部分功能主要都是参考 《Trading Systems —A new approach to system development and portfolio optimisation》这本书。

① 重新手写计算详尽的交易结果分析报告

![](data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='582' height='309'></svg>)

之前OnePy 1版本的时候,其实就有这个逻辑报告。只是那时候是直接复制Pinkfish(Github上另一个回测框架)的代码库,照抄过来的,也没仔细看计算逻辑是否正确。这次全部都自己重写了一遍,对每个指标也有了更进一步的认识。

② 更详尽的交易报告

![](data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1240' height='325'></svg>)

主要新增了每笔交易的run_up,drawdown和holding_period。便于后续分析策略结果。

③ 根据上述交易记录,画出每笔交易的散点图

![](data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='444' height='233'></svg>)

感觉这张图特别好用。比如在自己策略逻辑中加入Trailing Stop,就可以看到原本分散的点变得和图中一样,倾斜成一条斜线,也能间接反映自己的回测逻辑是否有问题(比如加入Trailing Stop后,图没有缩成一条斜线,那就要考虑是不是哪里算错了)。这张图非常有利于手动做参数优化,并从微观层面分析每笔交易,比如像趋势策略,就有很多小亏损,但是盈利点都很高;是否有很多笔浮盈的交易最终都以亏损出场等。

④ 添加日期指针模块

之前看rqalpha源码的时候发现有一个他有一个Calendar模块,就是不断更新记录当前时间。当时还觉得有些多此一举,但后来在写股票的停牌过滤逻辑的时候才意识到这个模块的重要性。之前OnePy更新时间的逻辑是直接获取最新bar之后,将bar的时间戳作为系统的当前时间。

但这其实很容易产生问题:假如同时回测AB两只股票,从2018年1月1日开始回测,但是A股票在2月1日停牌了,并于3月1日开牌。那回测到2月1日时,最新系统时间会自动变成3月1日,然后B股票就只能干瞪眼了。

最保险的做法是保证标的的时间序列一致,但这太不灵活。也有考虑过的做法是加入日期过滤逻辑,以最慢的日期为准。但假如是日线级别的股票和分钟级别的股票放一起回测(虽然基本没这样做的),或者期货回测(不同品种开闭盘时间不同),总感觉很容易出现Bug,也不符合实盘逻辑。这个时候就体现Calendar模块的重要性了,假如按1分钟线回测,那日期指针不断向前推进1分钟,然后数据更新保证不超过当前日期指针时间就可以了。这样更加符合实盘逻辑,也可以针对不同标的加入交易时段的判断。

⑤ 多进程对策略进行交叉验证

⑥ 多进程对策略进行参数优化

⑦ 新增撤单逻辑

⑧ 对接Oanda外汇实盘交易

⑨ 对每个模块都写了单元测试

⑩ 其他不可描述的功能

为什么实盘和回测结果不一样?

经常被讨论的有过拟合,幸存者偏差,回测代码逻辑算错,未来函数,滑点,策略失效等等,我就不赘述了。具体移步看这个问题 https://www.zhihu.com/question/24065933

而在这里我只想说一点:实盘和回测一定要用同一套代码。

记得以前作为小韭菜在股票市场上游走的时候,经常夜观星象,下单非常随性。后来在私募实习,了解到主观炒股原来依靠的是一系列清晰的逻辑分析,丰富的经验和过人的胆识,也跟着假装有模有样地分析,做交易。但是在下单的那一刻仍感觉内心惴惴不安,因为我无法确定这笔交易的准确性。(声明:这里只客观描述个人感受,没有否认主观交易的意思,我的观点是主观和量化一样都不容易,不相上下,没有优劣)

引用《Advances in Financial Machine Learning》的一小段:

Discretionary portfolio managers (PMs) make investment decisions that do not follow a particular theory or rationale (if there were one, they would be systematic PMs). They consume raw news and analyses, but mostly rely on their judgment or intuition. They may rationalize those decisions based on some story, but there is always a story for every decision.

现在茁壮成长为大韭菜,框架也搭了,量化策略也做了,下单时多了几分确定性,内心的不安却似乎丝毫没有减少。因为回测得好并不代表实盘好。回测是基于历史会重复的假设,而市场的组成是人,而人是会变的,市场会变,监管环境会变,经济环境也会变。所以圣杯可以说是不存在的,实盘好也许只是随机误差中的positive。当然对策是面对不同环境运行不同的策略和参数,或者寻找其他稳定的利润来源,比如套利等,这也是量化最大的魅力之一。

好的,扯远了。如果回测的好,实盘生成信号的过程和如果和回测不一样,那产生的信号也不一样,结果也就不一样了。就好像同一套策略,在不同的平台上跑,结果也可能不一样,而究竟不一样在什么地方呢?如果不清楚源码,这答案也就无从得知了。所以保证实盘和回测同一套代码,可以尽可能使误差减少到最小,而框架逻辑中就算有些许误差,也会成为策略的一部分。

所以我在对接Oanda外汇实盘API的时候,尝试了在不同订单下,同时Print回测框架本地和Oanda服务器计算的现有资金,保证金,总市值,仓位,浮动盈亏等等,保证本地和服务器端计算误差降至最小,经过一个多月的调整终于调整到基本一致了,同时也确保了recorder计算逻辑的准确性。

为什么一定要用tick级别做回测?

先说个背景,Oanda的API可以直接接收分钟行情,不需要自己合成。所以比如我可以直接回测30分钟线,然后实盘直接接收30分钟线进行交易就可以了,不需要自己本地接收tick合成分钟线。

然后机智的我很快就发现了问题:举个例子,30分钟线,只会在1:00,1:30,2:00这种时间点才能接收到新的30分钟bar,所以我的系统只会才1:00, 1:30, 2:00这种时间点做交易,这是非常有问题的,很多次眼睁睁看着1:15的盈利单在1:30亏损出场。

所以直接拿30分钟线回测,假设策略的技术指标是用30分钟线计算,那就意味着你只是在各个时间间隔的节点上进行交易,中间等待的30分钟只能保持沉默。所以做法是直接用Tick画出30分钟线,假设每秒 1 Tick,那30分钟就有1800个Tick。每过1秒,就用最新的1800个Tick进行计算,这样每一秒,你都能获得最新的30分钟线,所以能对行情做出最快反应。

下面我用回测结果再举个例子。假设一个最简单的布林带策略,加一根均线过滤。

![](data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1920' height='1080'></svg>)

周期指所用Bar的数量。

从左到右分别为,

10分钟线, 均线周期 = 20*3,布林带周期 = 120*3

15分钟线, 均线周期 = 20*2,布林带周期 = 120*2

30分钟线, 均线周期 = 20,布林带周期 = 120

即本质上,三个回测结果都是基于30分钟线的均线和布林带,即信号基本都是一样的,所以可以看到最大回撤都出现在2016-02-03。但是跑出来的结果收益率和回撤却不一样。不过转念一想,如果回测用30分钟线跑,那实盘也用30分钟线跑不就好了,这样这种只在bar出现时间点进行交易这个问题就内化称为了策略的一部分了。

当然还有类似分钟bar隐藏了很多蕴含在tick中的信息,这个问题就不深入讨论了,我只想说这个“时间点交易问题”而已。后面也不班门弄斧了,我猜要用tick级别做精准回测这个问题应该是常识吧,我才疏学浅,最近才想到这个问题:)

为什么要拥抱C++?

我们可以看到,上面三次回测结果消耗时间分别为26s, 17s, 9s。分别对应不同的bar数量。我们按照10分钟数据算,交易长度为131 days(含周末),外汇为24小时交易市场,除去周末,一共93个交易日左右。一共有93*24*60/10 = 13,392根数据,消耗26s,平均每根数据耗时.001941458s。而如果要回测Tick数据,假设每秒1个Tick,一天就有24*60*60 = 86,400根数据, 回测一天就需要耗时168s, 即2.8分钟, 回测一年Tick数据就要11个小时。外汇Tick数据是股票的5倍,相当于回测股票一年Tick就需要2.2小时左右。

最后总结,OnePy这个事件驱动框架回测股票一年Tick数据需要2.2小时左右,这还不包括那种信号多的策略,信号一多,撮合逻辑等各方面都会增加耗时。

这才使得我想用C++将OnePy都重新实现一遍,顺便学学C++。还有另一方面是国内做期货如CTP等各种接口都是原生C++,感觉还是逃不过。

引用 @Edward.Fu 的一句话

Python where we can, C++ where we must

这才深刻理解了这句话。

顺便安利下这个回答 https://www.zhihu.com/question/23244053/answer/24361822 , 每次学累了我都会看看这个回答补充能量,获得前进的动力。

从Python到C++的感受?

由于我是先学的Python,所以一开始非常不习惯静态语言,什么都要自己定义,很多觉得理所应当的东西在C++中竟然都要自己实现,甚至觉得很恶心,比如写个Csv读取器,Python直接调包两三行搞定,初学C++我洋洋洒洒写了快100行。不过在渐渐熟悉C++之后,我却渐渐喜欢上了C++。也更加深刻地理解“Python能让人把精力更多放在业务实现而不是语言层面上”是什么意思。

Python就像刚从新手村出来遇见的长得有点可爱的小BOSS蘑菇王,慢慢打着打着就可以驯服了。

C++就像会进化的成各种不同形态的大BOSS黑龙王,初级形态还好,稍不留意就被其他形态分分钟吊打。

就像去买早餐,用Python直接跟服务员说买个流沙包和鲜牛奶,流沙包要有流沙的,牛奶要牛产的。而用C++买的话,首先要跟服务员介绍什么是流沙包,什么是鲜牛奶,然后再介绍什么是流沙,什么是牛,然后再介绍牛奶要用什么杯子装,因为有些杯子只能放牛奶不能放羊奶。。一放错特么的就会报错。但是C++又强在还能控制牛奶的具体鲜度甚至牛的毛发需要深空灰还是钢琴黑,而Python就只会说你吵死了,我给你找头牛不就完了:)

C++学习记录分享

引用《Effective C++》中的第一小节—视 C++为一个语言联邦




1. C 语言。2. Object-Oriented C++。 包括 classes, 封装, 继承, 多态, virtual 函数等等。3. Template C++。即泛型编程(generic programming), 模板元编程(template metaprogramming, TMP)4. STL. STL 是 template 程序库, 包括容器、迭代器、算法和函数对象.

Python就类似于联邦中的1,2,4。照搬学Python的经验,我先花了两周的时间走马观花地看了《C++ Primer》的, 同时倍速播放看https://www.youtube.com/watch?v=18c3MTX0PK0&list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb 。感觉这个播放列表是我在Youtube上能找到最生动有趣的C++教学视频了。 然后又花了2周的时间看《Effective C++》,同时开始着手写个CsvReader。写完差不多就入门了,果然借助Python的基础速度快很多,之后感觉其实只要掌握C++的class,继承和多态,然后慢慢像Python一样慢慢开始写就可以了,期间遇到各种语言细节问题直接谷歌就可以,以后有空再读读各种C++进阶书。然后我就开始慢慢着手用C++写OnePy了,目前开发进度为30%,尝试以单元测试引导开发,学会了用CMake和gtest,还算顺利,也很有趣。

感觉C++很爽的是,有很多神奇的特性需要去挖掘,当然这也是C++让人不爽的原因。而不像Python,在感受语法糖的各种强大后,就发现语法糖也就那些。而C++会让人觉得每天都能发现新的特性(也可能仅仅是单纯因为初学者角度)。

后记

最近又发现这个画图库,http://rrag.github.io/react-stockcharts/documentation.html#/lots_of_data ,感觉真是太高级了,看了之后什么matplotlib啊Plotly啊完全不想用了。查了下原来是用JavaScript写的,啊React又是什么东西,学JavaScript原来还要先掌握HTML和CSS, 那HTML和HTML5又是什么区别,要先学哪个,啊不对我机器学习算法还没好好手撸完,还是先用C++把OnePy实现完再说,因为昨天看的研报好像很高级我再复现下试试,所以JavaScript和Java究竟又有啥区别,我等下还是………………

![](data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'></svg>)

标签

Python量化回测
评论
  • good!
  • 嘉亿真是量化工程师上渐行渐远啊
  • 兄弟,本末倒置了,我一开始也跟你一样,什么都想钻技术,回归初心啊,量化是拿来赚钱的,技术什么的差不多就行了。
  • 你好,我像问一下为什么只能建模30分钟的时间呢