文章 "交易员生存技巧: 由指标制作的快餐" - 页 3

 
Renat Fatkhullin:

......开始调用不同的参数,乘以指标,丢失所有句柄,然后怀疑刹车和内存消耗。

老实说,我还不明白,如果句柄存储在 MetaTrader 的后台,怎么会丢失呢?

p.s. 总的来说,让文章作者加入讨论,并解释一下他对在 MT5 中使用指标句柄的看法。

 
Vasiliy Sokolov:
老实说,我一直不明白,如果在 MetaTrader 的幕后记忆了一个句柄,它怎么会丢失呢?

有了这种提高代码质量的方法,我再也没有疑问了。

 
Vasiliy Sokolov:

不清楚您所说的是什么意思。据我所知,hendle 并没有在任何地方关闭 没有调用 IndicatorRelease)。在创建 hendle 时会不断调用标准函数,如 iMACD:

显然,整个游戏的基础是 iMACD 和类似函数将先前返回的句柄缓存在自己内部,因此不应该重新创建指标。


是的,我最初的想法是要说明,在 MQL5 中,应该以一种花哨的方式使用指标:应该在 OnInit() 中创建一个句柄,并通过 CopyXXXX 函数访问指标数据,如果使用 MQL4 风格的句柄再创建,那就大错特错了,而且将是一场灾难:它将占用内存。但在这一过程中,我们发现 MQL5 内核非常聪明(显然存在相同句柄的内部缓存),它不允许重新创建句柄。

这样做的副作用是,MQL5 内核设计得非常好,允许 MQL5 以不合时宜的方式工作。

 
Vasiliy Sokolov:

我没有看到任何相似之处。

两篇文章提供了相同的内容--在 MQL5 中编写最简单的 MQL4 风格变体。比较一下

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

讨论文章 "交易者的生活窍门:用指标烹饪快餐"

Vasiliy Sokolov, 2018.01.25 16:05

//+------------------------------------------------------------------+
//| 以 MQL4 符号表示的 iMACD 函数|
//| 缓冲区编号如下:|||......
//| mql4 0 - mode_main, 1 - mode_signal|
//| mql5 0 - main_line,1 - signal_line|
//+------------------------------------------------------------------+
double   iMACD(
               string                     symbol,              // 符号名称 
               ENUM_TIMEFRAMES            timeframe,           // 时限 
               int                        fast_ema_period,     // 快速平均计算期 
               int                        slow_ema_period,     // 用于计算慢速平均值的时间段 
               int                        signal_period,       // 差值平均的周期 
               ENUM_APPLIED_PRICE         applied_price,       // 价格或句柄类型 
               int                        buffer,              // 缓冲区 
               int                        shift                // 移位
               )
  {
   
   double result=NaN;
//---
   int handle=iMACD(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price);
   if(handle==INVALID_HANDLE)
     {
      Print(__FUNCTION__,": INVALID_HANDLE error=",GetLastError());
      return(result);
     }
   double val[1];
   int copied=CopyBuffer(handle,buffer,shift,1,val);
   if(copied>0)
      result=val[0];
   else
      Print(__FUNCTION__,": CopyBuffer error=",GetLastError());
   return(result);
  }

这个

double iMACDMQL4(string symbol,
                 int tf,
                 int fast_ema_period,
                 int slow_ema_period,
                 int signal_period,
                 int price,
                 int mode,
                 int shift)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   ENUM_APPLIED_PRICE applied_price=PriceMigrate(price);
   int handle=iMACD(symbol,timeframe,
                    fast_ema_period,slow_ema_period,
                    signal_period,applied_price);
   if(handle<0)
     {
      Print("Объект iMACD не создан: Ошибка ",GetLastError());
      return(-1);
     }
   else
      return(CopyBufferMQL4(handle,mode,shift));
  }

其实是一回事。

它们应该出现吗?我认为文章的标题(或者说其描述)明确表示只涉及指标?

从标题来看,它们不应该出现。但这篇文章涉及 MQL4 风格的时间序列工作。如果没有它,我们就会得到一个不完整的解决方案。几乎每个人都在 MQL4 中使用 "High[i]"。而且,它的实现也很容易找到。

不幸的是,MQL 不支持带有任意数量参数的函数,因此 iCustom 无法 "像 MT4 一样 "实现。

我认为在一篇文章中不可能写出一个完全模拟 MT4 风格的完整引擎。主题已经明确:以 MQL4 风格使用指标(可惜文章标题没有反映主题,令人困惑)。

MQL4 风格仍然是一个概念,但没有明确遵守语法。

 
Vladimir Karputov:

如果使用 MQL4 风格重新创建句柄,那就大错特错了,而且会带来麻烦:内存将被消耗。

这就是为什么会出现这样的问题:既然可以按照MQL4 的风格 正确地完成工作,为什么还要实现不正确的工作呢?

MQL5 并不聪明,它只是有万无一失的保护措施。否则,任何意外错误都会导致不幸的后果。但是,正如性能测量结果所显示的那样,这种万无一失的保护措施在设计上存在性能故障。这就是为什么有必要将 "重新创建句柄 "转移到 MQL5 封装器中,将其从用户眼前隐藏起来(OOP 功能的一小部分)。

 
fxsaber:

...但是,正如性能测量结果所显示的那样,在进行傻瓜化操作时,性能也会有所下降......

是的,这很有趣。我会测量一下速度,然后把结果发到这里。

 
Vasiliy Sokolov:

用最简单的坯料进行测量。

专家姓名说明性能
iMACD经典 MT5 风格 Hendle 工作EURUSD,M5: 26189141 ticks,生成 74266 bars。环境同步时间为 0:00:01.045。测试在 0:00:12.121 时通过(包括 0:00:01.966 时的 ticks 预处理)。
MACD MQL4 风格 EA 短线以 MQL4 风格工作EURUSD,M5: 26189141 ticks, 74266 bars generated.环境在 0:00:00.047 同步。测试在 0:00:34.960 时通过(包括 0:00:01.872 时的 ticks 预处理)。

开销约为原来的三倍。因此,是的,MetaTrader 5 需要大量时间来查找缓存句柄。


我有一个测试这个问题的想法:一个类似于"MACD MQL4 风格 EA short "的 EA,只是其中可以处理的指标不是两个,而是三个、四个、五个 ....。在这里,"指标 "是指(以 MACD 为例)具有不同参数的指标,但每个指标只有一个符号。

 

我删除了之前的帖子,因为我注意到MACD MQL4 风格 EA 还访问了图形子系统

//+------------------------------------------------------------------+
//| 专家勾选功能|
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double macd_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,1);
   Comment("MACD, main buffer, index 1: ",DoubleToString(macd_main_1,Digits()+1));
  }

也就是说,所做的测试是错误的。注释评论函数 后,性能几乎相同:

EURUSD,M5: 26189141 ticks, 74266 bars generated. Environment synchronized in 0:00:00.047. Test passed in 0:00:15.444 (including ticks preprocessing 0:00:01.872).

结论:MetaTrader 5 仍能有效找到之前创建的缓存,因此可以使用建议的代码样式。

fxsaber:

但正如性能测量结果所显示的那样,这种万无一失的保护方式会导致性能故障。这就是为什么有必要将 "重新创建句柄 "转移到 MQL5 封装器中,将其(OOP 功能的一小部分)从用户眼前隐藏起来。

如果最后的测试正确无误,那么转移到 OOP 封装器将没有任何作用。速度几乎相等。
 
Vasiliy Sokolov:

MetaTrader 5 需要大量时间才能找到缓存句柄。

用户无法确定能否以一般方式加快这一过程。显然,计算哈希函数需要花费大量时间。

这种指示器哈希函数的一个一般形式的变体发布在这里

  static string GetMyUniqueName( void )
  {
    const int handle = GetMyHandle();

    MqlParam Params[];
    ENUM_INDICATOR Type;

    const int Total = ::IndicatorParameters(handle, Type, Params);
    ::IndicatorRelease(handle);

    uchar Bytes[];

    for (int i = 1; i < Total; i++)
    {
      ::ArrayCopy(Bytes, _R(Params[i].double_value).Bytes, ::ArraySize(Bytes));
      ::ArrayCopy(Bytes, _R(Params[i].integer_value).Bytes, ::ArraySize(Bytes));
      ::ArrayCopy(Bytes, _R(Params[i].string_value).Bytes, ::ArraySize(Bytes));
    }

    return("::" + (string)::ChartID() + (string)INIT_SYNC::crc64(Bytes) + ::MQLInfoString(MQL_PROGRAM_NAME));
  }

我并不关心性能,但很明显,任何哈希函数的输入都必须是一个 MqlParam 值数组。考虑到有一个慢速字符串字段,这就无法快速工作。

因此,编写一个比 MT5 内置的哈希函数更快的通用指标是一项艰巨的任务。但我坚决反对从其他地方调用指标。这就是为什么我甚至不想了解这个问题。


关于智能 MQL5 还有另一个想法。有许多智能交易系统,在每个条形图上调用相同的指标,但输入参数不同。随着时间的推移,MQL5 会 "删除 "不必要的句柄。但这是一个通用的解决方案。在 Expert Advisor 中,作者可以自己承担这一责任,自己杀死句柄。很明显,在 100 个条形图中携带 100 个手柄的包袱是超级浪费计算资源 和内存的。但在同一个 kodobase 中,我还没见过有哪个 EA 会这样钉住句柄。一切都归功于 "MQL5 的聪明",从而迫使作者一点也不聪明。


但是,指标和条形图又是邪恶的。

 
fxsaber:

一般来说,用户无法确定能否加快这一过程。显然,计算散列函数需要花费大量时间。

这种指示器哈希函数的一个一般形式的变体发布在这里


你想在一篇文章中向读者提供大量信息。不过,关于你的方法--这是一个正面的解决方案,你是否尝试过其他方法?比较过性能吗?