量化平台上的指标陷阱

 

建议在其它量化平台使用技术指标的用户,也检查一下您用的指标是否也存在精度不足甚至一直在使用与指标算法无关的边界值的问题。...



本文由微信公众号:镭矿量化交易提供。『RaQuant镭矿』是一个集量化交易策略的学习、研究、开发、交易于一体的强大平台。致力于帮助有简单编程基础或投资基础的投资者快速入门,并可以高效的开发量化交易策略,帮助投资者进行更有效的分析决策。

小编最近刷知乎看到有人做了“多个量化平台的回测速度评测”,指出镭矿是速度最快的回测平台。作者分析原因可能是我们把TA-lib指标放到了后台统一计算,而别家的每个周期都要重新取历史数据,然后计算当前的值——相比之下,镭矿节省了频繁地重复获取数据的过程,所以速度就变快了。

当然,这样做回测速度肯定会显著提高——提升速度根本就不是我们这样做的原因。最初我们的主要目的是做给自己用,因为不涉及到封装通用API的问题,我们自己有极大的权限可以灵活的在内度根据策略的要求计算这些指标。所以我们最初没有过多考虑到提速的问题。

我们考虑的是指标算法的正确性!

许多技术指标的算法都依赖于上一周期的指标值或中间计算变量,这些指标的值会随着回测进度而慢慢提高其精度。如果总是一次性的临时计算这些指标,很有可能导致算法错误。这是个很严重的根本性的问题,但很少有人意识到。

随便找一个其它平台上使用指标的例子,看看大家是怎么使用MACD指标的:


a) 先取历史数据。

b) 将历史数据及相关参数代入talib.func()进行计算。

貌似没什么问题?对极少数据一些极其简单的指标来说,确实没什么问题,比如计算过去15日MA(均值);但只要稍复杂一点点,比如计算过去15日的EMA(指数平均数),问题就来了——更不要说计算MACD这样的指标了。下面先复习一下EMA指标的算法。

1.EMA指标的计算方法

EMA的计算要考虑到上一个指标值,并按照权重计入新的指标值中:

EMAtoday=α * Pricetoday + ( 1 - α ) * EMAyesterday

首次计算时没有“yesterday"的值怎么办?关于初值问题,看TA-lib内部是怎么处理的:



上面根据“this.compatibility”的值给出了两种处理结果,用来获得初值。如果你给出的历史数据区间有冗余,即要计算EMA10的时候,你给出了20条历史数据,那么TA-lib会尽量把前10条数据也引入计算。所以接下来的算法是这样的:



当然,如果你给出的历史数据没有冗余,那么上面第一个while循环就不会进入,prevMA的值就是原始的初值(根本未经EMA计算);你给出的历史数据冗余越大,prevMA按EMA算法处理的轮次就越多,EMA的值就计算的越准确。

2. 错误的用法

如果我们要计算EMA10,那么就给出10日的历史数据会发生什么?我看好多量化平台上大家晒出的代码都是这样计算的(下面是伪代码):

handle_data():

hist_data = history(-10, -1, ...);

ema10 = talib.ema(hist_data, 10, ...)

取10日历史数据,计算一条EMA10的值,根据就触发不了EMA算法!

这些数据仅足以计算出一条prevMA,即初值,根本没有多余的数据去按EMA的公式 “EMAtoday=α * Pricetoday + ( 1 - α ) * EMAyesterday” 去计算!

所以如果你按上面的方法计算EMA,每次得到的都是一个初值,根据“this.compatibility”的值,它可能是这10条数的均值(MA),或是第一条历史数据的值(inReal[0])——反正,绝对不会是EMA值。

每个周期计算的时候,将重复这一过程,你永远也得不到一个EMA值

那么多给一些历史数据不就行了?看给多少了,肯定给的数据冗余越多结果越精确。如取history(-20,-1)数据去计算EMA,可以看作增加了10次递归。但是,且不说每次读入前10条数的权重有多大意义——这样做回测速度会之前变得更慢,因为每次重复取值都已经够拖慢速度的了。

3.我们为什么决定把指标的算法承包了

事实上,本轮指标值需要用到上一轮指标值或中间数据的情况很多。用户要么自行写算法,并保留这些指标值和中间值;要么每次直接用Ta-lib的函数,但是给定大量的冗余数据——这需要有极大的耐心去忍受被严重拖慢的回测速度。既然去做一个量化平台,就应该让用户可以专注于写策略,方便的使用各个技术指标,而不是研究成千上百个技术指标的算法!

所以再次提醒,不要再这样错误地使用指标了:

handle_data():

hist_data = history(-10, -1, ...);

ema10 = talib.ema(hist_data, 10, ...)

在镭矿,我们希望您这样用:

Factor fema10 = new EMAFactor(10);  // 创建一个指标作为成员变量

public void handleData() {

double vema10 = fema10.get("sha-601318"); // 在每个回测周期内使用指标

}

是的,声明一个指标,然后在回测周期内直接使用即可,不需要您考虑到底该取多长的历史数据,或查看手册研究Ta-lib的函数参数该怎么填,或纠结为了精度要不要自己实现算法——我们在后台已经为您把需要的数据整个从头到尾地全部备好了。

我们把指标算法承包过来,根本不是追求速度,而是因为如果后台不承包这些脏活、累活,用户极有可能会错误的使用指标。回测速度只是副产品。建议在其它量化平台使用技术指标的用户,也检查一下您用的指标是否也存在精度不足甚至一直在使用与指标算法无关的边界值的问题。

【镭矿量化交易】公众号菜单栏提供选择因子生成策略的小工具(策略生成beta),欢迎大家尝试一下量化的神奇。

扫描二维码,关注微信公众号,获取更多量化故事。注册登录镭矿,即可获取策略编写教程和数千个经典策略代码
『RaQuant镭矿』是一个集量化交易策略的学习、研究、开发、交易于一体的强大平台。致力于帮助有简单编程基础或投资基础的投资者快速入门,并可以高效的开发量化交易策略,帮助投资者进行更有效的分析决策。

www.raquant.com拥有自带的一系列拷贝即可使用的策略,在镭矿平台编写5个以上策略可拥有申请策略实盘的权利。快来试试吧!


    关注 股票雷达


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册