今天开始争取每周一到两篇外汇指标原理分析以及mql4样例代码,今天要剖析的是最简单而又常用的移动平均线(Moving Averages)。
移动平均线又分为简单移动平均线(Simple Moving Averages),加权移动平均线(Weighted Moving Averages),指数移动平均线(Exponential Moving Averages)等
例如当前有XAUUSD的10天收盘价信息
2014.12.29 1182.97
2014.12.30 1200.02
2014.12.31 1182.16
2015.01.02 1188.04
2015.01.05 1204.55
2015.01.06 1218.15
2015.01.07 1210.64
2015.01.08 1208.42
2015.01.09 1222.65
2015.01.12 1227.33
根据以上数据我们可以拿到5天的SMA数据


2014.12.29 1182.97
2014.12.30 1200.02
2014.12.31 1182.16
2015.01.02 1188.04
2015.01.05 1204.55 1191.548
2015.01.06 1218.15 1198.584
2015.01.07 1210.64 1200.708
2015.01.08 1208.42 1205.96
2015.01.09 1222.65 1212.882
2015.01.12 1227.33 1217.438
再来看加权移动平均(线性加权)
指计算平均值时将数据乘以不同数值,在技术分析中,n日WMA的最近期一个数值乘以n、次近的乘以n-1,如此类推,一直到0:
上式可以推导出
2014.12.29 1182.97
2014.12.30 1200.02
2014.12.31 1182.16
2015.01.02 1188.04
2015.01.05 1204.55 1191.548 1193.626667
2015.01.06 1218.15 1198.584 1202.494
2015.01.07 1210.64 1200.708 1206.512667
2015.01.08 1208.42 1205.96 1209.083333
2015.01.09 1222.65 1212.882 1214.646667
2015.01.12 1227.33 1217.438 1219.462667
再来看指数移动平均数
是以指数式递减加权的移动平均。各数值的加权影响力随时间而指数式递减,越近期的数据加权影响力越重,但较旧的数据也给予一定的加权值
加权的程度以常数α决定,α数值介乎0至1。α也可用天数N来代表:
,所以,N=19天,代表α=0.1。
设时间t的实际数值为Yt,而时间t的EMA则为St;时间t-1的EMA则为St-1,计算时间t≥2是方程式为:

EMA的公式推导见

根据我们这边给N=5(通常用12和26比较常用)
那么可以知道k=20.7,也就是说我们要至少拿到前20天的数据才能推导出第一个EMA的值了(实际计算中并没有严格按照这样的数学逻辑计算,而是把第一天的收盘价当成第一个EMA值)
这边我们就不去计算了,因为mt4中都有现成的API计算好了,以上所有的指标都是有的
可以到
Include文件夹下看MovingAverages.mqh这个头文件
//+------------------------------------------------------------------+
//| MovingAverages.mqh |
//| Copyright 2009-2013, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Simple Moving Average |
//+------------------------------------------------------------------+
double SimpleMA(const int position,const int period,const double &price[])
{
//---
double result=0.0;
//--- check position
if(position>=period-1 && period>0)
{
//--- calculate value
for(int i=0;i<period;i++) result+=price[position-i];
result/=period;
}
//---
return(result);
}
//+------------------------------------------------------------------+
//| Exponential Moving Average |
//+------------------------------------------------------------------+
double ExponentialMA(const int position,const int period,const double prev_value,const double &price[])
{
//---
double result=0.0;
//--- calculate value
if(period>0)
{
double pr=2.0/(period+1.0);
result=price[position]*pr+prev_value*(1-pr);
}
//---
return(result);
}
//+------------------------------------------------------------------+
//| Smoothed Moving Average |
//+------------------------------------------------------------------+
double SmoothedMA(const int position,const int period,const double prev_value,const double &price[])
{
//---
double result=0.0;
//--- check position
if(period>0)
{
if(position==period-1)
{
for(int i=0;i<period;i++) result+=price[position-i];
result/=period;
}
if(position>=period)
result=(prev_value*(period-1)+price[position])/period;
}
//---
return(result);
}
//+------------------------------------------------------------------+
//| Linear Weighted Moving Average |
//+------------------------------------------------------------------+
double LinearWeightedMA(const int position,const int period,const double &price[])
{
//---
double result=0.0,sum=0.0;
int i,wsum=0;
//--- calculate value
if(position>=period-1 && period>0)
{
for(i=period;i>0;i--)
{
wsum+=i;
sum+=price[position-i+1]*(period-i+1);
}
result=sum/wsum;
}
//---
return(result);
}
//+------------------------------------------------------------------+
//| Simple moving average on price array |
//+------------------------------------------------------------------+
int SimpleMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
const int period,const double& price[],double& buffer[])
{
int i,limit;
//--- check for data
if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
bool as_series_price=ArrayGetAsSeries(price);
bool as_series_buffer=ArrayGetAsSeries(buffer);
if(as_series_price) ArraySetAsSeries(price,false);
if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
if(prev_calculated==0) // first calculation
{
limit=period+begin;
//--- set empty value for first bars
for(i=0;i<limit-1;i++) buffer[i]=0.0;
//--- calculate first visible value
double firstValue=0;
for(i=begin;i<limit;i++)
firstValue+=price[i];
firstValue/=period;
buffer[limit-1]=firstValue;
}
else limit=prev_calculated-1;
//--- main loop
for(i=limit;i<rates_total;i++)
buffer[i]=buffer[i-1]+(price[i]-price[i-period])/period;
//--- restore as_series flags
if(as_series_price) ArraySetAsSeries(price,true);
if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
return(rates_total);
}
//+------------------------------------------------------------------+
//| Exponential moving average on price array |
//+------------------------------------------------------------------+
int ExponentialMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
const int period,const double& price[],double& buffer[])
{
int i,limit;
//--- check for data
if(period<=1 || rates_total-begin<period) return(0);
double dSmoothFactor=2.0/(1.0+period);
//--- save as_series flags
bool as_series_price=ArrayGetAsSeries(price);
bool as_series_buffer=ArrayGetAsSeries(buffer);
if(as_series_price) ArraySetAsSeries(price,false);
if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
if(prev_calculated==0)
{
limit=period+begin;
//--- set empty value for first bars
for(i=0;i<begin;i++) buffer[i]=0.0;
//--- calculate first visible value
buffer[begin]=price[begin];
for(i=begin+1;i<limit;i++)
buffer[i]=price[i]*dSmoothFactor+buffer[i-1]*(1.0-dSmoothFactor);
}
else limit=prev_calculated-1;
//--- main loop
for(i=limit;i<rates_total;i++)
buffer[i]=price[i]*dSmoothFactor+buffer[i-1]*(1.0-dSmoothFactor);
//--- restore as_series flags
if(as_series_price) ArraySetAsSeries(price,true);
if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
return(rates_total);
}
//+------------------------------------------------------------------+
//| Linear weighted moving average on price array |
//+------------------------------------------------------------------+
int LinearWeightedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
const int period,const double& price[],double& buffer[],int &weightsum)
{
int i,limit;
double sum;
//--- check for data
if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
bool as_series_price=ArrayGetAsSeries(price);
bool as_series_buffer=ArrayGetAsSeries(buffer);
if(as_series_price) ArraySetAsSeries(price,false);
if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
if(prev_calculated==0)
{
weightsum=0;
limit=period+begin;
//--- set empty value for first bars
for(i=0;i<limit;i++) buffer[i]=0.0;
//--- calculate first visible value
double firstValue=0;
for(i=begin;i<limit;i++)
{
int k=i-begin+1;
weightsum+=k;
firstValue+=k*price[i];
}
firstValue/=(double)weightsum;
buffer[limit-1]=firstValue;
}
else limit=prev_calculated-1;
//--- main loop
for(i=limit;i<rates_total;i++)
{
sum=0;
for(int j=0;j<period;j++) sum+=(period-j)*price[i-j];
buffer[i]=sum/weightsum;
}
//--- restore as_series flags
if(as_series_price) ArraySetAsSeries(price,true);
if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
return(rates_total);
}
//+------------------------------------------------------------------+
//| Smoothed moving average on price array |
//+------------------------------------------------------------------+
int SmoothedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
const int period,const double& price[],double& buffer[])
{
int i,limit;
//--- check for data
if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
bool as_series_price=ArrayGetAsSeries(price);
bool as_series_buffer=ArrayGetAsSeries(buffer);
if(as_series_price) ArraySetAsSeries(price,false);
if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
if(prev_calculated==0)
{
limit=period+begin;
//--- set empty value for first bars
for(i=0;i<limit-1;i++) buffer[i]=0.0;
//--- calculate first visible value
double firstValue=0;
for(i=begin;i<limit;i++)
firstValue+=price[i];
firstValue/=period;
buffer[limit-1]=firstValue;
}
else limit=prev_calculated-1;
//--- main loop
for(i=limit;i<rates_total;i++)
buffer[i]=(buffer[i-1]*(period-1)+price[i])/period;
//--- restore as_series flags
if(as_series_price) ArraySetAsSeries(price,true);
if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
return(rates_total);
}
//+------------------------------------------------------------------+
今天写了一个涵盖SMA,WMA,EMA的indicator,同时显示在图表上,代码如下(EMA第一个值默认和第一个收盘价相同)
//+------------------------------------------------------------------+
//| moving_averages.mq4 |
//| Copyright 2014, MetaQuotes Software Corp. |
//| http://coderaladdin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link "http://coderaladdin.com"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3
//--- plot SMA
#property indicator_label1 "SMA"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- plot WMA
#property indicator_label2 "WMA"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrBlue
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- plot EMA
#property indicator_label3 "EMA"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrGreen
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
//--- input parameters
input int period=19;
//--- indicator buffers
double SMABuffer[];
double WMABuffer[];
double EMABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
IndicatorBuffers(3);
//--- indicator buffers mapping
SetIndexBuffer(0,SMABuffer);
SetIndexBuffer(1,WMABuffer);
SetIndexBuffer(2,EMABuffer);
string shortname = "EMA("+string(MODE_SMA)+")WMA("+string(MODE_LWMA)+")EMA("+string(MODE_EMA)+"["+string(period)+"]";
IndicatorShortName(shortname);
SetIndexLabel(0,"SMA");
SetIndexLabel(1,"WMA");
SetIndexLabel(2,"EMA");
SetIndexDrawBegin(0,period);
SetIndexDrawBegin(1,period);
SetIndexDrawBegin(2,period);
IndicatorDigits(Digits);
if(period<2)
return(INIT_FAILED);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
//---
if(rates_total < period -1 || period <2)
{
return 0;
}
ArraySetAsSeries(SMABuffer,false);
ArraySetAsSeries(WMABuffer,false);
ArraySetAsSeries(EMABuffer,false);
ArraySetAsSeries(close,false);
if(prev_calculated==0){
ArrayInitialize(SMABuffer,0);
ArrayInitialize(WMABuffer,0);
ArrayInitialize(EMABuffer,0);
}
CalculateSimpleMA(rates_total,prev_calculated,close);
CalculateLWMA(rates_total,prev_calculated,close);
CalculateEMA(rates_total,prev_calculated,close);
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
void CalculateSimpleMA(int rates_total,int prev_calculated,const double &price[])
{
int i,limit;
//--- first calculation or number of bars was changed
if(prev_calculated==0)
{
limit=period;
//--- calculate first visible value
double firstValue=0;
for(i=0; i<limit; i++)
firstValue+=price[i];
firstValue/=period;
SMABuffer[limit-1]=firstValue;
}
else
limit=prev_calculated-1;
//--- main loop
for(i=limit; i<rates_total && !IsStopped(); i++)
SMABuffer[i]=SMABuffer[i-1]+(price[i]-price[i-period])/period;
//---
}
//+------------------------------------------------------------------+
//| exponential moving average |
//+------------------------------------------------------------------+
void CalculateEMA(int rates_total,int prev_calculated,const double &price[])
{
int i,limit;
double SmoothFactor=2.0/(1.0+period);
//--- first calculation or number of bars was changed
if(prev_calculated==0)
{
limit=period;
EMABuffer[0]=price[0];
for(i=1; i<limit; i++)
EMABuffer[i]=price[i]*SmoothFactor+EMABuffer[i-1]*(1.0-SmoothFactor);
}
else
limit=prev_calculated-1;
//--- main loop
for(i=limit; i<rates_total && !IsStopped(); i++)
EMABuffer[i]=price[i]*SmoothFactor+EMABuffer[i-1]*(1.0-SmoothFactor);
//---
}
//+------------------------------------------------------------------+
//| linear weighted moving average |
//+------------------------------------------------------------------+
void CalculateLWMA(int rates_total,int prev_calculated,const double &price[])
{
int i,limit;
static int weightsum;
double sum;
//--- first calculation or number of bars was changed
if(prev_calculated==0)
{
weightsum=0;
limit=period;
//--- calculate first visible value
double firstValue=0;
for(i=0;i<limit;i++)
{
int k=i+1;
weightsum+=k;
firstValue+=k*price[i];
}
firstValue/=(double)weightsum;
WMABuffer[limit-1]=firstValue;
}
else
limit=prev_calculated-1;
//--- main loop
for(i=limit; i<rates_total && !IsStopped(); i++)
{
sum=0;
for(int j=0;j<period;j++)
sum+=(period-j)*price[i-j];
WMABuffer[i]=sum/weightsum;
}
}
来看下这个指标的具体效果,在图标中同时显示EMA,SMA,WMA

Ok,今天介绍的MA指标就这样了,下次介绍MACD指标