保持敬畏之心
交易是一场持久战

MQL4(62):自定义指标源代码

这是系列教学的最后一篇文章,不知大家学会了多少,想进一步交流的加学长的微信:u31u31。
下面是课程中的自定义指标源代码:
#property copyright "tudaojiaoyi"
#property indicator_chart_window         // 指定指标在主图表窗口中显示
#property indicator_buffers 3              // 指定指标使用的缓冲区数量 (中轨, 上轨, 下轨)
#property indicator_color1  DeepSkyBlue    // 设置第一个缓冲区(EMA)的颜色
#property indicator_color2  DeepSkyBlue    // 设置第二个缓冲区(UpperBand)的颜色
#property indicator_color3  DeepSkyBlue    // 设置第三个缓冲区(LowerBand)的颜色

// ===== 外部输入参数 =====
// 用户可以在指标属性中修改这些值
extern int BandsPeriod   = 20;      // 均线和标准差的计算周期
extern int BandsShift    = 0;       // 指标整体水平位移(K线根数)
extern int BandsMethod   = MODE_EMA;  // 移动平均线的计算方法 (EMA: 指数移动平均)
extern int BandsPrice    = PRICE_CLOSE; // 计算所使用的价格类型 (收盘价)
extern double Deviations = 2.0;    // 标准差的倍数,用于计算上下轨的宽度

// ===== 指标缓冲区 =====
// 这些数组用于存储指标线上每个点的值
double EMA[];       // 存储中轨(指数移动平均线)的值
double UpperBand[]; // 存储上轨的值
double LowerBand[]; // 存储下轨的值

// ===== 初始化函数 =====
// 在指标首次加载到图表时执行一次,用于设置指标属性
int OnInit()
{
    // --- 设置中轨线 (第0个缓冲区) ---
    SetIndexStyle(0, DRAW_LINE);      // 设置为画线模式
    SetIndexBuffer(0, EMA);           // 将第0个缓冲区与EMA数组关联
    SetIndexLabel(0, "EMA (" + BandsPeriod + ")"); // 设置在数据窗口中显示的标签

    // --- 设置上轨线 (第1个缓冲区) ---
    SetIndexStyle(1, DRAW_LINE);
    SetIndexBuffer(1, UpperBand);
    SetIndexLabel(1, "Upper Band (" + DoubleToStr(Deviations, 1) + " SD)"); // SD: Standard Deviation

    // --- 设置下轨线 (第2个缓冲区) ---
    SetIndexStyle(2, DRAW_LINE);
    SetIndexBuffer(2, LowerBand);
    SetIndexLabel(2, "Lower Band (" + DoubleToStr(Deviations, 1) + " SD)");

    // 如果设置了水平位移
    if(BandsShift != 0)
    {
        SetIndexShift(0, BandsShift); // 将中轨线水平移动指定的K线数
        SetIndexShift(1, BandsShift); // 将上轨线水平移动指定的K线数
        SetIndexShift(2, BandsShift); // 将下轨线水平移动指定的K线数
    }

    // 设置在图表左上角显示的指标简称
    IndicatorShortName("EMA Bands (" + BandsPeriod + "," + DoubleToStr(Deviations, 1) + ")");

    return(INIT_SUCCEEDED); // 返回初始化成功信号
}

// ===== 反初始化函数 =====
// 在指标从图表移除时执行,可用于释放资源
void OnDeinit(const int reason)
{
    // 此处无特殊操作
}

// ===== 主计算函数 =====
// 每当有新的报价(tick)或图表刷新时,此函数会被调用
int OnCalculate(const int rates_total,      // 图表上总的K线数
                const int prev_calculated,  // 上次调用此函数时已计算的K线数
                const datetime &time[],     // K线时间数组
                const double &open[],       // 开盘价数组
                const double &high[],       // 最高价数组
                const double &low[],        // 最低价数组
                const double &close[],      // 收盘价数组
                const long &tick_volume[],  // Tick成交量数组
                const long &volume[],       // 真实成交量数组
                const int &spread[])        // 点差数组
{
    // 如果K线总数不足以计算周期,则直接返回
    if(rates_total < BandsPeriod) return(0);

    int start_pos; // 定义计算的起始位置

    // 确定本次计算的起始K线索引,这是为了优化性能,避免重复计算历史数据
    if(prev_calculated == 0)
        start_pos = rates_total - 1;       // 首次计算:从图表最右侧(最新的K线)开始,一直算到最左侧
    else
        start_pos = rates_total - prev_calculated; // 后续调用:仅计算新生成的K线

    // 循环计算每个K线的指标值,从最新的K线向旧的K线方向计算
    for(int i = start_pos; i >= 0; i--)
    {
        // 调用内置iMA函数计算当前K线(i)的移动平均值
        EMA[i] = iMA(NULL, 0, BandsPeriod, 0, BandsMethod, BandsPrice, i);
        // 调用内置iStdDev函数计算当前K线(i)的标准差
        double StdDev = iStdDev(NULL, 0, BandsPeriod, 0, BandsMethod, BandsPrice, i);
        // 计算上轨 = 中轨 + (标准差 * 倍数)
        UpperBand[i] = EMA[i] + (StdDev * Deviations);
        // 计算下轨 = 中轨 - (标准差 * 倍数)
        LowerBand[i] = EMA[i] - (StdDev * Deviations);
    }

    // 返回已计算的K线总数,供下次调用时作为 prev_calculated 的值
    return(rates_total);
}
赞(0)
未经允许不得转载:图道交易 » MQL4(62):自定义指标源代码
分享到

评论 抢沙发