Wodurch soll OnTradeTransaction() in mql4 ersetzt werden? - Seite 8

 
Vitaly Muzichenko:

Die Lösung ist einfach: Wir führen eine weitere Prüfung ein, um die Historie zu ändern, so dass nichts verloren geht und es zu 100% funktioniert.

Dies kann sogar als unvollständiges OnTrade() verwendet werden

void OnTrade()
 {
  ...
 }

static __OTotal = -1;
static __HTotal = -1;
int OT=OrdersTotal();
int HT=OrdersHistoryTotal();
  if(OT!=__OTotal || HT!=__HTotal) // если изменилось - выполняем
   {
     OnTrade(); // здесь дёргаем текущую ситуацию на счёте и заполняем структуры
     __OTotal=OrdersTotal(); // запомним текущее количество
     __HTotal=OrdersHistoryTotal(); // запомним количество в истории
   }
 
Vitaly Muzichenko:

Ich bin wohl nicht schlau genug.)

Wie wende ich das an?

Es gibt nur ein Problem, und das ist extrem selten. Ich habe es heute zum ersten Mal seit ein paar Jahren gefunden, vielleicht war es schon vorher da, ich habe es nur nicht bemerkt.


Ich habe über die Berechnung der Hash-Summe gesprochen - wie man einen Zeichennamen zum Hash-Summenwert hinzufügen kann - und wie man die Werte der Buchstabencodes berechnet, aus denen der Zeichenname besteht.

 
Vitaly Muzichenko:

Das ist es, die Lösung ist einfach: Führen Sie eine weitere Änderungsprüfung der Historie ein, dann geht nichts verloren und es funktioniert zu 100%.

Hier ist ein Auszug aus meinem Artikel #3:

-------

Konzentrieren wir uns mehr auf den Hash-Betrag als Teil der Struktur.
Es reicht nicht aus, die Anzahl der Aufträge und Positionen zu kennen, um genau feststellen zu können, was sich auf dem Konto geändert hat - kann ein ausstehender Auftrag gelöscht werden, und in diesem Fall ändert sich die Gesamtzahl der Aufträge und Positionen auf dem Konto. Aber... Ein schwebender Auftrag kann ausgelöst und zu einer Position werden. In diesem Fall würde sich der Gesamtbetrag der Aufträge und Positionen nicht ändern (für Hedge-Konten und MQL4) - die Anzahl der Positionen hat sich erhöht, aber die Anzahl der Aufträge hat sich verringert, so dass der Gesamtbetrag immer noch der gleiche ist. Das funktioniert bei uns nicht.

Nehmen wir ein Ticket. Das Hinzufügen/Entfernen eines schwebenden Auftrags ändert die Gesamtmenge der Ticks auf dem Konto, das Auslösen eines schwebenden Auftrags ändert die Gesamtmenge der Ticks auf dem Konto nicht.

Betrachten wir das Gesamtvolumen. Sie haben einen schwebenden Auftrag erteilt oder gelöscht - Gesamtbetrag auf dem Konto hat sich geändert; wir haben ihn eröffnet oder geschlossen oder die Position geändert - Gesamtbetrag auf dem Konto hat sich geändert. Es scheint geeignet zu sein, aber auch hier gilt, dass die Aktivierung eines schwebenden Auftrags das Gesamtvolumen nicht verändert.

Betrachten wir also eine weitere Positionseigenschaft - Zeit ihrer Veränderung in Millisekunden: Das Eröffnen einer neuen Position verändert die gesamte Positionsveränderungszeit, das teilweise Schließen verändert die Positionsveränderungszeit, das Hinzufügen von Volumen zu einem Netting-Konto verändert die gesamte Positionsveränderungszeit.

Welche dieser Methoden ist geeignet, um den genauen Ort der Änderungen auf dem Konto zu bestimmen? Ticket + Zeitpunkt der Positionsänderung. Schauen wir nach:

  • Eröffnete eine Position - Menge der Tickets hat sich geändert + Menge der Zeit der Positionsänderung hat sich geändert - es gibt eine Änderung
  • Wir haben eine Position geschlossen - die Anzahl der Ticks hat sich geändert + die Zeit, in der die Position geändert wurde - es gibt eine Änderung.
  • Einen schwebenden Auftrag platziert - Ticket + Zeitpunkt der Positionsänderung hat sich nicht geändert - - es gibt eine Änderung
  • Gelöschte Pending Order - Ticketbetrag geändert + Positionsänderungszeitbetrag blieb unverändert - es gibt eine Änderung
  • Pending Order aktiviert - Ticketbetrag hat sich nicht geändert + Positionsänderung Zeitbetrag hat sich geändert - - es gibt eine Änderung
  • Teilweise Positionsschließung - Ticketbetrag geändert + Positionsänderungszeitpunkt geändert - - Es gibt eine Änderung
  • Volumen zur Position addieren - Ticketbetrag blieb unverändert + Positionsänderungszeitpunkt geändert - - es gibt eine Änderung
Daher verwenden wir für die Hash-Summe das Ticket + Änderungszeit einer Position in Millisekunden.

In diesem Fall habe ich jedoch kein Symbol zur Hash-Summe hinzugefügt - dafür gab es keine Präzedenzfälle. Aber ich habe es funktioniert in Verbindung mit der Überprüfung Geschichte. Daher sollte es ohne Fehler funktionieren. Ich werde es aber bei Gelegenheit überprüfen.

Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
  • www.mql5.com
В первой части данного цикла статей мы начали создавать большую кроссплатформенную библиотеку, целью которой является облегчение создания программ для платформы MetaTrader 5 и MetaTrader 4. Во второй части продолжили развитие библиотеки и сделали коллекцию исторических ордеров и сделок. В данной части повествования создадим класс для удобного...
 
Vitaly Muzichenko:

Die Lösung ist einfach: Führen Sie eine weitere Prüfung der Verlaufsänderungen ein, dann geht nichts verloren und es funktioniert zu 100 %.

Und ja, das wird sie. Wenn sich die Anzahl der offenen Aufträge nicht ändert, ändert sich auch die Anzahl in der Historie. (Ich kümmere mich nicht um ausstehende Bestellungen - ich benutze sie nicht) Und wir müssen nicht den ganzen Tag durchgehen, um nur ein Ereignis zu erfassen.

Und wenn der Benutzer eine Textnachricht erhalten hat und sich dafür entschieden hat, nur die Historie des letzten Monats im Terminal anzuzeigen, wird eine zusätzliche Prüfung durchgeführt, bei der alle Bestellungen ausprobiert werden, was nicht fatal ist.

Das scheint eine gute Lösung zu sein. Und zwar ohne Bezug auf etwas anderes als das, was wir haben, nämlich ein Handelskonto und ein Terminal.

 
Artyom Trishkin:

Hier ist ein Auszug aus meinem Artikel #3:

-------

Gehen wir näher auf den Hash-Betrag als Teil der Struktur ein.
Es reicht nicht aus, die Anzahl der Aufträge und Positionen zu kennen, die sich auf dem Konto geändert haben, um diese Änderung genau bestimmen zu können - kann ein ausstehender Auftrag gelöscht werden, und in diesem Fall ändert sich die Gesamtanzahl der Aufträge und Positionen auf dem Konto. Aber... Ein schwebender Auftrag kann ausgelöst und zu einer Position werden. In diesem Fall ändert sich der Gesamtbetrag der Aufträge und Positionen nicht (für Hedge-Konten und MQL4) - die Anzahl der Positionen hat sich erhöht, aber die Anzahl der Aufträge hat sich verringert, so dass der Gesamtbetrag immer noch der gleiche ist. Das funktioniert bei uns nicht.

Ziehen Sie ein Ticket in Betracht. Das Hinzufügen/Entfernen eines schwebenden Auftrags ändert die Gesamtzahl der Tickets im Konto, das Auslösen eines schwebenden Auftrags ändert nicht die Gesamtzahl der Tickets im Konto.

Betrachten Sie das Gesamtvolumen. Sie haben einen schwebenden Auftrag erteilt oder gelöscht - Gesamtvolumen des Kontos geändert, eröffnet, geschlossen oder Position geändert - Gesamtvolumen des Kontos geändert. Es scheint geeignet zu sein, aber auch hier gilt, dass die Aktivierung eines schwebenden Auftrags das Gesamtvolumen nicht verändert.

Schauen wir uns also eine weitere Positionseigenschaft an - Zeit ihrer Änderung in Millisekunden: Das Eröffnen einer neuen Position ändert die gesamte Positionsänderungszeit, das teilweise Schließen ändert die Positionsänderungszeit, das Hinzufügen von Volumen zu einem Netting-Konto ändert die gesamte Positionsänderungszeit.

Welche dieser Methoden ist geeignet, um den genauen Ort der Änderungen auf dem Konto zu bestimmen? Ticket + Zeitpunkt der Positionsänderung. Schauen wir nach:

  • Eröffnete eine Position - Menge der geänderten Tickets + Zeitdauer der Positionsänderung - es gibt eine Änderung
  • Wir haben eine Position geschlossen - die Anzahl der Ticks hat sich geändert + die Zeit, in der die Position geändert wurde - es gibt eine Änderung.
  • Einen schwebenden Auftrag platziert - Ticket + Zeitpunkt der Positionsänderung hat sich nicht geändert - - es gibt eine Änderung
  • Gelöschte Pending Order - Ticketbetrag geändert + Positionsänderungszeitbetrag blieb unverändert - es gibt eine Änderung
  • Pending Order aktiviert - Ticketbetrag hat sich nicht geändert + Positionsänderung Zeitbetrag hat sich geändert - - es gibt eine Änderung
  • Teilweise Positionsschließung - Ticketbetrag geändert + Positionsänderungszeitpunkt geändert - - Es gibt eine Änderung
  • Volumen zur Position addieren - Ticketbetrag blieb unverändert + Positionsänderungszeitpunkt geändert - - es gibt eine Änderung
Daher verwenden wir für die Hash-Summe das Ticket + die Änderungszeit einer Position in Millisekunden.

In diesem Fall habe ich jedoch kein Symbol zur Hash-Summe hinzugefügt - dafür gab es keine Präzedenzfälle. Aber ich habe es funktioniert in Verbindung mit der Überprüfung Geschichte. Daher sollte es ohne Fehler funktionieren. Ich werde es aber bei Gelegenheit überprüfen.

Fette Lösung, noch kein Bedarf für eine solche Variante.

Ich danke Ihnen!

 
Vitaly Muzichenko:

Fette Entscheidung, noch kein Bedarf für diese Option.

Ich danke Ihnen!

"Kühn" deshalb, weil es nicht für eine lokale Lösung gedacht war, sondern als Teil eines vollwertigen Ersatzes für OnTradeXXXX. Es gibt noch mehr Arbeiten, die Geschichte beinhalten.

Und das ist ein großer Vorteil - wir haben fertige Daten für die Suche und Sortierung beliebiger Aufträge und Positionen im Programm (wir brauchen nicht erneut nach Aufträgen und Positionen zu suchen, um die Anforderungen des Programms zu erfüllen - alles ist bereits in den Listen enthalten). Ein weiteres Plus ist, dass das Programm weiß, welcher Auftrag die Position in MQL4 verursacht hat, was in den oben genannten Versionen nicht möglich ist.

Ich möchte wiederholen, dass die Bibliothek dazu da ist, denjenigen die Arbeit zu erleichtern, die zu viel Zeit und Geld haben, um alles selbst zu machen. Ich bestehe natürlich nicht auf irgendetwas :)

 
Aleksandr Volotko:

Und so ist es auch. Wenn sich die Anzahl der offenen Aufträge nicht ändert, ändert sich die Anzahl in der Historie.(Ich kümmere mich nicht um ausstehende Aufträge - ich benutze sie nicht) Und Sie müssen Ihre Großmutter nicht den ganzen Tag damit belästigen, die Aufträge durchzugehen, um nur ein Ereignis zu erfassen.

Und wenn der Benutzer eine Textnachricht erhalten hat und sich entschlossen hat, die Historie im Terminal anzuzeigen, anstatt alles nur für den letzten Monat, wird es eine zusätzliche Prüfung mit dem Ausprobieren aller Aufträge sein, was nicht fatal ist.

Das scheint eine gute Lösung zu sein. Wenn Sie ein Handelskonto und ein Terminal haben, können Sie nur das nutzen, was Sie haben, ohne an etwas gebunden zu sein.

Um nicht durch den ganzen Tag zu gehen, können Sie nur überprüfen, wenn die Bedingungen, die zu einer Änderung führen kann, Öffnen, Schließen einer Position, dh auf die Erreichung der Preise, die der Expert Advisor verwendet, um offene, TP, SL konzentrieren. Nun, das hängt von der Logik des Expert Advisors ab, Sie wissen, was billiger ist.

 
Aleksey Mavrin:

Um nicht den ganzen Tag durchzugehen, können Sie nur prüfen, wann die Bedingungen, die zu einer Änderung, Eröffnung oder Schließung einer Position führen können, erfüllt sind, d.h. sich auf das Erreichen der Preise konzentrieren, die der Expert Advisor für Eröffnung, TP, SL verwendet. Nun, ja, es hängt von der Logik des Expert Advisors ab, Sie wissen, was billiger ist.

Ein EA (auf einem Computer, auf einem Kontinent) handelt. Der andere (auf einem anderen Computer, auf einem anderen Kontinent) befasst sich mit seinen Funktionen. Es wurde bereits eine Lösung gefunden.

 
fxsaber:

Ich wäre Ihnen dankbar, wenn Sie mir ein reproduzierbares Beispiel geben könnten (ohne den Handelsverlauf abzufragen).

Hier ist das, was herauskam (obwohl es hier nicht zum Thema gehört, aber es wurde hier angefragt).

Schnitt zum Leben. Keine MT4-Kompatibilität (natürlich), keine Fehlerbehandlung usw.

Der Handel ist primitiv, öffnet BUY, schließt auf SL/TP. Der einzige Punkt ist die Demonstration von OnTradeTransaction() im Vergleich zur "Abfrage des Servers".

Ich brauchte 2,34s gegenüber 3,06s, um die Prüfung in der vorgegebenen Zeit zu bestehen. Der Unterschied ist aufgrund der geringen Belastung der Serverfunktionen (nur eine Position, keine Prüfung auf Magie und Symbol) gering. In der realen EA wird der Unterschied viel größer sein. Die Differenz wird durch die Berechnung von Signalen und das Hinzufügen von Trailing-Stops etwas geglättet, aber sie müssen nicht bei jedem Tick durchgeführt werden. Meine ATR wird auf M1 berechnet, aber für 6 Stunden (d.h. es ist Platz, um TF zu vergrößern). Und Trailing und Breakeven werden auf H3 berechnet. Es hängt alles von der Strategie ab.

// Test OnTradeTransaction.mqh
#property version   "1.00"
#property copyright "(c)2020 Edgar Akhmadeev"
#property link      "https://www.mql5.com/en/users/dali"
// 2020.01.27

//      Primitive expert to test OnTradeTransaction().
//      BUY only one position a time. There's no any signals.
//      Try OHLC M1 EURUSD 2016.12.19-2018.04.14 (bull trend) with default SL/TP.



//#define TESTER



#define  MT4_TICKET_TYPE
#include <MT4Orders.mqh>
#include <mql4_to_mql5.mqh>



struct PosInfoBase {
        double                  price, sl, tp;
        datetime                time;
        int                     ticket;
        ENUM_ORDER_TYPE 	 type;

        #ifndef  TESTER
                int             mn;
                string          sym;
        #endif 
};

struct PosInfo {
        PosInfoBase             base;
        int                     ticket;
};



input int       SL              = 6;
input int       TP              = 900;



MqlTick         tick;
PosInfo         posInfo         = { 0 };



#ifdef  TESTER

//*************************************************************************************************************
void 
OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
        if (trans.type == TRADE_TRANSACTION_ORDER_DELETE && trans.order_state == ORDER_STATE_PLACED) {
                // No money
                //errFatal = true;
                return;
        }
        
        static long lastTick;

        if (trans.type == TRADE_TRANSACTION_DEAL_ADD && trans.order_state == ORDER_STATE_STARTED) {
                // Open on market step1, SL/Order triggered step1, SL/Order triggered step4
                
                if (!HistoryDealSelect(trans.deal)) {
                        //errFatal = true;
                        return;
                }
                
                ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
                if (entry != DEAL_ENTRY_OUT)
                        return;
                
                ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
                if (reason != DEAL_REASON_SL && reason != DEAL_REASON_TP)
                        return;
                
                if (lastTick == tick.time_msc)
                        return;

                posInfo.base.ticket = 0;
                InitPos();

                lastTick = tick.time_msc;
                return;
        }
}



#else // TESTER



//*************************************************************************************************************
bool
Support() {
        posInfo.base.ticket = 0;
        
        int cnt = PosTotal();
        if (cnt > 1)
                return false;
        
        PosInfo _posInfo;
        
        if (cnt == 0)
                _posInfo.base.ticket = 0;
        else {
                PosInfoFill(_posInfo);
                _posInfo.ticket = _posInfo.base.ticket;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Position: process
        
        if (_posInfo.base.ticket != 0 && posInfo.ticket != 0 && _posInfo.base.ticket == posInfo.ticket) {
                // Ничего не произошло, та же позиция
                
                posInfo.base.ticket = _posInfo.base.ticket;
                posInfo.base.time = _posInfo.base.time;
                //posInfo.base.price = _posInfo.base.price;
                posInfo.base.sl = _posInfo.base.sl;
                posInfo.base.tp = _posInfo.base.tp;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Инициализация новой позиции
        
        if (posInfo.base.ticket > 0)
                return true;
        
        return InitPos();
}

#endif // TESTER



//*************************************************************************************************************
bool
InitPos() {
        if (!SymbolInfoTick(_Symbol, tick))
                return false;
        
        posInfo.base.type = ORDER_TYPE_BUY;
        posInfo.base.sl = NormalizeDouble(tick.bid - SL * Point, Digits); 
        posInfo.base.tp = NormalizeDouble(tick.bid + TP * Point, Digits);       

        ResetLastError();
        int order = OrderSend(_Symbol, posInfo.base.type, 0.01, tick.ask, 99, posInfo.base.sl, posInfo.base.tp); 
        if (order < 0)
                return false;
        
        if (!OrderSelect(order, SELECT_BY_TICKET))
                return false;

        posInfo.base.price = OrderOpenPrice();
        posInfo.ticket = posInfo.base.ticket = order;
        posInfo.base.time = tick.time;
        return true;
}



//*************************************************************************************************************
int
PosTotal() {
        int posTotal = OrdersTotal();
        int cnt = 0;
        for (int i = posTotal - 1; i >= 0; --i) {
                if (!OrderSelect(i, SELECT_BY_POS)) {
                        //errFatal = true;
                        return -1;
                }

                if (OrderType() > OP_SELL)
                        continue;

                /*
                #ifndef TESTER
                        if (OrderMagicNumber() != MagicNum)
                                continue;
                        if (OrderSymbol() != symInfo.sym)
                                continue;
                #endif 
                */
                        
                ++cnt;
        } // for
        
        return cnt;
}


        
//*************************************************************************************************************
void
PosInfoFill(PosInfo& _posInfo) {
        ZeroMemory(_posInfo);

        _posInfo.base.ticket = (int)PositionGetInteger(POSITION_TICKET);
        _posInfo.base.type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
        _posInfo.base.price = PositionGetDouble(POSITION_PRICE_OPEN);
        _posInfo.base.time = (datetime)PositionGetInteger(POSITION_TIME);
        _posInfo.base.sl = PositionGetDouble(POSITION_SL);
        _posInfo.base.tp = PositionGetDouble(POSITION_TP);

        #ifndef  TESTER
                _posInfo.base.mn = (int)PositionGetInteger(POSITION_MAGIC);
                _posInfo.base.sym = PositionGetString(POSITION_SYMBOL);
        #endif 
}



//*************************************************************************************************************
void 
OnTick() {
        ResetLastError();
        if (!SymbolInfoTick(_Symbol, tick)) {
                int LE = GetLastError();
                //errFatal = true;
                return;
        }
        
        #ifdef  TESTER

                if (posInfo.base.ticket > 0)
                        return;
                
                if (!InitPos()) {
                        //errFatal = true;
                        return;
                }

        #else  // TESTER
                
                if (!Support()) {
                        //errFatal = true;
                        return;
                }
        
        #endif // TESTER
}



//*************************************************************************************************************
int 
OnInit() {
        return INIT_SUCCEEDED;
}



//*************************************************************************************************************
void 
OnDeinit(const int reason) {
}
 
prostotrader:

Sie sind hoffnungslos unzeitgemäß!

Diese Ereignisse sind schon seit langem garantiert!

Angenommen, in OnTradeTransaction() tritt ein Ereignis ein, nach dem eine Aktion ausgeführt werden muss, aber beim ersten Versuch, diese Aktion auszuführen, tritt ein Fehler auf. Was ist zu tun? Offensichtlich muss sie wiederholt werden, und dafür ist es notwendig, irgendwo Daten über die Notwendigkeit der Wiederholung dieser Aktion zu speichern - am ehesten werden diese Daten in den üblichen globalen Variablen von Expert Advisor oder in statischen Funktionen gespeichert. Und plötzlich musste ich das Terminal neu starten... die Daten sind weg.

Und wenn man die gegenwärtige Situation und die Geschichte analysiert, geht nichts mehr.