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

MQL4(55):自定义指标与脚本开发

#MQL4编程入门教学

若一本关于MQL语言的书籍,未能涵盖自定义指标与脚本的开发,那它无疑是不完整的。MetaTrader平台内置的指标虽多,但远非全部。幸运的是,MQL语言赋予了我们创造专属分析工具的强大能力。今天,我们将学习如何为我们的交易系统,打造独一无二的视觉化指标和便捷化脚本。

第一部分:自定义指标 —— 将你的策略“画”在图上

一个EA再智能,也只是在后台默默运算。而一个自定义指标,则能将你独特的交易逻辑、对市场的理解,直观地画在图表上,让你一目了然。

我们将亲手构建一个简单但非常实用的指标:一个以EMA为中轨的改良版布林带。为什么?因为很多交易员(包括我)都更偏爱EMA的灵敏性,而非标准布林带所使用的SMA(简单移动平均线)。我们不只是在编程,更是在升级一个经典工具。

核心概念:指标缓冲区(Buffers) —— 我们的“颜料桶”

要往图表上画线,我们首先需要准备好“颜料”。在MQL4中,指标缓冲区就是我们的“颜料桶”。

  • 每个自定义指标最多可以拥有8个颜料桶(缓冲区索引号从0到7)。
  • 每个桶里可以装一种“颜料”(一条指标线的数据)。
  • 比如,0号桶装蓝色颜料(中轨线),1号桶装红色颜料(上轨),2号桶装绿色颜料(下轨)。

OnInit()函数中,我们告诉MT4每个桶里是什么颜色、画成什么样式(SetIndexStyle),以及这个桶将由哪个数组来填装颜料(SetIndexBuffer)。在OnTick()(或OnCalculate)函数中,我们的代码就是那位辛勤的“画家”,负责计算数据,并将“颜料”填入每个桶中。

第一步:使用向导,搭建指标框架

通过MetaEditor的“新建”向导,我们可以快速生成一个自定义指标的基本模板。在向导中,我们设定指标包含3条线。以下是向导生成的初始代码(为简洁起见,暂时省略了 start() 函数部分):


#property copyright "tudoajiaoyi" // 版权声明
#property link      "http://www.eamql5.com" // 开发者链接

#property indicator_chart_window      // 指示指标在主图表窗口显示
#property indicator_buffers 3           // 指示指标使用3个缓冲区
#property indicator_color1 DeepSkyBlue   // 第1条线的颜色
#property indicator_color2 DeepSkyBlue   // 第2条线的颜色
#property indicator_color3 DeepSkyBlue   // 第3条线的颜色

//---- 定义指标缓冲区数组
double ExtMapBuffer1[]; // 第1个缓冲区数组 (稍后会重命名)
double ExtMapBuffer2[]; // 第2个缓冲区数组
double ExtMapBuffer3[]; // 第3个缓冲区数组

int init()
{
  //---- 指标设置
  SetIndexStyle(0, DRAW_LINE); 
  SetIndexBuffer(0, ExtMapBuffer1);

  // 设置第1号缓冲区的绘图风格为直线,并将其与ExtMapBuffer2数组绑定
  SetIndexStyle(1, DRAW_LINE);
  SetIndexBuffer(1, ExtMapBuffer2);

  // 设置第2号缓冲区的绘图风格为直线,并将其与ExtMapBuffer3数组绑定
  SetIndexStyle(2, DRAW_LINE);
  SetIndexBuffer(2, ExtMapBuffer3);
  //----
  return(0); // 初始化成功
}
  • #property indicator_chart_window: 告诉MT4,把指标画在主图表上。如果要画在下方的副图(像MACD那样),则用#property indicator_separate_window
  • #property indicator_buffers 3: 声明我们将使用3个“颜料桶”。
  • SetIndexBuffer(0, ExtMapBuffer1): 这是核心,它将0号“颜料桶”和ExtMapBuffer1这个数组“绑定”在了一起。未来,我们往ExtMapBuffer1数组里填的数据,就会自动显示为0号桶所代表的那条线。

第二步:为“颜料桶”取个好名字,并添加说明

向导生成的ExtMapBuffer1这种名字毫无意义。一个专业的开发者,会立刻给它们换上具有描述性的名称,并用SetIndexLabel()为每条线添加“标签”,方便使用者(也方便未来的自己)理解。

//---- 定义指标缓冲区数组
double EMA[];         // 用于存储指数移动平均线 (中轨)
double UpperBand[];   // 用于存储布林带上轨
double LowerBand[];   // 用于存储布林带下轨

int init()
{
  // 设置第0号缓冲区 (EMA - 中轨)
  SetIndexStyle(0, DRAW_LINE);        // 绘制为直线
  SetIndexBuffer(0, EMA);             // 绑定到EMA数组
  SetIndexLabel(0, "EMA (中轨)");     // 设置数据窗口标签

  // 设置第1号缓冲区 (UpperBand - 上轨)
  SetIndexStyle(1, DRAW_LINE);
  SetIndexBuffer(1, UpperBand);
  SetIndexLabel(1, "上轨");

  // 设置第2号缓冲区 (LowerBand - 下轨)
  SetIndexStyle(2, DRAW_LINE);
  SetIndexBuffer(2, LowerBand);
  SetIndexLabel(2, "下轨");
  //----
  return(0); // 初始化成功
}

学长建议:清晰的命名和标签,是你为自己的指标写的最好的“说明书”。当其他EA要通过iCustom()函数调用你的指标数据时,正是通过缓冲区索引号(0, 1, 2)来获取对应数据的。你的清晰标签,能让调用者一目了然,0号是中轨,1号是上轨。

第三步:核心计算逻辑 —— start()函数与增量计算

指标的核心计算,都发生在start()函数(在新版MQL中也叫OnCalculate())中。

IndicatorCounted() —— 聪明的画家 想象一下,一幅有2000根K线的壁画,每次价格跳动一下,我们就要把整幅画全部重画一遍,这是极其低效的。IndicatorCounted()函数就是让我们的“画家”变聪明的关键,它会告诉我们:“这幅画已经画了多少根K线了?”。这样,我们的代码就只需要计算和绘制那些新出现的、尚未被画过的K线,极大地提升了效率。这就是增量计算。

int counted_bars = IndicatorCounted(); 
int limit;

if(counted_bars > 0) 
{
    counted_bars--;  
}
limit = Bars - counted_bars - 1; 

for(int i = limit; i >= 0; i--)
{
    // 在此执行指标的具体计算逻辑,并将结果存入对应的缓冲区数组,例如 EMA[i], UpperBand[i] 等
}

第四步:填充计算逻辑,并使其“可定制”

现在,我们在循环中,调用MQL4内置的指标函数,来计算我们需要的值,并填入“颜料桶”。更进一步,我们将所有关键参数都设置为extern外部变量,让用户可以自由定制。

// 外部输入参数
extern int    BandsPeriod    = 20;         // 布林带周期
extern int    BandsShift     = 0;          // 均线位移
extern int    BandsMethod    = MODE_EMA;   // 均线计算方法
extern int    BandsPrice     = PRICE_CLOSE;
extern double Deviations     = 2.0;

// 在 start() 函数或 OnCalculate() 函数中:
// (counted_bars 和 limit 的计算如前所述)

for(int i = limit; i >= 0; i--)
{
    // 计算EMA (或其他类型的均线)
    EMA[i] = iMA(NULL, 0, BandsPeriod, BandsShift, BandsMethod, BandsPrice, i);

    // 计算标准差
    double StdDev = iStdDev(NULL, 0, BandsPeriod, BandsShift, BandsMethod, BandsPrice, i);

    // 计算上下轨,并应用标准差倍数
    UpperBand[i] = EMA[i] + (StdDev * Deviations);
    LowerBand[i] = EMA[i] - (StdDev * Deviations);
}

至此,一个功能强大、高度可定制的、远胜于平台自带的“EMA布林带”指标就诞生了!


第二部分:脚本(Scripts) —— 交易员的“一键宏”

脚本是一种“召之即来,挥之即去”的一次性MQL程序。当它被加载到图表上时,会自动执行一次,然后就结束使命。

它就像是为我们交易员量身定做的“快捷键”或“宏命令”,专门用于自动化处理那些繁琐、重复性的操作:

  • 一键平掉所有盈利的订单。
  • 一键将所有持仓单设置到保本损。
  • 一键删除所有挂单。

脚本的“启动确认”

标签为了规范脚本的执行,我们通常会在脚本开头,加入下面两个预处理指令之一:

  • #property show_confirm: 如果你的脚本是“一键平仓”这种不可逆的危险操作,用它。执行前会弹窗,让你“确认执行?”。
  • #property show_inputs: 如果你的脚本需要用户临时输入参数(比如一个“快速挂单”脚本需要用户输入价格和手数),用它。执行前会自动弹出参数设置窗口。
#property show_confirm  // 确认提示框
#property show_inputs   // 参数设置对话框

脚本的生命周期非常简单:init() -> start() -> deinit(),三个函数都只执行一次。并且,同一个图表在同一时间,只能运行一个脚本。所有脚本文件,都存放在\experts\scripts子文件夹中。

赞(0)
未经允许不得转载:图道交易 » MQL4(55):自定义指标与脚本开发
分享到

评论 抢沙发

评论前必须登录!

立即登录   注册

登录

找回密码

注册