MQL4语言提供了对一些预定义事件的处理。处理这些事件的函数必须在MQL4程序中定义;函数名、返回类型、参数的组成(如果有的话)以及它们的类型必须严格符合事件处理函数的描述。
客户端终端的事件处理程序通过返回值类型和参数类型来识别处理特定事件的函数。如果为相应函数指定了与下面描述不符的其他参数或指定了其他返回类型,这样的函数将不会被用作事件处理程序。
OnStart
OnStart()函数是启动事件处理程序,仅用于运行脚本时自动生成。它必须是void类型,并且不带参数:
void OnStart();
对于OnStart()函数,也可以指定int类型的返回类型。
OnInit
OnInit()函数是初始化事件处理程序。它必须是void类型或int类型,并且不带参数:
void OnInit();
在下载专家顾问或指标后立即生成Init事件;OnInit()函数用于初始化。如果OnInit()的返回值类型为int,则非零的返回代码表示初始化失败,并生成具有初始化原因REASON_INITFAILED的Deinit事件。
只有在使用#property strict编译程序时,终端的运行时子系统才会分析OnInit()函数的执行结果。
为了优化专家顾问的输入参数,建议使用ENUM_INIT_RETCODE枚举的值作为返回代码。在开始测试之前初始化专家顾问时,可以使用TerminalInfoInteger()函数请求有关配置和资源的信息。
void类型的OnInit()函数始终表示成功初始化。
OnDeinit
OnDeinit()函数在反初始化期间调用,是Deinit事件处理程序。它必须声明为void类型,并且应具有一个const int类型的参数,其中包含反初始化原因的代码。如果声明了不同的类型,编译器将生成警告,但不会调用该函数。
void OnDeinit(const int reason);
对于专家顾问和指标,会生成Deinit事件的情况如下:
•在由于附加到mql4程序的符号或图表周期的更改而重新初始化之前;
•在由于输入参数的更改而重新初始化之前;
•在卸载mql4程序之前。
OnTick
只有在收到专家顾问所附图表的符号的新
Tick时,才会为专家顾问生成NewTick事件。在自定义指标或脚本中定义OnTick()函数是无效的,因为它们不会生成NewTick事件。
Tick事件仅对专家顾问生成,但这并不意味着专家顾问需要OnTick()函数,因为专家顾问不仅会生成NewTick事件,还会生成Timer、BookEvent和ChartEvent事件。它必须声明为void类型,并且不带参数:
void OnTick();
OnTimer
OnTimer()函数在Timer事件发生时调用,该事件仅对专家顾问和指标生成-它不能在脚本中使用。事件发生的频率在订阅关于该事件的通知时通过EventSetTimer()函数设置。
您可以使用EventKillTimer()函数取消订阅特定专家顾问的定时器事件。该函数必须定义为void类型,并且不带参数:
void OnTimer();
建议在OnInit()函数中调用EventSetTimer()函数一次,在OnDeinit()中调用EventKillTimer()函数一次。
每个专家顾问以及每个指标都使用自己的定时器,并且只从它接收事件。一旦mql4程序停止运行,如果创建了定时器但未被EventKillTimer()函数禁用,该定时器将被强制销毁。
OnTester
OnTester()函数是测试器事件的处理程序,它在已选择的区间上对专家顾问进行历史测试后自动生成。该函数必须具有double类型,并且不带参数:
double OnTester();
该函数在调用OnDeinit()之前调用,并且具有相同类型的返回值-double。OnTester()仅可用于专家顾问的测试。其主要目的是计算作为遗传优化输入参数中的Custom max标准的某个值。
在遗传优化中,对于同一代中的结果应用降序排序。即从优化标准的角度来看,最佳结果是具有最大值的结果(对OnTester函数返回的Custom max优化标准值予以考虑)。在这样的排序中,最差的值位于末尾,并且被丢弃,不参与形成下一代。
OnChartEvent
OnChartEvent()是ChartEvent事件组的处理程序:
•CHARTEVENT_KEYDOWN-当图表窗口处于焦点时的按键事件;
•CHARTEVENT_MOUSE_MOVE-鼠标移动事件和鼠标点击事件(如果为图表设置了CHART_EVENT_MOUSE_MOVE=true);
•CHARTEVENT_OBJECT_CREATE-图形对象创建事件(如果为图表设置了CHART_EVENT_OBJECT_CREATE=true);
•CHARTEVENT_OBJECT_CHANGE-通过属性对话框更改对象属性的事件;
•CHARTEVENT_OBJECT_DELETE-图形对象删除事件(如果为图表设置了CHART_EVENT_OBJECT_DELETE=true);
•CHARTEVENT_CLICK-图表上的鼠标单击事件;
•CHARTEVENT_OBJECT_CLICK-图表中属于图形对象的鼠标单击事件;
•CHARTEVENT_OBJECT_DRAG-使用鼠标移动的图形对象移动事件;
•CHARTEVENT_OBJECT_ENDEDIT-在LabelEdit图形对象的输入框中完成文本编辑的事件;
•CHARTEVENT_CHART_CHANGE-图表更改事件;
•CHARTEVENT_CUSTOM+n-用户事件的ID,其中n的范围为0到65535。
•CHARTEVENT_CUSTOM_LAST-自定义事件的最后一个可接受的ID(CHARTEVENT_CUSTOM +65535)。
该函数只能在专家顾问和指标中调用。该函数应该是void类型,并且具有4个参数:
void OnChartEvent(const int id, // 事件ID
const long& lparam, // long类型事件的参数
const double& dparam, // double类型事件的参数
const string& sparam // string类型事件的参数
);
对于每种类型的事件,OnChartEvent()函数的输入参数具有特定的值,这些值对于处理此事件是必需的。
OnCalculate
OnCalculate()函数仅在需要通过Calculate事件计算指标值时,才会在自定义指标中调用。通常情况下,当为计算指标的符号接收到新的Tick时会发生这种情
况。此指标不需要附加到该符号的任何价格图表上。
OnCalculate()函数必须具有int类型的返回类型。
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[], // Tick成交量
const long& volume[], // 实际成交量
const int& spread[] // 价差
);
open[]、high[]、low[]和close[]参数包含当前时间框架的开盘价、最高价、最低价和收盘价的数组。time[]参数包含带有开盘时间值的数组,spread[]参数包含包含价差历史记录的数组(如果为交易的证券提供了任何价差)。volume[]和tick_volume[]参数包含交易和Tick成交量的历史记录,分别。
要确定time[]、open[]、high[]、low[]、close[]、tick_volume[]、volume[]和spread[]的索引方向,请调用ArrayGetAsSeries()。为了不依赖默认值,应对期望使用的那些数组无条件调用ArraySetAsSeries()函数。
第一个rates_total参数包含指标用于计算的柱子数量,并且对应于图表中可用的柱子数量。
我们应该注意OnCalculate()的返回值与第二个输入参数prev_calculated之间的连接。在函数调用期间,prev_calculated参数包含上一次调用OnCalculate()返回的值。这允许在计算自定义指标时使用经济算法,以避免对自上次运行此函数以来未发生更改的那些柱子进行重复计算。
为此,通常只需返回rates_total参数的值,该值包含当前函数调用中的柱子数量。如果自上次调用OnCalculate()以来价格数据发生了变化(下载了更深的历史记录或填充了历史空白),输入参数prev_calculated的值将被终端设置为零。
为了更好地理解,下面附上一个指标示例:
指标示例:
property indicator_chart_window
property indicator_buffers 1
//---- 绘制线
property indicator_label1 "Line"
property indicator_type1 DRAW_LINE
property indicator_color1 clrDarkBlue
property indicator_style1 STYLE_SOLID
property indicator_width1 1
//--- 指标缓冲区
double LineBuffer[];
int OnInit()
{
//--- 映射指标缓冲区
SetIndexBuffer(0,LineBuffer,INDICATOR_DATA);
//---
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 bars=Bars(Symbol(),0);
Print("Bars = ",bars,", rates_total = ",rates_total,", prev_calculated = ",prev_calculated);
Print("time[0] = ",time[0]," time[rates_total-1] = ",time[rates_total-1]);
//--- 为下一次调用返回prev_calculated的值
return(rates_total);
}