I 3 Livelli di Debug MQL5: Dal Più Semplice al Più Potente
Il debug in MQL5 non ha un’unica tecnica universale — ha una gerarchia di strumenti, ciascuno adatto a un tipo di problema. Il livello 1 è il logging con Print(): rapido, zero setup, ideale per capire cosa sta succedendo durante l’esecuzione. Il livello 2 è il Debugger integrato di MetaEditor: potente, richiede configurazione, indispensabile per bug logici complessi. Il livello 3 è il Strategy Tester in modalità visual: permette di replicare esattamente le condizioni storiche in cui si è verificato un bug.
In 19 anni di sviluppo Oracle, il 70% dei bug è stato trovato con Print(), il 20% con il Debugger, il 10% solo tramite Strategy Tester visuale su date specifiche. Non esistono bug MQL5 che non si trovano con la combinazione di questi tre strumenti — esistono solo sviluppatori che usano il livello sbagliato per il problema sbagliato.
Livello 1: Print() e PrintFormat() — Il Log Strutturato
// ─── Macro di debug condizionale ────────────────────── // Attiva solo in sviluppo, disattiva in produzione input bool InpDebugMode = false; #define DBG(msg) if(InpDebugMode) Print("[DBG] ", msg) #define DBG2(lbl,val) if(InpDebugMode) \ PrintFormat("[DBG] %s = %.5f | bar=%d | %s", \ lbl, (double)(val), \ Bars(_Symbol,_Period)-1, \ (string)TimeCurrent()) // ─── Uso nel codice ──────────────────────────────────── void OnTick() { double score = CalcOracleScore(); // Log condizionale — zero overhead in produzione DBG2("OracleScore", score); if(score > 70.0) { DBG("Segnale LONG attivato"); OpenLong(); } } // ─── Log con timestamp e simbolo ────────────────────── // Standard usato in Oracle per tutti i log critici void LogCritico(string msg) { PrintFormat("%s | %s | %s | %s", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES), _Symbol, EnumToString(_Period), msg); }
Livello 2: Il Debugger MetaEditor — Breakpoint e Watch
Il Debugger di MetaEditor è il tool più potente per bug logici dove Print() non è sufficiente — ad esempio quando una variabile ha un valore corretto a un certo punto ma poi viene sovrascritta in modo imprevisto più avanti nel codice. Il flusso di debug con MetaEditor è semplice: apri il file, clicca sul margine sinistro per aggiungere un breakpoint (cerchio rosso), premi F5 per avviare il debug nel Strategy Tester. Quando l’esecuzione raggiunge il breakpoint, si ferma e puoi ispezionare ogni variabile nel pannello Watch.
Il pannello Watch permette di aggiungere espressioni MQL5 arbitrarie: non solo variabili singole, ma anche ArraySize(myArray), close[i], iClose(_Symbol,PERIOD_H4,1). Per bug su condizioni logiche complesse, aggiungere l’espressione completa nel Watch evita di aggiungere decine di Print() nel codice.
Tabella dei 10 Errori MQL5 Più Frequenti e Come Risolverli
| Codice Errore | Nome | Causa Tipica | Soluzione |
|---|---|---|---|
| 4053 | Array out of bounds | Accesso a indice fuori range | Aggiungi if(i < period) continue; |
| 4401 | Invalid handle | iCustom/indicatore non trovato | Verifica nome file e percorso .ex5 |
| 4301 | Unknown symbol | Simbolo non disponibile nel broker | Aggiungi SymbolSelect(sym, true) |
| 10006 | Requote | Prezzo cambiato prima dell’esecuzione | Usa ORDER_FILLING_RETURN o gestisci retry |
| 10014 | Invalid volume | Lot size fuori limiti broker | Clamp tra SymbolInfoDouble VOLUME_MIN/MAX |
| 10016 | Invalid SL/TP | SL/TP troppo vicino al prezzo | Rispetta SymbolInfoInteger TRADE_STOPS_LEVEL |
| 4756 | Trade disabled | EA senza permesso di trading | Abilita “Allow Algorithmic Trading” nelle opzioni |
| 0 | No error | Tutto OK | Verifica comunque il risultato dell’operazione |
| 4051 | Wrong parameter type | Tipo errato passato a funzione | Controlla i cast espliciti (int)(double) |
| 4303 | Global var not found | GlobalVariableGet su GV non esistente | Usa GlobalVariableCheck() prima di Get() |
I Pattern di Debug Specifici per EA Trading
CopyBuffer(handle, 0, 1, 1, buf) — il secondo parametro 1 inizia dalla barra chiusa. Questo bug ha causato la differenza tra backtest PF 1.8 e live PF 0.9 su una versione intermedia di Oracle.if(!GlobalVariableCheck("UZ_XAUUSD_H4_SCORE")) return; Prima di ogni lettura di GV critica. Aggiungere anche un timestamp nella GV per verificare che il dato sia fresco: se il timestamp è più vecchio di 5 minuti su H4, il dato non è aggiornato.double lots = MathMax(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN), MathMin(calculatedLots, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX)));
Arrotonda poi al volume step: lots = MathRound(lots / volStep) * volStep;g_subWin > 0 (sbagliata) — corretta in g_subWin >= 0. Questo tipo di bug — una comparazione > invece di >= — è invisibile a un ispezione visiva rapida del codice e richiede il Debugger con watch sulla variabile g_subWin per essere trovato.// ─── Sistema di logging con livelli ─────────────────── enum ENUM_LOG_LEVEL { LOG_OFF=0, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG }; input ENUM_LOG_LEVEL InpLogLevel = LOG_ERROR; void Log(ENUM_LOG_LEVEL level, string msg) { if(level > InpLogLevel) return; string prefix; switch(level) { case LOG_ERROR: prefix = "[ERR] "; break; case LOG_WARN: prefix = "[WRN] "; break; case LOG_INFO: prefix = "[INF] "; break; case LOG_DEBUG: prefix = "[DBG] "; break; default: prefix = "[???] "; } Print(prefix, TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES), " | ", _Symbol, " | ", msg); } // Uso: Log(LOG_ERROR, "OrderSend fallito: "+(string)GetLastError()); Log(LOG_WARN, "SL adattato per stops level"); Log(LOG_DEBUG, "Score="+DoubleToString(score,2)); // ─── Assert per validazione invarianti ──────────────── #define ASSERT(cond, msg) \ if(!(cond)) { \ Log(LOG_ERROR, "ASSERT FAILED: " msg); \ return; \ } // Uso: ASSERT(lots > 0.0, "lot size deve essere positivo"); ASSERT(sl < price, "SL LONG deve essere sotto il prezzo");
Un bug trovato in sviluppo costa 1 ora di debug. Lo stesso bug in produzione su un conto reale può costare settimane di drawdown e settimane per capire cosa è andato storto. Il logging strutturato non è un lusso — è la garanzia minima che hai di capire il tuo sistema quando succede qualcosa di imprevisto. — Manuel Trotta, Fondatore MTInvestments
Ogni fix ha migliorato il Profit Factor o ridotto il drawdown.
I 6 bug critici di Oracle v78 includevano: FIX-EA-01 (canvas invisibile per FindSubWindow), FIX-EA-02 (condizione GARCH g_subWin), FIX-EA-03 (g_InitDone nel percorso TierBlocked), FIX-CLOSE-02 (EMA check da crossover singolo a 2 barre consecutive), FIX-MTF-H1 (blocco sessione 17–21 GMT, +9.2pp WR) e FIX-REVTOP (blocco REVERSAL TOP su H1/H4). Nessuno di questi bug era visibile compilando il codice: tutti richiedevano debug attivo su Strategy Tester o log strutturato su dati storici specifici.
Ogni versione di Oracle nasce da un audit sistematico del codice precedente — non da modifiche estemporanee. Il debug è una disciplina, non una reazione ai problemi.
Vedi Oracle v78 in Produzione dal Vivo
Live gratuite: iscriviti alla prossima. Sistema reale, conto reale, zero bug critici attivi.
ENTRA ALLA LIVE GRATUITA → CREARE INDICATORE MQL5 →FAQ — Debug MQL5
close[i - period] quando i < period. Fix: aggiungi if(i < period) continue; all’inizio del loop. Usa Print() con ArraySize() prima dell’accesso sospetto per verificare la dimensione dell’array in quel momento.