运用水平线与垂直线对象在图表上绘制网格的方式
量化分析
2022-04-24 10:12:21
2023年外汇交易商最新排名更多
在本篇章节中,将介绍如何运用水平线与垂直线对象在图表上绘制网格(纵横线)。
首先,在制作新档案中选择「客制化指标」,并将文件名命名为「Grid_test」。由于本次将使用「OnChartEvent」,因此在「客制化指针的事件处理程序」画面中,仅勾选「OnChartEvent」的字段并进入下一步;如此点击「完成」即是雏形。

因需使用到对象,故为了能够一次进行删除,应先登录接头辞;在档案上方的属性「 #property indicator_chart_window」下方,如以下所示加以定义。
#define PREFIX “Grid_”其后,在「Custom indicator initialization function」下方设定「Custom indicator deinit function」,并写入使用OnDeinit函数的以下编码。
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, PREFIX);
}
使用OBJ_VLINE设定垂直线
关于网格的绘图处理,应能够在图表变更时予以执行,并在每次重设之后绘制网格。
首先来设定垂直线;在绘制纵向线条时,将范围指定为左方K线至右方K线。
「CHART_FIRST_VISIBLE_BAR」是图表左边最先出现的K线,「CHART_WIDTH_IN_BARS」则是图表中的K线总数量;至于右边的K线,由于当图表位置变换时,最新的线条可能并不会出现在右边、并成为负数值,因此需将此状况的数值设定为「0」。
int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);接下来将使用for文体,从barF至barR进行计算。如果只希望在需要的位置绘制垂直线,便须再度新增条件;将绘制垂直线时机的「drawV」改为「true」,便会形成在此时绘制垂直线的模式。
int barR = barF – (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS);
if (barR < 0) barR = 0;
for (int i = barF; i >= barR; i–) {此处会从MQL4帮助档中,复制垂直线的范例编码并加以运用。点击MQL4相关参考目录的「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」,便会出现对象一览;从中选择「OBJ_ VLINE」后,复制预先准备的编码并贴至档案下方。
bool drawV = false;
if (drawV) {
}
}
删除不需要的「//— if the line time is not set, draw it via the last bar」等5行,以及「Print(__FUNCTION__,」「”: failed to create a vertical line! Error code = “,GetLastError());」2行。
另外,颜色从「clr = clrRed」改为「clr = clrGray」,风格则从实线「style = STYLE_SOLID」改为虚线「style = STYLE_DOT」,选择从「selection = true,」改为「selection = false」。
顺道一提,虽然此处为垂直线专用,但亦可将「VLineCreate」改为「LineCreate」以便水平线也能使用;而时间初始设定「datetime time = 0, // line time」的下方,将价格初始设定「double price = 0, // line price」新增double型,然后将「if(!ObjectCreate(chart_ID, name, OBJ_VLINE, sub_window, time, 0)) {」的「0」改为「price」即完成了准备工作。
//+——————————————————————+
//| Create the vertical line |
//+——————————————————————+
bool LineCreate(const long chart_ID = 0, // chart’s ID
const string name = “VLine”, // line name
const int sub_window = 0, // subwindow index
datetime time = 0, // line time
double price = 0, // line price
const color clr = clrGray, // line color
const ENUM_LINE_STYLE style = STYLE_DOT, // line style
const int width = 1, // line width
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 vertical line
if(!ObjectCreate(chart_ID, name, OBJ_VLINE, sub_window, time, price)) {
return(false);
}
//— set line color
ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//— set line display style
ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//— set line width
ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
//— 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 line by mouse
//— when creating a graphical object using ObjectCreate function, the object cannot be
//— highlighted and moved by default. Inside this method, selection parameter
//— is true by default making it possible to highlight and move the object
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);
}
使用switch处理绘制垂直线
接下来,将新增绘制垂直线的编码。
首先在「if (drawV) {」下方「LineCreate」,如以下所示设定参数。图表ID为「0」、名称为「PREFIX+VL+序号」、窗口编号为主要窗口的「0」、时间为核准时间,价格则因是「0」故予以省略。
LineCreate(0, PREFIX + “VL” + IntegerToString(i), 0, Time[i]);如欲在此处将设定改为依照时间周期,便须使用「switch文体」;其与if文体相同,常用于制作执行不同条件的程序。在Switch后方的括号中置入「条件公式」,便会跳到与该公式一致的case位置加以处理。
首先,如果显示图表时间周期的「_Period」数值为1分钟「PERIOD_M1」的处理时,需在「if (drawV) {」上方进行以下编写。在每分钟单位的公式中,如欲以15分钟作为间隔来绘制垂直线,便应将时间除以15分钟,并在余数为「0」时成为「true」。
switch (_Period) {如此便完成了每分钟的设定。
case PERIOD_M1 :
drawV = Time[i] % PeriodSeconds(PERIOD_M15) == 0;
break;
}
根据不同时间周期指定绘制垂直线的间隔
除了1分钟之外,时间周期亦有「5分钟」「15分钟」「30分钟」「1小时」「4小时」「每日」「每周」「每月」等8种,并可设定其各自的条件。
此处将5分钟时间周期设定为每小时间隔、15分钟及30分钟设定为每4小时间隔、1小时则设定为每日间隔。由于15分钟与30分钟同为每4小时进行处理,故可如下所示,删除15分钟的「break;」并一次进行编写。
case PERIOD_M5 :4小时则设定为每周间隔;若使用取得指定日期周间的「TimeDayOfWeek」,便只会在星期一执行处理,并拉出每周的垂直线。
drawV = Time[i] % PeriodSeconds(PERIOD_H1) == 0;
break;
case PERIOD_M15 :
case PERIOD_M30 :
drawV = Time[i] % PeriodSeconds(PERIOD_H4) == 0;
break;
case PERIOD_H1 :
drawV = Time[i] % PeriodSeconds(PERIOD_D1) == 0;
break;
case PERIOD_H4 :另外,每日则以每月间隔,故可使用「MN1」;但若不满一日,便会无法顺利绘制垂直线,因此此处将公式予以改变,运用「TimeMonth」在月份切换时进行绘制。
drawV = Time[i] % PeriodSeconds(PERIOD_D1) == 0 && TimeDayOfWeek(Time[i]) == MONDAY;
break;
case PERIOD_D1 :但是,当使用「i+1」、且「barF」存在于图表最左边的数据时,需注意是否超出序列的范围;为了消除此错误,可在「int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);」下方添加以下if文体。
drawV = TimeMonth(Time[i]) != TimeMonth(Time[i + 1]);
break;
if (barF > Bars – 2) barF = Bars – 2;至于每周的间隔,则以3个月作为区隔;以 TimeMonth(Time[i])除以3,便只会在余数为1、也就是1、4、7、10月时绘制垂直线。
case PERIOD_W1 :最后,每月则是以1年为区隔;使用「TimeYear」,藉以在年份切换时进行绘制。
drawV = TimeMonth(Time[i]) != TimeMonth(Time[i + 1]) && TimeMonth(Time[i]) % 3 == 1;
break;
在不同时间周期绘制不同间隔的水平线
接下来,就要进行水平线的设定。
水平线与垂直向相同,都会使用switch文体,根据不同时间周期变更间隔。
本次将1分钟、5分钟、15分钟以50pips做出区隔。「_Point」意指最小的价格单位,意即0.1pips;故若乘以500便成为50pips。另外, 30分钟、1小时、4小时单位是以100pips做出间隔;每日单位为200pips、每周及每月则是1000pips。double pitch = 0;针对水平线,目标范围仅从图表上方至下方,因此可透过「ChartGetDouble」取得第1个价格以及其下方1个价格;至于最下方的价格,则使用「MathMod」以间隔除算,将余数从最小值中减去、再予以四舍五入。举例来说,若最下方的价格为「104.2」,则间隔的50pips则为四舍五入的「104」。
switch (_Period) {
case PERIOD_M1 :
case PERIOD_M5 :
case PERIOD_M15 :
pitch = 500 * _Point;
break;
case PERIOD_M30 :
case PERIOD_H1 :
case PERIOD_H4 :
pitch = 1000 * _Point;
break;
case PERIOD_D1 :
pitch = 2000 * _Point;
break;
case PERIOD_W1 :
case PERIOD_MN1 :
pitch = 10000 * _Point;
break;
}
double max = ChartGetDouble(0, CHART_PRICE_MAX);为了将数字化为整数,可使用「NormalizeDouble」,从最小值处拉出n条水平线(「_Digits」会显示该货币对价格的小数点以下位数)。
double min = ChartGetDouble(0, CHART_PRICE_MIN);
min -= MathMod(min, pitch);
min = NormalizeDouble(min, _Digits);虽已使用for文体来处理n条列,但「Create the vertical line」的设定为VLINE专用型,故此处将予以修改,以便后续设定样式。在「Create the vertical line」的「const string name = “VLine”, // line name」下方写入以下公式,即可指定两者的样式。
int n = int((max – min) / pitch) + 1;
for (int i = 0; i < n; i++) {
const int type = OBJ_VLINE, // type其后将「if(!ObjectCreate(chart_ID, name, OBJ_VLINE, sub_window, time, price)) {」的「OBJ_VLINE」改为「type」。
if(!ObjectCreate(chart_ID, name, type, sub_window, time, price)) {与此同时,在绘制垂直线的「LineCreate(0, PREFIX + “VL” + IntegerToString(i), 0, Time[i]);」中,在「0」前方添加「OBJ_VLINE」。
LineCreate(0, PREFIX + “VL” + IntegerToString(i), OBJ_VLINE, 0, Time[i]);关于绘制水平线的编码,可延用前文的垂直线内容,并与前述for文体相互搭配。将「VL」改为「HL」、「OBJ_VLINE」改为「OBJ_HLINE」;另外, 因属于HLINE、故时间为「0」、价格为「min+i*pitch」。
原始码
本次制作的原始码如以下所示。//+——————————————————————+
//| Grid_test.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
#define PREFIX “Grid_”
//+——————————————————————+
//| Custom indicator initialization function |
//+——————————————————————+
int OnInit()
{
//— indicator buffers mapping
//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| Custom indicator deinit 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[])
{
//—
//— 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_CHART_CHANGE) {
ObjectsDeleteAll(0, PREFIX);
int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
if (barF > Bars – 2) barF = Bars – 2;
int barR = barF – (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS);
if (barR < 0) barR = 0;
for (int i = barF; i >= barR; i–) {
bool drawV = false;
switch (_Period) {
case PERIOD_M1 :
drawV = Time[i] % PeriodSeconds(PERIOD_M15) == 0;
break;
case PERIOD_M5 :
drawV = Time[i] % PeriodSeconds(PERIOD_H1) == 0;
break;
case PERIOD_M15 :
case PERIOD_M30 :
drawV = Time[i] % PeriodSeconds(PERIOD_H4) == 0;
break;
case PERIOD_H1 :
drawV = Time[i] % PeriodSeconds(PERIOD_D1) == 0;
break;
case PERIOD_H4 :
drawV = Time[i] % PeriodSeconds(PERIOD_D1) == 0 && TimeDayOfWeek(Time[i]) == MONDAY;
break;
case PERIOD_D1 :
drawV = TimeMonth(Time[i]) != TimeMonth(Time[i + 1]);
break;
case PERIOD_W1 :
drawV = TimeMonth(Time[i]) != TimeMonth(Time[i + 1]) && TimeMonth(Time[i]) % 3 == 1;
break;
case PERIOD_MN1 :
drawV = TimeYear(Time[i]) != TimeYear(Time[i + 1]);
break;
}
if (drawV) {
LineCreate(0, PREFIX + “VL” + IntegerToString(i), OBJ_VLINE, 0, Time[i]);
}
}
double pitch = 0;
switch (_Period) {
case PERIOD_M1 :
case PERIOD_M5 :
case PERIOD_M15 :
pitch = 500 * _Point;
break;
case PERIOD_M30 :
case PERIOD_H1 :
case PERIOD_H4 :
pitch = 1000 * _Point;
break;
case PERIOD_D1 :
pitch = 2000 * _Point;
break;
case PERIOD_W1 :
case PERIOD_MN1 :
pitch = 10000 * _Point;
break;
}
double max = ChartGetDouble(0, CHART_PRICE_MAX);
double min = ChartGetDouble(0, CHART_PRICE_MIN);
min -= MathMod(min, pitch);
min = NormalizeDouble(min, _Digits);
int n = int((max – min) / pitch) + 1;
for (int i = 0; i < n; i++) {
LineCreate(0, PREFIX + “HL” + IntegerToString(i), OBJ_HLINE, 0, 0, min + i * pitch);
}
}
}
//+——————————————————————+
//| Create the vertical line |
//+——————————————————————+
bool LineCreate(const long chart_ID = 0, // chart’s ID
const string name = “VLine”, // line name
const int type = OBJ_VLINE, // type
const int sub_window = 0, // subwindow index
datetime time = 0, // line time
double price = 0, // line price
const color clr = clrGray, // line color
const ENUM_LINE_STYLE style = STYLE_DOT, // line style
const int width = 1, // line width
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 vertical line
if(!ObjectCreate(chart_ID, name, type, sub_window, time, price)) {
return(false);
}
//— set line color
ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//— set line display style
ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//— set line width
ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
//— 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 line by mouse
//— when creating a graphical object using ObjectCreate function, the object cannot be
//— highlighted and moved by default. Inside this method, selection parameter
//— is true by default making it possible to highlight and move the object
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);
}
//+——————————————————————+
- 如何使用switch处理绘制垂直线?
哪些贵金属平台好?不错的贵金属交易汇平台推荐:哪些贵金属平台好?2023年平台最新排名
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
本文相关:无相关信息
留言与评论(共有 0 条评论) |