Con cosa sostituire OnTradeTransaction() in mql4? - pagina 8

 
Vitaly Muzichenko:

Ecco, la soluzione è semplice: introduciamo un altro controllo per cambiare la storia, in questo modo non si perde nulla e funziona al 100%.

Questo può anche essere usato come un OnTrade() incompleto

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:

Credo di non essere abbastanza intelligente).

Come posso applicarlo?

C'è solo un problema ed è estremamente raro, l'ho trovato oggi per la prima volta in un paio d'anni, potrebbe essere stato prima, solo non l'ho notato


Stavo parlando del calcolo della somma hash - come si può aggiungere un nome di carattere al valore della somma hash - calcolare i valori dei codici delle lettere che compongono il nome del carattere.

 
Vitaly Muzichenko:

Ecco, la soluzione è semplice: introdurre un altro controllo di modifica della cronologia, in questo modo non si perde nulla e funziona al 100%.

Ecco un estratto del mio articolo #3:

-------

Concentriamoci di più sulla quantità di hash come parte della struttura.
Non è sufficiente conoscere il numero di ordini e posizioni per poter determinare con precisione cosa è cambiato nel conto - un ordine in sospeso può essere cancellato, e in questo caso il numero totale di ordini e posizioni nel conto cambierà. Ma... Un ordine in sospeso può scattare e diventare una posizione. In questo caso, la quantità totale di ordini e posizioni non cambierebbe (per i conti hedge e MQL4) - il numero di posizioni è aumentato, ma il numero di ordini è diminuito, quindi la quantità totale è ancora la stessa. Questo non funziona per noi.

Consideriamo un biglietto. L'aggiunta/rimozione di un ordine pendente cambierà la quantità totale di tick sul conto, l'attivazione di un ordine pendente non cambierà la quantità totale di tick sul conto.

Guardiamo il volume totale. Avete piazzato o cancellato un ordine in sospeso - importo totale nel conto è cambiato; abbiamo aperto o chiuso, o cambiato la posizione - importo totale nel conto è cambiato. Sembra essere adatto, ma ancora una volta, l'attivazione di un ordine pendente non cambierà il volume totale.

Vediamo quindi un'altra proprietà della posizione - tempo del suo cambiamento in millisecondi: l'apertura di una nuova posizione cambierà il tempo totale di cambiamento della posizione, la chiusura parziale cambierà il tempo di cambiamento della posizione, l'aggiunta di volume a un conto di compensazione cambierà il tempo totale di cambiamento della posizione.

Quale di questi metodi è adatto per determinare la posizione precisa dei cambiamenti sul conto? Biglietto + ora del cambio di posizione. Controlliamo:

  • Aperto una posizione - quantità di biglietti è cambiato + quantità di tempo di cambiamento di posizione è cambiato - c'è un cambiamento
  • Abbiamo chiuso una posizione - la quantità di tick è cambiata + la quantità di tempo in cui la posizione è stata cambiata - c'è un cambiamento.
  • Piazzato un ordine in sospeso - Ticket + il tempo del cambiamento di posizione non è cambiato - - c'è un cambiamento
  • Ordine pendente cancellato - L'importo del biglietto è cambiato + l'importo del tempo di cambiamento della posizione è rimasto invariato - c'è un cambiamento
  • Ordine pendente attivato - L'importo del biglietto non è cambiato + l'importo del tempo di cambiamento della posizione è cambiato - - c'è un cambiamento
  • Chiusura parziale della posizione - Importo del biglietto cambiato + Tempo di cambio della posizione cambiato - - C' è un cambiamento
  • Aggiungere il volume alla posizione - L'importo del biglietto è rimasto invariato + il tempo di cambiamento della posizione è cambiato - - c'è un cambiamento
Così, useremo il biglietto + il tempo di cambiamento di una posizione in millisecondi per la somma hash.

Qui, però, non ho aggiunto un simbolo alla somma dell'hash - non c'erano precedenti per questo. Ma ho funziona insieme alla cronologia dei controlli. Pertanto - dovrebbe funzionare senza errori. Tuttavia, lo controllerò qualche volta.

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

La soluzione è semplice: introdurre un altro controllo del cambio di cronologia, in questo modo non si perde nulla e funziona al 100%.

E sì, lo farà. Se il numero di ordini aperti non cambia, allora il numero nella storia cambierà. (Non mi importa degli ordini in sospeso - non li uso) E non dovremo passare tutto il giorno per prendere un solo evento.

E se l'utente ha ricevuto un messaggio di testo e ha deciso di visualizzare solo la storia dell'ultimo mese nel terminale, sarà un controllo aggiuntivo con provare tutti gli ordini, che non è fatale.

Sembra essere una buona soluzione. E senza riferimento a nient'altro che a ciò che abbiamo, cioè un conto di trading e un terminale.

 
Artyom Trishkin:

Ecco un estratto del mio articolo #3:

-------

Concentriamoci di più sulla quantità di hash come parte della struttura.
Non è sufficiente conoscere la quantità di ordini e posizioni che sono cambiati nel conto per poter determinare con precisione questo cambiamento - un ordine in sospeso può essere cancellato e in questo caso, la quantità totale di ordini e posizioni nel conto cambierà. Ma... Un ordine in sospeso può scattare e diventare una posizione. In questo caso, la quantità totale di ordini e posizioni non cambierebbe (per i conti hedge e MQL4) - il numero di posizioni è aumentato, ma il numero di ordini è diminuito, quindi la quantità totale è ancora la stessa. Questo non funziona per noi.

Considera un biglietto. Aggiungendo/rimuovendo un ordine in sospeso cambierà la quantità totale di biglietti sul conto, attivando un ordine in sospeso non cambierà la quantità totale di biglietti sul conto.

Considera il volume totale. Hai piazzato o cancellato un ordine in sospeso - volume totale del conto cambiato, aperto, chiuso o cambiato posizione - volume totale del conto cambiato. Sembra essere adatto, ma ancora una volta, l'attivazione di un ordine pendente non cambierà il volume totale.

Vediamo quindi un'altra proprietà della posizione - tempo del suo cambiamento in millisecondi: l'apertura di una nuova posizione cambierà il tempo totale di cambiamento della posizione, la chiusura parziale cambierà il tempo di cambiamento della posizione, l'aggiunta di volume a un conto di compensazione cambierà il tempo totale di cambiamento della posizione.

Quale di questi metodi è adatto per determinare la posizione precisa dei cambiamenti sul conto? Biglietto + ora del cambio di posizione. Controlliamo:

  • Aperto una posizione - quantità di biglietti cambiati + quantità di tempo del cambiamento di posizione - c'è un cambiamento
  • Abbiamo chiuso una posizione - la quantità di tick è cambiata + la quantità di tempo in cui la posizione è stata cambiata - c'è un cambiamento.
  • Piazzato un ordine in sospeso - Ticket + il tempo del cambiamento di posizione non è cambiato - - c'è un cambiamento
  • Ordine pendente cancellato - L'importo del biglietto è cambiato + l'importo del tempo di cambiamento della posizione è rimasto invariato - c'è un cambiamento
  • Ordine pendente attivato - L'importo del biglietto non è cambiato + l'importo del tempo di cambiamento della posizione è cambiato - - c'è un cambiamento
  • Chiusura parziale della posizione - Importo del biglietto cambiato + Tempo di cambio della posizione cambiato - - C' è un cambiamento
  • Aggiungere il volume alla posizione - L'importo del biglietto è rimasto invariato + il tempo di cambiamento della posizione è cambiato - - c'è un cambiamento
Così, useremo il biglietto + il tempo del cambiamento di posizione in millisecondi per la somma dell'hash.

Qui, però, non ho aggiunto un simbolo alla somma dell'hash - non c'erano precedenti per questo. Ma ho funziona insieme alla cronologia dei controlli. Pertanto - dovrebbe funzionare senza errori. Tuttavia, lo controllerò qualche volta.

Soluzione grassa, non c'è ancora bisogno di una tale variante.

Grazie!

 
Vitaly Muzichenko:

Decisione grassa, non c'è ancora bisogno di questa opzione.

Grazie!

"Audace" perché non è stato fatto per una soluzione locale, ma come una parte di una sostituzione completa di OnTradeXXXX. C'è più lavoro con la storia.

E questo è un grande vantaggio - abbiamo dati pronti per la ricerca e l'ordinamento di qualsiasi ordine e posizione nel programma (non abbiamo bisogno di cercare di nuovo ordini e posizioni per soddisfare le esigenze del programma - tutto è già nelle liste). Un altro vantaggio è che il programma sa quale ordine ha originato la posizione in MQL4, cosa che non può essere fatta nelle versioni menzionate sopra.

Ripeto, la biblioteca è fatta per facilitare le cose a coloro che hanno troppo tempo e denaro per fare tutto da soli. Non insisto su nulla, naturalmente :)

 
Aleksandr Volotko:

E così è. Se il numero di ordini aperti non cambia, lo farà il numero nella storia.(Non mi importa degli ordini in sospeso - non li uso) E non devi disturbare tua nonna con l'andare attraverso gli ordini tutto il giorno per prendere solo un evento.

E se l'utente ha ricevuto un messaggio di testo e ha deciso di visualizzare la storia nel terminale invece di tutto solo per l'ultimo mese, sarà un controllo aggiuntivo con provare tutti gli ordini, che non è fatale.

Sembra essere una buona soluzione. Se hai un conto di trading e un terminale, puoi usare solo quello che hai senza essere legato a niente.

Al fine di non passare attraverso l'intera giornata, è possibile controllare solo quando le condizioni che possono portare ad un cambiamento, apertura, chiusura di una posizione, cioè concentrarsi sul raggiungimento dei prezzi che l'Expert Advisor utilizza per aprire, TP, SL. Beh, dipende dalla logica dell'Expert Advisor, sai cosa è più conveniente.

 
Aleksey Mavrin:

Per evitare di percorrere l'intera giornata, è possibile controllare solo quando le condizioni che possono portare a un cambiamento, all'apertura, alla chiusura di una posizione sono state soddisfatte, cioè concentrarsi sul raggiungimento dei prezzi che l'Expert Advisor utilizza per aprire, TP, SL. Beh, sì, dipende dalla logica dell'Expert Advisor, sai cosa è più conveniente.

Un EA (su un computer, in un continente) fa trading. L'altro (su un altro computer, in un altro continente) si occupa delle sue funzioni. Una soluzione è già stata trovata.

 
fxsaber:

Vi sarei grato se poteste fornire qualche esempio riproducibile (senza sondare la storia del trading).

Ecco cosa è venuto fuori (anche se offtopic qui, ma chiesto qui).

Tagliare per vivere. Nessuna compatibilità con MT4 (ovviamente), nessuna gestione degli errori, ecc.

Il trading è primitivo, apre BUY, chiude su SL/TP. L'unico punto è dimostrare OnTradeTransaction() rispetto al "polling del server".

Per me ci sono voluti 2.34s contro 3.06s per passare nel tempo dato. La differenza è piccola a causa del basso carico sulle funzioni del server (solo una posizione, nessun controllo per magik e simbolo). In EA reale la differenza sarà molto più grande. La differenza sarà leggermente compensata dal calcolo dei segnali e dall'aggiunta di trailing stop, ma non è necessario farlo ad ogni tick. Il mio ATR è calcolato su M1, ma per 6 ore (cioè c'è spazio per ingrandire TF). E il trailing e il Breakeven sono calcolati su H3. Tutto dipende dalla strategia.

// 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:

Sei irrimediabilmente indietro con i tempi!

Questi eventi sono garantiti da molto tempo!

Supponiamo che si sia verificato un evento in OnTradeTransaction() dopo il quale qualche azione deve essere eseguita, ma si è verificato un errore al primo tentativo di eseguire questa azione. Cosa fare? Ovviamente, deve essere ripetuto, e per questo è necessario salvare da qualche parte i dati sulla necessità di ripetere questa azione - molto probabilmente, questi dati sono salvati nelle solite variabili globali di Expert Advisor o in funzioni statiche. E improvvisamente ho dovuto riavviare il terminale... i dati sono spariti.

E quando si analizza la situazione attuale e la storia - niente va da nessuna parte.