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

 
// Возвращает тип исполнения ордера, равный Type, если он доступен на символе Symb, иначе - корректный вариант.
ENUM_ORDER_TYPE_FILLING GetFilling( const string Symb, const uint Type = ORDER_FILLING_FOK )
{
  const ENUM_SYMBOL_TRADE_EXECUTION ExeMode = (ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(Symb, SYMBOL_TRADE_EXEMODE);
  const int FillingMode = (int)::SymbolInfoInteger(Symb, SYMBOL_FILLING_MODE);

  return((FillingMode == 0 || (Type >= ORDER_FILLING_RETURN) || ((FillingMode & (Type + 1)) != Type + 1)) ?
         (((ExeMode == SYMBOL_TRADE_EXECUTION_EXCHANGE) || (ExeMode == SYMBOL_TRADE_EXECUTION_INSTANT)) ?
           ORDER_FILLING_RETURN : ((FillingMode == SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) :
          (ENUM_ORDER_TYPE_FILLING)Type);
}
Aplicación
Request.type_filling = GetFilling(Request.symbol);
 
// Возвращает тип истечения ордера, равный Expiration, если он доступен на символе Symb, иначе - корректный вариант.
ENUM_ORDER_TYPE_TIME GetExpirationType( const string Symb, uint Expiration = ORDER_TIME_GTC )
{
  const int ExpirationMode = (int)::SymbolInfoInteger(Symb, SYMBOL_EXPIRATION_MODE);

  if ((Expiration > ORDER_TIME_SPECIFIED_DAY) || (((ExpirationMode >> Expiration) & 1) == 0))
  {
    if ((Expiration < ORDER_TIME_SPECIFIED) || (ExpirationMode < SYMBOL_EXPIRATION_SPECIFIED))
      Expiration = ORDER_TIME_GTC;
    else if (Expiration > ORDER_TIME_DAY)
      Expiration = ORDER_TIME_SPECIFIED;

    uint i = 1 << Expiration;

    while ((Expiration <= ORDER_TIME_SPECIFIED_DAY) && ((ExpirationMode & i) != i))
    {
      i <<= 1;
      Expiration++;
    }
  }

  return((ENUM_ORDER_TYPE_TIME)Expiration);
}
Aplicación
Request.type_time = GetExpirationType(Request.symbol, (uint)Expiration); // Expiration может быть datetime-временем

if (Expiration > ORDER_TIME_DAY)
  Request.expiration = Expiration;
 
Conversión de estructuras MqlTrade en cadena
#define TOSTRING(A)  #A + " = " + (string)(A) + "\n"
#define TOSTRING2(A) #A + " = " + EnumToString(A) + " (" + (string)(A) + ")\n"

string ToString( const MqlTradeTransaction &Trans )
{
  return(TOSTRING(Trans.deal) + TOSTRING(Trans.order) + TOSTRING(Trans.symbol) +
         TOSTRING2(Trans.type) + TOSTRING2(Trans.order_type) + TOSTRING2(Trans.order_state) +
         TOSTRING2(Trans.deal_type) + TOSTRING2(Trans.time_type) +
         TOSTRING(Trans.time_expiration) + TOSTRING(Trans.price) + TOSTRING(Trans.price_trigger) +
         TOSTRING(Trans.price_sl) + TOSTRING(Trans.price_tp) + TOSTRING(Trans.volume) +
         TOSTRING(Trans.position) + TOSTRING(Trans.position_by));
}

string ToString( const MqlTradeRequest &Request )
{
  return(TOSTRING2(Request.action) + TOSTRING(Request.magic) + TOSTRING(Request.order) +
         TOSTRING(Request.symbol) + TOSTRING(Request.volume) + TOSTRING(Request.price) +
         TOSTRING(Request.stoplimit) + TOSTRING(Request.sl) +  TOSTRING(Request.tp) +
         TOSTRING(Request.deviation) + TOSTRING2(Request.type) + TOSTRING2(Request.type_filling) +
         TOSTRING2(Request.type_time) + TOSTRING(Request.expiration) + TOSTRING(Request.comment) +
         TOSTRING(Request.position) + TOSTRING(Request.position_by));
}

string ToString( const MqlTradeResult &Result )
{
  return(TOSTRING(Result.retcode) + TOSTRING(Result.deal) + TOSTRING(Result.order) +
         TOSTRING(Result.volume) + TOSTRING(Result.price) + TOSTRING(Result.bid) +  
         TOSTRING(Result.ask) + TOSTRING(Result.comment) + TOSTRING(Result.request_id) +  
         TOSTRING(Result.retcode_external));
}

#undef TOSTRING
#undef TOSTRING2
Aplicación
void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest &Request, const MqlTradeResult &Result )
{
  Print(ToString(Trans) + ToString(Request) + ToString(Result));
}
 
// Триггер срабатывания SL/TP - работает только на демо/реале (не в тестере).
void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest &Request, const MqlTradeResult &Result )
{
  if ((Trans.type == TRADE_TRANSACTION_ORDER_ADD) &&
       PositionSelectByTicket(Trans.position) && OrderSelect(Trans.order) &&
       (PositionGetInteger(POSITION_TYPE) == 1 - OrderGetInteger(ORDER_TYPE)))
  {
    const double Price = OrderGetDouble(ORDER_PRICE_OPEN);
    
    if (Price == PositionGetDouble(POSITION_TP))
      Print("Position #" + (string)Trans.position + " - triggered TP.");    
    else if (Price == PositionGetDouble(POSITION_SL))
      Print("Position #" + (string)Trans.position + " - triggered SL.");    
  }
}
 
ENUM_DAY_OF_WEEK GetDayOfWeek( const datetime time )
{
  MqlDateTime sTime = {0};

  ::TimeToStruct(time, sTime);

  return((ENUM_DAY_OF_WEEK)sTime.day_of_week);
}

// true - находимся в торговой сессии
bool SessionTrade( const string Symb )
{
  datetime TimeNow = ::TimeTradeServer();

  const ENUM_DAY_OF_WEEK DayOfWeek = GetDayOfWeek(TimeNow);

  TimeNow %= 24 * 60 * 60;

  bool Res = false;
  datetime From, To;

  for (int i = 0; (!Res) && ::SymbolInfoSessionTrade(Symb, DayOfWeek, i, From, To); i++)
    Res = ((From <= TimeNow) && (TimeNow < To));

  return(Res);
}

// Возвращает true, если символ торгуемый. Иначе - false.
bool SymbolTrade( const string Symb )
{
  MqlTick Tick;

  return(::SymbolInfoTick(Symb, Tick) ? ((Tick.bid != 0) && (Tick.ask != 0) && SessionTrade(Symb) /* &&
         ((ENUM_SYMBOL_TRADE_MODE)::SymbolInfoInteger(Symb, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_FULL) */
) : false);
}

Aplicación

if (OrderCheck(Request, CheckResult) && SymbolTrade(Request.symbol))
  OrderSend(Request, Result);
 

Las cosas son mucho más sencillas. Antes de enviar una orden, recordaba la longitud del historial, y después de enviarla, esperaba a que la longitud del historial aumentara. Hay que introducir un tiempo de espera, para que de repente no se quede atascado para siempre.

 
Dmitry Fedoseev:

Las cosas son mucho más sencillas. Antes de enviar una orden, recordaba la longitud del historial, y después de enviarla, esperaba a que la longitud del historial aumentara. Hay que introducir un tiempo de espera, para que de repente no se quede atascado para siempre.

Hay un tiempo de espera. En su variante, lamentablemente, puede haber problemas si varios OrderSends trabajan juntos (desde diferentes Expert Advisors).

Además, no sólo el historial no está sincronizado, sino también el SL/TP de las posiciones/órdenes abiertas, etc. En el caso de los mercados, el historial puede aumentar primero sólo por una orden, y un momento después por una operación. También hay otras situaciones. Por eso parece tan engorroso a primera vista.

 
Dmitry Fedoseev:

¿Cuál es el objetivo de su mensaje? Si se produce en OnTradeTransaction(), ¿qué significa eso? Significa que tenemos que esperar el evento. Todavía tienes que esperar. La esencia del mensaje de fxsaber es que después de ejecutar OrderSend(), la información sobre la acción realizada no aparecerá inmediatamente en el terminal. A algunos les gusta esperar a OnTradeTransaction(), mientras que a otros les gusta ver una orden o una transacción en la lista. Esta es la diferencia con respecto a MT4, como ejemplo. En M4, después de OrderSend(), la orden ya está en la lista de órdenes, y después de OrderClose(), siempre está en el historial.

¿Y por qué esperar a OnTradeTransaction()? Haz una cola de peticiones y si hay una respuesta, haz algo... al menos borra la petición de la cola. Es una pena que SB no tenga Queue, pero es una clase sencilla.

 
fxsaber:

Hay un tiempo de espera. En su versión, desafortunadamente, puede haber problemas si varios OrderSends trabajan juntos (desde diferentes EAs).

Además, no sólo el historial no está sincronizado, sino también el SL/TP de las posiciones/órdenes abiertas, etc. En el caso de los marcadores, el historial puede aumentar primero sólo por una orden, y un momento después por una operación. También hay otras situaciones. Por eso parece tan engorroso a primera vista.

Sí, estoy de acuerdo. Pero sólo he tenido un EA de este tipo, y si acaso no se produce ningún daño.

Sería mejor escribir una función separada para la espera, de modo que la clase de comercio estándar pudiera utilizarse también.

 
Alexey Volchanskiy:

¿Por qué esperar a OnTradeTransaction()? Haz una cola de peticiones, si la respuesta llega, haz algo... al menos elimina la petición de la cola. Es una pena que SB no tenga Cola, pero es una clase sencilla.

La cuestión es que OnTradeTransaction() no se activará inmediatamente después de OrderSend.

En resumen, aquí sólo hay una multitud de aficionados que discuten sin entrar en el tema de la discusión.

Hay dos variantes del algoritmo si hay que hacer algo inmediatamente después de OrderSend():

1. Podemos iniciar un bucle a la espera de las actualizaciones de las listas de pedidos y ofertas.

2. Finaliza OnTick() y espera a que se active OnTradeTransaction().

3. Compruebe por medio de una marca si aparece un nuevo pedido o acuerdo en la lista.

Razón de la queja: