事件处理函数

MQL5语言提供预定义事件处理。处理这些事件的函数由MQL5程序确定;函数名,返回类型,参数组成(有几个参数情况下)以及类型必须严格遵照事件处理程序函数。

客户端的事件处理程序通过返回值类型和参数类型确定函数,来处理这个或者那个事件。如果其他参数,与下面描述不一致,但已被指定了相关的函数或者另一个返回类型,那么这个函数不能用于事件处理程序。

OnStart #

OnStart() 函数就是 启动 事件处理程序,运行脚本时自动生成。一定是类型,无参数:

void OnStart();

对于OnStart()函数,指定整型 返回类型。

OnInit #

OnInit() 函数是 初始化 事件处理程序。 必须是空型或者整型,无参数:

void OnInit();

初始化事件处理程序在EA交易或者指标下载后即时生成;它不生成脚本。OnInit()函数用于初始化。如果OnInit()返回值为整型,非零结果意味着初始化失败,生成初始化失败原因代码REASON_INITFAILED

当返回INIT_FAILED时,EA会从图表中强制卸载。

返回INIT_FAILED时,指标不会从图表中卸载。图表上保留的指标无法运行 ― 事件处理程序不会在指标中调用。

要优化EA交易的输入参数,推荐使用ENUM_INIT_RETCODE枚举值作为返回代码。这些值用于组织优化的过程,包括选择最合适的测试代理。在EA交易的初始化期间测试开始之前您可以使用TerminalInfoInteger() 函数请求一个代理的配置和资源信息(内核数量,空余内存额,等等)。根据所获得的信息,您可以在EA交易优化过程中选择允许使用这个测试代理,或拒绝使用它。

ENUM_INIT_RETCODE

标识符

描述

INIT_SUCCEEDED

成功初始化,可以继续测试EA交易。

这段代码意味着与null值一样――在测试中EA交易已成功初始化。

INIT_FAILED

初始化失败;由于非常严重的错误而无法继续测试。例如,未能创建EA交易工作所需的指标。该返回值意味着等同非零值- 测试中初始化EA交易失败。测试给定的EA交易参数组将不会执行,代理可以任意接受新任务。

INIT_PARAMETERS_INCORRECT

这个值意味着错误的输入参数组。包含这个返回代码的结果字符串在普通优化表中以红色突出显示。

接到这个值后,该策略测试不会将这个任务确实地传递给其他代理进行重试。

INIT_AGENT_NOT_SUITABLE

在初始化期间没有错误,但出于某种原因,代理不适合测试。例如,没有足够的内存,没有OpenCL 支持,等等。返回这段代码后,代理将不会收到任务,直到这种优化结束。

空型OnInit() 函数代表初始化成功。

OnDeinit #

OnDeinit() 函数称为失败初始化,是初始化失败事件处理程序。必须是型且有一个包括初始化失败原因代码常量整型参数。如果声明不同类型,编译程序会发出警告,但函数不可调用。对于脚本来说不会生成初始化失败事件,因此OnDeinit()函数不用于脚本。

void OnDeinit(const int reason);

在以下情况下EA交易和指标生成初始化失败:Deinit事件在以下情况下为EA交易和指标而生成:

  • 再次初始化前,mql5程序下的交易品种和图表周期发生变化;
  • mql5程序卸载前。

OnTick #

仅仅EA交易依附的图表中,交易品种收到新订单号时EA交易会生成 新订单号 事件。自定义指标或者脚本中确定OnTick()函数是无效的,因为订单号事件不为它们而生。

订单号事件只为EA交易而生,但是却不意味着EA交易需要OnTick()函数,因为EA交易不仅需要生成订单号,也需要生成计时器,预定事件和图表事件。这些都需要空型,无参数:

void OnTick();

OnTimer #

计时器事件发生时调用OnTimer()函数,由系统计时器生成,仅用于EA交易-不能用于脚本或者指标。函数EventSetTimer()接收事件,当同意该事件声明时,设置事件发生频率 。

可以用函数EventKillTimer()为特殊EA交易注销计时器事件。函数必须为空值,没有参数:

void OnTimer();

建议在OnInit() 函数中调用EventSetTimer() 函数,而EventKillTimer() 函数可以在OnDeinit()中调用。

每个EA交易,每个指标都有其独自的计时器且仅通过它来接收事件。如果创建了计时器但没有用EventKillTimer() 函数禁止,那么一旦mal5程序停止,计时器被强制破坏。

OnTrade #

交易发生时调用这个函数,改变下订单持仓列表,订单历史记录交易历史记录时会出现。当交易活动执行挂单,持仓/平仓,停止设置,启动挂单等等,订单和交易历史记录或者仓位和当前订单列表也会相应改变。

void OnTrade();

接到这个事件时(需要交易策略状态)用户必须独自确认交易账户状态。如果函数OrderSend()成功调用,且返回了真实值,意味着交易服务器已经提交订单并确定了订单号。服务器一旦处理这个订单,交易事件就生成了。如果用户记住了订单号值,OnTrade() 函数执行时,用这个值可以看到订单情况。

OnTradeTransaction #

交易账户执行一些明确的行动时,其状态发生变化。这样的行为包括:

  • 在客户端使用OrderSendOrderSendAsync函数发送来自任何MQL5应用程序的交易请求及其进一步执行;
  • 通过程序端图形界面发送交易请求和它的进一步执行;
  • 挂单和停止订单在服务器上激活;
  • 在交易服务器端执行操作。

这些操作的结果是会执行以下交易事务:

  • 处理交易请求;
  • 改变持仓订单;
  • 改变订单历史;
  • 改变交易历史;
  • 改变持仓。

例如,当发送一个被处理的市场购买订单时,会为账户创建一个适当的购买订单,然后执行订单并从持仓列表中删除订单,然后将其添加到订单历史,适当的交易也会被添加到历史并创建一个新的持仓。所有这些行动都是交易事务。在程序端到这种事务就是一个TradeTransaction事件。它会调用OnTradeTransaction处理程序

void  OnTradeTransaction(
   const MqlTradeTransaction   trans,        // 交易结构
   const MqlTradeRequest&        request,      // 请求结构
   const MqlTradeResult&         result        // 结果结构
   );

处理程序包含三个参数:

  • trans - 该参数获得描述应用于交易账户的交易事务的 MqlTradeTransaction结构;
  • request - 该参数获得描述交易请求的MqlTradeRequest结构;
  • result - 该参数获得描述交易请求执行结果的MqlTradeResult结构。

最后两个requestresult参数填充值仅用于TRADE_TRANSACTION_REQUEST类型事务,事务数据可以从 trans变量的 type 参数接收。注意在这种情况下,trans变量描述的交易事务被执行后,在result变量的request_id字段包含request交易请求的ID。请求ID允许联系执行的操作(OrderSend或OrderSendAsync函数调用)发送到OnTradeTransaction()该操作的结果。

从程序端或通过OrderSend()/OrderSendAsync()函数手动发送的交易请求可以在交易服务器生成几个连续的事务。但不保证这些交易在程序端的优先到达。因此,开发您的交易算法时,您不必指望交易会一组接一组地到达。此外,交易可能在从服务器传递到终端过程中会丢失。

  • 所有类型的交易事务都在ENUM_TRADE_TRANSACTION_TYPE枚举中描述。
  • 交易事务中描述的MqlTradeTransaction结构根据事务类型以不同的方式填充。例如,只有类型字段(交易事务类型)必须为TRADE_TRANSACTION_REQUEST类型事务进行分析。OnTradeTransaction函数(请求和结果)的第二个和第三个参数必须为额外的数据进行分析。有关更多信息,请参见"交易事务结构"
  • 交易事务描述不提供关于订单,交易和持仓(如,评论)的所有可用的信息。OrderGet*HistoryOrderGet*HistoryDealGet*PositionGet* 函数应该用于获得扩展信息。

申请客户账户交易事务后,它们始终置于程序端交易事务队列,从这里它们一直送到OnTradeTransaction入口点以便到达程序端。

当使用OnTradeTransaction处理程序通过EA交易处理交易事务时,程序端会继续处理新来的交易事务。因此,交易账户的状态可以在OnTradeTransaction操作过程中已经改变。例如,当MQL5程序处理添加新订单的事件时,它可能被执行,从持仓列表删除并移动到历史记录。此外,应用程序将通知这些事件。

事务队列长度由1024个元素组成。如果OnTradeTransaction处理新事务太久,队列中的旧事务可能会被新的取代。

  • 一般来说,没有准确的OnTrade和OnTradeTransaction调用数量的比例。一个OnTrade调用对应于一个或几个OnTradeTransaction调用。
  • 适当地OnTradeTransaction调用后调用OnTrade。

OnTester #

函数OnTester()是外部EA交易历史测试结束后自动生成的测试事件处理程序。用双型确定函数,无参数:

double OnTester();

这个函数在OnDeinit() 之前调用,且有同样的双型返回值。只在EA交易测试时使用OnTester() 。其主要作用是计算某个值,该值用作遗传最优化自定义标准。

遗传优化中,生成结果用降序,例如从优化标准查看点,最佳结果是那些最大值(OnTester函数带进账户的最大自定义优化标准值)。这种情况下,最差值放在最后,或者排除,不参与下一步生成。

OnTesterInit #

OnTesterInit()函数是TesterInit事件的处理程序,它在策略测试的EA交易优化启动前自动生成。函数必须定义为void类型。它没有参数:

void OnTesterInit();

随着优化的开始,OnTesterDeinit()或OnTesterPass()处理程序的EA交易自动加载在一个测试中指定交易品种和周期的单独的程序端图表中,并接收TesterInit事件。优化启动前函数用于EA交易的初始化,用于进一步处理优化结果

OnTesterPass #

OnTesterPass()函数是TesterPass事件的处理程序,这是在策略测试EA交易优化过程中收到帧时自动生成的。函数必须定义为void类型。它没有参数:

void OnTesterPass();

OnTesterPass()处理程序的EA交易自动加载在一个单独的指定交易品种/周期的程序端图表进行测试,并当在优化中接收到帧时获得TesterPass事件。函数用于“当场”动态处理优化结果无需等待其完成。使用FrameAdd()函数添加帧,该函数可以在OnTester()处理程序单次结束后被调用。

OnTesterDeinit #

OnTesterDeinit()是TesterDeinit事件的处理程序,它是策略测试EA交易优化结束后自动生成的。函数必须定义为void类型。它没有参数:

void OnTesterDeinit();

TesterDeinit()处理程序的EA交易在优化初期自动加载在图表上,并在其完成后接收TesterDeinit。该函数用于最终处理全部的优化结果

OnBookEvent #

OnBookEvent()函数是BookEvent处理程序。 BookEvent只在市场深度改变时,转为EA交易而生成。它必须是空值,且有一个字符串类型参数:

void OnBookEvent (const stringsymbol);

若要接收任一交易品种的BookEvent,需要事先同意用函数MarketBookAdd()接收这个交易品种的BookEvent。如果不同接收某个特定交易品种的BookEvent,可以调用 MarketBookRelease()

与其他事件不同的是BookEvent是直播。意味着如果EA交易同意用MarketBookAdd接收BookEvent,其他有OnBookEvent()处理程序的EA交易也会收到这个事件。因此分析交易品种名称是必须的,可以const string& symbol参数传到处理程序。

OnChartEvent #

OnChartEvent() 是ChartEvent的处理程序:

  • CHARTEVENT_KEYDOWN ― 击键,图表窗口定格;
  • CHARTEVENT_MOUSE_MOVE ― 鼠标移动事件和鼠标点击事件 (if CHART_EVENT_MOUSE_MOVE=true is set for the chart);
  • CHARTEVENT_OBJECT_CHANGE ― 通过属性对话框改变物件属性;
  • CHARTEVENT_CLICK ― 鼠标单击图表;
  • CHARTEVENT_OBJECT_CLICK ― 鼠标单击属于图表的图解物件;
  • CHARTEVENT_OBJECT_DRAG ― 用鼠标移动图解物件;
  • CHARTEVENT_OBJECT_ENDEDIT ― 图解物件标签编辑输入框中完成文本编辑;
  • CHARTEVENT_CHART_CHANGE  ― 图表事件变化;
  • CHARTEVENT_CUSTOM+n ― 用户ID,0-65535之间范围。
  • CHARTEVENT_CUSTOM_LAST ―自定义(CHARTEVENT_CUSTOM +65535)接受的最后一个ID。

只在EA交易和指标中调用这个函数。函数是带有4个参数的空值:

void OnChartEvent(const int id,         // 事件 ID
                  const long& lparam,   // 长整型事件参量
                  const double& dparam, // 双精度事件参量
                  const string& sparam  // 字符串事件参量
  );

对于每一类型事件,函数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

移动的图解物件名称

图解物件标签编辑输入框中完成文本编辑

CHARTEVENT_OBJECT_ENDEDIT

文本编辑完成的图解物件名称

 

图表更改事件

CHARTEVENT_CHART_CHANGE

N下的用户ID

CHARTEVENT_CUSTOM+N

通过函数EventChartCustom() 设置值

通过函数EventChartCustom()设置值

 

通过函数EventChartCustom() 设置值

 

 

OnCalculate #

OnCalculate()函数只在自定义指标中调用,通过Calculate计算指标值是必须的。通常在接到指标计算的交易品种新订单号时发生。这个指标不需要附在交易品种的价格图表上。

OnCalculate() 函数有个返回值int。有两个可能定义。一个指标中不可以有两个函数版本。

一种是用于单数据缓冲中计算的指标。例如,自定义移动平均数指标。

int OnCalculate (const int rates_total,      // 价格[] 数组的大小
                 const int prev_calculated,  // 前一次调用处理的柱
                 const int begin,            // 有效数据起始位置
                 const double& price[]       // 计算的数组
   );

价格[]数组中,可以传送时间序列和计算的一些指标缓冲。ArrayGetAsSeries()函数确定价格[] 数组索引方向。为了不依赖默认值,需要无条件的调用ArraySetAsSeries()函数用于工作的数组。

价格[]数组中,在“参数”标签启动指标时,选择适当的时间序列或者指标。所以,需要在“应用于”字段的下拉列表中指定必要的项目。

选择时间序列计算一个指标

从其他mql5程序中接收自定义指标值,要使用iCustom()函数,返回嵌入指标处理程序。可以指定适当的价格[]数组或者另一个指标处理程序。这个参数在自定义指标输入变量列表中最后传送。
示例:

void OnStart()
  {
//---
   string terminal_path=TerminalInfoString(STATUS_TERMINAL_PATH);
   int handle_customMA=iCustom(Symbol(),PERIOD_CURRENT"Custom Moving Average",13,0, MODE_EMA,PRICE_TYPICAL);
   if(handle_customMA>0)
      Print("handle_customMA = ",handle_customMA);
   else
      Print("Cannot open or not EX5 file '"+terminal_path+"\\MQL5\\Indicators\\"+"Custom Moving Average.ex5'");
  }

这个示例中,通过的最后参数是PRICE_TYPICAL值(从ENUM_APPLIED_PRICE计数开始),指出自定义指标可以用获得的典型价格建立(高价+低价+平仓)/3。如果没有确定这个参数,指标基于PRICE_CLOSE 值建立,例如每栏平仓价。

另一个示例显示依照指定价格[]数组的最后一个参数传送指标处理程序,由函数iCustom()所描述。
 

另一种形式意在所有其他指标,计算更多的时间序列。

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

开盘价[],最高价[],最低价[]和收盘价[]参数由当前时间表的开盘价,最高和最低价和收盘价数组组成。时间参数[]包括开盘时间值数组,扩展参数[]有一个数组包括扩展历史记录(如果为交易安全提供扩展)。volume[] 和tick_volume[] 参数分别包括交易和交易量历史记录。

确定时间[]索引方向, 开盘价[], 最高价[], 最低价[], 收盘价[], 交易量[], 交易量[] 和 扩展[],需要调用ArrayGetAsSeries()函数。若不想依赖默认值,需要无条件的调用函数ArraySetAsSeries()用于工作的数组。

首先rates_total 参数包括栏的数量,可用来计算指标,与图表中现存的栏数一致。

需要注意OnCalculate() 返回值和第二输入参数prev_calculated的连接。调用函数时,prev_calculated 参数包括上次调用时OnCalculate() 返回值。这就允许用经济算法计算自定义指标,避免重复计算。

返回rates_total参数值足够了,包括当前调用函数的栏数。如果自从上次调用函数OnCalculate(),价格数据更改了(下载深度历史记录或者填满历史空白期),输入参数prev_calculated 值由终端机设置为零。

注:如果OnCalculate返回零,那么指标值不能显示在客户端的数据窗口。

为更好的理解,启动附加以下代码的指标很有用。

指标示例:

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   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);
  }
//+------------------------------------------------------------------+

另见

运行程序客户端事件工作事件