//+------------------------------------------------------------------+ //| HealthTrader.mq4 | //| Copyright 2026, Allan NiƱal | //| https://www.allanninal.dev/mql5 | //+------------------------------------------------------------------+ //| Test EA (not shipped) for EA Health Monitor MT4, run in the MT4 | //| Strategy Tester (tester trades only). It trades a seeded random | //| mix on every new bar: several magic numbers and "manual" (magic | //| 0) orders with comments, stop loss / take profit, partial closes | //| ("from #" chains), full closes and close-by. Every InpSnapBars | //| bars and at the end it writes a snapshot: | //| ____orders.csv the raw orders (history in | //| its reading order, then the open ones) | //| ____stats.csv its own book (HealthLive.mqh | //| EHRefresh: the whole history) | //| and ___snaps.csv (k, now, day start). | //| tests/mt4/check_mt4.py turns the raw orders into deals on its | //| own and compares everything with tests/reference.py. | //| Run it in the MT4 Strategy Tester (open prices), once per symbol | //| with the inputs in tests/mt4/configs.tsv. | //+------------------------------------------------------------------+ // SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE) #property strict #include "..\\..\\Indicators\\EAHealth\\HealthLive.mqh" input string InpTag = "eh"; input int InpSeed = 1; input int InpSnapBars = 400; // bars between snapshots input int InpMaxOpen = 12; // most open orders int g_k=0,g_bars=0,g_ops=0,g_fail=0; int g_err[8]; // refusals by error code (the most common ones) int g_errc[8]; datetime g_last_bar=0; EHLive g_all; string g_base; int g_snap=INVALID_HANDLE; bool g_done=false; long MAGICS[4]={0,11,22,771500}; string COMMENTS[4]={"","TrendEA","Grid v2","Swing EA"}; int LOTS[5]={1,2,3,5,10}; // order sizes in minimum lots (the symbol's own lot rules) int Rnd(const int n) { return(MathRand()%n); } void Refused() { g_fail++; int e=GetLastError(); for(int i=0; i<8; i++) if(g_errc[i]==0 || g_err[i]==e) { g_err[i]=e; g_errc[i]++; return; } } int OnInit() { MathSrand(InpSeed); g_base=StringFormat("%s_%s_%s",InpTag,_Symbol,StringSubstr(EnumToString((ENUM_TIMEFRAMES)_Period),7)); EHLiveInit(g_all,""); g_snap=FileOpen(g_base+"_snaps.csv",FILE_WRITE|FILE_TXT|FILE_ANSI); FileWriteString(g_snap,"k,now,day\n"); return(INIT_SUCCEEDED); } //--- the indicator through iCustom with its default inputs (it has no buffers: the call runs its OnCalculate, a smoke test; //--- the MT4 tester gives it no chart, so its panel cannot be read) void RunIndicator() { iCustom(NULL,0,"EAHealth\\EAHealthMonitor",0,0); } void Trade() { int r=Rnd(100); RefreshRates(); if(r<35 && OrdersTotal()OP_SELL) return; int tk=OrderTicket(),type=OrderType(); double lots=OrderLots(),price=(type==OP_BUY ? Bid : Ask); double mn=MarketInfo(_Symbol,MODE_MINLOT),st=MarketInfo(_Symbol,MODE_LOTSTEP); double half=MathFloor(lots/2.0/st+1e-9)*st; if(r<60 && half>=mn-1e-9) // partial close: half, rounded down to the lot step { g_ops++; if(!OrderClose(tk,NormalizeDouble(half,2),price,50,clrNONE)) Refused(); } else if(r<80) { g_ops++; if(!OrderClose(tk,lots,price,50,clrNONE)) Refused(); } else if(r<88) // close by an opposite order for(int i=0; i0; i++) why+=StringFormat(" %d x%d",g_err[i],g_errc[i]); PrintFormat("Dump4 %s.csv: %d bars, %d trade operations (%d refused:%s), %d snapshots, history %d orders, open %d", g_base,g_bars,g_ops,g_fail,why,g_k,OrdersHistoryTotal(),OrdersTotal()); } double OnTester() { Finish(); return(0.0); } void OnDeinit(const int reason) { Finish(); } //+------------------------------------------------------------------+