Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 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);
}
Applicazione
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);
}
Applicazione
Request.type_time = GetExpirationType(Request.symbol, (uint)Expiration); // Expiration может быть datetime-временем

if (Expiration > ORDER_TIME_DAY)
  Request.expiration = Expiration;
 
Conversione di strutture MqlTrade in stringhe
#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
Applicazione
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);
}

Applicazione

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

Le cose sono molto più semplici. Prima di inviare un ordine, ricordava la lunghezza della storia, e dopo averlo inviato, aspettava che la lunghezza della storia aumentasse. Si dovrebbe inserire un timeout, in modo che improvvisamente non si blocchi per sempre.

 
Dmitry Fedoseev:

Le cose sono molto più semplici. Prima di inviare un ordine, ricordava la lunghezza della storia, e dopo averlo inviato, aspettava che la lunghezza della storia aumentasse. Bisogna inserire un timeout, in modo che improvvisamente non si blocchi per sempre.

C'è un timeout. Nella tua variante, purtroppo, ci possono essere problemi se diversi OrderSend lavorano insieme (da diversi Expert Advisors).

Inoltre, non solo la storia non è sincronizzata, ma anche SL/TP di posizioni/ordini aperti, ecc. Per i mercati, la storia può aumentare prima solo con un ordine, e poi un attimo dopo con uno scambio. Ci sono anche altre situazioni. Ecco perché a prima vista sembra così ingombrante.

 
Dmitry Fedoseev:

Qual è lo scopo del suo messaggio? Viene in OnTradeTransaction(), e allora? Significa che dobbiamo aspettare l'evento. Devi ancora aspettare. L'essenza del messaggio di fxsaber è che dopo l'esecuzione di OrderSend(), le informazioni sull'azione eseguita non appariranno immediatamente nel terminale. Ad alcuni piace aspettare OnTradeTransaction(), mentre ad altri piace vedere un ordine o un affare nella lista. Ecco la differenza rispetto a MT4, come esempio. In M4, dopo OrderSend(), l'ordine è già nella lista degli ordini, e dopo OrderClose(), è sempre nella storia.

E perché aspettare OnTradeTransaction()? Fate una coda di richieste e se c'è una risposta, fate qualcosa... almeno cancellate la richiesta dalla coda. È un peccato che SB non abbia Queue, ma è una classe semplice.

 
fxsaber:

C'è un timeout. Nella tua versione, purtroppo, ci possono essere problemi se diversi OrderSend lavorano insieme (da diversi EA).

Inoltre, non solo la storia non è sincronizzata, ma anche SL/TP di posizioni/ordini aperti, ecc. Per i mercati, la storia può aumentare prima solo con un ordine, e poi un attimo dopo con uno scambio. Ci sono anche altre situazioni. Ecco perché sembra così ingombrante a prima vista.

Sì, sono d'accordo. Ma ho avuto solo un EA di questo tipo, e se non altro non ne verrà fuori nessun danno.

Sarebbe meglio scrivere una funzione separata per l'attesa, in modo da poter utilizzare anche la classe di trading standard.

 
Alexey Volchanskiy:

Perché aspettare OnTradeTransaction()? Fare una coda di richieste, se la risposta è arrivata, fare qualcosa... almeno rimuovere la richiesta dalla coda. È un peccato che SB non abbia Queue, ma è una classe semplice.

Il punto è che OnTradeTransaction() non si attiverà immediatamente dopo OrderSend.

In breve, qui c'è solo una folla di tifosi che litigano senza entrare nel merito della discussione.

Ci sono due varianti dell'algoritmo se qualcosa deve essere fatto immediatamente dopo OrderSend():

1. Possiamo avviare un ciclo in attesa degli aggiornamenti delle liste di ordini e offerte.

2. Termina OnTick() e aspetta che OnTradeTransaction() si attivi.

3. Controlla con un segno di spunta se un nuovo ordine o affare appare nella lista.

Motivazione: