¿Con qué sustituir OnTradeTransaction() en mql4? - página 8

 
Vitaly Muzichenko:

Ya está, la solución es sencilla: introducimos otra comprobación para cambiar el historial, así no se perderá nada y funcionará al 100%

Esto puede incluso utilizarse como 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:

Supongo que no soy lo suficientemente inteligente).

¿Cómo lo aplico?

Sólo hay un problema y es extremadamente raro, lo encontré hoy por primera vez en un par de años, puede haber sido antes, sólo que no lo noté


Me refería al cálculo de la suma de hash - cómo se puede añadir un nombre de carácter al valor de la suma de hash - calcular los valores de los códigos de letras que componen el nombre de carácter.

 
Vitaly Muzichenko:

Ya está, la solución es sencilla: introducir otra comprobación de cambios en el historial, así no se perderá nada y funcionará al 100%

Aquí hay un extracto de mi artículo #3:

-------

Centrémonos más en la cantidad de hash como parte de la estructura.
No basta con conocer el número de órdenes y posiciones para poder determinar con precisión lo que ha cambiado en la cuenta - una orden pendiente puede ser eliminada, y en este caso el número total de órdenes y posiciones en la cuenta cambiará. Pero... Una orden pendiente puede activarse y convertirse en una posición. En este caso, la cantidad total de órdenes y posiciones no cambiará (para cuentas de cobertura y MQL4) - el número de posiciones ha aumentado, pero el número de órdenes ha disminuido, por lo que la cantidad total sigue siendo la misma. Esto no funciona para nosotros.

Consideremos un billete. Añadir/eliminar una orden pendiente cambiará la cantidad total de ticks en la cuenta, activar una orden pendiente no cambiará la cantidad total de ticks en la cuenta.

Veamos el volumen total. Ha colocado o eliminado una orden pendiente - el importe total en la cuenta ha cambiado; la hemos abierto o cerrado, o hemos cambiado la posición - el importe total en la cuenta ha cambiado. Parece ser adecuado, pero una vez más, la activación de una orden pendiente no cambiará el volumen total.

Así que veamos una propiedad más de la posición - tiempo de su cambio en milisegundos: la apertura de una nueva posición cambiará el tiempo total de cambio de la posición, el cierre parcial cambiará el tiempo de cambio de la posición, la adición de volumen a una cuenta de compensación cambiará el tiempo total de cambio de la posición.

¿Cuál de estos métodos es adecuado para determinar la ubicación precisa de los cambios en la cuenta? Billete + hora del cambio de posición. Vamos a comprobarlo:

  • Abrió una posición - cantidad de entradas ha cambiado + cantidad de tiempo de cambio de posición ha cambiado - hay un cambio
  • Cerramos una posición - la cantidad de ticks ha cambiado + la cantidad de tiempo que la posición fue cambiada - hay un cambio.
  • Colocó una orden pendiente - Ticket + hora de cambio de posición no ha cambiado - - hay un cambio
  • Orden pendiente eliminada - El importe del ticket ha cambiado + El importe del tiempo de cambio de posición no ha cambiado - hay un cambio
  • Orden pendiente activada - El importe de la entrada no ha cambiado + el importe del cambio de posición ha cambiado - - hay un cambio
  • Cierre parcial de la posición - Se ha modificado el importe de la entrada + Se ha modificado la hora de cambio de la posición - - Hay un cambio
  • Añadir volumen a la posición - El importe de la entrada no ha cambiado + el tiempo de cambio de posición ha cambiado - - hay un cambio
Así, utilizaremos un ticket + tiempo de cambio de una posición en milisegundos para la suma hash.

En este caso, sin embargo, no añadí un símbolo a la suma de hash - no había precedentes para ello. Pero tengo que funciona en conjunto con el historial de cheques. Por lo tanto, debería funcionar sin errores. Sin embargo, lo comprobaré alguna vez.

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

La solución es sencilla: introducir otra comprobación de cambios en el historial, así no se perderá nada y funcionará al 100%.

Y sí, lo hará. Si el número de órdenes abiertas no cambia, entonces el número en el historial cambiará. (No me importan los pedidos pendientes - no los uso) Y no tendremos que pasar todo el día para coger un solo evento.

Y si el usuario ha recibido un mensaje de texto y ha decidido mostrar el historial en el terminal en lugar de todo sólo para el último mes, será una comprobación adicional con el intento de todas las órdenes, que no es fatal.

Parece ser una buena solución. Y sin hacer referencia a nada más que a lo que tenemos, que es una cuenta comercial y un terminal.

 
Artyom Trishkin:

Este es un extracto de mi artículo #3:

-------

Vamos a detallar la cantidad de hash como parte de la estructura.
No es suficiente conocer la cantidad de órdenes y posiciones que han cambiado en la cuenta para poder determinar con precisión este cambio - una orden pendiente puede ser eliminada y en este caso, la cantidad total de órdenes y posiciones en la cuenta cambiará. Pero... Una orden pendiente puede activarse y convertirse en una posición. En este caso, la cantidad total de órdenes y posiciones no cambiaría (para las cuentas de cobertura y MQL4) - el número de posiciones ha aumentado, pero el número de órdenes ha disminuido, por lo que la cantidad total sigue siendo la misma. Esto no funciona para nosotros.

Considera un billete. Añadir/eliminar una orden pendiente cambiará la cantidad total de tickets en la cuenta, activar una orden pendiente no cambiará la cantidad total de tickets en la cuenta.

Considera el volumen total. Ha colocado o eliminado una orden pendiente - ha cambiado el volumen total de la cuenta, ha abierto, ha cerrado o ha cambiado de posición - ha cambiado el volumen total de la cuenta. Parece ser adecuado, pero una vez más, la activación de una orden pendiente no cambiará el volumen total.

Así que veamos una propiedad más de la posición - tiempo de su cambio en milisegundos: la apertura de una nueva posición cambiará el tiempo total de cambio de la posición, el cierre parcial cambiará el tiempo de cambio de la posición, la adición de volumen a una cuenta de compensación cambiará el tiempo total de cambio de la posición.

¿Cuál de estos métodos es adecuado para determinar la ubicación precisa de los cambios en la cuenta? Billete + hora del cambio de posición. Vamos a comprobarlo:

  • Abrió una posición - cantidad de entradas cambiadas + cantidad de tiempo de cambio de posición - hay un cambio
  • Cerramos una posición - la cantidad de ticks ha cambiado + la cantidad de tiempo que la posición fue cambiada - hay un cambio.
  • Colocó una orden pendiente - Ticket + hora de cambio de posición no ha cambiado - - hay un cambio
  • Orden pendiente eliminada - El importe del ticket ha cambiado + El importe del tiempo de cambio de posición no ha cambiado - hay un cambio
  • Orden pendiente activada - El importe de la entrada no ha cambiado + el importe del cambio de posición ha cambiado - - hay un cambio
  • Cierre parcial de la posición - Se ha modificado el importe de la entrada + Se ha modificado la hora de cambio de la posición - - Hay un cambio
  • Añadir volumen a la posición - El importe de la entrada no ha cambiado + el tiempo de cambio de posición ha cambiado - - hay un cambio
Así, utilizaremos un ticket + tiempo de cambio de una posición en milisegundos para la suma hash.

En este caso, sin embargo, no añadí un símbolo a la suma de hash - no había precedentes para ello. Pero tengo que funciona en conjunto con el historial de cheques. Por lo tanto, debería funcionar sin errores. Sin embargo, lo comprobaré alguna vez.

Solución gorda, todavía no es necesaria esa variante.

Gracias.

 
Vitaly Muzichenko:

Decisión gorda, aún no es necesaria esa opción.

Gracias.

"Audaz" porque no se hizo para una solución local, sino como una parte de un reemplazo completo de OnTradeXXXX. Hay más obras con historia.

Y esto es una gran ventaja - tenemos datos listos para la búsqueda y clasificación de cualquier orden y posición en el programa (no necesitamos buscar órdenes y posiciones de nuevo para satisfacer las necesidades del programa - todo está ya en las listas). Otra ventaja es que el programa sabe qué orden originó la posición en MQL4, lo que no se puede hacer en las versiones mencionadas anteriormente.

Repito, la biblioteca está hecha para facilitar las cosas a quienes tienen demasiado tiempo y dinero para hacerlo todo por sí mismos. No insisto en nada, por supuesto :)

 
Aleksandr Volotko:

Y así es. Si el número de órdenes abiertas no cambia, el número en el historial sí lo hará. (No meimportan las órdenes pendientes - no las uso). Y no tienes que molestar a tu abuela con revisar las órdenes todo el día para coger un solo evento.

Y si el usuario ha recibido un mensaje de texto y ha decidido mostrar el historial en el terminal en lugar de todo el último mes, será una comprobación adicional con el intento de todas las órdenes, que no es fatal.

Parece ser una buena solución. Si tienes una cuenta de trading y un terminal, puedes usar sólo lo que tienes sin estar atado a nada.

Con el fin de no pasar por todo el día, se puede comprobar sólo cuando las condiciones que pueden conducir a los cambios, la apertura, el cierre de posiciones, es decir, centrarse en la consecución de los precios que el Asesor de Expertos utiliza para abrir, TP, SL. Bueno, depende de la lógica del Asesor Experto, ya sabes que es más barato.

 
Aleksey Mavrin:

Para evitar pasar por todo el día, puede comprobar sólo cuando las condiciones que pueden conducir a un cambio, la apertura, el cierre de una posición se han cumplido, es decir, para centrarse en la consecución de los precios que el Asesor de Expertos utiliza para abrir, TP, SL. Bueno, sí, depende de la lógica del Asesor Experto, ya sabes que es más barato.

Un EA (en un ordenador, en un continente) comercia. La otra (en otro ordenador, en otro continente) se ocupa de sus funciones. Ya se ha encontrado una solución.

 
fxsaber:

Te agradecería que me dieras algún ejemplo reproducible (sin sondear el historial de operaciones).

Esto es lo que ha surgido (aunque está fuera de tema aquí, pero se pidió aquí).

Cortar para vivir. Sin compatibilidad con MT4 (por supuesto), sin manejo de errores, etc.

El comercio es primitivo, abre la COMPRA, cierra en el SL/TP. El único punto es demostrar OnTradeTransaction() frente a "sondear el servidor".

A mí me costó 2,34s frente a 3,06s pasar en el intervalo dado. La diferencia es pequeña debido a la baja carga de las funciones del servidor (sólo una posición, no hay comprobación de magik y símbolo). En la EA real la diferencia será mucho mayor. La diferencia se suavizará ligeramente mediante el cálculo de las señales y la adición de trailing stops, pero no es necesario hacerlo en cada tick. Mi ATR se calcula en M1, pero para 6 horas (es decir, hay espacio para ampliar el TF). Y el trailing y el Breakeven se calculan en H3. Todo depende de la estrategia.

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

Estás irremediablemente atrasado.

Estos eventos están garantizados desde hace mucho tiempo.

Supongamos que se produce un evento en OnTradeTransaction() tras el cual se debe realizar alguna acción, pero se produce un error en el primer intento de realizar esta acción. ¿Qué hacer? Obviamente, debe repetirse, y para ello es necesario guardar en algún lugar los datos sobre la necesidad de repetir esta acción - lo más probable es que estos datos se guarden en las variables globales habituales del Asesor Experto o en funciones estáticas. Y de repente tuve que reiniciar el terminal... los datos han desaparecido.

Y cuando se analiza la situación actual y la historia, nada va a ninguna parte.