详情链接:2014-05-13-应用专题-数据提取专题03:非整周期行情数据提取陷阱和时点真实行情数据回溯
- 针对在使用行情类数据及其衍生指标做建模和回测的时候,可能用到“未来数据”的陷阱,可以使用天软的时点系统参数PN_ViewPoint()避免此问题的发生。
- 分析了使用行情类数据可能用到未来数据的原因:在基于非整周期行情数据建模中,犯使用“未来数据”的错误概率很大
取行情数据可能用到未来数据的分析
什么是非整周期?
在我们日常基于行情数据开发的策略中,存在两个日期的概念:
(1) 与周期参数对应的本周期最后一个交易日d1:即通常我们所说的日线、周线、1分钟线、10分钟线等用固定周期描述的“本周期最后一个交易日”。在我们开发中,一般不会特意提到这个日期或者忽略此日期。我们常说的是:这个策略用的日线数据,周线数据,10分钟数据等等
(2) 选股/回测日期d2:选股日期,即用户运行策略的日期
所谓整周期,即:d1=d2
所谓非整周期,即:d1<>d2
如果是整周期数据,一般不存在所谓的使用“未来数据”陷阱。在上述范例中,如果你使用的周线数据(其每个周期对应的最后一个交易日d1=2013-08-16、2013-08-23、2013-08-30),而你的调仓日/选股日如果正好是d2=2013-08-16、2013-08-23、2013-08-30。在本应用中,d1=d2为整周期应用,一般不会犯用“未来数据”的错误
而如果使用的是非整周期数据,则经常会犯使用“未来数据”的错误。在上述范例中,如果你使用的周线数据,而你的选股日期是d2=2013-08-16、2013-08-23、2013-08-29日。注意:其中的2013-08-29和周线的最后一个交易日2013-08-30不相等。 其中有d1<>d2为非整周期应用,犯使用“未来数据”的错误概率很大。
非整周期数据提取的陷阱
在实际开发基于行情数据的策略中,如上所述经常会用到多周期行情数据(或其衍生类数据)。要特别强调的是,即使这么一个简单的需求,经常会碰到数据提取的陷阱,即:很可能会用到所谓的“未来数据”。
低频非整周期数据提取时可能用到“未来数据”
我们还是以一个实例来说明。
假设我们的策略日期是2013-08-12日,我们可以取得到的SZ000002的真实收盘是10.13元。不管用什么周期,何时提取此数据(回测或实时监控),这都应该是确定的答案。事实真的如此吗?我们看一下几个范例(详细测试代码见范例:TSFL_SJTQ_TrapOfTradingData1):
EndT:=20130812T;
SetSysParam(PN_Stock(),"SZ000002");
SetSysParam(PN_Date(),EndT);
SetSysParam(PN_Rate(),0);
//日线数据:10.13
SetSysParam(PN_Cycle(),cy_day());
c1:=close();
//周线数据:9.89
SetSysParam(PN_Cycle(),cy_Week());
c2:=close();
//月线数据:9.46
SetSysParam(PN_Cycle(),cy_Month());
c3:=close();
//季线数据:9.13
SetSysParam(PN_Cycle(),cy_quarter());
c4:=close();
//半年线数据:8.03
SetSysParam(PN_Cycle(),cy_halfyear());
c5:=close();
//年线数据:8.03
SetSysParam(PN_Cycle(),cy_Year());
C6:=close();
Return array(c1,c2,c3,c4,c5,c6);
为什么会有这样的结果呢?原因在于行情数据的多周期转换机制(祥见上期内容-关于不同周期的变换规则)。所有的非日线类低频周期数据,都来自日线数据,且以“本周期的最后一个交易日”为参照点。虽然我们的截止日是2013-08-12(星期一,是一个非整周期),但是按照多周期转换机制,实际的各个周期的最后一个交易日分别为:
如果真的这样处理,在做历史回测的时候,相当于在2013-8-12的时候,我们已经知道2013-8-12所在的周收盘是2013/8/16的9.89;知道2013-08-12所在的月收盘是2013/8/30的9.46。
OMG,这就是典型的在做历史回测的时候用到“未来数据”的陷阱。
如果你的回测日期,正好是非整周期日期,一定存在用“未来数据”的陷阱和可能
在做历史回测的时候,不能用一点点未来数据,这是一个基本的底线。否则可能造成历史回测的时候,一个很好的策略在真实上线运行的时候,可能达不到预计的效果。去除掉其他因素,对于开发者而言,在你开发的策略中,是否用到了“未来数据”,这个弦必须绷紧,不能有丝毫的含糊。记住:我们做历史回测的目的,不是为了找到一个虚无缥缈的,看起来很好的一个策略。而应该是基于当时那个时点可以看到和用到的数据,未来数据是绝对不能使用的。
好在中国的证券市场不长,用户在开发策略的时候,如果用到多周期低频数据,多半用的最多的是周线。
高频非整周期数据提取时可能用到“未来数据”
同低频数据的提取,如果在高频策略中,你的策略回测时间是一个非整周期,也存在可能用到“未来数据”的陷阱(详细测试代码见范例:
TSFL_SJTQ_TrapOfTradingData2
SetSysParam(PN_Stock(),"SH600519");
EndT:=StrToDateTime("2013-08-12 14:08:05");
SetSysParam(PN_Date(),EndT);
//本周期的最后一个交易时间:2013-08-12 14:09:00 175.86
SetSysParam(PN_Cycle(),cy_1m());
c1:=close();
//本周期的最后一个交易时间:2013-08-12 14:10:00 175.90
SetSysParam(PN_Cycle(),cy_10m());
c2:=close();
//本周期的最后一个交易时间:2013-08-12 14:08:06 175.70
SetSysParam(PN_Cycle(),cy_6s());
c3:=close();
//本周期的最后一个交易时间:2013-08-1214:08:12 175.71
SetSysParam(PN_Cycle(),cy_12s());
c4:=close();
return array(c1,c2,c3,c4);
就本实例而言,我们通过Tick数据知道,在2013-08-12 14:08:05能取得到的收盘,只可能是175.70
SetSysParam(PN_Stock(),"SH600519");
EndT:=StrToDateTime("2013-08-12 14:08:05");
SetSysParam(PN_Date(),EndT);
SetSysParam(PN_Cycle(),cy_detail());
//在这个时点,能取得到的当前盘口数据,只能是截止2013-08-12 14:08:04的盘口数据 175.70
return close();
即在使用高频数据中,如果提取数据时间是非整周期,也可能存在使用“未来数据”的陷阱
非整周期数据提取陷阱汇总
从以上分析可以看出在做用行情数据做历史回测的时候,经常会犯使用“未来数据”陷阱。对此我们汇总如下:
结论:如果是非整周期,除了日线数据和Tick,都可能犯使用“未来数据”的陷阱
设置时点参数支持时点回测
设置时点参数的必要性
天软为了提供更好的历史回溯仿真支持,增加了新的系统参数PN_ViewPoint(),我们在下文中称之为:时点系统参数/时点参数/PN_ViewPoint()
使用时点参数,在非整周期中可以保证可以还原到该时点,避免使用到未来数据,从而提供更好的历史回溯仿真支持。
如何设置时点参数?
PN_ViewPoint(),该系统参数为一个日期时间类型,可以在非整周期的回溯中还原该时点,避免使用到未来数据。
在原来提取行情数据的模型中,只要加一条语句:
SetSysParam(PN_ViewPoint(),EndTTime);
其中:EndTTime一般是一个日期时间类型,行情数据对应的提取时点
注意:一般在PN_ViewPoint()设置的时点时间系统参数的值>=在PN_Date()设置的截止日参数的值。如:假设使用日线数据,PN_Date()和PN_ViewPoint()使用方法如下:
EndT:=20130812T;
SetSysParam(PN_Stock(),"SZ000002");
//在PN_Date()设置数据的截止日=2013-08-12
SetSysParam(PN_Date(),EndT);
//在PN_ViewPoint()设置数据的时点时间=2013-08-12 16:00:00,即时点时间是收盘后
SetSysParam(PN_ViewPoint(),EndT+16/24);
常见设置时点参数范例
说明:
(1) 对于日期格式,最好采用日期参数或者yyyymmddT格式
(2) 对于整点/整半点时点,最好使用/24模式。如:10:00:00用10/24,尽量不要采取StrToTime('10:00:00');10:30:00用10.5/24,尽量不要采取StrToTime('10:30:00')
(3) 除非万不得已,尽量少用StrToDate/StrToTime(大量使用可能带来性能问题)
除非万不得已,尽量少用StrToDate/StrToTime(大量使用可能带来性能问题)
除非万不得已,尽量少用StrToDate/StrToTime(大量使用可能带来性能问题)
重要的事情说三遍……