MT5和速度在行动 - 页 20

 
fxsaber:

可能有一个更快的选择。但是,在需要计算的条件中,向左走一步,逻辑可能就要发生很大的变化。不容易,一般来说。

CHashMap<ulong, ulong> DealsIn;  // По PositionID возвращает DealIn.


这不是缓存,是索引。这里是缓存(代码的一部分)。

class DealInfo {
public:
  datetime Closed;
  ulong Ticket;
  ulong Position;
  string Symbol;
  long Type;
  long Reason;
  double Volume;
  double Price;
  double Profit;
  double Swap;
  long Magic;
};

class DealsComparer : public IComparer<DealInfo*> {
  int Compare(DealInfo* x, DealInfo* y) {
    int res = (int)(x.Closed - y.Closed);
    if (res == 0) {
      res = (int)(x.Ticket - y.Ticket);
    }
    
    return res;
  }
};

CArrayList<DealInfo*> dealsHistory;

inline bool UpdateDeals(CArrayList<DealInfo*> &deals, datetime &lastUpdated) {
  DealInfo* dealsToAdd[];
  DealsComparer comparer;
  int toAdd = 0;
  DealInfo* deal;
  
  if (!HistorySelect(lastUpdated, TimeLocal() + 12*3600)) {
    return false;
  }

  for (int i = 0, total = HistoryDealsTotal(); i < total; i++) {
    DealInfo tmp;
    ulong ticket = HistoryDealGetTicket(i);
    if (ticket == 0) continue;
    
    datetime dt = (datetime)HistoryDealGetInteger(ticket, DEAL_TIME);
    if (lastUpdated < dt) {
      lastUpdated = dt;
    }

    if (HistoryDealGetInteger(ticket, DEAL_ENTRY) != DEAL_ENTRY_OUT) continue;

    ulong reason = HistoryDealGetInteger(ticket, DEAL_REASON);

    tmp.Ticket = ticket;
    tmp.Closed = dt;
    int idx = deals.BinarySearch(&tmp, &comparer);
    if (idx >= 0 && deals.TryGetValue(idx, deal) && deal != nullptr && deal.Ticket == ticket)
      continue;

    deal = new DealInfo;
    deal.Ticket = ticket;
    deal.Closed = dt;
    deal.Position = HistoryDealGetInteger(ticket, DEAL_POSITION_ID);
    deal.Symbol = HistoryDealGetString(ticket, DEAL_SYMBOL);
    deal.Type = HistoryDealGetInteger(ticket, DEAL_TYPE);
    deal.Reason = HistoryDealGetInteger(ticket, DEAL_REASON);
    deal.Volume = HistoryDealGetDouble(ticket, DEAL_VOLUME);
    deal.Price = HistoryDealGetDouble(ticket, DEAL_PRICE);
    deal.Swap = HistoryDealGetDouble(ticket, DEAL_SWAP);
    deal.Profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
    deal.Magic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
    
    ArrayResize(dealsToAdd, toAdd + 1, total);
    dealsToAdd[toAdd++] = deal;
  }
  
  if (toAdd > 0) {
    deals.AddRange(dealsToAdd);
    deals.Sort(&comparer);
  }
  
  return (toAdd > 0);
}

这段代码写得很仓促,考虑到频繁的ArrayResize,有很多需要完善的地方,但它确切地更新了缓存,按Closed排序。如果你想以后搜索,请使用你自己的索引。但你每次只需要更新一小部分。
我不记得为什么会有"12*3600",我不认为所有的交易都发给了我。

 
Andrey Pogoreltsev:

这不是缓存,是一个索引。

请仔细阅读。

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

MT5和速度在行动

fxsaber, 2020.08.28 21:10

纯粹的MQL5比部分(只有HistorySelectByPosition) 的缓存慢100倍。

架构上 做完全的缓存--你需要仔细思考。有很多隐患。

这里是缓存(代码的一部分)。

这段代码写得很仓促,考虑到频繁的ArrayResize,还有一些需要改进的地方,但它是按Close排序更新缓存的。如果你想以后搜索,请使用你自己的索引。但你每次只需要更新一小部分。

这只是一个正面拯救历史的例子,没有现实世界的噱头。即使在MT4Orders中,部分缓存也是以5秒的幅度进行的...

我不记得为什么会有"12*3600",我不认为所有的交易都发给了我。

总是设置INT_MAX。

 
fxsaber:

从架构上看, 做完整的缓存需要大量的思考。有很多隐患。

那里真的没有什么复杂的东西。你可以用几个小时的时间进行抽查,例如,对所有可能出现在历史上的订单进行追溯(顺便说一下,这非常奇怪)。

这只是一个没有任何实时噱头的正面历史保存的例子。即使在MT4Orders中,部分缓存也是以5秒的幅度进行的...

总是设置INT_MAX。

我不明白这种转变的意义。因为如果有一个当前的时间戳,我想获得相对于它的时间,而你必须指定一个不存在的时间,这很奇怪。我有点想要一个合理的解释。

顺便说一下,我的缓存在有10K以上交易的真实账户上工作。

而到目前为止,代码中的主要刹车是网络功能。

 
只是路过,我想我要总结一下这里已经暗示过的内容。如果你需要不惜一切代价获得超快的性能,那就以传统的方式实现--以牺牲其他资源消耗为代价,例如内存。换句话说,当需要计算一些总值(可以不只是总时长)时,没有必要每次都在整个历史中运行一个循环,提前在 "数组"(或其他优化的数据结构)中全部计算好,然后只进行增量。而通过位置标识符(或任何参数,通过它进行分解)对一个值的请求将退化为一个存储单元的引用。在最一般的形式下--它是类似于OLAP的东西(虽然在我的实现中没有完成在线更新),但对于一个特定的问题可以做得更简单。
 

在最新的测试版2588中,HistorySelect功能 的缓存非常好,几乎总是(除了第一次)是免费的。

我们可能会在发布前进行一些其他的改进。



正如我之前解释的那样,在MT5中,在每个事件发生前为每个EA自动创建市场快照,并没有额外的费用,因为在MT4中是这样做的。这减少了延迟,使机器人能够更快地运行。每个开发商都准确地问出了他的需求。

因此,你应该清楚地认识到,"在整个历史上调用HistorySelect,然后立即进行HistorySelectByPosition的另一次选择 "的做法会杀死之前创建的历史缓存。这是一针见血的做法。


发布后,我们将开始大量工作,增加新的更有效的MQL5函数和开放的本地订单/交易数据结构,因此我们可以简化和加快算法交易。

 
Renat Fatkhullin:

在最新的2588测试版中,HistorySelect功能 的缓存非常好,而且几乎总是(除了第一次)是免费的。

#include <fxsaber\Benchmark.mqh> // https://c.mql5.com/3/321/Benchmark.mqh

input int inAlertTime = 1; // Нижний порог в миллисекундах

#define _B2(A) _B(A, inAlertTime)
#define  ALERT(A) Alert(#A + " = " + (string)(A))

void OnInit()
{
  if (HistorySelect(0, INT_MAX))
  {
    ALERT(HistoryDealsTotal());
    ALERT(HistoryOrdersTotal());
  }
}

void OnTick()
{
  static int i = 0;
  
  ALERT(i++);
  
  _B2(HistorySelect(TimeCurrent(), INT_MAX));
  _B2(HistorySelect(0, INT_MAX));
}


结果。

2020.09.01 22:56:46.089 Test6 (EURAUD,M1)       Alert: HistoryDealsTotal() = 9435
2020.09.01 22:56:46.089 Test6 (EURAUD,M1)       Alert: HistoryOrdersTotal() = 12529
2020.09.01 22:56:46.575 Test6 (EURAUD,M1)       Alert: i++ = 0
2020.09.01 22:56:46.579 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:47.424 Test6 (EURAUD,M1)       Alert: i++ = 1
2020.09.01 22:56:47.428 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:47.765 Test6 (EURAUD,M1)       Alert: i++ = 2
2020.09.01 22:56:47.768 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:47.902 Test6 (EURAUD,M1)       Alert: i++ = 3
2020.09.01 22:56:47.906 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:48.453 Test6 (EURAUD,M1)       Alert: i++ = 4
2020.09.01 22:56:48.456 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:48.516 Test6 (EURAUD,M1)       Alert: i++ = 5
2020.09.01 22:56:48.521 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 4 ms.


每一次打勾都有一个问题。


ZY安装了Win10,LatencyMon显示一切正常。

 
目前我看到,在99%的情况下,只应该使用HistorySelect(0,INT_MAX)。尽量不要使用其他选项。
 
Renat Fatkhullin:

发布后,我们将开始大量的工作,增加新的更有效的MQL5函数,并开放本地订单/交易数据结构,以便简化 和加速算法交易。

MqlDeal、MqlOrder和MqlPosition会很好。它甚至可能变得更简单。

 
fxsaber:
目前,我看到在99%的情况下,我们应该只使用HistorySelect(0,INT_MAX)。尽量不要使用其他选项。

如果我的历史上有几十万个订单,是否也会比采取最后一分钟的历史更快?

那么,我是否必须经历所有这些历史?这是不符合逻辑的。

 
Dmi3:

如果我的历史上有几十万个订单,是否也比取最后一分钟的历史更快?

在战斗机器人中只留下0-INT_MAX的变体。不再注意到滞后的问题。