程序库: OnTickMulti

 

OnTickMulti:

多符号 OnTick。

OnTickMulti

Author: fxsaber

 
Мультисимвольное виртуальное окружение.
Мультисимвольное виртуальное окружение.
  • www.mql5.com
Данный пост посвящен дополнительному функционалу библиотеки виртуального окружения Virtual : Мультисимвольность. Теперь можно торговать в VIrtual не по одному символу, а по любым в одном виртуальном
 
   if (prev_calculated)
    EventChartCustom(Chart, 0, Index, 0, NULL);
如果事件未被放入队列,您可能会错过事件触发。这种情况有时会发生(主要出现在VPS或 运行缓慢的计算机上)。
 
Alain Verleyen 出现在VPS或 运行缓慢的计算机上)。

遗憾的是,即使是仅包含OnTick函数的简单交易机器人,也会遗漏Tick数据。对于实战型交易机器人,通常会使用CopyTicks函数及其他技巧,以确保运行时不会遗漏Tick数据。

该库仅在模拟器中保证不会遗漏 tick。其工作原理与 OnTick 完全相同。

 
下面是别人编写的一个简单专家顾问的代码,他主动提出用它来演示 OnTickMulti 的用法。
/*
//https://www.mql5.com/ru/blogs/post/755348
#define VIRTUAL_TESTER_MULTI // 在 OnTickMulti 虚拟交易环境中运行
#define VIRTUAL_LIMITS_TP_SLIPPAGE // 止损和止盈单按首个接受价格执行——正向滑点
#define VIRTUAL_CLOSEALL_BYEND // 在测试结束时强制平仓所有订单
// #define VIRTUAL_ALTERNATIVE // 替代结算速度
*/

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

/*
#define REPORT_TESTER             // 测试器将自动记录报告
#define REPORT_BROWSER            // 启动浏览器时生成报告——需要 DLL 授权。
#include <Report.mqh> //https://www.mql5.com/zh/code/18801
*/

input group "Trading"
input double             LotSize=0.01;
input double             TPdist=0.1;                        // TP (%)
input double             SLdist=0.2;                        // SL (%)
input long               MyMagic=123;

input group "Benchmark: https://www.mql5.com/ru/forum/282062/page49#comment_50801337"
input int inRange = 0;

// 多字符 OnTick。
void OnTickMulti( const string &Symb, const int &Index )
{
  TradeStep(Symb, Index);
}

double OnTester()
{
   return AccountInfoDouble(ACCOUNT_BALANCE);
}

int GetHour( const datetime time )
{
  return((int)(time / 3600) % 24);
}

void TradeStep( const string &symbol, const int &Index )
{
   if(GetHour(TimeTradeServer()) < 2)
      return;

   DoTrade(symbol, Index);
}

bool IsMySymbol( const string &Symb, const int &Index )
{
  return(OnTickMulti.IsOnlySymbolBase ||
         (
        #ifdef __VIRTUAL__
          VIRTUAL::GetHandle() ? (OrderSymbolID() == Index) : //https://www.mql5.com/ru/forum/282062/page52#comment_51051261
        #endif // #ifdef __VIRTUAL__
          (OrderSymbol() == Symb)));
}

void DoTrade(const string &symbol, const int &Index )
{
   int total=OrdersTotal();
   bool haveBuy=false;
   bool haveSell=false;
   for(int i=0; i<total; i++)
   {
      if(OrderSelect(i, SELECT_BY_POS) &&
         OrderMagicNumber()==MyMagic &&
         IsMySymbol(symbol, Index))
      {
         int type=OrderType();
         if(type==OP_BUY)
            haveBuy=true;
         if(type==OP_SELL)
            haveSell=true;
      }
   }
   
   if(!haveBuy)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_ASK);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0+TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0-SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_BUY,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         MyMagic);
   }

   if(!haveSell)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_BID);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0-TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0+SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_SELL,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         MyMagic);
   }
}


测试器的设置。



加速。

如果将开头的几行代码注释掉,就可以加快运行速度。


测试结果。

配置 结果
不使用 Virtual.mqh。 最短通过时间 0:00:13.184,最长通过时间 0:00:15.031,平均通过时间 0:00:13.633
启用 Virtual.mqh,inVirtualTester = false。 最短通过时间 0:00:14.735, 最长通过时间 0:00:16.384,平均通过时间 0:00:15.081
使用 Virtual.mqh,inVirtualTester = true。 最短通过时间 0:00:05.872, 最长通过时间 0:00:05.964,平均通过时间 0:00:05.919
使用 Virtual.mqh,inVirtualTester = true + VIRTUAL_ALTERNATIVE。 最短通过时间 0:00:06.172, 最长通过时间 0:00:07.791,平均通过时间 0:00:06.524

该专家顾问极其简单(每个交易品种最多开2个仓位,设有固定的止损/止盈,不使用挂单),因此在此方案下,速度仅能提升2.5倍。


TickValue+Swap+Commission。

上述测试是在点差模式下进行的(参见设置截图),以避免在每个 tick 时重新计算 TickValue,并为此连接其他交易品种。在此模式下,结果完全一致。

如果需要极致的提速效果,那么就必须采用这一方案。

OnTickMulti - с добавленными пересчетом прибыли в валюту депозита, свопами, комисссией в % за лот.
OnTickMulti - с добавленными пересчетом прибыли в валюту депозита, свопами, комисссией в % за лот.
  • 2023.12.25
  • www.mql5.com
Текущий вариант OnTickMulti https://www.mql5.com/ru/code/47647 считает прибыль в валюте каждого символа или можно получить в пипсах. Но на общий баланс они влияют в другой пропорции, согласно текущему
 

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

库:OnTickMulti

fxsaber, 2024年3月18日 18:36

void DoTrade(const string &symbol, const int &Index )
{
   int total=OrdersTotal();
   bool haveBuy=false;
   bool haveSell=false;
   for(int i=0; i<total; i++)
   {
      if(OrderSelect(i, SELECT_BY_POS) &&
         (OrderMagicNumber()==Index))
      {
         int type=OrderType();
         if(type==OP_BUY)
            haveBuy=true;
         if(type==OP_SELL)
            haveSell=true;
      }
   }
   
   if(!haveBuy)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_ASK);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0+TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0-SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_BUY,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         Index);
   }

   if(!haveSell)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_BID);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0-TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0+SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_SELL,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         Index);
   }
}

配置 结果
未使用 Virtual.mqh。 最短运行时间 0:00:13.184,最长运行时间 0:00:15.031,平均运行时间 0:00:13.633

上文在代码中演示了无需任何 Virtual 库即可加速多货币交易顾问的简便方法。

配置 结果
不使用 Virtual.mqh +MagicNumberOrderSymbol 最短运行时间 0:00:08.608,最长运行时间 0:00:10.236,平均运行时间 0:00:08.942

免费提速1.5倍!

 

测试了测试器在从单字符模式切换到多字符模式时的性能下降情况。测试过程并不完全理想——这是一个空顾问。


单符号专家顾问。

#property tester_no_cache

input group "Benchmark: https://www.mql5.com/ru/forum/282062/page49#comment_50801337"
input int inRange = 0;

const ulong StartTime = GetMicrosecondCount();
int AmountTicks = 0;

double OnTester()
{
  return((double)(GetMicrosecondCount() - StartTime));
//  return(AmountTicks);
//  return((double)AmountTicks / (GetMicrosecondCount() - StartTime));
}

void OnTick()
{
  AmountTicks++;
}
配置 (OnTick) 时间长度 (mcs) AmountTicks 性能 (ticks/mcs)
EURUSD 1079331 9927153 9.19
英镑兑美元 1229032 11309740 9.20
美元兑日元 1307322 11986756 9.16
美元/瑞郎 1121541 10359511 9.23
澳元兑美元 1175578 10758136 9.15

可以清楚地看到,以单位时间内的 tick 数衡量的测试器性能与交易品种无关(按点模式)。


多品种自动交易系统。

#property tester_no_cache

input group "Benchmark: https://www.mql5.com/ru/forum/282062/page49#comment_50801337"
input int inRange = 0;

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

const ulong StartTime = GetMicrosecondCount();
int AmountTicks = 0;

double OnTester()
{
  return((double)(GetMicrosecondCount() - StartTime));
//  return(AmountTicks);
//  return((double)AmountTicks / (GetMicrosecondCount() - StartTime));
}

// 多字符 OnTick。
void OnTickMulti( const string &Symb, const int &Index )
{
  AmountTicks++;
}
配置 (OnTickMulti) 时间长度 (OnTickMulti) 时间长度 (OnTick) AmountTicks Performance (OnTickMulti) 性能 (OnTickMulti)
EURUSD
3455901 1079331 9927153 2.87 9.19
欧元兑美元、英镑兑美元
6617085 2308363
21236893 3.20 9.19
欧元兑美元、英镑兑美元、美元兑日元
9188781 3615685 33223649 3.61 9.18
欧元兑美元、英镑兑美元、美元兑日元、美元兑瑞士法郎
11517804 4737226 43583160 3.78 9.20
欧元兑美元、英镑兑美元、美元兑日元、美元兑瑞郎、澳元兑美元
16058223 5912804 54341296 3.38 9.19

性能与字符数量的关系不大,但其性能仅为后者的三分之一。


结论。

如果您的多币种交易顾问是由多个独立的单币种子交易策略拼凑而成的,那么 (至少)将每个子交易系统单独优化(然后通过Validate在单次运行中合并)的速度,要比在同一个多币种智能交易系统中一次性优化所有子交易系统快三倍。

 
Мультивалютный Apart-режим.
Мультивалютный Apart-режим.
  • www.mql5.com
Большинство мультивалютных советников представляют из себя портфель независимых (по логике торговых сигналов) друг от друга ТС, где если связь и есть, то за счет ММ - все ТС оказывают влияние на общие
 
OnTickMulti 的函数签名略有变化。
// 多字符 OnTick。
void OnTickMulti( const string &Symb, const u int &Index )
 

您好,

看起来在最新的构建版本(5200+)中,代码无法再编译了:

#include <fxsaber\OnTickMulti\OnTickMulti.mqh> // 多字符 OnTick。

int TicksCounter[]; // 每个指定字符的接收时钟脉冲计数器。

void OnInit()
{
  // 初始化接收到的时钟脉冲计数器。
  ArrayResize(TicksCounter, ArraySize(OnTickMulti.Symbols));
  ArrayInitialize(TicksCounter, 0);
}

double OnTester()
{
  // 输出每个指定字符收到的时钟脉冲数量。
  for (uint i = ArraySize(TicksCounter); (bool)i--;)
    Print(OnTickMulti.Symbols[i] + " - " + (string)TicksCounter[i] + " ticks.");

  ArrayPrint(OnTickMulti.Symbols); // OnTickMulti 符号列表。

  return(0);
}

// 多字符 OnTick。
void OnTickMulti( const string &Symb, const uint &Index )
{
  TicksCounter[Index]++; // 增加了指定字符的接收时钟脉冲计数器。
}
 
Marat Sultanov #:

看起来在最新的构建版本(5200+)中,代码无法再编译了

该库已根据MQL5_b5200+的变更进行了更新。

Новая версия платформы MetaTrader 5 build 5200: расширение OpenBLAS и усиление контроля в MQL5 - Версия MetaTrader 5 расширила поддержку библиотеки линейной алгебры OpenBLAS.
Новая версия платформы MetaTrader 5 build 5200: расширение OpenBLAS и усиление контроля в MQL5 - Версия MetaTrader 5 расширила поддержку библиотеки линейной алгебры OpenBLAS.
  • 2025.07.31
  • www.mql5.com
SylvesterEquationTriangular решает уравнение Сильвестра для вещественных квазитреугольных или комплексных треугольных матриц верхнетреугольные. SylvesterEquationTriangularBlocked решает уравнение Сильвестра для вещественных квазитреугольных или комплексных треугольных матриц верхнетреугольные матрицы