Tick events in MQL5: complicated for now, but functional

[Versiunea romaneasca] [MQLmagazine.com in romana] [English edition]

Some time ago I asked MetaQuotes about the OnBookEvent(). The reason for me was that the OnTick() event works only for the current chart that the EA is attached on. In order to have events triggered when quotes come on other symbols, the only alternative is OnBookEvent() , provided that these symbols have depth of market enabled. The description says that OnBookEvent will trigger when there is a change in the depth of market. That means there will be a lot of triggers of the event, for all changes, including when a tick comes, meaningly when Bid or Ask changes.

OnBookEvent() is not done yet. So MetaQuotes released a quite complicated example, on how to obtain tick events using OnChartEvent().

It’s a pretty ugly code, but it works. C++ wizards might understand coding better.
It is all made of two expert advisors, and I’ll publish the original code for them , then we’ll coment how they were written.

One of the EAs (TickEventTarget2) plays the role of a “hub”, because it has to have only one instance, as it is the receiver of tick events. The other (TickEvent2) plays the role of a “quote server”, and it has to have one instance per each pair that it serves quotes for.

TickEventTarget2 has to be started first, as it is the hub. If a TickEvent2 is started before the hub, it will shut down by itself, as well as it will shut down by itself when if the hub is shut down by the user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//+------------------------------------------------------------------+
//|                                              TickEventTarget.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.02"
 
#define TICK_EVENT       12345
#define STOP_TICKS_EVENT 12346
#define TICK_EVENT_ID    "TickEventTarget"
struct long_str
  {
   long lvalue;
  };
struct double_str
  {
   double dvalue;
  };
 
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   long_str   ls;
   double_str ds;
//---
   ls.lvalue=ChartID();
   ds=ls;
   if(GlobalVariableTemp(TICK_EVENT_ID))
      GlobalVariableSet(TICK_EVENT_ID,ds.dvalue);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   string expert_name=MQL5InfoString(MQL5_PROGRAM_NAME);
   long   currChart=ChartFirst();
   int    i=0;
//---
   while(i<100)
     {
      EventChartCustom(currChart,STOP_TICKS_EVENT,0,0.0,expert_name);
      currChart=ChartNext(currChart);
      if(currChart==0) break;
      i++;
     }
//---
   GlobalVariableDel(TICK_EVENT_ID);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
 
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id==CHARTEVENT_CUSTOM+TICK_EVENT)
     {
      printf("Received bid %.5f from %s",dparam,sparam);
     }
  }
//+------------------------------------------------------------------+

Lines 10 to 12 define event identification elements, that are to be used to identify what type of a custom event comes via OnChartEvent(). Now what follows is very interesting : lines 13 to 20 set up two structures, in order to be used later, in a typecast. As you see, each of them has only field, one a long, one a double, which have the same length, 8 bytes, thus making typecast possible.

Next follows OnInit(). Line 30 stores the chart ID that the hub is running on. Then line 31 is the typecast. The contents of ls is copied byte by byte to ds, value which is used later to fill a global variable. The reason for the typecast is that it preserves the integrity of the chart ID. If a numerical conversion would have been used, part of the long wouldn’t have been copied correctly to the double (you would also get a tiny compiler warning). The GlobalVariableTemp() function is not in the help file. Probably the If at line 32 inquires if the global variable (the one having the name of tick id, “TickEventTarget”) exists as temporary (the kind of global variable which is deleted after the station is turned off). Only in this case, that it exists, the variable is set up with the ID.

Lines 40 to 55 contain OnDeinit(). First it is stored the name of the expert, then the first chart id, and then, in a loop, first 100 charts are being sent the custom OnChartEvent() event STOP_TICKS_EVENT (line 48), then the new chart id is enumerated (line 49) inside the loop. Then the global variable is deleted.

The OnTick() function is void, as the hub does not have a “server” role for itself, it has only to pick tick events from the servers.

And finally lines 67 to 77 , the OnChartEvent() , that will write from who the events are coming. Note how the TICK_EVENT is tested , as the event construction mode is similar to Windows API’s RegisterMessage() and WM_USER.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//+------------------------------------------------------------------+
//|                                                    TickEvent.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.02"
 
#define TICK_EVENT       12345
#define STOP_TICKS_EVENT 12346
#define TICK_EVENT_ID    "TickEventTarget"
struct long_str
  {
   long lvalue;
  };
struct double_str
  {
   double dvalue;
  };
 
long    ExtTargetChartID=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   long_str   ls;
   double_str ds;   
//---
   if(GlobalVariableCheck(TICK_EVENT_ID)==0)
     {
      Print("Target chart is absent");
      return(-1);
     }
   ds.dvalue=GlobalVariableGet(TICK_EVENT_ID);
   ls=ds;
   ExtTargetChartID=ls.lvalue;
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(ExtTargetChartID!=0)
     {
      double bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
      EventChartCustom(ExtTargetChartID,TICK_EVENT,Period(),bid,Symbol());
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id==CHARTEVENT_CUSTOM+STOP_TICKS_EVENT)
     {
      printf("Expert %s has been stopped",sparam);
      ExtTargetChartID=0;
      ExpertRemove();
     }
  }
//+------------------------------------------------------------------+

The server begins quite the same like the hub, with the same event constants and the two structures.
Follows OnInit() , lines 26 to 41. First checks if the global variable designating the hub exists , otherwise it stops rightaway. Then the typecast, by which the chart id of the hub is extracted from the “TickEventTarget” global variable, and is stored in ExtTargetChartID.

Follows OnTick(), lines 45 to 52. If it has a valid ExtTargetChartID, extracts the bid with SymbolInfoDouble(), line 49, then sends the tick event as a custom event to the chart designated by ExtTargetChartID, where the hub runs (line 50).

Finally OnChartEvent(), lines 56 to 67, has the same looks as in the hub definition, but now it is scanning for the STOP_TICKS_EVENT, that is broadcasted by the hub when it shuts down. Upon receival, it closes the server EA, using ExpertRemove().

embedded by Embedded Video

YouTube Direkt

This example will be the skeleton to implement quoting later. The position functions are coming handy as long as OnTrade() is not properly implemented. Upon the receival of a tick, position of that pair can be simply interrogated. Once that it’s not flattened, it means that our “quote” (pending order) has been executed.
We will return with a quoting example when currency futures will be available. For a review of quoting, see our article Quoting : a new activity in MT5.