# 针对初学者的 MQL 5 中的自定义指标

13 九月 2013, 07:28
2
2 881

### 作为简单示例的 SMA 指标

SMA = SUM (CLOSE (i)，MAPeriod) / MAPeriod

• SUM - 值的总和；
• CLOSE (i) - 第 i 个柱的收盘价；
• MAPeriod - 求平均的柱的数量（平均周期）。

```//+------------------------------------------------------------------+
//|                                                          SMA.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red

input int MAPeriod = 13;
input int MAShift = 0;

double ExtLineBuffer[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
void OnInit()
{
SetIndexBuffer(0, ExtLineBuffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_SHIFT, MAShift);
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MAPeriod - 1);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
if (rates_total < MAPeriod - 1)
return(0);

int first, bar, iii;
double Sum, SMA;

if (prev_calculated == 0)
first = MAPeriod - 1 + begin;
else first = prev_calculated - 1;

for(bar = first; bar < rates_total; bar++)
{
Sum = 0.0;
for(iii = 0; iii < MAPeriod; iii++)
Sum += price[bar - iii];

SMA = Sum / MAPeriod;

ExtLineBuffer[bar] = SMA;
}

return(rates_total);
}
//+------------------------------------------------------------------+```

### 使用注释

```//+------------------------------------------------------------------+
//|                                                          SMA.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+```
```//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+  ```
```//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+```
`//+------------------------------------------------------------------+`

### SMA 代码的结构

1. 在全局层面编写的未包含在括号中的代码，位于第一和第二段注释之间。
2. OnInit() 函数的说明。

3. OnCalculate() 函数的说明。

```//+------------------------------------------------------------------+
//| 自定义指标去初始化函数                                              |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{

}```

### SMA 指标的程序代码

```//---- 这个指标会在主窗口中绘图
#property indicator_chart_window
//---- 一个缓冲区用于指标的计算和绘图
#property indicator_buffers 1
//---- 只有一个绘图
#property indicator_plots   1
//---- 指标绘成线形
#property indicator_type1   DRAW_LINE
//---- 指标线的颜色是红色
#property indicator_color1  Red ```

```//---- 指标输入参数
input int MAPeriod = 13; //平均周期
nput int MAShift = 0; //水平转换 (柱数)
```

```//---- 动态数组的声明
//将被用于指标缓冲区
double ExtLineBuffer[];
```

OnInit() 函数的内容仅通过 3 个运算符表示，这些运算符是 MetaTrader 客户端的内置函数。

```void OnInit()
{
//----+
//---- 把动态数组 ExtLineBuffer 用作指标的第0个缓冲区
SetIndexBuffer(0,ExtLineBuffer,INDICATOR_DATA);
//---- 根据MAShift设置绘图中水平轴的基础转换
PlotIndexSetInteger(0,PLOT_SHIFT,MAShift);
//---- 根据MAPeriod设置绘图柱起点
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MAPeriod);
//----+
}```

PlotIndexSetInteger() 函数的最后调用传递等于 MAPeriod（通过函数 OnCalculate() 的参数 begin）的值到其他指标，如果其应用至我们的指标的值的话。逻辑很简单，最初的 MaPeriod-1 个柱没有什么需要平均，这就是该指标的绘图无用的原因。然而，需要传递该值以平移其他指标的计算原点。

```int OnCalculate(
const int rates_total,    // 当前订单下的历史中可用的柱数
const int prev_calculated,// 前一订单计算后的柱数
const int begin,          // 第一个柱的索引
const double &price[]     // 用于计算的价格数组
)
```

1. 检查计算所需的柱是否存在。
2. 声明局部变量。
3. 获取用于计算的起始柱的索引。
4. 指标计算的主循环。
5. 使用运算符 return() 将 rates_total 的值返回客户端。

```//---- 检查出现的柱的数目是否足够用于计算
if(rates_total<MAPeriod-1+begin)
return(0);```

```//---- 声明局部变量
int first,bar,iii;
double Sum,SMA;```

```//---- 计算主循环中 第一的起始索引
if(prev_calculated==0) // 指标的第一个起点
first=MAPeriod-1+begin; // 所有柱的起始索引
else first=prev_calculated-1; // 新柱的起始索引
```

```//---- 计算的主循环
for(bar=first;bar<rates_total;bar++)```

```     {
Sum=0.0;
//---- 为做平均循环得到总数
for(iii=0;iii<MAPeriod;iii++)
Sum+=price[bar-iii]; // 相当于　Sum = Sum + price[bar - iii];

//---- 计算平均数
SMA=Sum/MAPeriod;

//---- 把指标缓冲区中的元素值设为我们计算的SMA值
ExtLineBuffer[bar]=SMA;
}```

```//+------------------------------------------------------------------+
//|                                                          SMA.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
//---- 指标会在主窗口中绘图
#property indicator_chart_window
//---- 指标的计算和绘图会使用一个缓冲区
#property indicator_buffers 1
//---- 只有一个绘图
#property indicator_plots   1
//---- 绘图是线形
#property indicator_type1   DRAW_LINE
//---- 指标线颜色是红色
#property indicator_color1  Red

//---- 指标输入参数
input int MAPeriod = 13; //平均周期
input int MAShift = 0; //水平转换 (柱数)

//----动态数组定义
//将被用于做指标缓冲区
double ExtLineBuffer[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
void OnInit()
{
//----+
//---- 把动态数组 ExtLineBuffer 设为指标的第0个缓冲区
SetIndexBuffer(0,ExtLineBuffer,INDICATOR_DATA);
//---- 根据MAShift设置绘图和水平轴的转换
PlotIndexSetInteger(0,PLOT_SHIFT,MAShift);
//---- 根据MAPeriod设置绘图起点
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MAPeriod);
//----+
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(
const int rates_total,    // 当前订单下历史中可用的柱数
const int prev_calculated,// 前一订单计算的柱数
const int begin,          // 第一个柱的索引
const double &price[]     // 用于计算的价格数组
)
{
//----+
//---- 检查出现的柱数是否足够用于计算
if (rates_total < MAPeriod - 1 + begin)
return(0);

//---- 局部变量声明
int first, bar, iii;
double Sum, SMA;

//---- 主循环中计算第一个起点的索引
if(prev_calculated==0) // 检查是否是第一个起点
first=MAPeriod-1+begin; // 所有柱的起点
else first=prev_calculated-1; // 新柱的起点

//----计算的主循环
for(bar = first; bar < rates_total; bar++)
{
Sum=0.0;
//---- 为计算平均做循环累加
for(iii=0;iii<MAPeriod;iii++)
Sum+=price[bar-iii]; // 相当于 Sum = Sum + price[bar - iii];

//---- 计算平均值
SMA=Sum/MAPeriod;

//---- 把指标缓冲区元素的值设为我们计算的SMA值
ExtLineBuffer[bar]=SMA;
}
//----+
return(rates_total);
}
//+------------------------------------------------------------------+```

### 总结

sma.mq5 (1.74 KB)
sma_.mq5 (2.73 KB)

| 17 9月 2013 在 03:27

1. “将元素的索引设置为序列，这和 MQL4 中是一样的”- 这意味着什么？在我们的示例中，我们使用元素索引作为时间序列。换言之，当前柱（尚未形成）始终具有索引 [0]，上一个（已经形成）具有索引 [1]，等等。

所以要小心，到底用的是哪种情况。MQL4的例子大多使用的指标数组以当前为0， MQL5的例子大多使用的指标数组下标以过去为0。

| 17 9月 2013 在 06:24
DxdCn:

1. “将元素的索引设置为序列，这和 MQL4 中是一样的”- 这意味着什么？在我们的示例中，我们使用元素索引作为时间序列。换言之，当前柱（尚未形成）始终具有索引 [0]，上一个（已经形成）具有索引 [1]，等等。

所以要小心，到底用的是哪种情况。MQL4的例子大多使用的指标数组以当前为0， MQL5的例子大多使用的指标数组下标以过去为0。

MQL5中要使用ArraySetAsSeries()函数，将动态数组（向索引大的方向分配内存存储最新值）转换成时间序列形式，即，最新的数据存储在索引0的位置，次新的数据存储在索引为1的位置，以此类推，最新的数据永远存储在索引0位置。