mql5 언어의 특징, 미묘함 및 작업 방법 - 페이지 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);
}
애플리케이션
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);
}
애플리케이션
Request.type_time = GetExpirationType(Request.symbol, ( uint )Expiration); // Expiration может быть datetime-временем

if (Expiration > ORDER_TIME_DAY )
  Request.expiration = Expiration;
 
MqlTrade 구조를 문자열로 변환
#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
애플리케이션
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 );
}

애플리케이션

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

일이 훨씬 쉽습니다. 주문을 보내기 전에 히스토리의 길이를 기억하고 보내고 나면 히스토리의 길이가 늘어나기를 기다렸습니다. 갑자기 영원히 멈추는 일이 없도록 타임아웃을 입력해야 합니다.

 
드미트리 페도세프 :

일이 훨씬 쉽습니다. 주문을 보내기 전에 히스토리의 길이를 기억하고 보내고 나면 히스토리의 길이가 늘어나기를 기다렸습니다. 갑자기 영원히 멈추는 일이 없도록 타임아웃을 입력해야 합니다.

타임아웃이 있습니다. 불행히도 귀하의 버전에서는 여러 OrderSend가 함께 처리되는 경우 문제가 있을 수 있습니다(다른 Expert Advisors에서).

또한 이력이 동기화되지 않을 뿐만 아니라 열린 위치/주문 의 SL/TP도 동기화되지 않습니다. 시장의 경우 역사는 먼저 주문에 의해서만 증가할 수 있고 잠시 후에는 거래에 의해 증가할 수 있습니다. 다른 상황도 있습니다. 따라서 언뜻보기에는 너무 복잡해 보입니다.

 
드미트리 페도세예프 :

당신의 메시지의 의미는 무엇입니까? 글쎄, 그것은 OnTradeTransaction()에 올 것이다, 그래서 무엇? 즉, 이벤트를 기다려야 합니다. 아직 기다리고 있습니다. fxsaber 메시지의 의미는 OrderSend() 실행 후 수행된 작업에 대한 정보가 터미널에 즉시 나타나지 않는다는 것입니다. 누군가는 OnTradeTransaction()을 기다리는 것을 좋아하고 누군가는 목록에 있는 주문이나 거래의 출현을 좋아합니다. 예를 들어 MT4와의 차이점. M4에서 OrderSend() 이후 주문은 이미 주문 목록에 있고 OrderClose() 이후에는 항상 기록에 있습니다.

OnTradeTransaction() 을 기다리는 이유는 무엇입니까? 요청 대기열을 만들고 응답이 왔을 경우 조치를 취하십시오. 최소한 대기열에서 요청을 제거하십시오. SB에 Queue가 없는게 아쉽지만 간단한 클래스입니다.

 
fxsaber :

타임아웃이 있습니다. 불행히도 귀하의 버전에서는 여러 OrderSend가 함께 처리되는 경우 문제가 있을 수 있습니다(다른 Expert Advisors에서).

또한 이력이 동기화되지 않을 뿐만 아니라 열린 위치/주문 의 SL/TP도 동기화되지 않습니다. 시장의 경우 역사는 먼저 주문에 의해서만 증가할 수 있고 잠시 후에는 거래에 의해 증가할 수 있습니다. 다른 상황도 있습니다. 따라서 언뜻보기에는 너무 복잡해 보입니다.

그래, 난 동의. 그러나 그러한 조언자는 단 한 명이었고, 무슨 일이 있어도 끔찍한 일은 일어나지 않을 것입니다.

표준 거래 클래스도 사용할 수 있도록 별도의 대기 함수를 작성하는 것이 좋습니다.

 
알렉세이 볼찬스키 :

OnTradeTransaction() 을 기다리는 이유는 무엇입니까? 요청 대기열을 만들고 응답이 왔을 경우 조치를 취하십시오. 최소한 대기열에서 요청을 제거하십시오. SB에 Queue가 없는게 아쉽지만 간단한 클래스입니다.

요점은 OnTradeTransaction()에서 OrderSend 직후에 작동하지 않는다는 것입니다.

요컨대, 논쟁의 주제에 대해 깊이 파고들지 않고 논쟁을 벌이는 연인들의 무리가 있을 뿐입니다.

OrderSend() 직후에 작업을 수행해야 하는 경우 알고리즘에는 두 가지 변형이 있습니다.

1. 주문 및 거래 목록 업데이트 대기 루프를 켭니다.

2. OnTick()을 종료하고 OnTradeTransaction()이 실행될 때까지 기다립니다.

3. 새로운 주문이나 거래가 목록에 나타났는지 체크하세요.

사유: