Event Handling Functions
事件处理函数
MQL4语言提供了对某些预定义事件的处理功能。处理这些事件的函数必须在MQL4程序中定义;函数名称、返回类型、参数组成(如果有的话)及其类型必须严格符合事件处理函数的描述。
客户端终端的事件处理器通过返回值和参数类型的不同来识别处理特定事件的函数。如果为相应的函数指定了与以下描述不符的其他参数,或者指定了其他返回类型,那么该函数将不会用作事件处理器。
OnStart
OnStart()函数是开始事件处理器,它仅自动生成用于运行脚本。它必须是void类型,没有参数:
void OnStart();对于OnStart()函数,可以指定int返回类型。
OnInit
OnInit()函数是初始化事件处理器。它必须是void或int类型,没有参数:
void OnInit();初始化事件在专家顾问或指标下载后立即生成;OnInit()函数用于初始化。如果OnInit()的返回类型为int,非零返回码表示初始化失败,并将生成Deinit事件,说明初始化原因为REASON_INITFAILED。
只有当程序使用 #property strict编译时,终端的运行时子系统才会分析OnInit()函数的执行结果。
为了优化专家顾问的输入参数,建议使用ENUM_INIT_RETCODE枚举值作为返回码。在测试开始前,可以使用TerminalInfoInteger()函数请求关于配置和资源的信息。
ENUM_INIT_RETCODE
| 标识符 | 描述 |
|---|---|
| INIT_SUCCEEDED | 初始化成功,可以继续测试专家顾问。 此代码与空值相同——专家顾问已在测试器中成功初始化。 |
| INIT_FAILED | 初始化失败;由于致命错误,无法继续测试。例如,未能创建专家顾问所需的指标。 此返回值与其他非零值相同——专家顾问在测试器中的初始化失败。 |
| INIT_PARAMETERS_INCORRECT | 表示输入参数设置不正确。包含此返回码的结果字符串会在一般优化表中以红色高亮显示。 不会执行给定参数集的专家顾问测试。 |
OnInit()函数始终为void类型,表示初始化成功。
OnDeinit
OnDeinit()函数在初始化结束时调用,是终止事件处理器。它必须声明为void类型,并且应该有一个const int类型的参数,其中包含终止原因代码。如果声明了不同的类型,编译器将生成警告,但函数将不会被调用。
void OnDeinit(const int reason);对于专家顾问和指标,在以下情况下会生成Deinit事件:
- 由于符号或图表周期的变化而重新初始化之前;
- 由于输入参数的变化而重新初始化之前;
- 卸载mql4程序之前。
OnTick
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()函数是Tester事件的处理器,当在选定的间隔内对专家顾问进行历史测试后自动生成。该函数必须声明为double类型,没有参数:
double OnTester();该函数在调用OnDeinit()之前调用,返回值的类型也是double。OnTester()仅用于专家顾问的测试。其主要目的是计算一个值,该值用作输入参数的遗传优化中的自定义最大标准。
在遗传优化中, descends排序应用于同一代内的结果。即从优化标准的角度来看,最佳结果是那些具有最大值的结果(对于自定义最大优化标准,OnTester函数返回的值被考虑在内)。在这种排序中,最差值位于末尾并被丢弃,不参与下一代的形成。
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, // Event ID
const long& lparam, // Parameter of type long event
const double& dparam, // Parameter of type double event
const string& sparam // Parameter of type string events
);对于每种类型的事件,OnChartEvent()函数的输入参数都有固定的值,这些值是处理该事件所必需的。通过这些参数传递的事件和值如下表所示。
| 事件 | id参数的值 | lparam参数的值 | dparam参数的值 | sparam参数的值 |
|---|---|---|---|---|
| 按键事件 | CHARTEVENT_KEYDOWN | 按下的键的代码 | 重复次数(用户按住键时按键的重复次数) | 描述键盘按钮状态的位掩码的字符串值 |
| 鼠标事件(如果为图表设置了CHART_EVENT_MOUSE_MOVE=true) | CHARTEVENT_MOUSE_MOVE | X坐标 | Y坐标 | 描述鼠标按钮状态的位掩码的字符串值 |
| 图形对象创建事件(如果为图表设置了CHART_EVENT_OBJECT_CREATE=true) | CHARTEVENT_OBJECT_CREATE | — | — | 创建的图形对象的名称 |
| 通过属性对话框更改对象属性的事件 | CHARTEVENT_OBJECT_CHANGE | — | — | 修改过的图形对象的名称 |
| 图形对象删除事件(如果为图表设置了CHART_EVENT_OBJECT_DELETE=true) | CHARTEVENT_OBJECT_DELETE | — | — | 被删除的图形对象的名称 |
| 鼠标在图表上的点击事件 | CHARTEVENT_CLICK | X坐标 | Y坐标 | — |
| 鼠标在属于图表的图形对象上的点击事件 | CHARTEVENT_OBJECT_CLICK | X坐标 | Y坐标 | 发生事件的图形对象的名称 |
| 使用鼠标拖动图形对象的事件 | CHARTEVENT_OBJECT_DRAG | — | — | 被移动的图形对象的名称 |
| 在LabelEdit图形对象的输入框中完成文本编辑的事件 | CHARTEVENT_OBJECT_ENDEDIT | — | — | 完成文本编辑的LabelEdit图形对象的名称 |
| 图表更改事件 | CHARTEVENT_CHART_CHANGE | — | — | — |
| N号下的用户事件ID | CHARTEVENT_CUSTOM+N | EventChartCustom()函数设置的值 | EventChartCustom()函数设置的值 | EventChartCustom()函数设置的值 |
OnCalculate
OnCalculate()函数仅在自定义指标中调用,当需要通过Calculate事件计算指标值时使用。这通常发生在为符号接收了新交易日时,此时需要计算指标值。该指标不需要附加到该符号的任何价格图表上。
OnCalculate()函数的返回类型必须是int。
int OnCalculate (const int rates_total, // size of input time series
const int prev_calculated, // bars handled in previous call
const datetime& time[], // Time
const double& open[], // Open
const double& high[], // High
const double& low[], // Low
const double& close[], // Close
const long& tick_volume[], // Tick Volume
const long& volume[], // Real Volume
const int& spread[] // Spread
);open[]、high[]、low[]和close[]的参数包含当前时间帧的开放价、高价、低价和收盘价数组。time[]参数包含开放时间值的数组,spread[]参数包含历史价差数组(如果交易证券有价差)。volume[]和tick_volume[]的参数分别包含交易量和每笔交易量历史数据。
为了确定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
//---- plot Line
#property indicator_label1 "Line"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDarkBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- indicator buffers
double LineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0,LineBuffer,INDICATOR_DATA);
//---
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[])
{
//--- Get the number of bars available for the current symbol and chart period
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]);
//--- return value of prev_calculated for next call
return(rates_total);
}