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

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
Am mutat codul clasei intr-un fisier include, DealHandler.mqh .