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

 

我从未想过我会在源代码中使用机器生成的代码。尤其是在一个为了性能而存档的地方。


以下是生成的代码。

switch (this.Flag)
{
case 0:
  return(false);
case 1:
  return(Tick.bid >= this.bid.Max);
case 2:
  return(Tick.ask <= this.ask.Min);
case 3:
  return((Tick.bid >= this.bid.Max) || (Tick.ask <= this.ask.Min));
case 4:
  return(Tick.bid <= this.bid.Min);
case 5:
  return((Tick.bid >= this.bid.Max) || (Tick.bid <= this.bid.Min));
case 6:
  return((Tick.ask <= this.ask.Min) || (Tick.bid <= this.bid.Min));
case 7:
  return((Tick.bid >= this.bid.Max) || (Tick.ask <= this.ask.Min) || (Tick.bid <= this.bid.Min));
case 8:
  return(Tick.ask >= this.ask.Max);
case 9:
  return((Tick.bid >= this.bid.Max) || (Tick.ask >= this.ask.Max));
case 10:
  return((Tick.ask <= this.ask.Min) || (Tick.ask >= this.ask.Max));
case 11:
  return((Tick.bid >= this.bid.Max) || (Tick.ask <= this.ask.Min) || (Tick.ask >= this.ask.Max));
case 12:
  return((Tick.bid <= this.bid.Min) || (Tick.ask >= this.ask.Max));
case 13:
  return((Tick.bid >= this.bid.Max) || (Tick.bid <= this.bid.Min) || (Tick.ask >= this.ask.Max));
case 14:
  return((Tick.ask <= this.ask.Min) || (Tick.bid <= this.bid.Min) || (Tick.ask >= this.ask.Max));
case 15:
  return((Tick.bid >= this.bid.Max) || (Tick.ask <= this.ask.Min) || (Tick.bid <= this.bid.Min) || (Tick.ask >= this.ask.Max));
}

为生成编写的脚本要简洁得多。它可以方便地快速测试假设,避免人为错误。

 
fxsaber #:

我从未想过,我会在源代码中使用一段机器生成的代码。尤其是在对性能具有重要存档意义的地方。


以下是生成的代码。

为生成编写了更简洁的脚本。这可能有助于快速测试假设和避免人为错误。

请注意,同一个 ChatGPT 在语法和逻辑上都会犯很多错误,因此您必须仔细检查所有内容。

但它确实是一个很好的生成器,可以帮助您用代码表达想法。

 
fxsaber #:

以下是生成的代码。

生成的脚本更加简洁。这可能有助于快速测试假设和避免人为错误。

没有足够的背景信息:新代码是否比旧代码更快?

如果没有,为什么要把旧的可理解代码换成新的不可理解代码?

如果是,为什么 MQL 编译器不能立即生成性能最优的代码,而它在这方面的可能性比聊天要大得多?

 
Aleksey Vyazmikin #:

请注意,同一个 ChatGPT 在语法和逻辑上都会犯很多错误,因此您必须仔细检查所有内容。

但它确实是个好工具,有助于用代码表达想法。

生成脚本。

// Генерация switch-кода.
string GetString( const int Num )
{
  static const string Condition[] = {"(Tick.bid >= this.bid.Max)", "(Tick.ask <= this.ask.Min)",
                                     "(Tick.bid <= this.bid.Min)", "(Tick.ask >= this.ask.Max)"};
  string Str = NULL;

  for (int i = 0; i < ArraySize(Condition); i++)
    if ((bool)(Num & (1 << i)))
      Str += ((Str == NULL) ? NULL : " || ") + Condition[i];

  return(Str);
}

void OnStart()
{
  for (int i = 0; i < 16; i++)
    Print("case " + (string)i + ":\n  return(" + GetString(i) + ");");
}
 
A100 #:

背景信息不足:新代码是否比旧代码更快?

新代码更快了。

如果是,那么为什么 MQL 编译器不能立即生成性能最优的代码,而它有比聊天更多的可能性呢?

这是算法优化,而不是编译器优化。

 
fxsaber #:

新的速度更快。

这是算法优化,而不是编译器优化。

快多少?1.5%还是1.5倍?好像是快了?还是基于正确的测量?

所以你给的不是代码,而是算法?

 
A100 #:

快多少?1.5%还是1.5倍?是凭感觉还是具体测量?

所以你给的不是代码,而是算法?

这就是虚拟源代码使用的算法。您必须在每个刻度上进行四次检查。

return((Tick.bid >= this.bid.Max) || (Tick.ask <= this.ask.Min) || (Tick.bid <= this.bid.Min) || (Tick.ask >= this.ask.Max));


但在某些情况下(开关 0-15),检查次数可以少一些:0-4 次。这取决于 TS。


例如,如果 TS 只使用市场订单开仓/平仓,而不使用 SL/TP,则无需进行一次检查。

但如果同时使用所有类型的订单,则需要进行所有四次检查: 这样就不会加速。


这就是为什么您应该选择特定的 TS 并查看其测量结果。不同的 TS 有不同的加速度结果。


有可能将案例(案例数量)分为更多变体。老实说,我做不到。

 

在 MQL5 中,有一个StringReserve 函数,理论上可以减少字符串的内存重新分配次数:我们一次性分配一个足够大的缓冲区,然后在其中工作。

但实践表明,对该字符串的任何后续赋值都会改变其缓冲区的大小(也就是说,显然会发生内存重新分配)。

因此,使用

string str;
str.Reserve(8192);
str="test";

而不是

string str;
str.Reserve(8192);
StringSetLength(str,0);  // или str.SetLen(0); - в документации есть, но у меня в 4073 не поддерживается
str+="test";
 
JRandomTrader #:

使用

没错。这种机制对字符串补全非常有效。例如,在生成大型 HTML 报告时。

 

我怎样才能知道某个符号是否有数据,以便在没有数据时不会将其留在[市场观察]窗口中?

我在循环中使用了这种检查方法:

ulong first_server_date = (ulong)SeriesInfoInteger(symbol, PERIOD_M1, SERIES_SERVER_FIRSTDATE);

if(first_server_date == NULL) {
  SymbolSelect(symbol, false);
  continue;
}

在此之后当 Expert Advisor 处于图表上时, 我无法手动将符号从[Market Watch]窗口中逐个或一次全部 删除: