第一个indicator - ADX
公式
目前看来比较严谨的公式链接 百度经验公式链接
但是仍然要注意的是,实际上mql4/5里使用的公式是略有区别的
- 平均函数的选择,一般公式都是使用的
SMMA,但是mql4/5选择的是EMA - DI的计算,一般公式是先求的
ATR,APlusDM,AMinusDM。但是mql4/5是定义了一个tmpDI = 100 * DM / TR, DI = EMA(tmpDI, Period)
模板
发现最新版的mql4的模板文件和mql5一样了,每次的回调函数为
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[]){
}
这里需要注意的是,每次开始计算的位置
- 如果是首次,prev_calculated为0,此时开始计算位置就是数组的最后一个元素,rates_total - 1
- 如果是非首次,prev_calculated不为0,那么开始计算位置应该是上一次的位置,即rates_total - prev_calculated。也就是说上一次的位置是要重新计算的。因为周期的原因,举个例子,周期为1min,但是每次tick到来的时间间隔假设是1s,也就是说,1分钟内都没有新bar产生,但是当前bar的high,low,close会被更新。
indicator结构
buffers
indicator上的每个线,对应一个buffer,buffer大小就是和Bars的大小一样,在OnInit里初始化buffer,定义线条,颜色等信息。
- 指定buffer数目
#property indicator_buffers 3 //要显示的buffer
IndicatorBuffers(16); //总buffer数目,除了显示的外,其他为辅助buffer
- 画额外的东西
使用 ObjectCreate来在窗口上创建元素
int drawHLine(double value){
static int cnt = 0;
string name = "ADX("+IntegerToString(ADXPeriod)+")";
IndicatorShortName(name);
windowIndex=WindowFind(name);
if(windowIndex<0)
{
// if the subwindow number is -1, there is an error
Print("Can\'t find window");
return(0);
}
if(cnt == 0)
ObjectCreate(name,OBJ_HLINE,windowIndex,0,value);
else{
ObjectSet(name,OBJPROP_PRICE1, value);
}
cnt++;
// drawing a line in the indicator subwindow
ObjectSet(name,OBJPROP_COLOR,GreenYellow);
WindowRedraw();
return(1);
}
CODE
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 3 // Number of buffers
#property indicator_color1 Blue // Color of the 1st line
#property indicator_color2 Red
#property indicator_color3 Green
input int ADXPeriod = 14;
//buffers
double bufTr[], bufPDM[], bufMDM[], bufADX[],bufPDI[], bufMDI[];
double bufTr14[], bufPDM14[], bufMDM14[], bufDX[];
double bufTmpPDM[], bufTmpMDM[];
double bufDX2[], bufADX2[], bufPDI2[], bufMDI2[];
int windowIndex = 0;
int OnInit()
{
IndicatorBuffers(16);
SetIndexBuffer(0, bufADX);
SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,1);
SetIndexBuffer(1, bufPDI);
SetIndexStyle(1, DRAW_LINE,STYLE_DOT,1);
SetIndexBuffer(2, bufMDI);
SetIndexStyle(2, DRAW_LINE,STYLE_DOT,1);
SetIndexBuffer(3, bufADX2);
//...
return(INIT_SUCCEEDED);
}
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[])
{
int i = 0;
int p = prev_calculated;
int limit = rates_total - p;
int n = ADXPeriod;
int lastIndex = limit ;//the last one should re-calculate
if(p == 0){
lastIndex = limit - 2;
}
for(i=lastIndex;i>=0;i--){
double up = high[i] - high[i+1];
double down = low[i+1] - low[i];
if( (up < 0 && down < 0) || (up == down)){
bufPDM[i] = 0;
bufMDM[i] = 0;
}
else if(up > down){
bufPDM[i] = up;
bufMDM[i] = 0;
}
else if(down > up){
bufMDM[i] = down;
bufPDM[i] = 0;
}
double tr1 = high[i] - low[i];
double tr2 = MathAbs(high[i] - close[i+1]);
double tr3 = MathAbs(low[i] - close[i+1]);
bufTr[i] = MathMax(MathMax(tr1,tr2),tr3);
if(bufTr[i] == 0){
bufPDI2[i] = 0;
bufMDI2[i] = 0;
}
else{
bufPDI2[i] = 100.0 * (bufPDM[i] / bufTr[i]);
bufMDI2[i] = 100.0 * (bufMDM[i] / bufTr[i]);
}
}
ema(bufPDI, bufPDI2, lastIndex, n, p == 0);
ema(bufMDI, bufMDI2, lastIndex, n, p == 0);
for(i=0;i<=lastIndex;i++){
//the last one maybe zero
if( bufTr14[i] == 0 ){
bufTr14[i] = 1;
}
double sumPM = bufPDI[i] + bufMDI[i];
if(sumPM == 0){
sumPM = 1;
}
bufDX[i] = 100 * ( MathAbs(bufPDI[i] - bufMDI[i]) / (sumPM) );
}
ema(bufADX, bufDX, lastIndex, n, p == 0);
return(rates_total);
}
void ema(double &target[], const double &source[], int indexLast, int n, bool first){
double sum = 0.0;
int cnt = 0;
double a = 2.0/(n+1);
for(int i=indexLast;i>=0;i--){
if(first && cnt < n){
sum += source[i];
target[i] = 0;
if(cnt == n - 1){
target[i] = nd(sum / n);
}
}
else{
target[i] = nd (target[i+1] * (1-a) + source[i] * a );
}
cnt++;
}
}