程序库: MT4Orders - 页 63

 

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

库: MT4Orders

fxsaber, 2021.06.02 10:09

应我的要求,MetaQutoes 已将该库的最新更新完全本地化为英文。现在可以在英文页面上看到最新版本的库,源代码中的注释已翻译成英文。


这与之前在英文页面上提供的版本有所不同。

// 更改列表:
// 02.11.2018
// 修复:现在 MT4 仓位开仓价格在触发前不能为零。
// 修复:已考虑到某些交易服务器的一些罕见执行问题。
// 26.11.2018
// 修复:MT4 平仓头寸的魔法和注释:开仓交易相关字段的优先级高于平仓交易。
// 修复:在计算 MT4 订单总额和 MT4 订单选择时考虑 MT5 订单总额和 MT5 仓位总额的罕见变化。
// 修复:库不考虑已开仓但尚未从 MT5 中删除的订单。
// 17.01.2019
// 修复:修复了在选择挂单时出现的不幸错误。
// 08.02.2019
// 添加:通过 OrderClose 在部分平仓时保存仓位注释。
// 如果需要在部分平仓时修改未结头寸的注释,可以在 OrderClose 中指定。
// 20.02.2019
// 修复:在没有 MT5 订单的情况下,程序库将期望从现有的 MT5 交易中同步历史记录。如果失败,它将发出通知。
// 13.03.2019
// 添加:已添加 OrderTicketID() - MT5 交易或 MT5 仓位的 PositionID,以及 MT4 挂单的 ticket。
// 添加:SELECT_BY_TICKET 适用于所有 MT5 票(和 MT5-PositionID)。
// 02.11.2019
// 修复:更正了 "平仓 "头寸的手数、佣金和平仓价格。
// 12.01.2020
// 修复:余额交易的 OrderTicketID() 现在可返回正确的值。
// 修复:修复了 SELECT_BY_TICKET - 通过 OrderTicketID() 进行选择的问题(MT5-PositionID)。
// 修复:更改了内部库方法的名称,以便与宏更加兼容。
// 10.04.2020
// 修复:部分执行的实时挂单未进入 OrdersTotal() 中的问题。
// 09.06.2020
// 添加:平仓的 StopLoss/TakeProfit/ClosePriceRequest 现在定义得更好了。
// 10.06.2020
// 添加:在 OrderPrint() 中添加毫秒,删除价格和订单四舍五入。
// 13.08.2020
// 添加:增加了通过 MT4ORDERS_BENCHMARK_MINTIME 宏检查库部件性能的功能。
// 20.08.2020
// 修正:考虑到部分订单执行所揭示的特征。
// 29.08.2020
// 修复:更快地处理历史交易。
// 24.09.2020
// 添加:通过 SELECT_BY_TICKET(相同的票据)选择 MT4 实时订单时,如果需要提高 MT5 订单相对于 MT5 仓位的优先级、
// 可以通过将票据大小改为负值来实现:OrderSelect(-Ticket, SELECT_BY_TICKET)。
// 添加:如果您需要在修改 MT4 实时订单时指定只选择 MT5 订单(相同的票据)、
// 可以通过将票据大小改为负值来实现:OrderModify(-Ticket, ...)。
// 添加:OrderSelect(INT_MAX, SELECT_BY_POS) - 无需检查是否存在和更新,即可切换到 MT5 仓位。
// OrderSelect(INT_MIN, SELECT_BY_POS) - 切换到 MT5 实时订单,无需检查是否存在和更新。
// 修复:更快地处理历史交易。
// 30.09.2020
// 修复:更快地处理历史交易。
// 08.10.2020
// 修复:由于 MT5 新交易搜索中的缺陷,市场订单的 OrderSend 执行时间可能更长。
// 21.10.2020
// 添加:为与 MT4 兼容,添加 OrderTicketID() - 返回 OrderTicket()。
// 11.11.2020
// 修复:OrderTicketID() 和 OrderTicketOpen() 返回 TICKET_TYPE 中指定的值类型。
// 06.12.2020
// 修复:MT5 交易历史中出现错误的 SL/TP 执行记录的情况现在会得到考虑。
// 添加:MT4ORDERS_TESTER_SELECT_BY_TICKET 市场强制 SELECT_BY_TICKET 仅通过 OrderTicketID() 在测试器中运行。
// 04.05.2021
// 修复:建仓但未能消失的 MT5 订单不再添加到 MT4 订单列表中。
// 修复:CloseBy MT5 订单不再出现在 MT4 订单列表中。
// 12.05.2021
// 添加:MT4ORDERS_BYPASS_MAXTIME 宏可改变 MT5 中不断出现的交易环境不同步情况。
// 13.05.2021
// 修复:修复了 OrderOpenReason() 中的错误。
// 14.05.2021
// 修复:BYPASS 机制不再影响 OrderSelect(INT_MAX, SELECT_BY_POS) 和 OrderSelect(INT_MIN, SELECT_BY_POS)。
// 01.06.2021
// 修复:与编译器第 2449 版及更高版本的兼容性问题。
// 修复:改进了同步功能。ByPass.mqh 必须是最新版本。
// 添加:OrderLots(true) - 所选仓位的同步大小,考虑到关闭该仓位的所有订单。


我建议使用最新版本和同步机制。这样,所有其他交易库无法解决的问题都会迎刃而解。

#define  MT4ORDERS_BYPASS_MAXTIME 1000000 // 等待交易环境同步的最长时间(以微秒为单位
#include <MT4Orders.mqh> //https://www.mql5.com/en/code/16006

为使该机制发挥作用,您需要下载该库。所有复杂而有效的交易环境正确性检查都将自动完成,用户在编写交易逻辑时不会分心。

 
MT4Orders (+ByPass) 仅适用于 HistorySelect(0,INT_MAX),因此不会产生当前将刚删除的订单添加到历史表(+同步)末尾的问题。
 
fxsaber:
MT4Orders (+ByPass) 仅适用于 HistorySelect(0,INT_MAX),因此不会产生当前将刚删除的订单添加到历史表(+sync)末尾的问题。

已损坏! 我不建议更新 MT5。谁能理解并帮助解释 MT5 以前的行为是正确的。现在不是了。

 
fxsaber:

坏了! 我不建议更新 MT5。谁能理解并帮助解释 MT5 以前的行为是正确的。现在不是了。

可悲。

我草拟了一段代码,说明如何跟踪历史订单插入情况,并仅在 "移位 "期间+不超过 100 个历史仓位(即血量很少)时更新 TradesID 类。

我没有测试过这段代码,而且它当然也不是最佳的 - 只是演示一下这个想法。(黄色 - 与您的原始代码相比有哪些变化)

//跟踪订单插入和历史缓存的示例想法
//不跟踪票号的删除或更改
// 基于交易 ID
#include "Classificator.mqh"
class TRADESID
  {
   CLASSIFICATOR<ulong, ulong> OrdersID;
   CLASSIFICATOR<ulong, ulong> DealsID;

   int               LastTotalOrders;
   int               LastTotalDeals;

   //在历史记录的每一百个位置上都有一个订单
   ulong             OrderTickets[];


   void              RefreshOrders(void)
     {
      static ulong LastOrderTicket = -1;     //从上一次传递中提取的订单票据

      if(::HistorySelect(0, INT_MAX))
        {
         const int Total = ::HistoryOrdersTotal();

         if(this.LastTotalOrders > 0 && LastOrderTicket != ::HistoryOrderGetTicket(this.LastTotalOrders - 1))
           {
            int i;
            //按相反顺序检查每一百张票
            for(i = ArraySize(OrderTickets) - 1; i >= 0 && OrderTickets[i] !=::HistoryOrderGetTicket(i * 100) ; i--)
               ;
            if(i < 0)
               LastTotalOrders = 0;
            else
               {LastTotalOrders = i * 100 + 1; LastOrderTicket = OrderTickets[i];}
            ArrayResize(OrderTickets, i + 1);
           }

         while(this.LastTotalOrders < Total)
           {
            const ulong Ticket = LastOrderTicket = ::HistoryOrderGetTicket(this.LastTotalOrders); //(this.LastTotalOrders++)
            
            // 为历史记录的每一百个位置添加一张票到数组中
            if(LastTotalOrders++ % 100 == 0)
               OrderTickets[::ArrayResize(OrderTickets, ::ArraySize(OrderTickets) + 1) - 1] = Ticket;


            const ulong PositionID = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID);

            if(PositionID)
              {
               this.OrdersID.Add(PositionID, Ticket);

               const ulong PositionBy = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_BY_ID);

               if(PositionBy)
                  this.OrdersID.Add(PositionBy, Ticket);

              }
           }
        } 

      return;
     }
  };

跟踪订单删除/更改要困难得多,但您的 "圣经 "也没有解决这个问题。

当然,ByPASS 和 MT4HISTORY 需要更复杂的算法来进行校正,但似乎并不复杂(我还没研究过)。

 

您还可以跟踪TRADE_TRANSACTION_HISTORY_UPDATE 和 TRADE_TRANSACTION_HISTORY_DELETE 交易:

https://www.mql5.com/ru/forum/366029/page2#comment_22442705

如果他们提供了票据编号,并且历史记录中的订单是按票据排序的,那么就可以通过 OrderTickets 数组轻松跟踪订单在历史记录中的位置。


附注:作为最后手段,您还可以添加 HashMap...

Библиотеки: TradesID
Библиотеки: TradesID
  • 2021.05.13
  • www.mql5.com
Статьи и техническая библиотека по автоматическому трейдингу: Библиотеки: TradesID
 
mktr8591:

真可悲

如果他们不按原样返回,我们可以制作一个拐杖。 我草拟了一个代码,如何在历史记录中跟踪订单插入情况,并仅在 "移位 "期间 + 不超过 100 个历史仓位时在 TradesID 类中进行更新,即几乎不流血。

我没有测试过这段代码,而且它当然也不是最佳代码,只是演示一下而已。(黄色 - 与您的原始代码相比有何变化)

如果我没有理解错的话,您是在寻找发生移动的百位数。但我不明白,新票据本身是如何出现在那一百张票据中的?特别是如果有多个票单,而且它们位于不同的百位上。

跟踪订单删除/更改要困难得多,但你的 "圣经 "也没有解决这个问题。

我不明白。到底是什么没有被跟踪?我建议暂时停止b2958

如果是为了追溯编辑历史--那就不值得了。创建解决方案不是为了书呆子气,而是为了交易。

当然,ByPASS 和 MT4HISTORY 需要更复杂的算法来进行此类修正,但似乎并不复杂(我还没研究过)。

问题是,每次传递调用的常规函数越多,出现滞后的概率就越高。EA 开始挂起。多个智能交易系统--情况更糟。当有多个终端时,情况就更糟糕了。甚至 OnTradeTransaction 的到达也会变慢--例如,OrderSend 的时间开始比 ping 的时间长几倍。事实上,这根拐杖不仅意味着疯狂调试,还会造成滞后。试想一下,在枚举过程中,历史记录等会被更新。这样就会出现大量的 bug。


毕竟,最重要的是一切都工作得很完美。他们只是把它弄坏了,却不做任何评论。


对我来说,ZЫ 是一个谜,为什么几乎没有人明白它是怎么回事。

 
fxsaber:

ZЫ 我很奇怪,为什么几乎没有人明白这一切是怎么回事。

因为没有人尝试过在 MT5 中(a)轻松、(b)正确、(c)快速地使用订单。包括我在内。

 
fxsaber:

如果我没有理解错的话,你是在寻找发生转变的那一百张票。但我不明白,新票据本身如何位于这一百个中。特别是如果有几张票,而且它们位于不同的百位上。


如果只有插入而没有删除,那么循环

for(i = ArraySize(OrderTickets) - 1; i >= 0 && OrderTickets[i] !=::HistoryOrderGetTicket(i * 100) ; i--)
               ;

循环搜索插入票据的最早百位的开头。您不需要搜索票据本身,只需要查看从这一百个开始的所有订单和下一个(更新的)订单,并将它们添加到哈希米表中。这通常是在 while(this.LastTotalOrders < Total) 循环中完成的,几乎总是最后的 1-2 百个订单。

减少步长可能更好,不是 100 步,而是 40 或 20 步。

如果在 for 期间历史发生了变化--在找到的百单之前插入了一些东西,可以将其放入循环:

 void              RefreshOrders(void)
     {
      static ulong LastOrderTicket = -1;     //从上一次传递中提取的订单票据

      if(::HistorySelect(0, INT_MAX))
        {
         // 我们需要对 IsStopped 和最大执行时间添加检查
         while(this.LastTotalOrders > 0 && LastOrderTicket != ::HistoryOrderGetTicket(this.LastTotalOrders - 1))
           {
            int i;
            //按相反顺序检查每一百张票
            for(i = ArraySize(OrderTickets) - 1; i >= 0 && OrderTickets[i] !=::HistoryOrderGetTicket(i * 100) ; i--)
               ;
            if(i < 0)
               LastTotalOrders = 0;
            else
              {LastTotalOrders = i * 100 + 1; LastOrderTicket = OrderTickets[i];}
            ArrayResize(OrderTickets, i + 1);
            ::HistorySelect(0, INT_MAX);
           }

         const int Total = ::HistoryOrdersTotal();

         while(this.LastTotalOrders < Total)
           {
            const ulong Ticket = LastOrderTicket = ::HistoryOrderGetTicket(this.LastTotalOrders);

            // 为历史记录的每一百个位置添加一张票到数组中
            if(LastTotalOrders++ % 100 == 0)
               OrderTickets[::ArrayResize(OrderTickets, ::ArraySize(OrderTickets) + 1) - 1] = Ticket;


            const ulong PositionID = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID);

            if(PositionID)
              {
               this.OrdersID.Add(PositionID, Ticket);

               const ulong PositionBy = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_BY_ID);

               if(PositionBy)
                  this.OrdersID.Add(PositionBy, Ticket);

              }
           }
        } 
      return;
     }

但这种情况很少见。

 
mktr8591:

如果只有插入而没有删除,那么循环

循环会搜索发生插入的最早 100 张订单的起始位置。您不需要搜索票据本身,只需查看从这一百张票开始的所有订单以及下一张(较新的)订单,并将它们添加到哈希米表中。这通常是在 while(this.LastTotalOrders < Total) 循环中完成的,几乎总是最后 1-2 个百次。

也就是说,重复将同一票添加到哈希米表不会改变哈希米表吗?

我曾遇到过订单达到第八百个的情况。在活跃的交易中,这是新建仓的常见现象。 在这种情况下,您需要哈希米表几百个订单

 
fxsaber:

也就是说,重复向哈希米表添加同一张票不会改变哈希米表吗?


是的,刚才我注意到--如果重复添加票据 OrdersID.Add(PositionID,票据),那么在 OrdersID.ValuesID[] 中,该票据将被反转。也就是说,哈希表会膨胀。

我们需要以某种方式进行检查。或者使用 HashSet 代替 VALUESID 的数组结构。或者类似的方法。