新版的 MT4 指标计算在 OnCalculate 函数中,每次 tick 数据变动,相当于刷新最后一根 bar 的 Close。这时只需要重新计算最后一根的 bar 上的数据。显然不希望在最后一根 bar 上不断更新收盘价时,均线缺不变化。
但是如果在 EA 中用 iCustom 来引用这根均线时,可以采用上一根已收盘的 bar 的来计算。
采用 Bars - IndicatorCounted() - 1 的方式
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[]) {
    // 每次响应 tick 数据时都会回调
    // 未计算的 bars
    int limit = Bars - IndicatorCounted() - 1;              // 这种方式如果计算过, limit = 0
    LOG_INFO(StringFormat("limit: %d", limit));
    // 从前往后算
    for (int i = limit; i >= 0; i--) {
        log_info(log_handle, StringFormat(
                 "Open: %f\tHigh: %f\tLow: %f\tClose: %f", Open[i], High[i], Low[i], Close[i]
             ));
        BufUP[i] = iBands(NULL, 0, BB_Period, 3, 0, PRICE_CLOSE, 1, i); 
        BufCenter[i] = iBands(NULL, 0, BB_Period, 3, 0, PRICE_CLOSE, 0, i); 
        BufDOWN[i] = iBands(NULL, 0, BB_Period, 3, 0, PRICE_CLOSE, 2, i); 
        BufDOWN_Arrow[i] = EMPTY_VALUE;
        BufUP_Arrow[i] = EMPTY_VALUE;
        if(BufUP[i] < High[i]) { 
            BufDOWN_Arrow[i] = High[i] + 30 * Point; 
        }
        if(BufDOWN[i] > Low[i]) { 
            BufUP_Arrow[i] = Low[i] - 30 * Point; 
        }
    }
    return(rates_total);
}
采用 rates_total - prev_calculated - 1 的方式
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[]) {
    // 每次响应 tick 数据时都会回调
    // 未计算的 bars
    int limit = rates_total - prev_calculated - 1;        // 这种方式必须 -1, 不然第一次计算引用第一根 bar 会出现错误,limit = -1
    if (limit < 0) 
        limit = 0;
    LOG_INFO(StringFormat("limit: %d", limit));
    // 从前往后算
    for (int i = limit; i >= 0; i--) {
        log_info(log_handle, StringFormat(
                 "Open: %f\tHigh: %f\tLow: %f\tClose: %f", Open[i], High[i], Low[i], Close[i]
             ));
        BufUP[i] = iBands(NULL, 0, BB_Period, 3, 0, PRICE_CLOSE, 1, i); 
        BufCenter[i] = iBands(NULL, 0, BB_Period, 3, 0, PRICE_CLOSE, 0, i); 
        BufDOWN[i] = iBands(NULL, 0, BB_Period, 3, 0, PRICE_CLOSE, 2, i); 
        BufDOWN_Arrow[i] = EMPTY_VALUE;
        BufUP_Arrow[i] = EMPTY_VALUE;
        if(BufUP[i] < High[i]) { 
            BufDOWN_Arrow[i] = High[i] + 30 * Point; 
        }
        if(BufDOWN[i] > Low[i]) { 
            BufUP_Arrow[i] = Low[i] - 30 * Point; 
        }
    }
    return(rates_total);
}
另外一种写法
   int limit;
   if (prev_calculated == 0)
      limit = rates_total - 1;
   else
      limit = rates_total - prev_calculated;
总结
- 不管用何种方式,都要使 
limit = 0,这样在正向循环计算时始终计算最后一根。 - 有也从后往前计算的方式,但是像 supertrend 这样的指标需要前一根 bar 的数据,不能倒着计算。均线可以倒着计算。