Tiki en tiempo real - página 22

 
Andrey Khatimlianskii:

Mira la hora del registro. Todo esto ocurrió en un ms, y al lado (en el mismo ms) un montón de OnBooks.

Puedes contar todos los eventos mediante contadores, pero incluso visualmente puedes ver que hay más OnBooks.

Andrew, los números allí son microsegundos fijos, cuando OnFunctions se dispara, y todo se imprime juntos entonces de la matriz. Puede que haya más OnBooks en total - los contaré, pero no está claro por qué saltan por delante de los OnTicks en la cola. ¿O no todos los OnTick se corresponden con un OnBook?
 
prostotrader:


¿No has escrito que utilizas órdenes Async?
Me preguntaba, ¿qué algoritmo utilizan para controlar la ejecución de las operaciones?

 
Aleksey Mavrin:
Andrew, los números allí son microsegundos fijos cuando OnFunctions se dispara, y todo se imprime juntos entonces de la matriz. Los OnBooks en total pueden ser más - voy a contar, pero no está claro por qué saltan por delante de los OnTicks en la cola o qué. ¿O no todos los OnTick se corresponden con un OnBook?

bienvenido al mundo de la red ))))

Lo más fácil es ejecutarNetstat - a -b bajo el administrador.

Verás puertos y software, no quiero molestar, pero creo que el servidor de MT5 pasa asincrónicamente paquetes con diferente información que el terminal pone en los "estantes" necesarios.

HH: ¿Sabes lo de Print() y la omisión de impresiones si sacas muchas a la vez? - Sólo tienes que escribir tu información en el archivo, así lo guardarás todo y en orden, pero no te olvides de cerrar el archivo antes de cerrarlo. En teoría y Print() en los registros en el archivo debe ser completa, pero no han comprobado y en general no confío en si una gran cantidad de datos de salida. Se discute aquíhttps://www.mql5.com/ru/forum/329730, muy a menudo se discuten las "huellas perdidas" ))) - búsqueda

 
Aleksey Mavrin:
Andrew, los números son microsegundos fijos cuando se disparan las OnFunctions, y luego se imprimen todos juntos desde el array. Puede que haya más OnBooks en total - los contaré, pero no está claro por qué saltan por delante de los OnTicks en la cola. ¿O no todos los OnTick se corresponden con un OnBook?

Lo tengo.

De todos modos, hay muchos OnBooks por ahí. Es difícil sacar conclusiones con un registro así.

 
Roman:

Creí que habías escrito que utilizabas órdenes Async.
Me preguntaba, ¿qué algoritmo utilizan para controlar la ejecución de las operaciones?

En OnTradeTransaction()+ función de comprobación si no hay respuesta del servidor durante mucho tiempo.

Generalmente por arte de magia.

Reservo 65535 símbolos mágicos para cada símbolo al configurar un EA,

y al enviar una orden le asigno un número mágico único que no se cruza con otros símbolos de ninguna manera.

que no se solapa en absoluto con otros instrumentos.

Así es como establezco el número mágico inicial para un símbolo

//+------------------------------------------------------------------+
//|                                                    AutoMagic.mqh |
//|                                 Copyright 2017-2018 prostotrader |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//version   "1.01
ulong symb_magic;
//-------------------------------------------------------------------+
// Split string function                                             |
//+------------------------------------------------------------------+
string SplitString(const string a_str,ulong &a_month,ulong &a_year)
  {
   int str_size=StringLen(a_str);
   int str_tire=StringFind(a_str, "-");
   int str_tochka=StringFind(a_str, ".", str_tire);
   if((str_tire>0) && (str_tochka>0) &&(str_size > 0))
     {
      a_month= ulong(StringToInteger(StringSubstr(a_str,str_tire+1,str_tochka-str_tire-1)));
      a_year = ulong(StringToInteger(StringSubstr(a_str,str_tochka+1,str_size-str_tochka-1)));
      if((a_month > 0) && (a_year > 0)) return(StringSubstr(a_str, 0, str_tire));
     }
   return("");
  }
//-------------------------------------------------------------------+
// Get Magic function                                                |
//+------------------------------------------------------------------+
ulong GetMagic(const string a_symbol)
{
  symb_magic = 0;
  if(SymbolSelect(Symbol(), true) == false)
  {
    Print(__FUNCTION__, ": Нет такого символа!");
    return(0);
  }
  ulong month = 0;
  ulong year = 0;
  string new_str = SplitString(a_symbol,month,year);
  if(StringLen(new_str)>0)
  {
    uchar char_array[];
    int result=StringToCharArray(new_str,char_array,0,WHOLE_ARRAY,CP_ACP);
    if(result>0)
   {
     ulong value;
     for(int i = 0; i < result - 1; i++)
     {
       value=ulong(char_array[i]);
       value<<=(56 -(i*8));
       symb_magic += value;
     }
     month<<=24;
     symb_magic += month;
     year<<=16;
     symb_magic += year;
     return(symb_magic);
   }
 }
  return(0); 
}
//-------------------------------------------------------------------+
// Is my magic function                                              |
//+------------------------------------------------------------------+
bool IsMyMagic(const ulong m_magic)
{
  if(m_magic > 0)
  {
    ulong stored_magic=symb_magic;
    stored_magic>>=16;
    ulong in_magic = m_magic;
    in_magic>>=16;
    if(in_magic == stored_magic) return(true);
  }  
  return(false);
}
//-------------------------------------------------------------------+
// Get stored magic function                                         |
//+------------------------------------------------------------------+
ulong GetStoredMagic()
{
  if(symb_magic > 0) return(symb_magic);
  return(0);  
}
//+------------------------------------------------------------------+

Magia - ulong (8 bytes) por ejemplo

GAZR-3.12

Byte[7] (byte alto) es "G"

Byte[6] es "A"

Byte[5] para "Z"

El byte[4] es "R

Byte[3] es "3

Byte[2] es "12"

Byte[1] y Byte[0] son reserva de magos (65535)

Así es como paso por los magos al enviar un pedido:

  mem_magic = magic_storage + 1;
  if(magic_storage >= (magic_number + 65530)) mem_magic = magic_number;

Pero esto sólo funciona para FORTS, ya que los nombres de los símbolos están estandarizados.

Añadido

Si el pedido se envía con éxito, entonces

recuerda el tiempo

  if(OrderSendAsync(request, result) == true)
  {
    if((result.retcode == TRADE_RETCODE_PLACED) || (result.retcode == TRADE_RETCODE_DONE)) 
    {
      req_id = result.request_id;
      magic_storage = mem_magic;
      state = ORD_DO_SET;
      mem_time = GetMicrosecondCount();
      mem_start_time = TimeCurrent();
      SetTransCount();
    }
    else
    {
      mem_magic = 0;
      mem_time = 0;
      mem_start_time = 0;
      CheckError(result.retcode, "Place: Ордер не установлен! Причина: ", order_status, ticket);
    }
  }
mem_time = GetMicrosecondCount(); - для проверки времени задержки OnTradeTransaction
mem_start_time = TimeCurrent();   - для сужения рамок поиска в истории

Y luego (si no hay respuesta en OnTradeTransaction)

ticket = FindOrderBuyMagic(mem_magic, start_time);

Y luego la propia funciónFindOrderBuyMagic

#define  TIME_DELAY    180
//+------------------------------------------------------------------+
// Expert Find order Buy Magic function                              |
//+------------------------------------------------------------------+
ulong FindOrderBuyMagic(const ulong a_magic, const datetime set_time)
{
  if(a_magic > 0)
  {
    if(IsMyMagic(a_magic) == true)
    {
      ulong cur_ticket = 0;
      for(int i = OrdersTotal() - 1; i >= 0; i--)
      {
        cur_ticket = OrderGetTicket(i);
        if(OrderSelect(cur_ticket))
        {
          if( ulong(OrderGetInteger(ORDER_MAGIC)) == a_magic) return(cur_ticket);
        }  
     }
      cur_ticket = 0;
      datetime start_time = datetime(ulong(set_time) - TIME_DELAY);
      datetime end_time = datetime(ulong(TimeCurrent()) + TIME_DELAY);    
      if(HistorySelect(start_time, end_time))
      {
        for(int i = HistoryOrdersTotal() - 1; i >= 0; i--)
        {
          cur_ticket = HistoryOrderGetTicket(i);
          if(ulong(HistoryOrderGetInteger(cur_ticket, ORDER_MAGIC)) == a_magic) return(cur_ticket);
        }
      }
    }
  }
  return(0);
}

Añadido por

"Buena idea" añadir el identificador de EA (0-255) al 1er byte del autómata,

pero aún no lo necesito, así que no lo he hecho :)

Документация по MQL5: Основы языка / Функции / Функции обработки событий
Документация по MQL5: Основы языка / Функции / Функции обработки событий
  • www.mql5.com
В языке MQL5 предусмотрена обработка некоторых предопределенных событий. Функции для обработки этих событий должны быть определены в программе MQL5: имя функции, тип возвращаемого значения, состав параметров (если они есть) и их типы должны строго соответствовать описанию функции-обработчика события. Именно по типу возвращаемого значения и по...
 
prostotrader:

En OnTradeTransaction()+ función de comprobación si no hay respuesta del servidor durante mucho tiempo.

Gracias por el consejo.

 
prostotrader:

1. El segundo y los siguientes terminales del broker son de pago y no tengo estrategias en las que opere sólo con acciones(carteras de acciones).

2. Si va a emitir elGetMicrosecondCount() acumulado, entonces

hazlo sin temporizador en OnDeinit(), cuando el EA salga, todo se imprimirá.

Por favor, envíenme el enlace del corredor, es posible en la LC.

Esta es una rama interesante... :-)

 
Igor Makanu:

bienvenido al mundo de la red ))))

Lo más fácil es ejecutarNetstat - a -b bajo el administrador.

Verás puertos y software, no me quiero molestar, pero creo que el servidor de MT5 pasa asincrónicamente paquetes con diferente información que el terminal pone en los "estantes" necesarios.

SZZY: sobre Print() y la omisión de impresiones si se imprimen muchas a la vez, ¿lo sabes? - Sólo tienes que escribir tu información en el archivo, así lo guardarás todo y en orden, pero no te olvides de cerrar el archivo antes de cerrarlo. En teoría y Print() en los registros en el archivo debe ser completa, pero no han comprobado y en general no confío en si una gran cantidad de datos de salida. Se discute aquíhttps://www.mql5.com/ru/forum/329730, muy a menudo se discuten las "huellas perdidas" ))) - búsqueda

Igor, la pérdida de impresiones es discutida por aquellos que no han abierto el archivo de registro, cien veces y el propio Rinat Fatkullin escribió que no se pierde nada en el archivo de registro. Pero para tu post no fue en vano :) He añadido la salida en un archivo separado, además he hecho el segundo archivo, donde la salida un poco diferente (recogiendo todos los eventos en CArrayObj) para evitar posibles errores de mi diseño, que ordena dos matrices, es decir, pongo todo en CArrayObj de dos matrices, a continuación, ordenar por microsegundos y la salida con el marcado de lo que el evento Tick o Libro.

Y sí, ¿qué tiene que ver eso con los puertos, qué tiene que ver? Sólo estoy probando la cola de eventos de EA. Si se produce un tick, deben formarse dos eventos - OnTick, y el correspondiente OnBook, y OnBook siempre se pone en cola, y OnTick puede desaparecer si ya hay OnTick en la cola (como en manual), es decir . la situación cuando uno tras otro OnTick sin OnTick puede ser sólo si 1. los OnTicks van "sin cola" 2. hay un retraso del sistema de OnBook, esto es lo que quiero comprobar, esto puede explicar el retraso de segundos, previamente identificado por los colegas. Si este retraso se debe a los paquetes asíncronos y al análisis sintáctico, tal vez, pero hasta ahora sólo compruebo el hecho de su ingreso en el EA. Cómo hacer la prueba teniendo en cuenta el resto de los matices, aún no lo he pensado.

Aquí está el nuevo código, en la apertura voy a probar la corrección del trabajo y ejecutar para el día.

s.w. La razón también puede ser: si Tick pasó a los mismos precios sin cambiar la copa - OnBook no se forma? No soy un especialista en el comercio de acciones, que me puede decir. Pensaba que OnTick siempre provoca OnBook.

//+------------------------------------------------------------------+
//|                                                   TestOnBook.mq5 |
//|                                           Copyright 2019, Allex@ |
//|                                                 alex-all@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Allex@"
#property link      "alex-all@mail.ru"
#property version   "1.00"
#include <Allex\Logger.mqh>
#include <Arrays\ArrayObj.mqh>
//---
bool is_book;
enum ENUM_BOOK_OR_TICK
{
        USE_BOOK,       // Use OnBookEvent
        USE_TICK        // Use OnTick
};
class CMcsOn: public CObject
{
public:
ulong mcs;
ENUM_BOOK_OR_TICK Ontype;
CMcsOn(ulong m, ENUM_BOOK_OR_TICK t):mcs(m),Ontype(t){};
int       Compare(const CObject*Object,const int mode=0) const
     {
      const CMcsOn* obj1=dynamic_cast<const CMcsOn*>(Object);
      CMcsOn* obj=(CMcsOn*)(obj1);
      if(!obj)return 0;
      return (mcs-obj.mcs);
      }
};
input ENUM_BOOK_OR_TICK Mode = USE_BOOK;
input int   SecForPrint =  3600;
//---
ulong TimeArrayBook[65536];
ulong TimeArrayTick[65536];
ushort curBook,curTick;
ulong  DelaySum=0,DelayCount=0,CountOnBook=0,CountOnTick=0;
int delay,delayMax=0;
CLogger* Logger,*Logger2;
CArrayObj ArrayObj;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   curBook=0;
   curTick=0; 
   DelaySum=0;DelayCount=0;CountOnBook=0;CountOnTick=0;delayMax=0;
   ArrayInitialize(TimeArrayBook,INT_MAX);
   ArrayInitialize(TimeArrayTick,INT_MAX);
   Logger=CLogger::GetLogger();
   Logger2= new CLogger();
   Logger.SetSetting(__FILE__+"\\",Symbol()+"_"+EnumToString(Period())+"_"+TimeToString(TimeCurrent(),TIME_DATE));  
   Logger2.SetSetting(__FILE__+"\\","Alt_"+Symbol()+"_"+EnumToString(Period())+"_"+TimeToString(TimeCurrent(),TIME_DATE));  
  if(Mode == USE_BOOK) is_book = MarketBookAdd(Symbol());
  ArrayObj.Shutdown();
  if (EventSetTimer(SecForPrint) &&  Logger.Init() && Logger2.Init()) 
  return(INIT_SUCCEEDED);
  else return (INIT_FAILED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  if(Mode == USE_BOOK)
  {
    if(is_book == true) MarketBookRelease(Symbol());
  }  
   delete Logger;
   delete Logger2;
}
//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{  
  TimeArrayBook[curBook++]=GetMicrosecondCount();
  CountOnBook++;
  //Print(__FUNCTION__, " ",curBook);
}
void OnTick()
{
  TimeArrayTick[curTick++]=GetMicrosecondCount();
  CountOnTick++;
  //Print(__FUNCTION__, " ",curTick);

}
//+------------------------------------------------------------------+
void OnTimer()
  {
   string out=NULL;
   int total=MathMax(curBook,curTick);
   int i=0,k=0;
   while(i<total)
     {
      while(i<total && TimeArrayBook[i]<TimeArrayTick[k] )
        {
          MyPrint("Book "+TimeArrayBook[i++]);
        }    
      if(k<curTick-1)
        {
        if(i<total)
          {
           delay=TimeArrayBook[i]-TimeArrayTick[k];
           if (delay>delayMax) 
            delayMax=delay;
           if (delay>0)
              {
                 DelaySum+=delay;
                 DelayCount++;
              }
          }
         MyPrint("Tick "+TimeArrayTick[k++]+ " delay mcs "+delay);
        }       
        i++;
     }
     if (curTick>0)
     {
     MyPrint("Tick "+TimeArrayTick[curTick-1]+ " last");
     string out="Count Event Book after Tick "+DelayCount+". Delay Average "+DoubleToString(DelaySum/DelayCount,2)+". Max "+delayMax+" OnBooks "+CountOnBook+" OnTicks "+CountOnTick;
     MyPrint (out);
     Comment(out);
     }
     Logger.Logger();
     Alt();
     curBook=0;
     curTick=0;
  }
//---
void MyPrint(string out)  
{
   Print(out);
   Logger.Log(__FUNCTION__,out,2,false);
}
//---
void Alt()
{
int last=ArrayObj.Total();
for(int i=0;i<curBook;i++)
  {
   if (!ArrayObj.Add(new CMcsOn(TimeArrayBook[i],USE_BOOK)))
      Logger2.Log(__FUNCTION__,"Error Book Add",0);   
  }
for(int i=0;i<curTick;i++)
  {
   if (!ArrayObj.Add(new CMcsOn(TimeArrayTick[i],USE_TICK)))
      Logger2.Log(__FUNCTION__,"Error Tick Add",0);   
  }
  ArrayObj.Sort();
  int total=ArrayObj.Total();
  total-=last;
  CMcsOn*Obj;
  for(int i=0;i<total;i++)
    {    
     Obj=ArrayObj.At(i);
     if(CheckPointer(Obj)==POINTER_INVALID )
      { Logger2.Log(__FUNCTION__,"Error At Array",0); continue;}
      string out = Obj.USE_BOOK ? "Book ": "Tick ";
      out+= Obj.mcs  ;
      Logger2.Log(__FUNCTION__,out,2);
    }
   Logger2.Log("ArrayObj_","Last "+last+" total "+ArrayObj.Total(),1);  
   Logger2.Logger();
   //ArrayObj.Shutdown(); 
}
 
prostotrader:
Pero me pregunto si el responsable está satisfecho con las respuestas a su pregunta.

Ya he recibido todas las respuestas y he sacado mis propias conclusiones.
Necesito analizar la tira de operaciones durante un periodo de tiempo determinado: precios de las operaciones, volúmenes realizados, etc.
También necesito simular el funcionamiento del algoritmo en el probador de estrategias.
El evento OnTick se adapta perfectamente a esto, los resultados de las operaciones reales y los resultados del modelado en el probador coinciden con un pequeño error para mi satisfacción.
Si necesita un análisis más rápido de la tira, puede utilizar OnTimer.

Y no es necesario que cada tick que llegue al terminal se coloque en OnBook - esto es lo específico de la ejecución de órdenes de mercado.

 
Vladimir Mikhailov:


Y cada tic que entra en el terminal no tiene por qué entrar en OnBook: son las particularidades de la ejecución de órdenes de mercado.

Por el contrario, cada tick(evento) que llega al manejador OnTick debe ser sincronizado con OnBook.
Hay tres eventos en el manejador OnTick, el cambio de precio de la mejor oferta, el cambio de precio de la mejor demanda, y la operación (última).
Si el precio de compra o venta cambia sin que haya una operación, esto será un evento y OnTick recibirá estos eventos.
Y OnBook también tiene que atrapar estos eventos, pero sus propios eventos, su manejador, de lo contrario habrá un desajuste de precios de oferta y demanda entre los manejadores.

Y si OnTick recibe un último evento, significa que una operación ha pasado.
La operación genera el evento en OnTick, porque después de la operación el precio o el volumen de las ofertas y demandas a cambiar en el mercado.
Es un círculo vicioso.

Tanto en OnTick como en OnBook, existe un evento de Mejor Oferta y Mejor Demanda.
Estos eventos deben ser siempre sincrónicos en ambos manejadores.
Y el evento dura por sí mismo, genera un evento en OnBook después de la operación.
Por lo tanto, cualquier evento que llegue al manejador OnTick debe reflejarse sincrónicamente en OnBook.