Caractéristiques du langage mql5, subtilités et techniques - page 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);
}
Application
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);
}
Application
Request.type_time = GetExpirationType(Request.symbol, (uint)Expiration); // Expiration может быть datetime-временем

if (Expiration > ORDER_TIME_DAY)
  Request.expiration = Expiration;
 
Conversion des structures MqlTrade en chaîne de caractères
#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
Application
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);
}

Application

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

Les choses sont beaucoup plus simples. Avant d'envoyer un ordre, on se souvient de la longueur de l'historique, et après l'avoir envoyé, on attend que la longueur de l'historique augmente. Il convient d'introduire un délai d'attente, afin que l'opération ne reste pas bloquée pour toujours.

 
Dmitry Fedoseev:

Les choses sont beaucoup plus simples. Avant d'envoyer un ordre, on se souvient de la longueur de l'historique, et après l'avoir envoyé, on attend que la longueur de l'historique augmente. Un délai d'attente doit être saisi, afin d'éviter que l'opération ne reste bloquée pour toujours.

Il y a un délai d'attente. Dans votre variante, malheureusement, il peut y avoir des problèmes si plusieurs OrderSends fonctionnent ensemble (à partir de différents Expert Advisors).

En outre, non seulement l'historique n'est pas synchronisé, mais aussi les SL/TP des positions/ordres ouverts, etc. Pour les marchés, l'historique peut s'accroître d'abord seulement par un ordre, puis un instant plus tard par une transaction. Il existe également d'autres situations. C'est pourquoi il semble si encombrant à première vue.

 
Dmitry Fedoseev:

Quel est le but de votre message ? Il arrive dans OnTradeTransaction(), et alors ? Ça veut dire qu'on doit attendre l'événement. Vous devez encore attendre. L'essence du message de fxsaber est qu'après l'exécution de OrderSend(), les informations concernant l'action effectuée n'apparaîtront pas immédiatement dans le terminal. Certaines personnes aiment attendre la fonction OnTradeTransaction(), tandis que d'autres aiment voir un ordre ou une transaction dans la liste. Voici la différence avec MT4, à titre d'exemple. Dans M4, après OrderSend(), l'ordre est déjà dans la liste des ordres, et après OrderClose(), il est toujours dans l'historique.

Et pourquoi attendre OnTradeTransaction()? Faites une file d'attente des demandes et s'il y a une réponse, faites quelque chose... au moins supprimez la demande de la file d'attente. C'est dommage que SB n'ait pas de Queue, mais c'est une classe simple.

 
fxsaber:

Il y a un délai d'attente. Dans votre version, malheureusement, il peut y avoir des problèmes si plusieurs OrderSends fonctionnent ensemble (à partir de différents EAs).

En outre, non seulement l'historique n'est pas synchronisé, mais aussi les SL/TP des positions/ordres ouverts, etc. Pour les marchés, l'historique peut augmenter d'abord seulement par un ordre, puis un instant plus tard par une transaction. Il existe également d'autres situations. C'est pourquoi il semble si lourd à première vue.

Oui, je suis d'accord. Mais je n'ai eu qu'une seule évaluation environnementale de ce type, et il n'y aura aucun mal à cela.

Il serait préférable d'écrire une fonction distincte pour l'attente, de sorte que la classe de négociation standard puisse également être utilisée.

 
Alexey Volchanskiy:

Pourquoi attendre OnTradeTransaction()? Faites une file d'attente de demandes, si la réponse est venue, faites quelque chose... au moins retirez la demande de la file d'attente. C'est dommage que SB n'ait pas de Queue, mais c'est une classe simple.

Le fait est que OnTradeTransaction() ne se déclenchera pas immédiatement après OrderSend.

En bref, il y a juste une foule de fans qui se disputent ici sans entrer dans le sujet de la dispute.

Il existe deux variantes de l'algorithme si quelque chose doit être fait immédiatement après OrderSend() :

1. Nous pouvons démarrer une boucle en attendant les mises à jour des listes de commandes et d'offres.

2. Terminez OnTick() et attendez le déclenchement de OnTradeTransaction().

3. Vérifiez par cochage si une nouvelle commande ou une nouvelle affaire apparaît dans la liste.

Raison: