Bibliotecas: MT4Orders - página 33

 
// Lista de cambios:
// 08.02.2019
// Añadir: El comentario de posición se guarda cuando se cierra parcialmente mediante OrderClose.
// Si es necesario cambiar el comentario de una posición abierta al cierre parcial, se puede establecer en OrderClose.
 

Hay tareas que no se pueden resolver sólo con MQL4.

Pero el estilo MT4 y el estilo MT5 pueden utilizarse en paralelo. Aquí hay un ejemplo de tal combinación.

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

Procesamiento de transacciones OnTradeTransaction

fxsaber, 2019.02.08 12:37 pm.

Tarea

Las órdenes pendientes se colocan en Netting (pueden ser multidireccionales y cualquier número de cada tipo). Es necesario colocar su SL/TP en forma de órdenes pendientes Stop/Limit en cada activación de la orden pendiente original. En este caso las órdenes SL/TP deben ser dependientes: si una orden se dispara, la segunda se elimina. Las órdenes pendientes iniciales y SL/TP pueden activarse parcialmente. El Asesor Experto puede ser recargado en cualquier momento, incluyendo la transferencia a otro Terminal.


Solución

#include <MT4Orders.mqh> // https://www.mql5.com/es/code/16006

input int inTP = 100;
input int inSL = 200;
sinput MAGIC_TYPE inMagicNumber = 0;
sinput string inStrKey = "SLTP";

int GetAmountDeals()
{
  return(HistorySelect(0, INT_MAX) ? HistoryDealsTotal() : 0);
}

bool IsMyString( const string Str, const string Key )
{
  return(StringSubstr(Str, 0, StringLen(Key)) == Key);
}

string ToMyString( const string Str, const string Key )
{
  return(Key + Str);
}

struct ORDER
{
  int Type;
  TICKET_TYPE Ticket;
  double Lots;
  double OpenPrice;
  MAGIC_TYPE Magic;
  string Comment;
  
  ORDER() : Type(OrderType()), Ticket(OrderTicket()), Lots(OrderLots()),
            OpenPrice(OrderOpenPrice()), Magic(OrderMagicNumber()), Comment(OrderComment())
  {
  }
};

#define _CS(A) ((!::IsStopped()) && (A))

bool GetPairOrder()
{
  bool Res = false;

  ORDER Order;
  Order.Type = 6 - Order.Type + ((Order.Type & 1) << 1);
  
  for (int i = OrdersTotal() - 1; _CS((i >= 0) && (!Res)); i--)
    Res = OrderSelect(i, SELECT_BY_POS) && (OrderType() == Order.Type) &&
          (OrderMagicNumber() == Order.Magic) && (OrderComment() == Order.Comment);
    
  return(Res);
}

void CheckSLTP( const string Symb, const MAGIC_TYPE Magic, const string Key, const int Slip = 100 )
{    
  for (int i = OrdersTotal() - 1; _CS(i >= 0); i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() > OP_SELL)  &&
        (OrderMagicNumber() == Magic) && (OrderSymbol() == Symb) && IsMyString(OrderComment(), Key))
    {
      const ORDER Order;      
      
      if (!_CS(GetPairOrder()))
      {
        OrderDelete(Order.Ticket);
        
        i = OrdersTotal();
      }
      else if (_CS(OrderLots() < Order.Lots))
      {
        if (OrderDelete(Order.Ticket))
          OrderSend(OrderSymbol(), Order.Type, OrderLots(), Order.OpenPrice, Slip, 0, 0, Order.Comment, Order.Magic);
          
        i = OrdersTotal();          
      }
    }
}

void CheckFill( const string Symb, const MAGIC_TYPE Magic, const string Key, const int SL, const int TP )
{    
  static int PrevDeals = GetAmountDeals();
  
  const double point = SymbolInfoDouble(Symb, SYMBOL_POINT);
  const int NewDeals = GetAmountDeals();
  
  while (_CS(PrevDeals < NewDeals))
  {
    const ulong Ticket = HistoryDealGetTicket(PrevDeals);
    
    if (Ticket && (HistoryDealGetInteger(Ticket, DEAL_MAGIC) == Magic) &&
                  (HistoryDealGetString(Ticket, DEAL_SYMBOL) == Symb) &&
                  !IsMyString(HistoryDealGetString(Ticket, DEAL_COMMENT), Key))
    {
      const double Lots = HistoryDealGetDouble(Ticket, DEAL_VOLUME);
      const double Price = HistoryDealGetDouble(Ticket, DEAL_PRICE);
      const int Type = 1 - (int)HistoryDealGetInteger(Ticket, DEAL_TYPE);
      const double Koef = Type ? -point : point;
      const string Comment = ToMyString((string)Ticket, Key);
      
      if (OrderSend(Symb, Type + OP_BUYLIMIT, Lots, Price - Koef * TP, 0, 0, 0, Comment))
        OrderSend(Symb, Type + OP_BUYSTOP, Lots, Price + Koef * SL, 0, 0, 0, Comment);
    }
    
    PrevDeals++;
  }
}

void System()
{
  CheckFill(_Symbol, inMagicNumber, inStrKey, inSL, inTP);
  CheckSLTP(_Symbol, inMagicNumber, inStrKey);
}

void OnTrade()
{
  System();
}

void OnInit()
{
  OnTrade();
}
 

Foro sobre negociación, sistemas automatizados de negociación y ensayo de estrategias de negociación

Bibliotecas: MT4Orders

fxsaber, 2019.01.13 17:23 PM.

Las funciones de Kim bajo MT4 son bastante populares, así que descargué todas las fuentes de su sitio y escribí un simple "convertidor" para ellas bajo MT5.
#include <KimIVToMT5.mqh> // https://c.mql5.com/3/263/KimIVToMT5.mqh

#include "e-Trailing.mq4" // http://www.kimiv.ru/index.php?option=com_remository&Itemid=13&func=fileinfo&id=14

void OnTick() { start(); }

Resulta que el convertidor de Kim hace que algunos otros asesores de MT4 funcionen también bajo MT5

#include <KimIVToMT5.mqh> // https://c.mql5.com/3/263/KimIVToMT5.mqh

#include "Reaction.mq4"   // https://www.mql5.com/es/code/24609

void OnTick() { start(); }
 
// Lista de cambios:
// 20.02.2019
// Fix: Si no hay ninguna orden MT5 de una operación MT5 existente, la librería esperará a la sincronización del histórico. En caso de fallo se informará de ello.


Evitado este escollo en MT5

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

Nueva versión de MetaTrader 5 build 2005: Calendario económico, programas MQL5 como servicios y API para lenguaje R

fxsaber, 2019.02.20 21:06

Hola Servicios
// El script captura situaciones cuando una orden de transacción está ausente en el historial.

#define _CS(A) ((!::IsStopped()) && (A))
#define  TOSTRING(A) #A + " = " + (string)(A) + " "
#define  OFFSET 100

void OnStart()
{
  datetime PrevTime = OFFSET;
  
  while (_CS(true))
  {
    if (HistorySelect(PrevTime - OFFSET, INT_MAX))
    {
      const int Total = HistoryDealsTotal();
      
      for (int i = 0; _CS(i < Total); i++)
      {
        const ulong DealTicket = HistoryDealGetTicket(i);
        const ulong OrderTicket = HistoryDealGetInteger(DealTicket, DEAL_ORDER);        
        
        int Count = 0;
        const ulong StartTime = GetMicrosecondCount();
        
        while ((HistoryOrderGetInteger(OrderTicket, ORDER_TICKET) != OrderTicket) && !HistoryOrderSelect(OrderTicket)) // Si no hay orden de transacción
          Count++;
        
        if (Count)
          Alert(TOSTRING(DealTicket) + TOSTRING(OrderTicket) + TOSTRING(Count) + TOSTRING(GetMicrosecondCount() - StartTime)); // Imprimir la situación
        
        PrevTime = (datetime)HistoryDealGetInteger(DealTicket, DEAL_TIME);
      }
    }
    
    Sleep(0); // Sin esto, el Terminal se colgará instantáneamente.
  }
}


Si comentas Sleep, matarás instantáneamente el Terminal al ejecutarlo. Pero esto será por otra cosa.

Resulta que es fácil detectar una situación en la que falta una orden de trato en el historial: hay un trato, pero su orden no está.

El resultado del script en MQ-Demo

Alert: DealTicket = 336236873 OrderTicket = 356249474 Count = 1614408 GetMicrosecondCount()-StartTime = 229880 
Alert: DealTicket = 336236882 OrderTicket = 356249486 Count = 1565921 GetMicrosecondCount()-StartTime = 229998 
Alert: DealTicket = 336236887 OrderTicket = 356249492 Count = 1559345 GetMicrosecondCount()-StartTime = 229788 
Alert: DealTicket = 336236898 OrderTicket = 356249505 Count = 157107 GetMicrosecondCount()-StartTime = 22878 
Alert: DealTicket = 336236901 OrderTicket = 356249508 Count = 1544271 GetMicrosecondCount()-StartTime = 220879 

Se tarda más de 200 ms en esperar a que aparezca una orden en el historial. Durante todo este tiempo es imposible determinar, por ejemplo, el deslizamiento y la duración de la ejecución.

Imagínese una situación en la que necesite un Servicio que escriba en un archivo los datos de sólo las posiciones cerradas. Debido a esta "característica" es simplemente imposible hacerlo.


¿Estoy en lo cierto que esta característica arquitectónica de MT5 no puede ser corregida de ninguna manera?


Es dificil contar cuantas cosas de este tipo se tienen en cuenta en la libreria.

 
Andrey Khatimlianskii:

Sí, pero no puedes ver en qué están. Te lo enseñaré cuando lo haga.


Exacto. Los zips no están actualizados.

Cuando descargas los archivos uno a uno, se pierden las fechas de modificación. Tengo que navegar por tamaño, pero no todas las correcciones cambian el tamaño.

Aquí va una sugerencia:

Añade en la cabecera de CADA archivo la fecha de modificación, opcionalmente el número de versión, opcionalmente el historial de cambios.

Además de los archivos, publique su zip/rar, como hacen algunas personas.

 
bool IsTradeAllowed(void)
  {
   return(::MQLInfoInteger(::MQL_TRADE_ALLOWED));       // expresión no booleana
  }
 
Edgar:

La biblioteca está contenida en un solo archivo. Todo el resto es oropel alrededor, que no se ha actualizado desde hace mucho tiempo.

Sin embargo, también hay OrderSend_Test2.mq5 - es una prueba de estrés de MT5 y la biblioteca. Hace spams al servidor de trading para que corte el autotrading.

 

Lo sé. En este caso, sí. Pero 3 archivos han cambiado desde la última vez.

Me refiero a la metodología general que simplifica el versionado. Yo mismo siempre añado fecha a la cabecera mqh, fecha y versión a mq5.

E incluir mi archivo completo (para guardar las fechas de modificación) permitirá actualizar todo sin pensar.
 
Edgar:

Lo sé. En este caso, sí. Pero 3 archivos han cambiado desde la última vez.

Me refiero a la metodología general que simplifica el versionado. Yo mismo siempre añado fecha a la cabecera mqh, fecha y versión a mq5.

Me ofrecieron un análogo público ya-listo-para-el-trabajo-de-QB de github, donde todo esto está en modo automático. Pero la vejez no da alegrías: es complicado.

Tal vez para usted tal opción será adecuada.

Yo anuncio los cambios e incluso mantengo un sombrero sólo para MT4Orders, ya que no soy el único que lo utiliza.

En cuanto a otros trabajos, lo hago silenciosamente.

 

Me di cuenta de una peculiaridad tan interesante


Tengo un indicador de estadísticas (gratis) para mt4.

Decidí hacer uno para mt5.

La biblioteca es justo a tiempo! (Soy demasiado perezoso para escribir una biblioteca de este tipo a mí mismo).


Antes tenia una version para MT5, pero funcionaba con sus propios fallos.


He eliminado todo el código MQL5 - conectado MT4Orders biblioteca - y muestra tonterías en el arranque.


al mismo tiempo todo es normal en el historial:


y OrderPrint muestra todo correctamente (como en el historial).


Tengo operaciones seleccionadas por número de ticket (sistema complicado y confuso, yo mismo siempre me confundo y al cabo de un rato se me olvida como funciona :-)) )

aquí hay un trozo de código:

      if(SearchNextTicket(firsttimeticket,ticketREPORT,i,HistoryarrayNumber)==2)
        {
         firsttimeticket=MT45_OrderCloseTime();
        }
      ticketREPORT=MT45_OrderTicket();


La cuestión es que el siguiente ticket (para las estadísticas) se selecciona ordenando por hora de cierre, y si la hora es la misma, se selecciona por número de ticket.

por lo que en este caso muestra un sinsentido.


Pero si añado una cadena de impresión inofensiva:

 Print("1=== i="+i+" firsttimeticket="+firsttimeticket+" ticketREPORT="+ticketREPORT+" HistoryarrayNumber="+HistoryarrayNumber);
      if(SearchNextTicket(firsttimeticket,ticketREPORT,i,HistoryarrayNumber)==2)
        {
         firsttimeticket=MT45_OrderCloseTime();
        }
      ticketREPORT=MT45_OrderTicket();

entonces todo funciona.



¿Cuál es la magia de Print?


Esta impresión funciona bien:

       Print("1=== i="+i);


tal impresión ya no funciona normalmente.

       Print("1=== i=");