MT4/MT5 的指标计算都带缓存,不用每次都从头到尾的在每一根 bar 上计算。指标提供了 OnCalculate 回调函数。也就是在初次加载指标时,OnCalculate 回调函数会计算一下历史 bar,然后就等待 tick 更新最后一根 bar,tick 每更新一次就刷新一次 OnCalculate,这时可能还会出现断网再重连补数据的情况,那么就需要不光要绘制最后一根 bar, 要多绘制最后几根 bar。
那么在 OnCalculate 中就可以正向循环计算和反向循环计算两种方法。
从后往前计算
//+------------------------------------------------------------------+ //| Bill Williams' Alligator | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int limit = rates_total - prev_calculated; //---- main loop for(int i = 0; i < limit; i++) { double Range = 0; double AvgRange = 0; for(int counter = 0; counter <= 0 + 9; counter++) { AvgRange = AvgRange + MathAbs(High[counter] - Low[counter]); } Range = AvgRange / 10; //---- ma_shift set to 0 because SetIndexShift called abowe ExtBlueBuffer[i] = iMA(NULL, 0, InpJawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtRedBuffer[i] = iMA(NULL, 0, InpTeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtLimeBuffer[i] = iMA(NULL, 0, InpLipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); double rosokuValueCloseP = iClose(NULL, 0, i); double JAW_ATAI_1 = ExtBlueBuffer[i]; double JAW_ATAI_2 = iMA(NULL, 0, InpJawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i + 1); double TEETH_ATAI_1 = ExtRedBuffer[i]; double TEETH_ATAI_2 = iMA(NULL, 0, InpTeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i + 1); double LIPS_ATAI_1 = ExtLimeBuffer[i]; double LIPS_ATAI_2 = iMA(NULL, 0, InpLipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i + 1); if(LIPS_ATAI_1 > TEETH_ATAI_1 && LIPS_ATAI_1 > JAW_ATAI_1 && JAW_ATAI_2 < JAW_ATAI_1 && rosokuValueCloseP > LIPS_ATAI_1) { CrossUp[i] = Low[i] - Range * 0.5; } else if(LIPS_ATAI_1 < TEETH_ATAI_1 && LIPS_ATAI_1 < JAW_ATAI_1 && JAW_ATAI_2 > JAW_ATAI_1 && rosokuValueCloseP < LIPS_ATAI_1) { CrossDown[i] = High[i] + Range * 0.5; } else { } } return(rates_total); }
从前往后计算
//+------------------------------------------------------------------+ //| Bill Williams' Alligator | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int limit = rates_total - prev_calculated - 1; //---- main loop for(int i = limit; i >= 0; i--) { double Range = 0; double AvgRange = 0; for(int counter = 0; counter <= 0 + 9; counter++) { AvgRange = AvgRange + MathAbs(High[counter] - Low[counter]); } Range = AvgRange / 10; //---- ma_shift set to 0 because SetIndexShift called abowe ExtBlueBuffer[i] = iMA(NULL, 0, InpJawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtRedBuffer[i] = iMA(NULL, 0, InpTeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtLimeBuffer[i] = iMA(NULL, 0, InpLipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); double rosokuValueCloseP = iClose(NULL, 0, i); double JAW_ATAI_1 = ExtBlueBuffer[i]; double JAW_ATAI_2 = iMA(NULL, 0, InpJawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i + 1); double TEETH_ATAI_1 = ExtRedBuffer[i]; double TEETH_ATAI_2 = iMA(NULL, 0, InpTeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i + 1); double LIPS_ATAI_1 = ExtLimeBuffer[i]; double LIPS_ATAI_2 = iMA(NULL, 0, InpLipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i + 1); if(LIPS_ATAI_1 > TEETH_ATAI_1 && LIPS_ATAI_1 > JAW_ATAI_1 && JAW_ATAI_2 < JAW_ATAI_1 && rosokuValueCloseP > LIPS_ATAI_1) { CrossUp[i] = Low[i] - Range * 0.5; } else if(LIPS_ATAI_1 < TEETH_ATAI_1 && LIPS_ATAI_1 < JAW_ATAI_1 && JAW_ATAI_2 > JAW_ATAI_1 && rosokuValueCloseP < LIPS_ATAI_1) { CrossDown[i] = High[i] + Range * 0.5; } else { } } return(rates_total); }