- www.mql5.com
if (prev_calculated) EventChartCustom(Chart, 0, Index, 0, NULL);Es posible que se salten los ticks si el evento no se ha puesto en cola. A veces ocurre (sobre todo en un VPS o en un ordenador lento).
Por desgracia, incluso los asesores sencillos que solo cuentan con la función OnTick se saltan ticks. Para los asesores de trading, se utilizan funciones CopyTicks y otros trucos para que funcionen sin saltarse ticks.
Esta biblioteca garantiza que no se pierdan ticks únicamente en el simulador. Todo funciona exactamente igual que con OnTick.
/* // https://www.mql5.com/ru/blogs/post/755348 #define VIRTUAL_TESTER_MULTI // Ejecución en el entorno de trading virtual OnTickMulti #define VIRTUAL_LIMITS_TP_SLIPPAGE // Los órdenes de límite y TP se ejecutan al primer precio aceptado: deslizamiento positivo #define VIRTUAL_CLOSEALL_BYEND // Cierra de forma forzada todas las órdenes al final de la simulación // #define VIRTUAL_ALTERNATIVE // Velocidad alternativa de liquidación */ #include <MT4Orders.mqh> // https://www.mql5.com/es/code/16006 #include <fxsaber\OnTickMulti\OnTickMulti.mqh> // https://www.mql5.com/es/code/47647 /* #define REPORT_TESTER // Los informes se guardarán automáticamente en el tester #define REPORT_BROWSER // Creación de un informe al iniciar el navegador: requiere autorización de la DLL. #include <Report.mqh> // https://www.mql5.com/es/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 multicarácter. 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); } }
Configuración del simulador.
Aceleración.
Se puede acelerar si se descomentan las primeras líneas.
| Configuración | Resultado |
|---|---|
| Sin Virtual.mqh. | paso más corto 0:00:13,184, paso más largo 0:00:15,031, paso medio 0:00:13,633 |
| Con Virtual.mqh, inVirtualTester = false. | paso más corto 0:00:14,735, paso más largo 0:00:16,384, paso medio 0:00:15,081 |
| Con Virtual.mqh, inVirtualTester = true. | recorrido más corto 0:00:05,872, recorrido más largo 0:00:05,964, recorrido medio 0:00:05,919 |
| Con Virtual.mqh, inVirtualTester = true + VIRTUAL_ALTERNATIVE. | recorrido más corto 0:00:06,172, recorrido más largo 0:00:07,791, recorrido medio 0:00:06,524 |
El asesor es extremadamente sencillo (0-2 posiciones abiertas por cada símbolo con SL/TP fijos, sin órdenes pendientes), por lo que, en esta variante, solo se puede lograr una aceleración de 2,5 veces.
TickValue+Swap+Commission.
Las pruebas anteriores se realizaron en modo por pips (véase la captura de pantalla de la configuración), para no tener que recalcular el TickValue en cada tick, conectando para ello otros símbolos. En este modo, los resultados son idénticos.
Si se necesita una aceleración a toda máquina, hay que utilizar esta solución.
- 2023.12.25
- www.mql5.com
Foro sobre trading, sistemas de trading automáticos y pruebas de estrategias de trading
fxsaber, 18 de marzo de 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); } }
| Configuración | Resultado |
|---|---|
| Sin Virtual.mqh. | paso más corto 0:00:13,184, paso más largo 0:00:15,031, paso medio 0:00:13,633 |
Arriba he destacado en el código una forma sencilla de acelerar un asesor multimoneda sin necesidad de bibliotecas Virtual.
| Configuración | Resultado |
|---|---|
| Sin Virtual.mqh +MagicNumberOrderSymbol | paso más corto 0:00:08,608, paso más largo 0:00:10,236, paso medio 0:00:08,942 |
¡Una aceleración gratuita de 1,5 veces!
He comprobado la ralentización del Tester al pasar del modo monosimbólico al multisimbólico. No lo he hecho de forma del todo perfecta: el asesor es ficticio.
Un asesor de un solo 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++; }
| Configuración (OnTick) | Duración (mcs) | Número de ticks | Rendimiento (ticks/mcs) |
|---|---|---|---|
| EURUSD | 1079331 | 9 927 153 | 9,19 |
| GBPUSD | 1 229 032 | 11 309 740 | 9,20 |
| USDJPY | 1 307 322 | 11986756 | 9,16 |
| USDCHF | 1 121 541 | 10359511 | 9,23 |
| AUDUSD | 1 175 578 | 10758136 | 9,15 |
Se aprecia claramente que el rendimiento del Tester, expresado en número de ticks por unidad de tiempo, no depende del símbolo (modo por pips).
Asesor multisí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/es/code/47647 const ulong StartTime = GetMicrosecondCount(); int AmountTicks = 0; double OnTester() { return((double)(GetMicrosecondCount() - StartTime)); // return(AmountTicks); // return((double)AmountTicks / (GetMicrosecondCount() - StartTime)); } // OnTick multicarácter. void OnTickMulti( const string &Symb, const int &Index ) { AmountTicks++; }
| Configuración (OnTickMulti) | Duración (OnTickMulti) | Duración (OnTick) | Número de ticks | Rendimiento (OnTickMulti) | Rendimiento (OnTick) |
|---|---|---|---|---|---|
| EURUSD | 3455901 | 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 |
| EURUSD, GBPUSD, USDJPY | 9188781 | 3615685 | 33 223 649 | 3,61 | 9,18 |
| EURUSD, GBPUSD, USDJPY, USDCHF | 11517804 | 4 737 226 | 43.583.160 | 3,78 | 9,20 |
| EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD | 16058223 | 5912804 | 54 341 296 | 3,38 | 9,19 |
El rendimiento depende ligeramente del número de caracteres, pero es tres veces menor.
Conclusión.
Si tu asesor multimoneda es una mezcla de sub-TS independientes de una sola moneda, será (como mínimo) tres veces más rápido optimizar cada uno de los sub-TS por separado (y luego combinarlos mediante Validate en una sola pasada) que optimizarlos todos juntos en un único asesor multimoneda.
- www.mql5.com
// OnTick multicarácter. void OnTickMulti( const string &Symb, const u int &Index )
Hola,
Parece que en las últimas versiones (5200+) el código ya no se compila:
#include <fxsaber\OnTickMulti\OnTickMulti.mqh> // OnTick multicaracter. int TicksCounter[]; // Contador de los ticks recibidos de cada carácter especificado. void OnInit() { // Inicializamos el contador de ticks recibidos. ArrayResize(TicksCounter, ArraySize(OnTickMulti.Symbols)); ArrayInitialize(TicksCounter, 0); } double OnTester() { // Mostramos el número de ticks recibidos para cada carácter especificado. for (uint i = ArraySize(TicksCounter); (bool)i--;) Print(OnTickMulti.Symbols[i] + " - " + (string)TicksCounter[i] + " ticks."); ArrayPrint(OnTickMulti.Symbols); // Lista de caracteres de OnTickMulti. return(0); } // OnTick multicaracter. void OnTickMulti( const string &Symb, const uint &Index ) { TicksCounter[Index]++; // Se ha incrementado el contador de ticks recibidos para el símbolo especificado. }
La biblioteca se ha actualizado para adaptarse a los cambios deMQL5_b5200+.
- 2025.07.31
- www.mql5.com
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso


OnTickMulti:
Multisímbolo OnTick.
Author: fxsaber