Debug MQL5: Tecniche Professionali per Trovare e Correggere i Bug | Manuel Trotta

Debug MQL5 — Tecniche Professionali su Codice di Produzione

Oracle v78 ha 8.293 righe di MQL5. In 17 versioni ho trovato e corretto bug che costavano punti di Profit Factor. Il debug non è una fase opzionale: è la differenza tra un sistema che funziona su carta e uno che sopravvive al mercato reale. Ti mostro le tecniche che uso in produzione.

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

◆ Pattern di Logging Professionale in MQL5
// ─── 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 ErroreNomeCausa TipicaSoluzione
4053Array out of boundsAccesso a indice fuori rangeAggiungi if(i < period) continue;
4401Invalid handleiCustom/indicatore non trovatoVerifica nome file e percorso .ex5
4301Unknown symbolSimbolo non disponibile nel brokerAggiungi SymbolSelect(sym, true)
10006RequotePrezzo cambiato prima dell’esecuzioneUsa ORDER_FILLING_RETURN o gestisci retry
10014Invalid volumeLot size fuori limiti brokerClamp tra SymbolInfoDouble VOLUME_MIN/MAX
10016Invalid SL/TPSL/TP troppo vicino al prezzoRispetta SymbolInfoInteger TRADE_STOPS_LEVEL
4756Trade disabledEA senza permesso di tradingAbilita “Allow Algorithmic Trading” nelle opzioni
0No errorTutto OKVerifica comunque il risultato dell’operazione
4051Wrong parameter typeTipo errato passato a funzioneControlla i cast espliciti (int)(double)
4303Global var not foundGlobalVariableGet su GV non esistenteUsa GlobalVariableCheck() prima di Get()

I Pattern di Debug Specifici per EA Trading

Pattern 01
Il Bug del Segnale che “Scompare” — Shift=0 vs Shift=1
Sintomo: il sistema entra in un trade in backtest ma nelle live non lo fa mai, o viceversa. Causa quasi sempre: si legge il segnale su shift=0 (barra in formazione) invece di shift=1 (barra chiusa). In backtest, il tester ricostruisce i segnali su barra chiusa correttamente. In live, il segnale su shift=0 cambia durante la barra. Fix: 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.
Pattern 02
Il Bug del GlobalVariable Non Trovato
Oracle v78 usa GlobalVariables per comunicare tra l’indicatore e l’EA. Il bug classico: l’EA legge la GV prima che l’indicatore la scriva, ottenendo 0.0 o EMPTY_VALUE. Fix: 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.
Pattern 03
Il Bug del Lot Size Fuori Range
La formula di position sizing calcola un lot size che può essere leggermente sotto il minimo del broker (es. 0.009 invece di 0.01 minimo). Il broker rifiuta l’ordine con errore 10014. Fix standard Oracle: 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;
Pattern 04
Il Bug del Canvas Invisibile
Bug specifico risolto in Oracle v78: la dashboard CCanvas non veniva visualizzata su alcuni simboli perché FindSubWindow() ritornava 1 invece di 0 su grafici senza finestre separate. Fix: la condizione di skip era 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.
◆ Template di Debug Completo — Standard Oracle
// ─── 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
◆ Oracle v78 — Bug Critici Risolti nell’Ultima Versione
6 bug documentati risolti in v77.
Ogni fix ha migliorato il Profit Factor o ridotto il drawdown.
6
Bug Critici v77
+0.11
PF Guadagnato
−28%
DD Ridotto
3.2k
Ore Sviluppo

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

Come si fa il debug in MQL5? ▶
3 livelli: 1) Print() e PrintFormat() per logging rapido nel tab Esperti del terminale. 2) Debugger MetaEditor (F5) con breakpoint e watch per bug logici complessi. 3) Strategy Tester visual per replicare esattamente le condizioni di un bug storico. Il 70% dei bug si trova con Print(), il 20% con il Debugger, il 10% richiede Strategy Tester.
Cosa significa errore 4053 array out of bounds in MQL5? ▶
Accesso a un indice fuori dal range dell’array. Causa più comune: 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.
Come usare il Debugger di MetaEditor? ▶
1) Clicca sul margine sinistro della riga per aggiungere un breakpoint. 2) F5 per avviare il debug nel Strategy Tester. 3) Quando il codice si ferma al breakpoint: F10 (Step Over) per eseguire riga per riga, F11 (Step Into) per entrare nelle funzioni. 4) Pannello Watch: aggiungi espressioni MQL5 per monitorare variabili in tempo reale. Combinato con una data specifica nel Strategy Tester, permette di replicare esattamente un bug storico.
Come trovare un bug che avviene solo live e non in backtest? ▶
La causa più comune è la lettura di shift=0 (barra in formazione) invece di shift=1 (barra chiusa). In backtest il tester valuta i segnali su barra chiusa automaticamente. In live, shift=0 cambia a ogni tick. Fix universale: leggi sempre shift=1 per segnali operativi. Aggiungi Print() con il valore a shift=0 e shift=1 per confrontare — se sono diversi, hai trovato la causa.
Manuel Trotta — Trader quantitativo, fondatore MTInvestments, autore Hoepli
◆ Scritto da

Manuel Trotta

Trader quantitativo italiano dal novembre 2007 — 19 anni online. Fondatore MTInvestments, creatore UlcerZenith Oracle v78 con 65.587 trade reali verificati H4 XAUUSD. Autore di 18 libri sul trading e finanza personale: "Fare Trading con Excel" (Hoepli 2019), "Diventa Investitore Profittevole in 15 Minuti al Giorno", "Il Latte con la Mucca" (memoir 2026), più 2 volumi tecnici. Speaker IT Forum Rimini. Online dal 2007 — stesso nome, stessa P.IVA.

P.IVA 14349331000 Dal Novembre 2007 18 Libri su Amazon ↗ 150K+ Follower