MetaTrader 5 build 3490:移动网页端版本和MQL5的新矩阵方法

MetaTrader 5新功能

4 十一月 2022

网页平台的移动端版本

全新网页端为移动设备提供全功能的支持。该界面将自动适应屏幕尺寸,实现iOS与Android手机和平板电脑的高效操作:

在新网页端中添加对移动设备的支持

此外,网页端还进行多项修复和改进。

全新MetaTrader 5网页端支持全部交易功能。使用户能够:

  • 使用模拟账户和真实账户进行交易
  • 接收任何交易品种的报价
  • 在任何市场进行交易
  • 使用30多个指标和20个图形对象分析交易品种报价
  • 使用经济日历数据进行基本面分析


程序端

  1. 扩展任务管理器功能。新版本可以更准确地监控消耗的资源。
    • 添加线程中堆栈大小的显示。
    • 添加上下文切换数量的显示。
    • 添加对系统和第三方DLL线程的识别。
    • 添加内核模式运行时间的显示。与在用户模式下花费的时间相比,该指标的增加可能表明系统级问题:驱动程序问题、硬件错误或减缓硬件。更多细节,请参阅Microsoft文档
    • 添加用户模式运行时间的显示。

    控制可用设备的OpenCL管理器


  2. 程序端设置中用于管理可用设备的新OpenCL选项卡。新OpenCL管理器能够明确指定用于计算的设备。

    控制可用设备的OpenCL管理器

  3. 为在FIFO模式下运行的账户添加在市场深度中止损和止盈水平的指示(该模式可以在交易商端启用)。

    根据FIFO规则,每个交易品种的持仓只能按照开仓的相同顺序进行平仓。为确保通过止损位平仓符合FIFO标准,在客户端实施以下逻辑:

    如果同一交易品种存在多个持仓,则为任何持仓设置止损水平会导致所有其他持仓也设置相同的水平。因此,如果触发一个水平,则所有仓位都将按照FIFO规则平仓。

    现在,当用户为已经有未结持仓的交易品种打开市场深度时,现有持仓水平(如果有)会自动在止损和止盈字段中指定。

  4. 修正使用工具箱\交易窗口中的X按键删除止损和止盈水平的问题。该错误通常在禁用快速交易功能时发生。单击该按键将打开一个交易对话框,其中包含相关级别的空值。

  5. 修正交易报告中的图形标题和最后手续费计算的问题。该部分可能显示报告统计中的不正确的利润,和净值与结余图的工具提示中的不正确值。

MQL5

  1. 添加向量和矩阵方法CopyTicks和CopyTicksRange。它们可以轻松地将报价数据数组复制到向量和矩阵中。
    bool matrix::CopyTicks(string symbol,uint flags,ulong from_msc,uint count);
    bool vector::CopyTicks(string symbol,uint flags,ulong from_msc,uint count);
    
    bool matrix::CopyTicksRange(string symbol,uint flags,ulong from_msc,ulong to_msc);
    bool matrix::CopyTicksRange(string symbol,uint flags,ulong from_msc,ulong to_msc);
    复制的数据类型使用ENUM_COPY_TICKS枚举在"flags"参数中指定。以下值可供使用:
    COPY_TICKS_INFO    = 1,       // 由卖价和/或买价更改得出的报价
    COPY_TICKS_TRADE   = 2,       // 由最后价和交易量更改得出的报价
    COPY_TICKS_ALL     = 3,       // 所有报价都发生变化
    COPY_TICKS_TIME_MS = 1<<8,    // 以毫秒为单位的时间
    COPY_TICKS_BID     = 1<<9,    // 卖价
    COPY_TICKS_ASK     = 1<<10,   // 买价
    COPY_TICKS_LAST    = 1<<11,   // 最后价
    COPY_TICKS_VOLUME  = 1<<12,   // 交易量
    COPY_TICKS_FLAGS   = 1<<13,   // 报价标识
    如果选择了多种数据类型(仅适用于矩阵),矩阵中的行序将对应于枚举中的值的顺序。

  2. 扩展了matrix::Assignvector::Assign方法的功能。

    现在可以为矩阵分配一个一维数组或向量:
    bool matrix::Assign(const vector &vec);
    结果将是一个单行矩阵。

    此外,现在可以将矩阵分配给向量(将执行矩阵平滑):
    bool vector::Assign(const matrix &mat);
  3. 为向量和矩阵添加Swap方法。
    bool vector::Swap(vector &vec);
    bool vector::Swap(matrix &vec);
    bool vector::Swap(double &arr[]);
    bool matrix::Swap(vector &vec);
    bool matrix::Swap(matrix &vec);
    bool matrix::Swap(double &arr[]);
    每个数组、向量或矩阵都指向一个包含该对象元素的内存缓冲区。Swap方法实际上交换指向这些缓冲区的指针,而不将元素写入内存。因此,矩阵仍然是矩阵,向量仍然是向量。交换矩阵和矢量会产生一个带有矢量元素的单行矩阵和一个平面表示的带有矩阵元素的矢量(见Flat方法)。
    //+------------------------------------------------------------------+
    //| 脚本程序起始函数                           |
    //+------------------------------------------------------------------+
    void OnStart()
     {
    //---
      matrix a= {{1, 2, 3},
    
    
    
     {4, 5, 6}};
      Print("a before Swap: \n", a);
      matrix b= {{5, 10, 15, 20},
    
    
    
     {25, 30, 35, 40},
    
    
    
     {45, 50, 55, 60}};
      Print("b before Swap: \n", b);  
    //--- swap矩阵指针
      a.Swap(b);
      Print("a after Swap: \n", a);
      Print("b after Swap: \n", b);
      /*
      a before Swap:
      [[1,2,3]
      [4,5,6]]
      b before Swap:
      [[5,10,15,20]
      [25,30,35,40]
      [45,50,55,60]]
      
      a after Swap:
      [[5,10,15,20]
      [25,30,35,40]
      [45,50,55,60]]
      b after Swap:
      [[1,2,3]
      [4,5,6]]
      */
      vector v=vector::Full(10, 7);
      Print("v before Swap: \n", v);
      Print("b before Swap: \n", b);
      v.Swap(b);
      Print("v after Swap: \n", v);
      Print("b after Swap: \n", b);
      /*
      v before Swap:
      [7,7,7,7,7,7,7,7,7,7]
      b before Swap:
      [[1,2,3]
      [4,5,6]]
      
      v after Swap:
      [1,2,3,4,5,6]
      b after Swap:
      [[7,7,7,7,7,7,7,7,7,7]]
      */
     }
    Swap()方法还可以使用动态数组进行操作(固定大小的数组不能作为参数传递)。数组可以是任何维度,但具有约定的大小,这意味着矩阵或向量的总大小必须是数组零维度的倍数。数组零维度是第一个索引处包含的元素数。例如,对于动态三维数组"double array[][2][3]",零维是第二维和第三维大小的乘积:2x3=6。因此,这样的数组只能在Swap方法中用于总大小为6的倍数的矩阵和向量:6、12、18、24等。

    考虑以下示例:
    //+------------------------------------------------------------------+
    //| 脚本程序起始函数                           |
    //+------------------------------------------------------------------+
    void OnStart()
     {
    //--- 用7.0值填写1x10矩阵
      matrix m= matrix::Full(1, 10, 7.0);
      Print("matrix before Swap:\n", m);
    //--- 尝试交换矩阵和数组
      double array_small[2][5]= {{1, 2, 3, 4, 5},
    
    
    
     {6, 7, 8, 9, 10}};
      Print("array_small before Swap:");
      ArrayPrint(array_small);
      if(m.Swap(array_small))
       {
        Print("array_small after Swap:");
        ArrayPrint(array_small);
        Print("matrix after Swap: \n", m);
       }
      else // 矩阵大小不是第一个数组维度的倍数
       {
        Print("m.Swap(array_small) failed. Error ", GetLastError());
       }
      /*
      matrix before Swap:
      [[7,7,7,7,7,7,7,7,7,7]]
      array_small before Swap:
               [,0]     [,1]     [,2]     [,3]     [,4]
      [0,]  1.00000  2.00000  3.00000  4.00000  5.00000
      [1,]  6.00000  7.00000  8.00000  9.00000 10.00000
      m.Swap(array_small) failed. Error 4006
      */
    //--- 使用更大的矩阵并重试交换操作
      double array_static[3][10]= {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
    
    
    
    
         {2, 4, 6, 8, 10, 12, 14, 16, 18, 20},
    
    
    
    
         {3, 6, 9, 12, 15, 18, 21, 24, 27, 30}
       };
      Print("array_static before Swap:");
      ArrayPrint(array_static);
      if(m.Swap(array_static))
       {
        Print("array_static after Swap:");
        ArrayPrint(array_static);
        Print("matrix after Swap: \n", m);
       }
      else // 静态数组不能用于与矩阵交换
       {
        Print("m.Swap(array_static) failed. Error ", GetLastError());
       }
      /*
      array_static before Swap:
             [,0]     [,1]     [,2]     [,3]     [,4]     [,5]     [,6]     [,7]     [,8]     [,9]
      [0,]  1.00000  2.00000  3.00000  4.00000  5.00000  6.00000  7.00000  8.00000  9.00000 10.00000
      [1,]  2.00000  4.00000  6.00000  8.00000 10.00000 12.00000 14.00000 16.00000 18.00000 20.00000
      [2,]  3.00000  6.00000  9.00000 12.00000 15.00000 18.00000 21.00000 24.00000 27.00000 30.00000
      m.Swap(array_static) failed. Error 4006
      */
    //--- 交换数组和矩阵的另一种尝试
      double array_dynamic[][10];    // 动态数组
      ArrayResize(array_dynamic, 3); // 设置第一维度大小
      ArrayCopy(array_dynamic, array_static);
    //--- 现在为swap使用动态数组
      if(m.Swap(array_dynamic))
       {
        Print("array_dynamic after Swap:");
        ArrayPrint(array_dynamic);
        Print("matrix after Swap: \n", m);
       }
      else //  没有错误
       {
        Print("m.Swap(array_dynamic) failed. Error ", GetLastError());
       }
      /*
      array_dynamic after Swap:
            [,0]    [,1]    [,2]    [,3]    [,4]    [,5]    [,6]    [,7]    [,8]    [,9]
      [0,] 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000
      matrix after Swap:
      [[1,2,3,4,5,6,7,8,9,10,2,4,6,8,10,12,14,16,18,20,3,6,9,12,15,18,21,24,27,30]]
      */
     }
  4. 添加向量和矩阵的LossGradient方法。这种方法计算损失函数对预测值的偏导函数的向量或矩阵。在线性代数中,这样的向量被称为梯度,并在机器学习中使用。
    vector vector::LossGradient(const vector &expected,ENUM_LOSS_FUNCTION loss) const;
    matrix matrix::LossGradient(const matrix &expected,ENUM_LOSS_FUNCTION loss) const;
  5. 启用SQLite中的FOREIGN KEYS,以在SQL查询中加强表格之间的关系。  示例:
    CREATE TABLE artist(
      artistid    INTEGER PRIMARY KEY, 
      artistname  TEXT
    );
    
    CREATE TABLE track(
      trackid     INTEGER, 
      trackname   TEXT, 
      trackartist INTEGER,
      FOREIGN KEY(trackartist) REFERENCES artist(artistid)
    );

  6. 修正根据方法和对象的不变性,选择对应类方法的问题。

MetaEditor

  1. 添加提交到MQL5存储中的评论的允许长度。 在大型项目中,向存储库提交修改时的详细评论被认为是很好的实践,但以前评论的长度被限制在128个字符。现在允许的长度最多260个字符。

MetaTester

  1. 提高可视模式下测试速度开关的灵敏度。

修正崩溃日志中的错误报告。