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);
 

事情就简单多了。在发送订单 之前,记住了历史的长度,发送之后,等待历史的长度增加。应该输入一个超时,这样就不会突然永远卡住。

 
Dmitry Fedoseev:

事情就简单多了。在发送订单之前,记住了历史的长度,发送之后,等待历史的长度增加。必须输入一个超时时间,这样就不会突然永远卡住。

有一个超时。在你的变体中,不幸的是,如果几个OrderSends一起工作(来自不同的Expert Advisors),就会出现问题。

另外,不仅历史记录不同步,而且未结头寸/订单的 SL/TP也不同步,等等。对于市场来说,历史可能首先只增加了一个订单,然后一会儿又增加了一个交易。也有其他情况。这就是为什么它乍看之下如此繁琐。

 
德米特里-费多塞耶夫

你的信息的重点是什么?所以它出现在OnTradeTransaction()中,所以呢? 这意味着我们必须等待事件。你仍然需要等待。fxsaber信息的实质是,在OrderSend()被执行后,所执行的动作的信息不会立即出现在终端。有些人喜欢等待OnTradeTransaction(),而有些人则喜欢在列表中看到一个订单或交易。以下是与MT4的区别,作为一个例子。在M4中,在OrderSend()之后,订单已经在订单列表中,而在OrderClose()之后,它一直在历史中。

而为什么要等待OnTradeTransaction()?建立一个请求队列,如果有答案,就做一些事情......至少从队列中删除请求。很遗憾,SB没有Queue,但它是一个简单的类。

 
fxsaber:

有一个超时。遗憾的是,在你的版本中,如果几个OrderSends一起工作(来自不同的EA),就会出现问题。

另外,不仅历史记录不同步,而且未结头寸/订单的 SL/TP也不同步,等等。对于市场来说,历史可能首先只增加了一个订单,然后一会儿又增加了一个交易。也有其他情况。这就是为什么它乍看之下如此繁琐。

是的,我同意。但我只有一个这样的EA,如果有的话,也不会有什么危害。

最好是为等待写一个单独的函数,这样也可以使用标准交易类。

 
阿列克谢-沃尔昌斯基

为什么要等待OnTradeTransaction()?建立一个请求队列,如果答案来了,就做一些事情......至少把请求从队列中删除。很遗憾SB没有Queue,但这是一个简单的类。

重点是OnTradeTransaction()不会在OrderSend之后立即触发。

总之,这里只是一群争论者,没有进入争论的主题。

如果必须在OrderSend()之后立即做一些事情,有两种算法的变体。

1.我们可以启动一个循环,等待订单和交易清单的更新。

2.完成OnTick()并等待OnTradeTransaction()触发。

3.通过打勾检查,看是否有新的订单或交易出现在列表中。