- www.mql5.com
if (prev_calculated) EventChartCustom(Chart, 0, Index, 0, NULL);이벤트가 대기열에 추가되지 않은 경우 티크를 놓칠 수 있습니다. 이런 경우가 가끔 발생합니다(주로 VPS나 성능이 낮은 컴퓨터에서 ).
/* // https://www.mql5.com/ru/blogs/post/755348 #define VIRTUAL_TESTER_MULTI // OnTickMulti 가상 트레이딩 환경에서 실행 #define VIRTUAL_LIMITS_TP_SLIPPAGE // 리미트 주문 및 TP는 첫 번째 체결 가격에 따라 실행됨 - 양의 슬리피지 #define VIRTUAL_CLOSEALL_BYEND // 테스트 종료 시 모든 주문을 강제 청산합니다 // #define VIRTUAL_ALTERNATIVE // 대체 계산 속도 */ #include <MT4Orders.mqh> // https://www.mql5.com/ko/code/16006 #include <fxsaber\OnTickMulti\OnTickMulti.mqh> // https://www.mql5.com/ko/code/47647 /* #define REPORT_TESTER // 테스터에 보고서가 자동으로 기록됩니다. #define REPORT_BROWSER // 브라우저를 실행하며 보고서 생성 - DLL 권한이 필요합니다. #include <Report.mqh> // https://www.mql5.com/ko/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 |
이 Expert Advisor는 매우 간단합니다(각 종목당 0~2개의 오픈 포지션, 고정된 SL/TP, 보류 주문 없음). 따라서 이 설정에서는 속도가 2.5배만 향상됩니다.
TickValue+Swap+Commission.
위의 테스트는 매 틱마다 TickValue를 재계산하지 않기 위해(설정 스크린샷 참조) 핍 단위로 수행되었으며, 이를 위해 다른 종목들을 연결했습니다. 이 모드에서도 결과는 동일합니다.
완벽한 최적화를 통해 속도를 높이고 싶다면 이 솔루션을 사용해야 합니다.
- 2023.12.25
- www.mql5.com
트레이딩, 자동 매매 시스템 및 매매 전략 테스트에 관한 포럼
fxsaber, 2024.03.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) | TimeLength (mcs) | AmountTicks | 성능 (틱/mcs) |
|---|---|---|---|
| EURUSD | 1079331 | 9927153 | 9.19 |
| GBPUSD | 1229032 | 11309740 | 9.20 |
| USDJPY | 1307322 | 11986756 | 9.16 |
| USDCHF | 1121541 | 10359511 | 9.23 |
| AUDUSD | 1175578 | 10758136 | 9.15 |
테스터의 성능(단위 시간당 틱 수)이 종목에 영향을 받지 않는다는 점이 명확히 드러납니다(핍 단위 모드).
다중 종목 EA.
#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/ko/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) | TimeLength (OnTickMulti) | TimeLength (OnTick) | 틱 수 | 성능 (OnTickMulti) | 성능 (OnTick) |
|---|---|---|---|---|---|
| EURUSD | 3455901 | 1079331 | 9927153 | 2.87 | 9.19 |
| EURUSD, GBPUSD | 6617085 | 2308363 | 21236893 | 3.20 | 9.19 |
| EURUSD, GBPUSD, USDJPY | 9188781 | 3615685 | 33223649 | 3.61 | 9.18 |
| EURUSD, GBPUSD, USDJPY, USDCHF | 11517804 | 4737226 | 43,583,160 | 3.78 | 9.20 |
| EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD | 16058223 | 5912804 | 54341296 | 3.38 | 9.19 |
처리량은 문자 수에 거의 영향을 받지 않지만, 그 수치는 3배 더 낮습니다.
결론.
여러분의 다중 통화 EA가 서로 독립적인 단일 통화 서브 EA들의 모음이라면, (최소한) 하나의 다중 통화 EA에서 모두 함께 최적화하는 것보다 각 하위 TS를 따로따로 최적화한 후(Validate를 통해 한 번에 통합) 하는 것이 세 배 더 빠릅니다.
- www.mql5.com
// 다중 문자 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]++; // 지정된 기호에 대한 수신 틱 카운터를 증가시켰습니다. }
MQL5_b5200+의변경 사항에 맞춰 라이브러리가 업데이트되었습니다.
- 2025.07.31
- www.mql5.com


온틱멀티:
멀티심볼 온틱.
Author: fxsaber