Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 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);
}
Anmeldung
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);
}
Anmeldung
Request.type_time = GetExpirationType(Request.symbol, (uint)Expiration); // Expiration может быть datetime-временем

if (Expiration > ORDER_TIME_DAY)
  Request.expiration = Expiration;
 
Umwandlung von MqlTrade-Strukturen in Strings
#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
Anmeldung
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);
}

Anmeldung

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

Die Dinge sind viel einfacher. Vor dem Absenden einer Bestellung wird die Länge des Verlaufs gespeichert, und nach dem Absenden wird gewartet, bis die Länge des Verlaufs zunimmt. Es sollte ein Timeout eingegeben werden, damit es nicht plötzlich für immer hängen bleibt.

 
Dmitry Fedoseev:

Die Dinge sind viel einfacher. Vor dem Absenden einer Bestellung wird die Länge des Verlaufs gespeichert, und nach dem Absenden wird gewartet, bis die Länge des Verlaufs zunimmt. Es muss ein Timeout eingegeben werden, damit es nicht plötzlich für immer hängen bleibt.

Es gibt eine Zeitüberschreitung. Bei Ihrer Variante kann es leider zu Problemen kommen, wenn mehrere OrderSends zusammenarbeiten (von verschiedenen Expert Advisors).

Außerdem wird nicht nur die Historie nicht synchronisiert, sondern auch SL/TP von offenen Positionen/Ordern usw. Bei Märkten kann die Historie zunächst nur durch einen Auftrag und einen Moment später durch einen Handel zunehmen. Es gibt aber auch andere Situationen. Deshalb sieht es auf den ersten Blick so umständlich aus.

 
Dmitry Fedoseev:

Was ist der Sinn Ihrer Botschaft? Es kommt also in OnTradeTransaction(), na und? Es bedeutet, dass wir auf das Ereignis warten müssen. Sie müssen noch warten. Der Kern der Nachricht von fxsaber ist, dass nach der Ausführung von OrderSend() die Informationen über die durchgeführte Aktion nicht sofort im Terminal erscheinen. Manche Leute warten gerne auf OnTradeTransaction(), während andere gerne einen Auftrag oder ein Geschäft in der Liste sehen möchten. Hier ist der Unterschied zu MT4, als Beispiel. In M4 befindet sich der Auftrag nach OrderSend() bereits in der Liste der Aufträge und nach OrderClose() immer in der Historie.

Und warum auf OnTradeTransaction() warten? Erstellen Sie eine Warteschlange von Anfragen, und wenn es eine Antwort gibt, tun Sie etwas... löschen Sie zumindest die Anfrage aus der Warteschlange. Es ist schade, dass SB keine Warteschlange hat, aber es ist eine einfache Klasse.

 
fxsaber:

Es gibt eine Zeitüberschreitung. In Ihrer Version kann es leider zu Problemen kommen, wenn mehrere OrderSends zusammenarbeiten (von verschiedenen EAs).

Außerdem ist nicht nur die Historie nicht synchronisiert, sondern auch SL/TP von offenen Positionen/Ordern usw. Bei Märkten kann die Historie zunächst nur durch einen Auftrag und einen Moment später durch einen Handel zunehmen. Es gibt aber auch andere Situationen. Deshalb sieht es auf den ersten Blick so umständlich aus.

Ja, ich stimme zu. Aber ich habe nur einen solchen EA gehabt, und wenn überhaupt, dann ist das nicht schlimm.

Es wäre besser, eine separate Funktion für das Warten zu schreiben, so dass die Standard-Handelsklasse ebenfalls verwendet werden kann.

 
Alexey Volchanskiy:

Warum auf OnTradeTransaction() warten? Erstellen Sie eine Warteschlange von Anfragen, und wenn die Antwort kommt, tun Sie etwas... entfernen Sie zumindest die Anfrage aus der Warteschlange. Es ist schade, dass SB keine Warteschlange hat, aber es ist eine einfache Klasse.

Der Punkt ist, dass OnTradeTransaction() nicht unmittelbar nach OrderSend ausgelöst wird.

Kurz gesagt, es gibt hier nur eine Menge streitender Fans, ohne auf das Thema des Streits einzugehen.

Es gibt zwei Varianten des Algorithmus, wenn unmittelbar nach OrderSend() etwas getan werden muss:

1. Wir können eine Schleife starten, in der wir auf die Aktualisierung der Listen der Bestellungen und Angebote warten.

2. Beenden Sie OnTick() und warten Sie auf die Auslösung von OnTradeTransaction().

3. Prüfen Sie durch Ankreuzen, ob ein neuer Auftrag oder ein neues Geschäft in der Liste erscheint.