2.3 异常处理
做机器学习或数据挖掘的人都知道,数据集往往有很多缺失、错误的地方,需要先人工进行处理。比如期货数据会有很多非交易时间段的数据需要专门处理,例如:
第一行的数据买一价、卖一价、买一量、卖一量都是零,而且交易时间是19:12:02.500,这是非交易时段,这个数据理应去掉。事实上,我们之前的数据处理程序已经考虑了这点:
从第一个bid价和卖价至少一个不为零的数据开始,有时候行情出现涨跌停板,比如涨停板时ask是零,因此,只有当两个都是零的时候才是异常的。
2.3.1 夜盘数据
现在不少期货品种开通了夜盘,一般是从晚上9点开始,但结束时间各不一样。如果机械记录每个品种的夜盘结束时间,其实也不大好,因为这个时间不是一成不变的,而是会随着一些新的规定一直改变。比如螺纹钢一开始夜盘交易到凌晨1点,现在交易到晚上11点。因此,我们需要一个更灵活的方式来处理夜盘数据。为此,我把夜盘分成以下几段:
最早结束夜盘的品种是23:00:00,但很多时候会有23:00:00.500这笔行情,因此,用data$time<“23:00:01”可以把这笔行情包含进来,其他时间也类似处理。
2.3.2 涨跌停处理
在涨停板,卖价是空值,一般行情软件用零代替,而在跌停板,买价是空值,也是用零代替。今后处理一些因子和因变量的时候要特别注意,因为这个时候的交易实际上并没有产生价格变化,而此时计算的预测指标,由于买量很大,一般都会预示有很强的上涨动能,因此会出现预测值与技术指标值的相关性极不正常的情况,这些就是异常值,在训练模型拟合系数的时候需要剔除。这里原始数据并没有做特别处理,这点留到以后再详细说明。当然,如果某些品种涨跌停板的比例很低,不会对模型参数拟合产生太大影响,也可以不用考虑。
事实上,涨跌停板数据占总数据量并不多,以螺纹钢为例:
由此可见,正常的无涨跌行情占99.6%,因此涨跌停行情对数据影响不会很大。可能很多人会担心涨跌停板时期价格基本处于停滞状态,但技术指标的取值往往却比较极端,这时候如果价格变化与技术指标取值很不一致,会影响拟合的效果。但因为这部分行情占比很小,所以对实际参数估计的影响并不大。
2.3.3 为什么保留买卖盘口
之前章节也提到过,虽然用最新价也可以较准确的回测策略,但这里我们还是保留了买卖盘口,哪怕是用5分钟K线做中低频的策略,原因有以下几点。
(1)很多品种买卖价差相对于价格来说很大,比如螺纹钢,价格一般在1800~3600元,买卖价差是1,即买卖价差是盘口的0.28%~0.56%,其实挂单量也蕴含了很多信息,此时的最新价一般在二者之一,不能较准确反映当前的行情,如果用挂单量加权平均价或许更有意义。
(2)对于一些基于挂单价成交的策略,可以设置当前买一价买入,或者低于当前买一价若干价位买入,然后看5分钟内能否成交。事实上,回测时可以更严格一些,比如我们挂买一价,如果最低价低于买一价才算是成交,即使相等也不算,这样可以更为严格的估算挂单成交。
比如回测一个策略,可以出信号后立刻对手价+滑点成交,也可以假设挂单,如果下一根K线的最低价低于挂单价,则挂单价成交;如果下一根K线的最低价大于等于挂单价,则用下一根K线收盘价+滑点成交,这样可以跟原来的成交情况进行对比,或许有所改进。
由于涉及挂单的策略会更复杂一些,这里不作专门讨论,本书讨论的趋势策略默认都是加滑点即时成交。
2.3.4 跟其他行情软件对比
每个行情软件都有自己切割K线的方法,关于500毫秒应该放上一根还是下一根的问题每个软件处理方法都不一样。其实这些方法整体上都是大同小异的,没必要刻意强求,但是要保证自己实盘程序跟研究程序用到的K线是一致的。因为这类机器学习模型,对数值计算高度敏感,随着计算次数的增加,误差是一直累积的并不会抵消,由此可能造成实盘和回测优化很不一致,比如开平仓时间点不一样甚至缺少一些交易等。因此,最重要的是保持自己K线的一致性,而不是跟某个行情软件的一致性。
另外,现在有很多免费或付费的基于第三方平台的策略程序,也可以用自己的K线去测试一下。一般规则型的策略对数值不会很敏感,事实上如果对数值过于敏感也可能由过度拟合所导致。总之,如果是5分钟K线的话应该差别不会很大,因此不必过于纠结。
对于夜盘结束等停止交易的时段要特别小心,交易所可能会把最后一条行情反复推送,或者自己的程序在夜盘结束后关闭,而白天重新启动时会再次接收到夜盘的数据,很可能把成交量等再次累积计算,这些都要被过滤掉。本人曾经因为类似的原因导致白天开盘K线总是跟回测对不上,而且总是容易触发交易而亏钱。