首页 > 提升投资报酬 > 量化分析

如何计算移动平均线角度并将其显示于图表上的方法

量化分析 2022-04-24 10:06:59

登录移动平均线用的缓冲器


在本篇章节中,将说明如何计算移动平均线角度并显示于图表中。

首先,在制作新档案中选择「自定义指标」,并将文件名命名为「MA_angle」。由于本次将使用「OnChartEvent」,因此在「自定义指针程序的事件处理程序」画面中,仅勾选「OnChartEvent」并进入下一步登录移动平均线用的缓冲器。卷标设定为「MA」、样式为「Line」、颜色为「White」后点击「完成」即是雏形。

自定义指标
 

定义接头辞以利删除对象


首先,由于缓冲器名称略嫌冗长,因此将「MABuffer」变更为「MA」。
 
double MA[];

SetIndexBuffer(0,MA);
因本次将使用到对象,故为了能够一次进行删除,应先登录接头辞;在档案上方的属性「#property indicator_width1 1」下方,将「PREFIX」如以下所示加以定义。
 
#define PREFIX “MA_angle_”
另外,在「Custom indicator initialization function」下方设定「Custom indicator deinitialization function」,并写入使用OnDeinit函数的以下编码。
 
void OnDeinit(const int reason)

{

ObjectsDeleteAll(0, PREFIX);

}
接下来,在OnCalculate函数下写入移动平均线的绘制公式。此处为假设绘制,故将省略详细说明; 可使用for文体,如以下所示进行编写。
 
 

取得光标位置的移动平均线信息


接下来将制作程序,以检测光标的位置,并计算该处的移动平均线角度。

为了检测光标的位置,需在「ChartSetInteger」使用「CHART_EVENT MOUSE_MOVE」进行宣言。在OnInit函数下的「SetIndexBuffer(0,MA);」下方,如以下所示写入编码。
 
ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
接着,在OnChartEvent函数旗下写入移动鼠标的处理动作。首先以「ChartXYToTimePrice」,将光标的XY坐标变更为价格与时间信息。X坐标为「lparam」、Y坐标为「dparam」。取得光标位置的时间之后,以「iBarShift」取得该时间的K线数量与位置。
 
if (id == CHARTEVENT_MOUSE_MOVE) {

datetime time;

double price;

int win = 0;

ChartXYToTimePrice(0, (int)lparam, (int)dparam, win, time, price);

int bar = iBarShift(NULL, 0, time);
其后,将取得该光标位置的移动平均线信息。具体来说,应取得移动平均线的2个点,并从该处得出角度。使用将图表时间与价格变更为XY坐标的「ChartTimePriceToXY」,第1点为K线位置,故写入x[0]与y[0] ;第2点为前一个点,因此依样写入x[1]与y[1] 。
 
int x[2], y[2];

ChartTimePriceToXY(0, 0, Time[bar], MA[bar], x[0], y[0]);

ChartTimePriceToXY(0, 0, Time[bar + 1], MA[bar + 1], x[1], y[1]);
如此即可取得2个点。
 

从移动平均线的2点信息计算角度


接下来,将利用已取得的移动平均线2点来计算角度。角度计算将在x[0]与x[1]不一致时进行,而计算公式如以下画面所示。

移动平均线

先前取得的2点即为黄色坐标。为了算出角度,应先求出三角形底边A的长度以及B的高度;而由于tanθ为A分之B,故能以「arctan(B/A)」来计算角度。

此处所运用的函数,为可返回指定数值arctan(反正切)的「MathArctan」;此函数所得出的答案,会以「弧度」为单位,故若希望转换为计算的单位「次」,便须乘以180并除以π(MT4的M_PI等同于π)。
 
double angle = 90;

if (x[0] != x[1]) angle = MathArctan(double(y[1] – y[0]) / (x[0] – x[1])) * 180 / M_PI;
如此便能够得出角度。另外,X坐标与Y坐标的减法算式中,「1」与「0」将呈现颠倒,此原因在于坐标的标准点位于左上方,故Y坐标越往下、则数值会越发增加。
 

设定Label对象


方才已说明了如何利用移动平均线的2点信息来计算角度;其次,将尝试运用Label对象,把计算结果显示于图表中。

此处会从MQL4帮助文件中,复制Label对象的样本编码并加以运用。点击MQL4帮助文件目录的「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」,便会出现对象一览。

从中选择「OBJ_LABEL」后,复制预先准备的「Create a text label」编码,并贴至档案下方。

首先,删除不需要的「//— reset the error value」「ResetLastError();」等2行,以及「 Print(__FUNCTION__,」「”: failed to create text label! Error code = “,GetLastError());」2行。

另外,为了使显示数值能够改变,在「if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)){」下方插入「ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);」;为了使显示数值能够改变,则插入「ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);」。
 
//+——————————————————————+

//| Create a text label |

//+——————————————————————+

bool LabelCreate(const long chart_ID=0, // chart’s ID

const string name=”Label”, // label name

const int sub_window=0, // subwindow index

const int x=0, // X coordinate

const int y=0, // Y coordinate

const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER, // chart corner for anchoring

const string text=”Label”, // text

const string font=”Arial”, // font

const int font_size=10, // font size

const color clr=clrRed, // color

const double angle=0.0, // text slope

const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // anchor type

const bool back=false, // in the background

const bool selection=false, // highlight to move

const bool hidden=true, // hidden in the object list

const long z_order=0) // priority for mouse click

{

//— create a text label

if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)){

ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);

ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);

return(false);

}

//— set label coordinates

ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);

ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);

//— set the chart’s corner, relative to which point coordinates are defined

ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);

//— set the text

ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);

//— set text font

ObjectSetString(chart_ID,name,OBJPROP_FONT,font);

//— set font size

ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);

//— set the slope angle of the text

ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);

//— set anchor type

ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);

//— set color

ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);

//— display in the foreground (false) or background (true)

ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);

//— enable (true) or disable (false) the mode of moving the label by mouse

ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);

ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);

//— hide (true) or display (false) graphical object name in the object list

ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);

//— set the priority for receiving the event of a mouse click in the chart

ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);

//— successful execution

return(true);

}

依据角度大小改变文字颜色


将设定的LabelCreate写于OnChartEvent函数内;参数的X设定为「5」、Y为「15」、内容为「DoubleToString」的2行、文字字体为「Arial Bold」、大小为「30」。至于文字颜色的设定,则会在LabelCreate上执行;本次将文字颜色设为白色。
 
color clr = clrWhite;

LabelCreate(0, PREFIX + “angle”, 0, 5, 15, CORNER_LEFT_UPPER, DoubleToString(angle, 2), “Arial Bold”, 30, clr);
另外,如欲在K线尺寸大于MA序列尺寸时停止计算,便应在「int bar = iBarShift(NULL, 0, time);」下方增加以下if文体。
 


最后,当移动平均线的角度大于45度时,将文字颜色设定为红色;负45度以下时则是蓝色。只要在「color clr = clrWhite;」下方添加下列if文体即可。
 
 

原始码


本次制作的原始码如以下所示。
 
//+——————————————————————+

//| MA_angle.mq4 |

//| Copyright 2021, MetaQuotes Software Corp. |

//| https://www.mql5.com |

//+——————————————————————+

#property copyright “Copyright 2021, MetaQuotes Software Corp.”

#property link “https://www.mql5.com”

#property version “1.00”

#property strict

#property indicator_chart_window

#property indicator_buffers 1

#property indicator_plots 1

//— plot MA

#property indicator_label1 “MA”

#property indicator_type1 DRAW_LINE

#property indicator_color1 clrWhite

#property indicator_style1 STYLE_SOLID

#property indicator_width1 1

#define PREFIX “MA_angle_”

//— indicator buffers

double MA[];

//+——————————————————————+

//| Custom indicator initialization function |

//+——————————————————————+

int OnInit()

{

//— indicator buffers mapping

SetIndexBuffer(0, MA);

ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

//—

return(INIT_SUCCEEDED);

}

//+——————————————————————+

//| Custom indicator deinitialization function |

//+——————————————————————+

void OnDeinit(const int reason)

{

ObjectsDeleteAll(0, PREFIX);

}

//+——————————————————————+

//| 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[])

{

//—

int limit = Bars – prev_calculated – 1;

if (limit < 1) limit = 1;

for (int i = limit; i >= 0; i–)

MA[i] = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, i);

//— return value of prev_calculated for next call

return(rates_total);

}

//+——————————————————————+

//| ChartEvent function |

//+——————————————————————+

void OnChartEvent(const int id,

const long &lparam,

const double &dparam,

const string &sparam)

{

if (id == CHARTEVENT_MOUSE_MOVE) {

datetime time;

double price;

int win = 0;

ChartXYToTimePrice(0, (int)lparam, (int)dparam, win, time, price);

int bar = iBarShift(NULL, 0, time);

if (bar > ArraySize(MA) – 2) return;

int x[2], y[2];

ChartTimePriceToXY(0, 0, Time[bar], MA[bar], x[0], y[0]);

ChartTimePriceToXY(0, 0, Time[bar + 1], MA[bar + 1], x[1], y[1]);

double angle = 90;

if (x[0] != x[1]) angle = MathArctan(double(y[1] – y[0]) / (x[0] – x[1])) * 180 / M_PI;

color clr = clrWhite;

if (angle >= 45) clr = clrRed;

else if (angle <= -45) clr = clrDodgerBlue;

LabelCreate(0, PREFIX + “angle”, 0, 5, 15, CORNER_LEFT_UPPER, DoubleToString(angle, 2), “Arial Bold”, 30, clr);

}

}

//+——————————————————————+

//| Create a text label |

//+——————————————————————+

bool LabelCreate(const long chart_ID = 0, // chart’s ID

const string name = “Label”, // label name

const int sub_window = 0, // subwindow index

const int x = 0, // X coordinate

const int y = 0, // Y coordinate

const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring

const string text = “Label”, // text

const string font = “Arial”, // font

const int font_size = 10, // font size

const color clr = clrRed, // color

const double angle = 0.0, // text slope

const ENUM_ANCHOR_POINT anchor = ANCHOR_LEFT_UPPER, // anchor type

const bool back = false, // in the background

const bool selection = false, // highlight to move

const bool hidden = true, // hidden in the object list

const long z_order = 0) // priority for mouse click

{

//— create a text label

if(!ObjectCreate(chart_ID, name, OBJ_LABEL, sub_window, 0, 0)) {

ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

return(false);

}

//— set label coordinates

ObjectSetInteger(chart_ID, name, OBJPROP_XDISTANCE, x);

ObjectSetInteger(chart_ID, name, OBJPROP_YDISTANCE, y);

//— set the chart’s corner, relative to which point coordinates are defined

ObjectSetInteger(chart_ID, name, OBJPROP_CORNER, corner);

//— set the text

ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);

//— set text font

ObjectSetString(chart_ID, name, OBJPROP_FONT, font);

//— set font size

ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, font_size);

//— set the slope angle of the text

ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, angle);

//— set anchor type

ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);

//— set color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— display in the foreground (false) or background (true)

ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);

//— enable (true) or disable (false) the mode of moving the label by mouse

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);

//— hide (true) or display (false) graphical object name in the object list

ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);

//— set the priority for receiving the event of a mouse click in the chart

ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);

//— successful execution

return(true);

}

//+——————————————————————+
为了检测光标的位置,需在「ChartSetInteger」使用「CHART_EVENT MOUSE_MOVE」进行宣言。在OnInit函数下的「SetIndexBuffer(0,MA);」下方,如以下所示写入编码。
 
ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
接着,在OnChartEvent函数旗下写入移动鼠标的处理动作。首先以「ChartXYToTimePrice」,将光标的XY坐标变更为价格与时间信息。X坐标为「lparam」、Y坐标为「dparam」。取得光标位置的时间之后,以「iBarShift」取得该时间的K线数量与位置。
 
if (id == CHARTEVENT_MOUSE_MOVE) {

datetime time;

double price;

int win = 0;

ChartXYToTimePrice(0, (int)lparam, (int)dparam, win, time, price);

int bar = iBarShift(NULL, 0, time);
其后,将取得该光标位置的移动平均线信息。具体来说,应取得移动平均线的2个点,并从该处得出角度。使用将图表时间与价格变更为XY坐标的「ChartTimePriceToXY」,第1点为K线位置,故写入x[0]与y[0] ;第2点为前一个点,因此依样写入x[1]与y[1] 。
 
int x[2], y[2];

ChartTimePriceToXY(0, 0, Time[bar], MA[bar], x[0], y[0]);

ChartTimePriceToXY(0, 0, Time[bar + 1], MA[bar + 1], x[1], y[1]);
如此即可取得2个点。
 
哪些贵金属平台好?不错的贵金属交易汇平台推荐:哪些贵金属平台好?2023年平台最新排名
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
本文相关:无相关信息

留言与评论(共有 0 条评论)
验证码:

免责声明

特别提示:根据《关于严厉查处非法外汇期货和外汇按金交易活动的通知》(证监发字[1978]105号)规定凡未经批准的机构在大陆境内擅自开展外汇期货交易均属非法,提高意识,谨防损失!

本网站所有刊登内容,以及所提供的信息资料,目的是为了更好地服务我们的访问者,本网站不保证所有信息、文本、图形、链接及其它项目的绝对准确性和完整性,网站没有任何盈利目的,故仅供访问者参照使用。本网站已尽力确保所有资料是准确、完整及最新的。就该资料的针对性、精确性以及特定用途的适合性而言,本网站不能作出最对应的方案。所以因依赖该资料所致的任何损失,本网均不负责。 除特别注明之服务条款外,其他一切因使用本站而引致的任何意外、疏忽、合约毁坏、隐秘汇漏、诽谤、版权或知识产权侵犯及其所造成的损失,本站概不负责,亦不承担任何法律责任。如您(单位或个人)认为本网站某部分内容有侵权嫌疑,敬请立即通知我们,我们将在第一时间予以更改或删除。以上声明之解释权归牛犇财经网站所有。法律上有相关解释的,以中国法律之解释为基准。如有争议限在我方所在地司法部门解决。