程序库: OnTickMulti - 页 4

 
fxsaber #:

将不再显示基于最后已知时间的时标。

毫秒级 OnTimer 可确保在此定时器事件发生之前,所有计时点均已过去。也就是说,对于所有符号而言,计时点均是最新的。

如果是指间谍指标可能因某些技术原因延迟发送“旧” tick,并在另一个工具的更新 tick 之后才发送,那么这种情况确实可能发生。除此之外,我没有发现代码本身存在问题。

我不认为该定时器能提供更多保证,即确保所有 tick 数据都在新“事件”(时间单位计数)发生之前已处理完毕。 计时器以本地时间运行,而数据包中的时间戳则包含服务器时间。因此,最好不要依赖计时器来同步不同工具。

 
Stanislav Korotky #:

好吧,对于滴答信号来说,这还可以接受,毕竟同步比较复杂,尽管我们可以设置毫秒级的时间间隔,并调整滴答信号的时间。

但开盘价的情况也是一样的,尽管所有交易品种的开盘时间都是一样的。

而且由于这种行为,一些系统无法进行正常的测试。

 

问题演示。

#include <fxsaber\OnTickMulti\OnTickMulti.mqh> //https://www.mql5.com/zh/code/47647

#include <MT4Orders.mqh> //https://www.mql5.com/zh/code/16006

input bool inTimer = false; // false - OnTick,true - OnTimer

ulong TimeMsc = TimeTradeServer() * 1000 + (inTimer && EventSetMillisecondTimer(1));

void PositionOpen()
{
  for (uint i = ArraySize(OnTickMultiObject.Symbols); (bool)i--;)
  {
    const string SymbName = OnTickMultiObject.Symbols[i];
    
    OrderSend(SymbName, OP_BUY, 1, SymbolInfoDouble(SymbName, SYMBOL_ASK), 0, 0, 0);
  }
}

void OnTimer()
{
  if (TimeMsc++ == 1759280400081) // 2025.10.01 01:00:00.081
    PositionOpen();
}

// 多字符 OnTick。
void OnTickMulti( const string &Symb, const uint &Index )
{  
  MqlTick Tick;
  
  if (!inTimer && SymbolInfoTick(Symb, Tick) && (Tick.time_msc == 1759280400081) && // 2025.10.01 01:00:00.081
      !OrdersTotal())
    PositionOpen();
}

截图中显示了在MetaQuotes-Demo上 重现该问题所需的所有数据。可以清楚地看到,通过OnTick处理时,报价数据无法同步;而通过OnTimer(极其卡顿)处理时,则能实现同步。

 
fxsaber #:

通过 OnTick 处理的 tick 事件未同步,而通过OnTimer(极其卡顿) 处理的 tick 事件则已同步。

看来,在同步模式下加快计算速度的唯一方法是采用类似于EAToMath的 数学模式。


或者,预先将单次迭代的数据写入文件。

#include <fxsaber\OnTickMulti\OnTickMulti.mqh> //https://www.mql5.com/zh/code/47647

// 多字符 OnTick。
void OnTickMulti( const string &Symb, const uint &Index )
{  
  static MqlTick Ticks[];
  static const int Size = ArrayResize(Ticks, ArraySize(OnTickMultiObject.Symbols));  
  
  bool Res = SymbolInfoTick(Symb, Ticks[Index]);

  for (int i = 1; Res && (i < Size); i++)
    Res = (Ticks[i].time_msc == Ticks[i - 1].time_msc);
    
  if (Res)
    ArrayPrint(Ticks);  
}
2025.10.01 01:00:00                    [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
2025.10.01 01:00:00   [0] 2025.10.01 01:00:00 1.17345 1.17363 0.0000        0 1759280400081     134       0.00000
2025.10.01 01:00:00   [1] 2025.10.01 01:00:00 1.34417 1.34501 0.0000        0 1759280400081     134       0.00000
2025.10.01 01:00:00   [2] 2025.10.01 01:00:00 0.66103 0.66122 0.0000        0 1759280400081     134       0.00000
2025.10.01 06:07:02                    [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
2025.10.01 06:07:02   [0] 2025.10.01 06:07:02 1.17388 1.17390 0.0000        0 1759298822726     134       0.00000
2025.10.01 06:07:02   [1] 2025.10.01 06:07:02 1.34417 1.34422 0.0000        0 1759298822726     130       0.00000
2025.10.01 06:07:02   [2] 2025.10.01 06:07:02 0.65959 0.65967 0.0000        0 1759298822726     134       0.00000
2025.10.01 07:30:23                    [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
2025.10.01 07:30:23   [0] 2025.10.01 07:30:23 1.17467 1.17469 0.0000        0 1759303823965       4       0.00000
2025.10.01 07:30:23   [1] 2025.10.01 07:30:23 1.34486 1.34490 0.0000        0 1759303823965     134       0.00000
2025.10.01 07:30:23   [2] 2025.10.01 07:30:23 0.65970 0.65978 0.0000        0 1759303823965       4       0.00000

并在自己的专家顾问中使用该文件中的数据,以在OnTick中实现同步。这样既能快速运行,又能确保结果准确。

Подробнее о способах ускорения оптимизации советников в MT5.
Подробнее о способах ускорения оптимизации советников в MT5.
  • 2025.09.02
  • www.mql5.com
Классификация советников. Все советники, запускаемые в Оптимизаторе, делятся на два типа. Торговые. Статистические: "обучение", обработка котировочных данных. Каждый из них тоже делится на два типа
 
fxsaber #:

问题演示。

截图中包含在MetaQuotes-Demo上 复现该问题所需的所有数据。可以清楚地看到,通过OnTick处理时,Tick数据无法同步,而通过OnTimer(极其卡顿)处理时,则能够同步。

您使用的代码中,入场条件使用了 == 运算符。我之前已经指出,条件必须使用严格大于 >,且不能包含等于。 若要针对所有交易品种,以截至2025年10月1日01:00:00.081前已知的最新价格执行同步交易,您必须在此时间点之前开始监控Tick数据,即设定一个演示常量, 例如 >1759280400080。针对每个算法都需要修改逻辑——仅将一种处理程序类型替换为另一种是行不通的。

附注:我所说的同步是指根据最新已知价格进行交易。 要实现毫秒级精确同步,当然需要额外的验证,但这种情况(不同交易品种的 tick 时间毫秒完全一致)发生的概率很小,这意味着可能会遗漏潜在的交易信号。我不确定这种同步方式在实践中是否有实际意义。

 
Stanislav Korotky #:

若要按截至2025年10月1日01:00:00所知的最新价格进行同步交易,081,您必须在此时间之前开始监控报价 tick,即选择一个演示常数,例如 >1759280400080。

我愿意查看您在代码中的实现方案。
 

最简单的同步方法是创建一个由所用字符的时钟脉冲时间组成的集合。

在运行过程中,仅通过一次迭代实现同步相当困难。

难点在于延迟的不确定性。无法确定哪个符号会成为主导符号。

 
fxsaber #:
我愿意看看您在代码中的实现方案。

为了编写完整的测试用例,我需要了解实际的业务场景——我们是否仅根据时间精确到毫秒的同步 tick 进行交易?

如果是人为设定的示例,即仅有一笔交易,且交易时间点是预先已知的,所有交易品种的 tick 时间完全同步——虽然可以设计出人为的优化算法,但这又有何意义呢?

 
Rorschach #:

但开盘价其实都一样,尽管所有股票的开盘时间都是一样的。

有必要明确一下问题。就开盘价而言,如果算法要求所有符号都存在K线,我们就等待所有符号的iTime(,,0)值一致。 对于K线而言,这种方法通常不会有逻辑问题,因为K线(即使是M1)很少缺失;但对于秒级及更细的计时单位,同步失效的情况可能很常见。这种时候该怎么办?

我认为,在实际操作中,应将“存在任何不超过某个预设超时时间的报价”视为同步条件,而非严格要求各 tick 的时间戳完全一致。

 
Stanislav Korotky #:

需要进一步明确任务要求。 就开盘价而言,如果算法要求所有品种都存在K线,我们就等待所有品种的iTime(,,0)值相同时。对于K线而言,这种方法通常不会出现逻辑问题,因为K线(即使是M1周期)很少缺失

这里指的是基于开盘价的测试器模式。

Stanislav Korotky#:
,对于秒级及更细的计时单位,同步失效的情况可能较为频繁。这种情况下该如何处理?

使用最后一个已知值。