跨周期数据的实现
TB的跨周期调用,以前已经有一些解决方案。但总体来说,使用还不够方便。以前的帖子中Nopain曾提出过一个算法,非常精巧。最近在这个算法的基础上, 把整个实现方法完善了一下。下面把总体思路和函数代码贴出来,请大家试用,也欢迎大家提出修改意见。
总体思路:
1、小周期调用大周期的数据;
2、具体方法是新编一个函数,用来根据小周期下的数据推算出大周期的BAR数据,为了省事,计算时,会将大周期下的开高低收以及成交量和持仓量等数据都算出来,然后将这些数据通过引用参数返回。当然有的朋友可能只需要一个收盘价就可以了,那样的话,可以自行修改这个函数,把多余的数据去掉;
3、返回的大周期数据将以序列变量的形式保留在对应的小周期K线上,以便以后调用;
4、另外为了便于大周期的数据计算出来后的回溯使用,函数会将小周期下当前BAR到大周期下的前一个BAR的最后一个小周期BAR需要回溯的BAR数目,作为函数的结果返回。这句话,不容易描述清楚,估计大家听起来也费力,但没关系,后面用例子来解释,知道这回事就行了。
5、另外还增加了一个返回值(也是通过引用参数返回),表示的是当前小周期K线对应的大周期K线在整个大周期中的索引值。举例来说,5分钟图,样本数300,那转换成30分钟周期图,总共应该是50根K线,那最新一根5分钟图对应的30分钟K线在整个30分钟图中的索引值就应该是49(类似CurrentBar 0-49);
好,其他先不废话,把代码贴出来,再举几个例子。
新建用户函数MtBar, 返回值为数值类型,代码如下:
- Params
- Numeric TimeFrame(1440);
- // 目标时间周期:月线=40320,周线=10080,日线=1440,4小时线=240
- // 其他1小时内的周期等于相应的分钟数,如:1小时=60, 30分钟=30。。。
- // 支持不规则分钟数,如3分钟,8分钟,之类都行
- Numeric BarsBack(1);
- // 目标时间周期BAR偏移:
- // 1--表示将目标时间周期下的前1根K线数据作为与当前Bar对应的目标时间周期下的K线数据
- // 0--表示将目标时间周期下的截止到目前为止的数据转换为与当前BAR对应的目标时间周期下K线数据
- NumericRef oCurBar; // 目标时间周期下的Bar索引
- NumericRef oOPenHT; // 目标时间周期下的开盘价
- NumericRef oHighHT; // 目标时间周期下的最高价
- NumericRef oLowHT; // 目标时间周期下的最低价
- NumericRef oCloseHT; // 目标时间周期下的收盘价
- NumericRef oVolHT; // 目标时间周期下的成交量
- NumericRef oOpenIntHT; // 目标时间周期下的持仓量
- Vars
- NumericSeries barCnt;
- NumericSeries CurBar;
- NumericSeries barCntSum;
- NumericSeries OpenHT;
- NumericSeries HighHT;
- NumericSeries LowHT;
- NumericSeries CloseHT;
- NumericSeries VolHT;
- NumericSeries OpenIntHT;
- Numeric CurTime;
- Numeric PreTime;
- bool condition(false);
- Numeric i;
- Begin
- If (TimeFrame == 40320) // 月线
- {
- CurTime = Month;
- PreTime = Month[1];
- }
- Else If (TimeFrame == 10080) // 周线
- {
- CurTime = IntPart(DateDiff(19700105,Date)/7);
- PreTime = IntPart(DateDiff(19700105,Date[1])/7);
- }
- Else // 其他时间周期
- {
- CurTime = IntPart((DateDiff(19700105,date)*1440 + Hour*60 + Minute)/TimeFrame);
- PreTime = IntPart((DateDiff(19700105,date[1])*1440 + Hour[1]*60 + Minute[1])/TimeFrame);
- }
- condition = CurTime != PreTime;
- If (CurrentBar==0) // 如果是第一根Bar, CurBar=0
- {
- barCnt = 0;
- CurBar = 0;
- OpenHT = Open;
- HighHT = High;
- LowHT = Low;
- CloseHT = Close;
- VolHT = Vol;
- OpenIntHT = OpenInt;
- }
- Else
- {
- If(Condition)
- // 如果在目标周期下,属于另一根K线,则CurBar加1
- {
- barCnt = 1;
- CurBar = CurBar[1] + 1;
- OpenHT = Open;
- HighHT = High;
- LowHT = Low;
- VolHT = Vol;
- }Else
- // 如果在目标周期下,属于同一根K线,则CurBar不变,但最高价和最低价要记录价格的变化,成交量要累加
- {
- barCnt = barCnt[1] + 1;
- CurBar = CurBar[1];
- OpenHT = OpenHT[1];
- HighHT = Max(HighHT[1],High);
- LowHT = Min(LowHT[1],Low);
- VolHT = VolHT[1] + Vol;
- }
- // 收盘价和持仓量总是取最新值
- CloseHT = Close;
- OpenIntHT = OpenInt;
- }
- // 上面的程序,在每根小周期的K线上,记录了它所属的大时间周期下的开高低收等值的变化。
- // 接下来,要把在大的时间周期级别上,属于同一根K线的开高低收这些数据,记录在这一组小周期K线的最后一根上。
- barCntSum = barCnt ;
- If(BarsBack == 0)
- // 如果Bar偏移参数为0,则取每根小周期K线上保留的大时间周期截止到这根小周期K线为止的BAR数据
- {
- barCntSum = 0 ;
- }Else If(BarsBack == 1)
- // 如果Bar偏移参数为1,则取大时间周期的上一根K线的BAr数据
- {
- barCntSum = barCnt ;
- }Else
- // 如果BAR偏移参数为其他,则取大时间周期的指定偏移后的那根K线的BAR数据
- {
- For i = 2 To BarsBack
- {
- barCntSum = barCntSum + barCnt[barCntSum];
- }
- }
- // 最后将相应的K线数据作为引用参数返回
- oCurBar = CurBar;
- oOpenHT = OpenHT[barCntSum];
- oHighHT = HighHT[barCntSum];
- oLowHT = LowHT[barCntSum];
- oCloseHT = CloseHT[barCntSum];
- oVolHT = VolHT[barCntSum];
- oOpenIntHT = OpenIntHT[barCntSum];
- Return barCnt;
- End
忘了说一句,以上代码是在TB V4中编写与调试的。
接下来,我们来实现跨周期的求和函数MtSummation,上面的函数中特地返回了一个值oCurBar,就是我上面提到的大周期下的BAR索引值,就是想为实现MtSummationFC留下的伏笔,等以后有时间再解决。现在先还是用最笨的循环累加的算法。
- Params
- NumericSeries Price(1);
- NumericSeries BarCnt(0);
- Numeric Length(10);
- Vars
- NumericSeries SumValue(0);
- Numeric i;
- Numeric j(0);
- Begin
- SumValue = 0;
- For i = 1 to Length
- {
- If (Price[j] <> InvalidNumeric)
- {
- SumValue = SumValue + Price[j];
- j = j + BarCnt[j];
- }
- else Break;
- }
- Return SumValue;
- End
接下来,就可以实现计算跨周期简单移动平均的函数MtMa。
- Params
- Numeric TimeFrame(1440); // 目标时间周期参数,参数说明参见MtBar
- Numeric BarsBack(1); // 目标时间周期BAR偏移参数,说明见MtBar函数
- Numeric Length(10); // 均线周期
- NumericRef oMA; // 以目标时间周期下的K线数据计算出的移动平均线
- Vars
- NumericSeries mtBarCnt;
- NumericSeries mtClose;
- Numeric refCurBar;
- Numeric refOpen;
- Numeric refHigh;
- Numeric refLow;
- Numeric refClose;
- Numeric refVol;
- Numeric refOpenInt;
- Numeric SumValue(0);
- Numeric i;
- Numeric j(0);
- Begin
- mtBarCnt = MtBar(TimeFrame,BarsBack,refCurBar,refOpen,refHigh,refLow,refClose,refVol,refOpenInt);
- mtClose = refClose;
- SumValue = MtSummation(mtClose,mtBarCnt,Length);
- oMA = SumValue/Length;
- Return mtBarCnt;
- End
现在可以举个例子来说明,怎么用上面的几个函数来做交易策略了。假如我们的策略如下:
1、我们以日线的均线交叉来判断大趋势,然后在5分钟图上来做交易;
2、日线的短期均线上穿长期均线,则只做多,不做空;反之只做空,不做多;
3、确定了大趋势后,我们再根据5分钟图来判断小趋势,以决定进场时机。我们仍然用均线来判断,在多头大趋势下,如果5分钟的短期均线上穿长期均线,则进场做多,反穿出场,但不反手做空;在空头大趋势下,类似;
我们在5分钟图上调用刚才的函数的来实现。新建公式应用TestMtMa,代码如下:
- Params
- Numeric TimeFrame(1440); // 目标时间周期参数,参数说明参见MtBar
- Numeric BarsBack(1); // 目标时间周期BAR偏移参数,说明见MtBar函数
- Numeric Length1(10); // 大周期的短期均线周期
- Numeric Length2(20); // 大周期的长期均线周期
- Numeric Length3(10); // 小周期的短期均线周期
- Numeric Length4(20); // 小周期的长期均线周期
- Numeric Lots(1);
- Vars
- NumericSeries MA1;
- NumericSeries MA2;
- Numeric oMA1;
- Numeric oMA2;
- NumericSeries MA3;
- NumericSeries MA4;
- Begin
- MtMa(TimeFrame,BarsBack,Length1,oMA1);
- MA1 = oMA1;
- PlotNumeric("MA1",MA1);
- MtMa(TimeFrame,BarsBack,Length2,oMA2);
- MA2 = oMA2;
- PlotNumeric("MA2",MA2);
- MA3 = AverageFC(Close,Length3);
- MA4 = AverageFC(Close,Length4);
- PlotNumeric("MA3",MA3);
- PlotNumeric("MA4",MA4);
- If (MA1>MA2) // 大周期均线金叉,多头趋势
- {
- if (MarketPosition!=1 and MA3[1]>MA4[1])
- {
- Buy(Lots,Open);
- }
- if (MarketPosition==1 and MA3[1]<MA4[1])
- {
- Sell(Lots,Open);
- }
- }
- If (MA1<MA2) // 大周期均线死叉,空头趋势
- {
- if (MarketPosition!=-1 and MA3[1]<MA4[1])
- {
- SellShort(Lots,Open);
- }
- if (MarketPosition==-1 and MA3[1]>MA4[1])
- {
- BuyToCover(Lots,Open);
- }
- }
- End