Evenimente de tick in MQL5 : complicate deocamdata, dar functionale

[English version] [MQLmagazine.com in english] [Editia romaneasca]

Cu ceva vreme in urma am intrebat MetaQuotes in legatura cu OnBookEvent(). Motivul pentru mine era acela ca OnTick() functioneaza numai pentru chartul curent pe care e atasat expertul. Pentru a avea evenimente lansate cand cotatii vin pe alte simboluri, singura alternativa este OnBookEvent(), daca aceste simboluri au disponibila adancimea pietei. Descrierea spune ca OnBookEvent() va fi lansat de fiecare data cand exista o schimbare in adancimea pietei, de unde rezulta ca va fi lansat de foarte multe ori, inclusiv la un nou tick, adica atunci cand se schimba Bid sau Ask.

OnBookEvent() nu este gata inca. Asa ca MetaQuotes a lansat un cod destul de complicat, pe tema obtinerii evenimentelor de tick folosind OnChartEvent().

Este un cod destul de urat scris, dar merge. Vrajitorii C++ l-ar putea intelege mai bine.
E facut din doi experti, si includ aici codul lor, si apoi o sa comentam modul lor de scriere.

Unul dintre experti (TickEventTarget2) joaca rolul unui “hub”, pentru ca are doar o singura instanta, si el este receptorul ticksilor.
Celalalt (TickEvent2) joaca rolul unui “server de cotatii”, si are o singura instanta per fiecare pereche pentru care serveste cotatiile.

TickEventTarget2 trebuie sa fie pornit primul, pentru ca este hubul. Daca TickEvent2 este pornit inainte de hub, se va opri singur, tot asa cum se va opri singur cand hubul este inchis de 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);
     }
  }
//+------------------------------------------------------------------+

Liniile de la 10 la 12 definesc elementele de identificare ale evenimentelor, care sunt folosite pentru a identifica tipul unui eveniment utilizator care vine prin OnCharEvent(). Acum ce se intampla e foarte interesant : liniile de la 13 la 20 introduc doua structuri, care sunt folosite mai tarziu, intr-un typecast. Asa cum vezi, fiecare dintre ele are doar un camp, unul long, altul double, care au aceeasi lungime, 8 bytes, facand astfel typecast-ul posibil.

Urmeaza OnInit(). Linia 30 stocheaza ID-ul chartului pe care ruleaza hubul. Linia 31 este typecast-ul. Continutul lui ls este copiat byte cu byte in ds, valoare care este folosita apoi pentru a umple o variabila globala. Motivul typecast-ului este acela ca pastreaza integritatea ID-ului. Daca ar fi fost folosita o conversie numerica, o parte din long n-ar fi fost copiata corect in double (ai vazut un mic avertisment de la compilator). Functia GlobalVariableTemp() nu este in fisierul help. Probabil If-ul la linia 32 intreaba daca variabila globala (cea care are acelasi nume ca idul de tick, “TickEventTarget”) exista ca temporara (genul de variabila globala care este stearsa dupa ce statia este stinsa). Numai in acest caz, in care exista, variabila este initializata cu ID-ul.

Liniile de la 40 la 55 contin OnDeinit(). Mai intai este stocat numele expertului, apoi id-ul primului chart, apoi, intr-un loop, primelor 100 de charturi le este trimis mesajul custom STOP_TICKS_EVENT prin OnChartEvent() (linia 48) apoi nou id de chart este enumerat (linia 49) in interiorul loop-ului. Apoi variabila globala este stearsa.

Functia OnTick() e goala de continut, pentru ca hubul nu are un rol de “server” pentru el insusi, trebuie doar sa culeaga evenimente de le servere.

Si in final liniile de la 67 la 77, OnChartEvent(), care va scrie de unde sosesc evenimentele tick. vezi cum TICK_EVENT este testat, iar modul de constuctie a evenimentului e similar cu WM_USER si RegisterMessage() din Windows API.

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();
     }
  }
//+------------------------------------------------------------------+

Serverul incepe cu un cod similar hubului, cu aceleasi constante eveniment si cele doua structuri.
Urmeaza OnInit(), liniile 26 la 41. Mai intai verifica daca exista variabila globala desemnand hubul, altfel se opreste imediat. Apoi typecastul, prin care idul de chart este extras din variabila globala “TickEventTarget”, si este stocat in ExtTargetChartID.

Urmeaza OnTick(), liniile de la 45 la 52. If it has a valid ExtTargetChartID, extrage bid-ul cu SymbolInfoDouble(), linia 49, iar apoi trimite evenimentul de tick ca si eveniment custom de chart desemnat de ExtTargetChartID, unde ruleaza hubul (linia 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

Acest exemplu va fi scheletul pe care se va implementa cotarea mai tarziu. Functiile de pozitie devin utile atata timp cat OnTrade() nu este implementat cum trebuie. Dupa primirea unui tick, pozitia acelei perechi poate fi simplu interogata. Odata ce pozitia nu e neutra , “cotatia” noastra (ordinul pending) a fost executat.
Ne vom intoarce cu un exemplu de cotare cand vom avea disponibile futures pe valute. Pentru a revedea cotarea, vezi articolul nostru Cotarea – o noua activitate in MT5.

Editii