mql5语言的特点、微妙之处以及技巧 - 页 70

 

关于交易、自动交易系统和交易策略测试的论坛

如何识别图表的替换?

fxsaber, 2018.02.08 12:39

void OnTick()
{  
  const long Chart = ChartID();
  string PrevSymbol = _Symbol;
  ENUM_TIMEFRAMES PrevTF = _Period;
    
  while (!IsStopped())
  {
    if ((PrevSymbol != ChartSymbol(Chart)) || (PrevTF != ChartPeriod(Chart))) // ноль указывать НЕЛЬЗЯ!
    {      
      PrevSymbol = ChartSymbol(Chart);
      PrevTF = ChartPeriod(Chart);
      
      Alert(PrevSymbol + " " + EnumToString(PrevTF));      
    }
    
    Sleep(0);
  }
}

某些函数中的ChartID输入参数为零,不会导致数值的重新计算。如果你想要当前图表的实际数据,你需要使用完整的ID。

 

关于交易、自动交易系统和策略测试的论坛

position_ticket != position_identifier

fxsaber, 2018.02.12 20:14

结论

如果我们假设这是正常的MT5行为,而不是经纪人黑客的特殊性,那么

  • ORDER_STATE_PARTIAL不出现在历史订单中。
  • 已执行的订单总是具有ORDER_STATE_FILLED状态。
  • 当一个订单被部分执行时,交易服务器会创建一个相应的新市场 订单(ORDER_REASON_CLIENT - 即使初始订单是自动下的(EXPERT))。
  • 旧的实时订单(票据没有改变)仍然是待定的,但数量减少(ORDER_VOLUME_CURRENT)。
  • 在这种情况下,旧的实时订单的状态是ORDER_STATE_PARTIAL。实际上,这个标志是ORDER_VOLUME_CURRENT和ORDER_VOLUME_INITIAL的比较结果。
  • 所有未结头寸都收到ID == OrderTicket。其中OrderTicket是由交易服务器生成的票据。
  • 一个交易总是正好有一个历史订单,其状态是ORDER_STATE_FILLED。
  • 每个被执行的历史订单正好有一个交易。
  • 任何已执行的订单的ORDER_VOLUME_INITIAL等于它被执行的数量。也就是说,即使是被取消的初始订单,其ORDER_VOLUME_INITITAL也等于其产生的交易量。
  • 初始订单(被部分执行)的时间不会改变,也不等于其交易的时间。
  • 历史表是按订单时间(ORDER_TIME_SETUP)排序的,但不是按交易时间。因此,如果我们从DEAL_TIME做HistorySelect,我们不能把相应的订单弄到历史表中。
  • HistorySelectByPosition总是返回必要的交易/订单集。
  • 你可以计算出任何交易的滑点。

弱点

  • 缺少ORDER_REASON_PARTIAL、DEAL_REASON_PARTIAL和POSITION_REASON_PARTIAL。这些标志必须紧随REASON_EXPERT之后,放在各自的列表中。
  • 相应的市场订单,当部分执行限价订单时,根据其性质可以有一个负的滑点。这似乎只是订单类型的错误,确实没有市场订单--它只是在MT5内部创建,并没有向外走。

ZZY 完全证实的假说。

关于交易、自动交易系统和交易策略测试的论坛

position_ticket != position_identifier

Pavel Kolchin, 2018.02.12 13:31

(不确定,很难检查,类似于部分位置关闭)

这一切都像这样运作。

1) 挂单被部分触发 - Position_ID = Order_Ticket1的头寸被打开

2)剩余的订单形成一个新的订单Order_Ticket2 并等待执行;新的Order_Ticket2 !=Order_Ticket1,因为在历史上不可能有两个相同的Order_Ticket订单。

3) 剩余的订单已被执行 - 开立一个Position_ID = Order_Ticket2的头寸。

在历史上有两个订单,在终端有两个位置,一切都对应着

 

关于交易、自动交易系统和测试交易策略的论坛

关于 "交易者的生活秘诀:将ForEach混入定义中(#define)"的讨论

fxsaber, 2018.02.14 10:54

绩效评估

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double GetAsk()
{
  static MqlTick tick = {0};
  
  return(SymbolInfoTick(Symbol(),tick) ? tick.ask : 0);
}

#define  AMOUNT 1 e6

void OnStart()
{
  double Sum = 0;
  
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += GetAsk())
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += SymbolInfoDouble(_Symbol, SYMBOL_ASK))
  
  Print(Sum);
}


结果

Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 78952
Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 162606

我完全错了!SymbolInfoDouble的速度是SymbolInfoTick的两倍。

关于交易、自动交易系统和交易策略测试的论坛

关于 "交易者的生活秘诀:将ForEach混入定义中(#define)"的讨论

fxsaber, 2018.02.14 11:58

无能。测试结果。

2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 87424
2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 83410

在需要性能的地方(优化器),最好使用SymbolInfoDouble。在现实世界中,这没有什么区别。


ZZY功能速度测量应该在一个性能很重要的环境中进行测量--测试者

 

关于交易、自动交易系统和交易策略测试的论坛

虫子,虫子,问题

fxsaber, 2018.02.12 23:10

在两个交易模拟服务器上手工开立BUY头寸


RoboForex-MetaTrader 5

2018.02.13 00:02:08.424 '8520459': market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': accepted market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': deal #90389019 buy 1.00 GBPUSD at 1.38387 done (based on order #107426544)
2018.02.13 00:02:10.101 '8520459': order #107426544 buy 1.00 / 1.00 GBPUSD at 1.38387 done in 1683.949 ms


FXOpen-MT5

2018.02.13 00:00:25.780 '18000903': market buy 1.00 GBPUSD
2018.02.13 00:00:25.912 '18000903': accepted market buy 1.00 GBPUSD
2018.02.13 00:00:25.922 '18000903': market buy 1.00 GBPUSD placed for execution
2018.02.13 00:00:25.942 '18000903': order #896454 buy 1.00 / 1.00 GBPUSD at market done in 154.252 ms
2018.02.13 00:00:25.942 '18000903': deal #80559 buy 1.00 GBPUSD at 1.38387 done (based on order #896454)

相同颜色的线条表示相同的事情。然而,我们可以清楚地看到,它们的顺序是不同的。对于Robo来说,关于订单执行的信息是在交易执行后出现的。在公开的情况下,它是在前面的!由于这个原因,OrderSend返回幸运,但还没有交易。也就是说,我们得到了不同步的OrderSend与历史记录。

FXOpen-MT5的代码

#define  PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{
  MqlTradeRequest Request = {0};
  
  Request.action = TRADE_ACTION_DEAL;
  Request.symbol = _Symbol;
  Request.volume = 1;
  Request.type_filling = ORDER_FILLING_IOC;
  
  MqlTradeResult Result;
  
  PRINT(OrderSend(Request, Result));
  PRINT(Result.deal);
}


结果

OrderSend(Request,Result) = true
Result.deal = 0


这种情况有如下解释

关于交易、自动交易系统和策略测试的论坛

虫子,虫子,问题

Rashid Umarov, 2018.02.15 06:25

如果一个订单被发送到外部交易系统,MetaTrader 5交易服务器不会等待它的响应,并立即将请求的结果返回为 "下单"。出于这个原因,OrderSend将总是返回deal=0,因为还没有关于已执行交易的信息。在OnTrade或OnTradeTransaction中抓住它。

创建MOEX交易机器人时从哪里开始- TradeTransactionListener.mq5一文中给出了一个交易事件监听器的例子。

OrderSend - 发送订单以执行市场交易。订单被放置- 我们需要读取Result.order但没有人等待交易--可能有很多交易,而且执行的总时间也没有确定。

这取决于经纪人一方对输出的具体实现。在一般情况下,它没有被定义。

因此,我强烈建议使用FXOpen-MT5的模拟账户作为你的代码测试,因为它与其他模拟账户不同。


例如,我建议尝试在MQL5中写一个具有这样交易逻辑的脚本(MQL4风格仅用于快速感知显示)

void OnStart()
{
  OrderCloseBy(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0), OrderSend(_Symbol, OP_SELL, 1, Bid, 0, 0, 0));
}

这一点也不容易。我还推荐所提到的演示服务器来进行部分执行的工作。

 
fxsaber:
删除了一个对MT5最常见错误之一进行解释的帖子。
它不在被删除之列。这很奇怪。你能再贴一次吗?
 
fxsaber:

这个帖子很大。没想到会被删除。我想听听删除的原因。因为再次被删除是受虐狂的表现。

我告诉你,它不在被删除之列。也许有一个小故障?
 

关于交易、自动交易系统和测试交易策略的论坛

组织一个订单循环

fxsaber, 2018.02.16 09:40

在MT5中,事情进展得一点也不顺利。显示问题的例子

// Пример неправильного считывания торгового окружения на каждом тике
// Скрипт эмулирует два тика ТС, которая должна открыть одну позицию, если ее нет.

#include <Trade/Trade.mqh>

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  // Этот MQL5-код с ошибкой
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;

/*
  // В MT4 такой код выполняется без ошибки
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

// Пример OnTick
void ExampleOnTick()
{
  static CTrade Trade;
  
  // Если нет позиции, открываем
  if (!GetAmountPositions(_Symbol))
    Trade.Buy(1);    
}

// Эмуляция прихода двух Tick-событий
void OnStart()
{
  ExampleOnTick(); 
  
  Sleep(10); // Между двумя тиками ~10 мс.
  
  ExampleOnTick();
}

你认为如果你在一个没有位置的符号上运行这个脚本,最终会发生什么?

正确的答案是,将开设一个或两个职位

发生这种情况的原因。在第一次OrderSend之后,出现了一个市场订单,如果在执行订单的时刻之前出现了一个新的tick,那么还没有头寸,就会进行第二次OrderSend。

正因为如此,一个看似正常的MT5模式无法正常工作,因此,codobase中的大多数MT5专家顾问。同时,几乎相同的MT4模板 将继续工作,没有任何问题。

在MT5中还需要分析市场订单的OrdersTotal,这让PositionsTotal这个看似不错的想法有些黯然失色。

要小心!

 
fxsaber:

正因为如此,一个看似正常的MT5模式无法正常工作,因此,kodobase中的大多数MT5 EAs

作为这一声明的证明,我们可以采取MT5 kodobase中几乎所有的专家顾问。我们不要挑三拣四,而是以目前最新的专家顾问 为例。很好的是,它是由一个在QB的MT5-出版方面有丰富经验的作者写的。

源代码中有以下字符串(我的评论被高亮显示)。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//....
   int total=0; // для расчета количества открытых советником позиций
//....
//--- main cycle
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            total++; // расчет количества открытых позиций
//....
   if(total==0) // Если нет открытых советником позиций
     {
      if(!RefreshRates())
        {
         PrevBars=iTime(1);
         return;
        }
      //--- open BUY 
      if(MACD_MAIN_2>MACD_SIGNAL_2 && MACD_MAIN_4<MACD_SIGNAL_4) // Сигнал на покупку
        {
         double sl=(InpStopLoss!=0)?m_symbol.Ask()-ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Ask()+ExtTakeProfit:0.0;
         OpenBuy(sl,tp); // Отправка маркет-ордера на покупку
         return;
        }
      //--- open SELL
      if(MACD_MAIN_2<MACD_SIGNAL_2 && MACD_MAIN_4>MACD_SIGNAL_4) // Сигнал на продажу
        {
         double sl=(InpStopLoss!=0)?m_symbol.Bid()+ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Bid()-ExtTakeProfit:0.0;
         OpenSell(sl,tp); // Отправка маркет-ордера на продажу
        }
     }
   return;
  }

我们有一个与上述情况相同的情况。

关于交易、自动交易系统和策略测试的论坛

mql5语言的特殊性,技巧和窍门

fxsaber, 2018.02.16 19:52

在第一次OrderSend之后,出现了一个市场订单,如果在其执行之前出现了一个新的tick,那么就还没有头寸,就会进行第二次OrderSend。

在MT5中还需要分析市场订单的OrdersTotal,这让PositionsTotal这个看似不错的想法有些黯然失色。

这意味着,在一般情况下,专家顾问将打开两个、三个等,而不是一个位置。取决于接收点子的频率和执行市场订单的时间。


由于kodobase中几乎所有的MT5 EAs都是用与MT5模板 相同的逻辑编写的,它们也有相同的错误,这些错误包含在其中。不幸的是,KB中几乎所有的MT5 EAs都是如此。

MACD EA
MACD EA
  • 投票: 4
  • 2018.02.15
  • Vladimir Karputov
  • www.mql5.com
При поступлении сигнала противоположная позиция закрывается. Также советник может закрывать половину позиции (параметр Profit for closing half of the position), может переводить позицию в безубыток (параметр Breakeven). Размер открываемой позиции может задавать вручную (параметр Lots) или в процентах риска от свободной маржи (параметр Risk in...
 

在净值交易中,可以有一个未结头寸,同时在同一符号上有几个方向的市场订单。例如,一个买入头寸和一个买入订单。这是真的,我没有设法找到这样的模拟账户,因为到处都有异步的规则。

关于交易、自动交易系统和交易策略测试的论坛

虫子,虫子,问题

fxsaber, 2018.02.14 08:58

整个OnTradeTransaction 事件序列是在OrderSend完成之后。

EA

void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest&, const MqlTradeResult& )
{ 
  static bool FirstRun = true;  
  static ulong StartTime;
  
  if (FirstRun)
  {
    StartTime = GetMicrosecondCount();
    
    FirstRun = false;
  }

  Print(EnumToString(Trans.type));
  Print((GetMicrosecondCount() - StartTime) / 1000);    
}

手动发送交易指令。

纪录

2018.02.14 09:41:46.671 '8854170': instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': accepted instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': deal #192088422 sell 1.00 EURUSD at 1.23673 done (based on order #208541700)
2018.02.14 09:41:46.853 '8854170': order #208541700 sell 1.00 / 1.00 EURUSD at 1.23673 done in 190.608 ms


专家顾问结果

2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_ADD
2018.02.14 09:41:46.853 0
2018.02.14 09:41:46.853 TRADE_TRANSACTION_DEAL_ADD
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_DELETE
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_HISTORY_ADD
2018.02.14 09:41:46.853 2
2018.02.14 09:41:46.853 TRADE_TRANSACTION_REQUEST
2018.02.14 09:41:46.853 2


我们完全可以从时间栏和EA的数字数据中看到,交易订单执行的时间对OnTradeTransaction事件的顺序没有影响。所有的异步都下地狱了!他们设法把事情搞得如此糟糕。建于1755年。

例如,当OrderSendAsync市场订单在终端放置时,市场订单甚至不会出现片刻。也许开发商决定这样做是为了加快事情的进展。

 

关于交易、自动交易系统和交易策略测试的论坛

讨论文章 "MetaTrader 5中交易策略优化的可视化"

fxsaber, 2018.02.22 08:39

在框架模式下,OnInit、OnDeinit、OnTick、OnTrade、OnTradeTransaction和OnTimer被忽略。只有OnChartEvent有效。

当然,由于OnChartEvent异常,它需要强制检查frame-mode标志。