- www.mql5.com
Infelizmente, mesmo os consultores simples que possuem apenas a função OnTick deixam de receber os ticks. Para consultores de negociação, utilizam-se as funções CopyTicks e outros recursos para que funcionem sem perder ticks.
Esta biblioteca garante que não há perda de ticks apenas no Testador. Tudo funciona exatamente da mesma forma que com a função OnTick.
/* // https://www.mql5.com/ru/blogs/post/755348 #define VIRTUAL_TESTER_MULTI // Execução no ambiente de negociação virtual OnTickMulti #define VIRTUAL_LIMITS_TP_SLIPPAGE // Os ordens de limite e TP são executadas ao primeiro preço de aceitação — slippage positivo #define VIRTUAL_CLOSEALL_BYEND // Fechamento forçado de todas as ordens ao final do teste // #define VIRTUAL_ALTERNATIVE // Velocidade alternativa de cálculos */ #include <MT4Orders.mqh> // https://www.mql5.com/pt/code/16006 #include <fxsaber\OnTickMulti\OnTickMulti.mqh> // https://www.mql5.com/pt/code/47647 /* #define REPORT_TESTER // Os relatórios serão gravados automaticamente no testador #define REPORT_BROWSER // Criação de relatório com abertura do navegador — requer permissão da DLL. #include <Report.mqh> // https://www.mql5.com/pt/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 com vários caracteres. 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); } }
Configurações do Testador.
Aceleração.
É possível acelerar o código se você descomentar algumas linhas no início.
| Configuração | Resultado |
|---|---|
| Sem o Virtual.mqh. | passagem mais curta 0:00:13,184, passagem mais longa 0:00:15,031, média das passagens 0:00:13,633 |
| Com o Virtual.mqh, inVirtualTester = false. | passagem mais curta 0:00:14,735, passagem mais longa 0:00:16,384, média das passagens 0:00:15,081 |
| Com Virtual.mqh, inVirtualTester = true. | passagem mais curta 0:00:05,872, passagem mais longa 0:00:05,964, média das passagens 0:00:05,919 |
| Com Virtual.mqh, inVirtualTester = true + VIRTUAL_ALTERNATIVE. | passagem mais curta 0:00:06,172, passagem mais longa 0:00:07,791, média das passagens 0:00:06,524 |
O consultor é extremamente simples (0 a 2 posições abertas por cada instrumento, com SL/TP fixos, sem ordens pendentes); portanto, nessa variante, é possível obter apenas uma aceleração de 2,5 vezes.
TickValue+Swap+Commission.
Os testes acima foram realizados no modo por pips (veja a captura de tela das configurações), para não precisar recalcular o TickValue a cada tick, conectando outros símbolos para isso. Nesse modo, os resultados são idênticos.
Se for necessário um aumento de velocidade com todas as opções ativadas, deve-se usar esta solução.
- 2023.12.25
- www.mql5.com
Fórum sobre trading, sistemas de negociação automatizados e testes de estratégias de trading
fxsaber, 18/03/2024 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); } }
| Configuração | Resultado |
|---|---|
| Sem o Virtual.mqh. | passagem mais curta 0:00:13,184, passagem mais longa 0:00:15,031, média das passagens 0:00:13,633 |
Acima, destaquei no código uma maneira simples de acelerar um robô multimoeda sem o uso de nenhuma biblioteca Virtual.
| Configuração | Resultado |
|---|---|
| Sem o Virtual.mqh +MagicNumberOrderSymbol | passagem mais curta 0:00:08,608, passagem mais longa 0:00:10,236, passagem média 0:00:08,942 |
Aceleração gratuita em 1,5 vez!
Verifiquei a lentidão do Tester ao passar do modo monossimbólico para o multissimbólico. Não fiz isso de maneira totalmente ideal — o consultor é fictício.
Consultor de um único símbolo.
#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++; }
| Configuração (OnTick) | TimeLength (mcs) | Quantidade de Ticks | Desempenho (ticks/mcs) |
|---|---|---|---|
| EURUSD | 1.079.331 | 9.927.153 | 9,19 |
| GBPUSD | 1.229.032 | 11.309.740 | 9,20 |
| USDJPY | 1.307.322 | 11.986.756 | 9,16 |
| USDCHF | 1.121.541 | 10.359.511 | 9,23 |
| AUDUSD | 1.175.578 | 10758136 | 9,15 |
Fica bem claro que o desempenho do Testador, medido pelo número de ticks por unidade de tempo, não depende do símbolo (modo por pips).
Eximador multissímbolo.
#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/pt/code/47647 const ulong StartTime = GetMicrosecondCount(); int AmountTicks = 0; double OnTester() { return((double)(GetMicrosecondCount() - StartTime)); // return(AmountTicks); // return((double)AmountTicks / (GetMicrosecondCount() - StartTime)); } // OnTick com vários caracteres. void OnTickMulti( const string &Symb, const int &Index ) { AmountTicks++; }
| Configuração (OnTickMulti) | TimeLength (OnTickMulti) | TimeLength (OnTick) | Quantidade de Ticks | Desempenho (OnTickMulti) | Desempenho (OnTick) |
|---|---|---|---|---|---|
| EURUSD | 3.455.901 | 1.079.331 | 9.927.153 | 2,87 | 9,19 |
| EUR/USD, GBP/USD | 6617085 | 2.308.363 | 21.236.893 | 3,20 | 9,19 |
| EUR/USD, GBP/USD, USD/JPY | 9188781 | 3615685 | 33.223.649 | 3,61 | 9,18 |
| EUR/USD, GBP/USD, USD/JPY, USD/CHF | 11517804 | 4.737.226 | 43.583.160 | 3,78 | 9,20 |
| EUR/USD, GBP/USD, USD/JPY, USD/CHF, AUD/USD | 16.058.223 | 5912804 | 54.341.296 | 3,38 | 9,19 |
O desempenho depende pouco do número de caracteres, mas é três vezes menor.
Conclusão.
Se o seu consultor multimoeda for uma mistura de sub-TS independentes de uma única moeda, será (no mínimo) três vezes mais rápido otimizar cada um dos sub-TS (e depois uni-los por meio do Validate em uma única execução) separadamente do que otimizar todos juntos em um único consultor multimoeda.
- www.mql5.com
// OnTick com vários caracteres. void OnTickMulti( const string &Symb, const u int &Index )
Olá,
Parece que, nas versões mais recentes (5200+), o código não compila mais:
#include <fxsaber\OnTickMulti\OnTickMulti.mqh> // OnTick com vários caracteres. int TicksCounter[]; // Contador de ticks recebidos para cada caractere definido. void OnInit() { // Inicializamos o contador de ticks recebidos. ArrayResize(TicksCounter, ArraySize(OnTickMulti.Symbols)); ArrayInitialize(TicksCounter, 0); } double OnTester() { // Exibimos o número de ticks recebidos para cada símbolo especificado. for (uint i = ArraySize(TicksCounter); (bool)i--;) Print(OnTickMulti.Symbols[i] + " - " + (string)TicksCounter[i] + " ticks."); ArrayPrint(OnTickMulti.Symbols); // Lista de símbolos do OnTickMulti. return(0); } // OnTick com vários caracteres. void OnTickMulti( const string &Symb, const uint &Index ) { TicksCounter[Index]++; // Aumentamos o contador de ticks recebidos para o símbolo especificado. }
A biblioteca foi atualizada para se adequar às alteraçõesdo MQL5_b5200+.
- 2025.07.31
- www.mql5.com
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso


OnTickMulti:
OnTick de vários símbolos.
Author: fxsaber