Características del lenguaje mql5, sutilezas y técnicas - página 70

 

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

¿Cómo identificar una sustitución de la carta?

fxsaber, 2018.02.08 12:39

void OnTick()
{  
  const long Chart = ChartID();
  string PrevSymbol = _Symbol;
  ENUM_TIMEFRAMES PrevTF = _Period;
    
  while (!IsStopped())
  {
    if ((PrevSymbol != ChartSymbol(Chart)) || (PrevTF != ChartPeriod(Chart))) // ноль указывать НЕЛЬЗЯ!
    {      
      PrevSymbol = ChartSymbol(Chart);
      PrevTF = ChartPeriod(Chart);
      
      Alert(PrevSymbol + " " + EnumToString(PrevTF));      
    }
    
    Sleep(0);
  }
}

El parámetro de entrada ChartID a cero en algunas funciones no provoca el recálculo de los valores. Si quiere los datos reales del gráfico actual, debe utilizar el ID completo.

 

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

POSICIÓN_TICKET != POSICIÓN_IDENTIFICADOR

fxsaber, 2018.02.12 20:14

Conclusiones

Si asumimos que esto es un comportamiento normal de MT5 y no una peculiaridad del hack del broker, entonces

  • ORDER_STATE_PARTIAL no aparece en los pedidos históricos.
  • Las órdenes ejecutadas siempre tienen el estado ORDER_STATE_FILLED.
  • Cuando una orden se ejecuta parcialmente, el servidor comercial crea una nueva orden de mercado correspondiente (ORDER_REASON_CLIENT - incluso si la orden inicial se coloca automáticamente (EXPERT)).
  • La antigua orden en vivo (el ticket no se modifica) sigue pendiente con un volumen reducido (ORDER_VOLUME_CURRENT).
  • En este caso, la antigua orden viva tiene el estado ORDER_STATE_PARTIAL. En realidad, esta bandera es el resultado de la comparación de ORDER_VOLUME_CURRENT y ORDER_VOLUME_INITIAL.
  • Todas las posiciones abiertas reciben ID == OrderTicket. Donde OrderTicket es el ticket generado por el servidor comercial.
  • Una operación siempre tiene exactamente una orden histórica y su estado es ORDER_STATE_FILLED.
  • Cada orden histórica ejecutada tiene exactamente una operación.
  • El ORDER_VOLUME_INITIAL de cualquier orden ejecutada es igual al volumen para el que se ejecutó. Es decir, incluso la orden inicial que fue cancelada tiene un ORDER_VOLUME_INITITAL que es igual al volumen de la operación que generó.
  • La hora de la orden inicial (que fue parcialmente ejecutada) no cambia y no es igual a la hora de su negociación.
  • La tabla del historial está ordenada por la hora del pedido (ORDER_TIME_SETUP) pero no por la hora de la operación. Así que si hacemos HistorySelect desde DEAL_TIME, no podemos obtener la orden correspondiente en la tabla de historial.
  • HistorySelectByPosition siempre devuelve el conjunto necesario de ofertas/órdenes.
  • Puede calcular el deslizamiento para cualquier operación.

Puntos débiles

  • Faltan el ORDER_REASON_PARTIAL, el DEAL_REASON_PARTIAL y el POSITION_REASON_PARTIAL. Estos indicadores deben colocarse inmediatamente después de REASON_EXPERT en los respectivos listados.
  • Las órdenes de mercado correspondientes, al ejecutar parcialmente las órdenes limitadas, pueden, por su naturaleza, tener un deslizamiento negativo. Esto parece ser un error en el tipo de orden solamente y realmente no hay ninguna orden de mercado - sólo se crea dentro de MT5 y no sale al exterior.

ZZY Hipótesis totalmente confirmada.

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias de comercio

POSICIÓN_TICKET != POSICIÓN_IDENTIFICADOR

Pavel Kolchin, 2018.02.12 13:31

(no estoy seguro, es difícil de comprobar, es similar al cierre parcial de la posición)

Todo funciona así:

1) orden pendiente activada parcialmente - se abre la posición con Position_ID = Order_Ticket1

2) la orden restante se convierte en una nueva orden Order_Ticket2 y espera su ejecución; la nueva Order_Ticket2 != Order_Ticket1 ya que no puede haber 2 órdenes con la misma Order_Ticket en el historial

3) la orden restante ha sido ejecutada - se abre una posición con Position_ID = Order_Ticket2

hay dos órdenes en el historial, dos posiciones en el terminal, todo corresponde

 

Foro sobre comercio, sistemas de comercio automatizados y prueba de estrategias de comercio

Discussion on "LifeHack para trader: mezclando ForEach en defines (#define)"

fxsaber, 2018.02.14 10:54

Medición del rendimiento

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double GetAsk()
{
  static MqlTick tick = {0};
  
  return(SymbolInfoTick(Symbol(),tick) ? tick.ask : 0);
}

#define  AMOUNT 1 e6

void OnStart()
{
  double Sum = 0;
  
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += GetAsk())
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += SymbolInfoDouble(_Symbol, SYMBOL_ASK))
  
  Print(Sum);
}


Resultado

Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 78952
Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 162606

Estaba totalmente equivocado. SymbolInfoDouble es dos veces más lento que SymbolInfoTick.

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

Discussion on "LifeHack para trader: mezclando ForEach en defines (#define)"

fxsaber, 2018.02.14 11:58

Incompetente. Resultado de la prueba.

2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 87424
2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 83410

Cuando se necesita rendimiento (optimizador), es mejor utilizar SymbolInfoDouble. En el mundo real no hay ninguna diferencia.


La medición de la velocidad de la función ZZY debe medirse en un entorno en el que el rendimiento sea importante: el probador.

 

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

Bichos, errores, preguntas

fxsaber, 2018.02.12 23:10

Abrir una posición de COMPRA a mano en dos servidores de demostración de operaciones


RoboForex-MetaTrader 5

2018.02.13 00:02:08.424 '8520459': market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': accepted market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': deal #90389019 buy 1.00 GBPUSD at 1.38387 done (based on order #107426544)
2018.02.13 00:02:10.101 '8520459': order #107426544 buy 1.00 / 1.00 GBPUSD at 1.38387 done in 1683.949 ms


FXOpen-MT5

2018.02.13 00:00:25.780 '18000903': market buy 1.00 GBPUSD
2018.02.13 00:00:25.912 '18000903': accepted market buy 1.00 GBPUSD
2018.02.13 00:00:25.922 '18000903': market buy 1.00 GBPUSD placed for execution
2018.02.13 00:00:25.942 '18000903': order #896454 buy 1.00 / 1.00 GBPUSD at market done in 154.252 ms
2018.02.13 00:00:25.942 '18000903': deal #80559 buy 1.00 GBPUSD at 1.38387 done (based on order #896454)

Las líneas del mismo color indican lo mismo. Sin embargo, se ve claramente que están en distinto orden. En el caso de Robo, el mensaje sobre la ejecución de la orden llega después de que se ejecute la operación. ¡En abierto viene ANTES! Por esta razón OrderSend devuelve suerte, pero aún no hay transacción. Es decir, obtenemos un OrderSend no sincronizado con el historial

Código para FXOpen-MT5

#define  PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{
  MqlTradeRequest Request = {0};
  
  Request.action = TRADE_ACTION_DEAL;
  Request.symbol = _Symbol;
  Request.volume = 1;
  Request.type_filling = ORDER_FILLING_IOC;
  
  MqlTradeResult Result;
  
  PRINT(OrderSend(Request, Result));
  PRINT(Result.deal);
}


Resultado

OrderSend(Request,Result) = true
Result.deal = 0


Esta situación tiene la siguiente explicación

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

Bichos, errores, preguntas

Rashid Umarov, 2018.02.15 06:25

Si se envía una orden a un sistema comercial externo, el servidor comercial de MetaTrader 5 no espera la respuesta de éste y devuelve inmediatamente el resultado de la solicitud como "orden realizada". Por esta razón, OrderSend siempre devolverá deal=0, ya que todavía no hay información sobre la operación ejecutada. Cógelo en OnTrade o OnTradeTransaction.

Un ejemplo de escuchador de eventos de comercio se da en el artículo Dónde empezar cuando se crea un robot de comercio para MOEX - TradeTransactionListener.mq5

OrderSend - envía una orden para ejecutar una operación de mercado.La orden está colocada- tenemos que leer Result.order. Pero nadie espera el o los acuerdos - puede haber muchos y el tiempo total de su ejecución no está definido.

Depende de la implementación específica de la salida en el lado del corredor. En el caso general no está definido.

Por lo tanto, recomiendo encarecidamente utilizar la cuenta de demostración en FXOpen-MT5 como una prueba para su código, ya que se distingue de otras demos.


Por ejemplo, le sugiero que intente escribir un script en MQL5 con esta lógica de negociación (estilo MQL4 sólo para mostrar el sentido rápido)

void OnStart()
{
  OrderCloseBy(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0), OrderSend(_Symbol, OP_SELL, 1, Bid, 0, 0, 0));
}

No es nada fácil. También recomiendo el mencionado servidor de demostración para trabajar en la ejecución parcial.

 
fxsaber:
Se ha borrado un post que daba una explicación de uno de los errores más comunes en MT5.
No está entre los borrados. Eso es extraño. ¿Puede publicarlo de nuevo?
 
fxsaber:

El puesto era grande. No esperaba ser borrado. Me gustaría saber el motivo de la eliminación. Porque es masoquista que te borren de nuevo.

Te digo que no está entre los borrados. ¿Tal vez hubo un fallo?
 

Foro sobre comercio, sistemas de comercio automatizados y prueba de estrategias de comercio

Organizar un bucle de pedidos

fxsaber, 2018.02.16 09:40

Las cosas no van nada bien en MT5. Ejemplo que muestra el problema

// Пример неправильного считывания торгового окружения на каждом тике
// Скрипт эмулирует два тика ТС, которая должна открыть одну позицию, если ее нет.

#include <Trade/Trade.mqh>

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  // Этот MQL5-код с ошибкой
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;

/*
  // В MT4 такой код выполняется без ошибки
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

// Пример OnTick
void ExampleOnTick()
{
  static CTrade Trade;
  
  // Если нет позиции, открываем
  if (!GetAmountPositions(_Symbol))
    Trade.Buy(1);    
}

// Эмуляция прихода двух Tick-событий
void OnStart()
{
  ExampleOnTick(); 
  
  Sleep(10); // Между двумя тиками ~10 мс.
  
  ExampleOnTick();
}

¿Crees que si ejecutas este script en un símbolo sin posiciones, qué acabará pasando?

La respuesta correcta es que se abrirán uno o dos puestos.

La razón por la que esto ocurre. Después del primer OrderSend, aparece una orden de mercado y si un nuevo tick llega antes del momento de su ejecución, no hay posición todavía y se realiza el segundo OrderSend.

Debido a esto, un patrón aparentemente normal de MT5no funcionará correctamente y como consecuencia, la mayoría de los Asesores Expertos de MT5 en codobase. Al mismo tiempo, la plantilla casi idéntica de MT4 seguirá funcionando sin problemas.

La aparentemente buena idea de PositionsTotal se ve algo ensombrecida por la necesidad en MT5 de analizar también OrdersTotal para las órdenes de mercado.

¡Tenga cuidado!

 
fxsaber:

Debido a esto, un patrón MT5 aparentemente normalno funcionará correctamente y, como consecuencia, la mayoría de los EAs MT5 en el kodobase.

Como prueba de esta afirmación podemos tomar casi cualquier Asesor Experto en el kodobase de MT5. No busquemos algo, sino que tomemos directamente el EA más reciente del momento. Es bueno que haya sido escrito por un autor con gran experiencia en la publicación de MT5 en QB.

El código fuente tiene las siguientes cadenas (mis comentarios están resaltados)

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//....
   int total=0; // для расчета количества открытых советником позиций
//....
//--- main cycle
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            total++; // расчет количества открытых позиций
//....
   if(total==0) // Если нет открытых советником позиций
     {
      if(!RefreshRates())
        {
         PrevBars=iTime(1);
         return;
        }
      //--- open BUY 
      if(MACD_MAIN_2>MACD_SIGNAL_2 && MACD_MAIN_4<MACD_SIGNAL_4) // Сигнал на покупку
        {
         double sl=(InpStopLoss!=0)?m_symbol.Ask()-ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Ask()+ExtTakeProfit:0.0;
         OpenBuy(sl,tp); // Отправка маркет-ордера на покупку
         return;
        }
      //--- open SELL
      if(MACD_MAIN_2<MACD_SIGNAL_2 && MACD_MAIN_4>MACD_SIGNAL_4) // Сигнал на продажу
        {
         double sl=(InpStopLoss!=0)?m_symbol.Bid()+ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Bid()-ExtTakeProfit:0.0;
         OpenSell(sl,tp); // Отправка маркет-ордера на продажу
        }
     }
   return;
  }

Tenemos una situación idéntica a la descrita anteriormente.

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

Peculiaridades del lenguaje mql5, consejos y trucos

fxsaber, 2018.02.16 19:52

Después del primer OrderSend aparece una orden de mercado y si un nuevo tick llega antes de su ejecución entonces no hay posición todavía y se hace un segundo OrderSend.

La aparentemente buena idea de PositionsTotal se ve algo ensombrecida por la necesidad en MT5 de analizar también OrdersTotal para las órdenes de mercado.

Significa que en el caso general, en lugar de una posición el Asesor Experto abrirá dos, tres, etc. Dependiendo de la frecuencia de recepción de ticks y del tiempo de ejecución de las órdenes de mercado.


Dado que casi todos los EAs de MT5 en el kodobase están escritos con la misma lógica que la plantilla de MT5, también tienen el mismo error que contiene. Esto es cierto para casi todos los EAs de MT5 en KB, desafortunadamente.

MACD EA
MACD EA
  • votos: 4
  • 2018.02.15
  • Vladimir Karputov
  • www.mql5.com
При поступлении сигнала противоположная позиция закрывается. Также советник может закрывать половину позиции (параметр Profit for closing half of the position), может переводить позицию в безубыток (параметр Breakeven). Размер открываемой позиции может задавать вручную (параметр Lots) или в процентах риска от свободной маржи (параметр Risk in...
 

En una red puede haber una posición abierta y varias órdenes de mercado de cualquier dirección sobre el mismo símbolo al mismo tiempo. Por ejemplo, una posición de COMPRA y una orden de COMPRA. Es cierto, no he logrado encontrar una cuenta demo de este tipo, porque había una regla con asincronía en todas partes

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

Bichos, errores, preguntas

fxsaber, 2018.02.14 08:58

Toda la secuencia de eventos OnTradeTransaction viene después de que el OrderSend se haya completado.

EA

void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest&, const MqlTradeResult& )
{ 
  static bool FirstRun = true;  
  static ulong StartTime;
  
  if (FirstRun)
  {
    StartTime = GetMicrosecondCount();
    
    FirstRun = false;
  }

  Print(EnumToString(Trans.type));
  Print((GetMicrosecondCount() - StartTime) / 1000);    
}

Enviar manualmente una orden de comercio.

Registro

2018.02.14 09:41:46.671 '8854170': instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': accepted instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': deal #192088422 sell 1.00 EURUSD at 1.23673 done (based on order #208541700)
2018.02.14 09:41:46.853 '8854170': order #208541700 sell 1.00 / 1.00 EURUSD at 1.23673 done in 190.608 ms


Resultado del Asesor Experto

2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_ADD
2018.02.14 09:41:46.853 0
2018.02.14 09:41:46.853 TRADE_TRANSACTION_DEAL_ADD
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_DELETE
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_HISTORY_ADD
2018.02.14 09:41:46.853 2
2018.02.14 09:41:46.853 TRADE_TRANSACTION_REQUEST
2018.02.14 09:41:46.853 2


Podemos ver perfectamente en la columna de tiempo y en los datos numéricos del EA que la duración de la ejecución de la orden comercial no tiene ningún efecto en la secuencia de eventos OnTradeTransaction. ¡Toda la asincronía se va al infierno! Se las han arreglado para estropearlo todo. Construye 1755.

Por ejemplo, cuando se coloca la orden de mercado OrderSendAsync en el Terminal, la orden de mercado no aparecerá ni por un momento. Quizás los desarrolladores decidieron hacer esto para acelerar un poco las cosas.

 

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

Discusión sobre el artículo "Visualización de la optimización de la estrategia comercial en MetaTrader 5"

fxsaber, 2018.02.22 08:39

En el modo marco, OnInit, OnDeinit, OnTick, OnTrade, OnTradeTransaction y OnTimer se ignoran. Sólo funciona OnChartEvent.

Por supuesto, debido a la excepción OnChartEvent, requiere una comprobación obligatoria del indicador de modo de cuadro.