Bibliotecas: MT4Orders - página 85

 

Foro sobre trading, sistemas automatizados de trading y testeo de estrategias de trading

Bibliotecas: MT4Orders

fxsaber, 2023.07.07 13:12

Rendimiento.

Tabla de rendimiento (tiempo de ejecución en milisegundos) para b3815 y b2958.

MT5 construir LastCloseTimeMQL4 LastCloseTimeMQL5 LastCloseTimeMQL4_2 LastCloseTimeMQL4+VIRTUAL::Instantánea LastCloseTimeMQL4+VirtualTester
b3815 2875 113 708 732 45
b2958 2718 107 675 715 50

MT4Orders del 20.07.2022 se utilizó en todas partes.

Utilizando la misma metodología, una tabla comparativa de dos builds de MT5: b4040 y b4057.

MT5 build LastCloseTimeMQL4 LastCloseTimeMQL5 LastCloseTimeMQL4_2 LastCloseTimeMQL4+VIRTUAL::Instantánea LastCloseTimeMQL4+VirtualTester
b4040 3663 117 881 928 27
b4057 246 122 171 213 27

En b4057+ el rendimiento de MT4Orders al trabajar con históricos no es inferior al nativo de MQL5.


En consecuencia, la recomendación dada anteriormente ya no es relevante (para MT5 b4057+).

Foro sobre trading, sistemas automatizados de trading y testeo de estrategias de trading.

Bibliotecas: MT4Orders

fxsaber, 2023.07.07 13:12

  • Es necesario reducir las llamadas a OrderSelect para las órdenes históricas. Esto se puede lograr de las maneras que se muestran en las tres columnas de la derecha de la tabla.
 

Foro sobre trading, sistemas automatizados de trading y testeo de estrategias de trading

Bibliotecas: MT4Orders

fxsaber, 2017.06.14 11:30 AM.

// Lista de cambios:
// 14.06.2017:
// Añadir: Se habilita la implementación de la detección SL/TP de posiciones cerradas (cerradas mediante OrderClose).
// Añadir: MagicNumber es ahora de tipo long - 8 bytes (antes era int - 4 bytes).
// Añadir: Si en OrderSend, OrderClose o OrderModify el parámetro de entrada de color (el más reciente) se establece igual a INT_MAX, se generará.
// la solicitud de operación MT5 correspondiente (MT4ORDERS::LastTradeRequest), pero NO se enviará. En su lugar, se comprobará MT5,
// cuyo resultado estará disponible en MT4ORDERS::LastTradeCheckResult.
// Si OrderModify y OrderClose tienen éxito, devolverán true, en caso contrario devolverán false.
// OrderSend devolverá 0 si tiene éxito, en caso contrario -1.
//
// Si el parámetro de entrada de color correspondiente se establece antes que INT_MIN, то ТОЛЬКО в случае успешной MT5-проверки сформированного
// solicitud comercial (como en el caso de INT_MAX) se enviará.
// Añadir: Añadidos análogos asíncronos de las funciones de trading de MQL4: OrderSendAsync, OrderModifyAsync, OrderCloseAsync, OrderDeleteAsync.
// Devuelve el Result.request_id correspondiente si tiene éxito, en caso contrario 0.

Si usted necesita entender, el terminal hizo un rechazo en la orden de comercio o el servidor.

// Si se rechaza, vea el motivo.  
if (!OrderDelete(OrderTicket(), INT_MIN)) // https://www.mql5.com/ru/forum/93352/page12#comment_5290455
  Print(ToString(MT4ORDERS::LastTradeRequest) + // https://www.mql5.com/en/forum/203931#comment_5287237
        ToString(MT4ORDERS::LastTradeResult) +
        ToString(MT4ORDERS::LastTradeCheckResult));
 

Real. Utilizo MT4Orders, entorno virtual a través de Virtual, sincronizo virtual con real. Para ello, en cada tick paso varias veces por las órdenes abiertas en real. Para ello, en la primera pasada formo una lista de órdenes de interés, y en las otras pasadas trabajo con esta lista.

Antes tenía un código de este tipo:

long OrderTickets[];
for(int i=OrdersTotal()-1;i>=0;--i)
{
  if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    continue;
  AddToArray(OrderTickets,OrderTicket());
}
...
for(int i=ArraySize(OrderTickets)-1;i>=0;--i)
{
  if(!OrderSelect(OrderTickets[i],SELECT_BY_TICKET,MODE_TRADES))
    continue;
  do_something();
}

La práctica ha demostrado que no es una buena manera de hacerlo. Un limitador parcialmente lleno generará 2 órdenes con el mismo ticket, y en la segunda pasada será una desgracia.

Ahora he cambiado a este código

int Orders[];
for(int i=OrdersTotal()-1;i>=0;--i)
{
  if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    continue;
  AddToArray(Orders,i);
}
...
for(int i=0;i!=ArraySize(Orders);++i)
{
  if(!OrderSelect(Orders[i],SELECT_BY_POS,MODE_TRADES))
    continue;
  do_something();
}

Además, se hace una instantánea antes de trabajar. ¿Funcionará esto correctamente o puede surgir algo más?

 
traveller00 cada tick paso varias veces por las órdenes abiertas en real. Para ello, en la primera pasada formo una lista de órdenes de interés, y en otras pasadas trabajo con esta lista.

El código solía ser así:

La práctica ha demostrado que esta no es una buena forma de hacerlo. Un limitador parcialmente lleno generará 2 órdenes con el mismo ticket, y en la segunda pasada será una desgracia.

No habrá tristeza si lo hace de esta manera.

AddToArray(OrderTickets, (OrderType() <= OP_SELL) ? OrderTicket() : - OrderTicket());

Esta es una característica de MT4Orders. Sin embargo, SELECT_BY_TICKET no es un mecanismo rápido en MT4/5 y virtualización. Una de las razones es que si no encuentra entre los vivos, irá al historial (MODE_TRADES-flag es sólo una indicación de prioridad de dónde buscar primero).


Ahora he cambiado a este código

Además, se hace una instantánea antes de trabajar. ¿Funcionará esto correctamente o puede surgir algo más?

Aquí ya estamos hablando del complemento de Virtual.mqh. Por supuesto, las instantáneas acelerarán el trabajo muy bien si hay muchos personajes/magias que se intercambian.

Las instantáneas reducen al mínimo el trabajo con el entorno externo al Asesor Experto (API de trading). Es decir, las funciones más lentas se llaman una vez para la lectura inicial, y luego todo el trabajo con el entorno de trading va dentro del EA sin que el programador se dé cuenta, porque es el mismo estilo MT4.


Tiene sentido utilizar una de estas variantes de snapshot.

#define  VIRTUAL_SNAPSHOT_REFRESHTIME 1000 // Tiempo de vida de la instantánea para la actualización. En MT5 requiere conectado MT4Orders.mqh
#define  VIRTUAL_SNAPSHOT_WITHOUT_HISTORY // Descartar la instantánea del historial para mejorar el rendimiento
#include <fxsaber\Virtual\Virtual.mqh>

VIRTUAL::Snapshot(); // 1: один (_Symbol) символ, все мэджики.
VIRTUAL::Snapshot(VIRTUAL_SNAPSHOT_REFRESHTIME, MyMagic); // 2: один (_Symbol), один мэджик.
VIRTUAL::Snapshot(VIRTUAL_SNAPSHOT_REFRESHTIME, -1, false, ""); // 3: все символы и мэджики.


  1. Yo la uso. Puedo tener varios sub-OTCs (cada uno con su propio majic) en un EA monovalue. E incluso si hay varios Expert Advisors en un mismo símbolo, sigo viendo razonable utilizar esta opción. Es decir, una vez snapshot, y luego todos los sub-OTCs trabajan con el resultado.
  2. Si un Asesor Experto monodivisa trabaja con un solo majic, es la opción más rápida.
  3. Asesor Experto multidivisa, donde puede establecer un majic o todos los majics.


Puede llamar a VIRTUAL::Snapshot() mil veces seguidas, pero no interactuará con la API externa de trading más a menudo de lo establecido en VIRTUAL_SNAPSHOT_REFRESHTIME (en el ejemplo es un milisegundo - para mí es suficiente). Así que nada tiene que ser memorizado, el código más o menos se convierte en esto.

VIRTUAL::Snapshot();

for (uint i = OrdersTotal(); (bool)i--;)
{
  VIRTUAL::Snapshot();
  
  do_something();
}


Aquí está mi código de sincronización (llamado para cada subTS) con entornos virtuales.

  // Sincroniza VirtualPointerTo-environment basándose en las posiciones actual (seleccionada) y VirtualPointerOut (para cerrar).
  static bool SyncChannel( const string &Symb, const MAGIC_TYPE Magic, const double Lots,
                           const VIRTUAL_POINTER &VirtualPointerTo, const VIRTUAL_POINTER &VirtualPointerOut, const int FlagChange = false )
  {      
    // Necesario para el mecanismo IsNull.
    if (!VirtualPointerTo.GetHandle() || !VIRTUAL::GetHandle())
      _B2(VIRTUAL::Snapshot());    
    
    const bool IsNull = !OrdersTotal() && !_VP(VirtualPointerTo, OrdersTotal());
    bool Res = IsNull || !FlagChange || _B(SYNCCHANNEL::IsNotChange(true), 500);
  
    if (!IsNull)
    {
      Res &= SYNCCHANNEL::IsCloseBy(/*Symb*/.) && MACRO_ISCHANGE(SYNCCHANNEL::SyncCloseBy(Symb, Magic, VirtualPointerTo/*, (inMinLotCorrection <= 0)*/));
      
      Res &= MACRO_ISCHANGE(SYNCCHANNEL::SyncExistOrders(Symb, Magic, VirtualPointerTo, VirtualPointerOut));

      if (Lots && (inMinLotCorrection > Lots))
        ::Alert("inMinLotCorrection(" + (string)inMinLotCorrection + ") > Lots(" + (string)Lots + ")");
      
      Res &= MACRO_ISCHANGE(SYNCCHANNEL::SetNewLimit(Symb, Magic, Lots, OP_BUYLIMIT, VirtualPointerTo, inMinLotCorrection));
      Res &= MACRO_ISCHANGE(SYNCCHANNEL::SetNewLimit(Symb, Magic, Lots, OP_SELLLIMIT, VirtualPointerTo, inMinLotCorrection));
    }    

    return(Res);    
  }

Desde el resaltado, se puede ver la creación de la instantánea. Debe ser llamado después de las funciones de frenado. Por ejemplo, OrderSend. Si se llama una vez más, no es un gran problema, como se muestra en el código anterior.

Sin embargo, el código fuente se da por otra razón. Puse todas las funciones potencialmente lentas en una macro que detiene la sincronización completamente si un nuevo tick (SymbolInfoTick o CopyTicks) llega durante la sincronización, porque los nuevos ticks deben ser lanzados primero a través de todos los virtuales y sólo entonces sincronizados con el real. Todo es exactamente igual a como debería funcionar para los copiadores de operaciones y las bolsas de criptomonedas externas.

 
Atrapados OrderBug22 ¿Cuál puede ser el problema? RP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Line = 1537 NF 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Antes de MT4ORDERS::HistoryDealSelect(Result): DP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) MT4ORDERS::OrderSendBug = 22 CL 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Result.deal = 0
 
Sviatoslav Tyshchyk :HistoryDealSelect(Result): DP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) MT4ORDERS::OrderSendBug = 22 CL 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Result.deal = 0

No hay problema.

 
Esta técnica permite eliminar las órdenes pendientes del historial de operaciones.
int HistoryOrdersTotalTmp( void ) { return(-1); }

#define HistoryOrdersTotal HistoryOrdersTotalTmp
  #include <MT4Orders.mqh> // https://www.mql5.com/es/code/16006
#undef HistoryOrdersTotal
 
Line = 1773
Before ::HistoryOrderSelect(Result.order):
MT4ORDERS::OrderSendBug = 96
Result.deal = 0
Line = 1796
Before MT4ORDERS::HistoryDealSelect(Result):
MT4ORDERS::OrderSendBug = 96
Result.deal = 0
Alert: OrderSend(1505369998) - BUG!
Alert: Please send the logs to the coauthor - https://www.mql5.com/en/users/fxsaber
Alert: C:\Program Files\MetaTrader 5 5\MQL5\Logs\20240402.log

algún fallo

 
leonerd #:

algún fallo

Es normal.

 
Gracias por compartirlo.