Distingirea executiilor cvasisimultane – clasa de raportare a ultimelor tranzactii

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

Se spune ca esti un magician daca poti face o femeie sa rida. Cred ca ar trebui sa incerci asta cu Irene Aldridge. Sa-i spui ca in MT5 timpul e bazat pe secunde. Si daca nu obtii decat un zambet, spune-i ca OnTrade() nu raporteaza care e ultimul ordin care a avut o executie! Crede-ma, o sa se tavaleasca pe jos de ris!

Problema e ca stampilele de timp in MT5 sunt bazate pe secunde. Acum latenta e masurata in microsecunde, adica a milioana parte dintr-o secunda, spre deosebire de cum era acum doi ani, cand latenta era masurata in milisecunde (a mia parte dintr-o secunda). Nu mai e nevoie sa o spunem, daca timpul MT5 ar fi standard, incluzand sutimi de secunda, ar fi tot impractic fie si pentru a incerca trading cu frecventa mai ridicata

Executii, Cotatii si Secunde

O problema importanta e ca nu cunosti latenta cotatiilor, adica timpul dintre doi ticksi. In forex de nivelul II sunt sunt sute de executii pe secunda, si sunt foarte multi ticksi care lipsesc in statiile de retail. Deci te poti astepta de la cativa ticksi pe secunda, la un tick la un tick la catava secunde sau mai mult (sesiunea asiatica). De exemplu, cand te uiti pe graficul de mai sus, poti vedea ca executiile 2 si 3 sunt in interiorul secundei 2. Totusi, pana cand se ajunge la secunda 2, executiile 2 si 3 sunt raportate in secunda 1. In acelasi timp, ambii ticksi 1 si 2 au secunda 1 ca si TimeCurrent(). O secunda pare un moment, dar este de fapt un interval de timp.

Cea mai proasta solutie de a adresa problema distingerii executiilor este folosirea HistorySelect() cu timpi de selectie stransi.. Pentru ca acesti timpi vor fi intotdeauna gresiti – intervalul va fi ori prea mare ori prea mic. Cea mai buna solutie este selectia intregului istoric, dar procesarea a numai ce s-a facut de la ultima procesare. Timpul ultimei tranzactii este o metoda buna de a sti unde se opreste scanarea, dar apentru aceleasi motive ca inainte, mai multe tranzactii pe secunda, tichetul este o cale ideala de a stoca ultima tranzactie raportata. De fapt doua componente trebuie sa fie stocate: tichetul si indexul. Timpul nu este obligatoriu, dar poate fi adaugat daca vreti sa faceti modificari clasei.

Avem urmatoarele scenarii:
a. Indexul ultimei tranzactii reale < Indexul stocat al ultimei tranzactii. Ceva s-a intamplat cu istoricul. Cauta ultimul tichet. Daca este gasit, raporteaza tranzactiile de la el spre timpul prezent, altfel nu raporteaza nimic.

b. Indexul ultimei tranzactii reale = Indexul stocat al ultimei tranzactii. Dupa cum stii, OnTrade() este executat de doua ori la o tranzactie, deci acest caz trebuie tratat. De asemenea, este posibil ca istoricul sa fie limitat ca numar de intrari, astfel incat ultimul index sa fie la fel. La fel ca in cazul precedent, este necesara scanarea ultimului tichet.

c. Indexul ultimei tranzactii reale > Indexul stocat al ultimei tranzactii. Selecteaza si raporteaza tranzactiile pana la ultima in istoric.

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//+------------------------------------------------------------------+
//|                                                  DealHandler.mq5 |
//|                                       Copyright Bogdan Caramalac |
//|                                           http:\\mqlmagazine.com |
//+------------------------------------------------------------------+
#property copyright "Bogdan Caramalac"
#property link      "http:\\mqlmagazine.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
 
class DealHandler
  {
   private:
   int LastDealIndex;
   ulong LastDealTicket;
   datetime LastDealTime;      
   bool setup;
 
   public:
   bool IsSetup();
   void Setup();
   void ReportDeals();
 
   //sadly, virtual methods must reside in the class body
   virtual void EnumDealsCallback(int fromindex,int toindex) 
      {       
       for (int i=fromindex;i<=toindex;i++)
          {
           Print("Deal ",i," has ticket ",HistoryDealGetTicket(i));       
          }
       return;
      } 
 
   DealHandler()
      {
       setup=false;
       Setup();
       return;
      }
   };//DealHandler class end
 
    bool DealHandler::IsSetup()
      {
       return(setup);
      }
 
    void DealHandler::Setup()
      {
       HistorySelect(0,TimeCurrent()+5*60);
       LastDealIndex=HistoryDealsTotal()-1;
       if (LastDealIndex!=-1)
         {
          LastDealTicket=HistoryDealGetTicket(LastDealIndex);
          LastDealTime=HistoryDealGetInteger(LastDealTicket,DEAL_TIME);
         }   
       else       
         {
          LastDealTicket=0;
          LastDealTime=0;
         }
       if (TerminalInfoInteger(TERMINAL_CONNECTED)==true)
         setup=true;
       return;
      }       
 
    void DealHandler::ReportDeals()
       {
        datetime dtime;
        ulong ticket;
        int lasti;
        if (setup==false)
          {
           Setup();
           return;
          }
        lasti=0;
        HistorySelect(0,TimeCurrent()+5*60);
        if (HistoryDealsTotal()==0)
          return;
        if (HistoryDealsTotal()-1<LastDealIndex) //damn, they deleted deals from history
          {
           for (int i=HistoryDealsTotal()-1;i>=0;i--)
              {
               ticket=HistoryDealGetTicket(i);
               if (ticket==LastDealTicket)
                 {
                  lasti=i+1;
                  break;
                 }               
              }
           if (lasti!=0)
             {
              if (lasti<HistoryDealsTotal())                
                {
                 EnumDealsCallback(lasti,HistoryDealsTotal()-1);
                 LastDealIndex=HistoryDealsTotal()-1;
                 LastDealTicket=HistoryDealGetTicket(LastDealIndex);
                 LastDealTime=HistoryDealGetInteger(LastDealTicket,DEAL_TIME);
                }
             }
          }
        else
          {
           if (HistoryDealsTotal()-1==LastDealIndex) 
             {//possible limited history to a fixed number of deals
              //or a multiple OnTrade() triggers per deal
              for (int i=HistoryDealsTotal()-1;i>=0;i--)
                 {
                  ticket=HistoryDealGetTicket(i);
                  if (ticket==LastDealTicket)
                    {
                     lasti=i+1;
                     break;
                    }                  
                 }
              if (lasti!=0)
                {
                 if (lasti<HistoryDealsTotal())                
                   {
                    EnumDealsCallback(lasti,HistoryDealsTotal()-1);
                    LastDealIndex=HistoryDealsTotal()-1;
                    LastDealTicket=HistoryDealGetTicket(LastDealIndex);
                    LastDealTime=HistoryDealGetInteger(LastDealTicket,DEAL_TIME);
                   }
                }              
             }
           else
             {
              if (HistoryDealsTotal()-1>LastDealIndex) //current index is larger; simple selection;
                {
                 EnumDealsCallback(LastDealIndex+1,HistoryDealsTotal()-1);
                 LastDealIndex=HistoryDealsTotal()-1;
                 LastDealTicket=HistoryDealGetTicket(LastDealIndex);
                 LastDealTime=HistoryDealGetInteger(LastDealTicket,DEAL_TIME);
                }
             }//else if (HistoryDealsTotal()-1==LastDealIndex) 
          }//if (HistoryDealsTotal()-1<LastDealIndex)
        return;
    };
 
 
 
 
 
DealHandler DealHandlerDevice;
 
 
 
 
void OnTrade()
  {
   DealHandlerDevice.ReportDeals();
  }
 
int OnInit()
  {
   if (DealHandlerDevice.IsSetup()==false)
     DealHandlerDevice.Setup();
 
 
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
 
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if (DealHandlerDevice.IsSetup()==false)
     DealHandlerDevice.Setup();
 
 
   return;
  }
//+------------------------------------------------------------------+

Dupa cum se poate vedea, clasa DealHandler e folosita asa cum este, prin obiectul DealHandlerDevice. OnInit() si OnTick() verifica daca obiectul este initializat cum trebuie (contine informatii valide), pentru ca numai in acest caz tranzactiile vor fi raportate. Este necesar ca OnTrade() sa apeleze metoda ReportDeals() a obiectului. Metoda ReportDeals() va verifica daca exista executii neraportate de la ultimul raport, si le va trimite mai departe spre EnumDealsCallback(), care este o metoda virtuala; deci poti mosteni DealHandler intr-o clasa noua si-ti poti defini propriul EnumDealsCallback(), sau poti scrie peste exemplul meu. De aceea am lasat spatii lipsa in OnInit() si OnTick(). Ce urmeaza e alegerea ta.

Pentru a testa, activeaza expertul pe un instrument, apoi activeaza tabul Experts din Toolbox. Apoi joaca-te cu cateva tranzactii manuale.

File link:
DealHandler.mqh

One Response to “ Distingirea executiilor cvasisimultane – clasa de raportare a ultimelor tranzactii ”

  1. Bogdan Caramalac, MQLmagazine sr.editor on July 10, 2010 at 3:01 pm

    Am mutat codul clasei intr-un fisier include, DealHandler.mqh .

Leave a Reply