MQL5 — La Guida Completa alla Programmazione per MetaTrader 5 | MTInvestments

MQL5 — La Guida Completa
alla Programmazione
per MetaTrader 5

Da zero alla programmazione professionale su MT5: struttura del linguaggio, i tre tipi di programmi, l'architettura event-driven, le funzioni fondamentali, la gestione degli ordini e i template base pronti da usare. Con esempi di codice reali estratti da UlcerZenith Oracle v78 — 12.000+ righe di MQL5 produzione.

Cos'è MQL5 — Il Linguaggio di MetaTrader 5

MQL5 (MetaQuotes Language 5) è il linguaggio di programmazione proprietario sviluppato da MetaQuotes per la piattaforma MetaTrader 5. È un linguaggio compilato, basato sulla sintassi di C++, con supporto completo per la programmazione orientata agli oggetti — classi, ereditarietà, polimorfismo, template.

Rispetto a MQL4 (il predecessore per MT4), MQL5 è profondamente diverso: è più potente, più vicino a un vero linguaggio di programmazione, e ha un ecosistema di librerie standard molto più ricco. La curva di apprendimento è più ripida — ma chi impara MQL5 ha in mano uno strumento professionale che può costruire sistemi della complessità di UlcerZenith Oracle.

◈ MQL4 vs MQL5 — confronto tecnico
Caratteristica MQL4 (MT4) MQL5 (MT5)
PiattaformaMetaTrader 4MetaTrader 5
ParadigmaProceduraleOOP + Procedurale
BacktestingOHLC — limitatoTick data reale
Multi-threadingNoSì
Account modelSolo hedgingNetting + Hedging
Libreria standardMinimaleCompleta (STL-like)
Market DepthNoSì
FuturoDeprecato lentamenteAttivamente sviluppato

I Tre Tipi di Programmi MQL5

Prima di scrivere una riga di codice, devi scegliere quale tipo di programma stai creando. In MQL5 esistono tre tipi fondamentali, ognuno con funzione e struttura diversa:

📊
Indicatore
Custom Indicator · .ex5
Calcola valori numerici e li visualizza sul grafico come linee, istogrammi, punti o testo. Non apre ordini — analizza e mostra dati. UlcerZenith Oracle è un indicatore.
#property indicator_chart_window
🤖
Expert Advisor
EA Automatico · .ex5
Sistema automatico che apre, gestisce e chiude ordini autonomamente. Gira sul grafico H24. Decide e agisce senza intervento umano. ZENITH EXECUTOR EA è un EA.
#property expert_auto_trading
⚡
Script
Programma monouso · .ex5
Esegue una singola operazione quando viene avviato manualmente — poi si ferma. Usato per inserire hash di licenza, esportare dati, chiudere tutte le posizioni in un click.
#property script_show_inputs

Architettura Event-Driven — Come Pensa MQL5

MQL5 è un linguaggio event-driven: i tuoi programmi non girano in un loop continuo. Dormono e si svegliano solo quando MetaTrader genera un evento specifico. Ogni tipo di evento corrisponde a una funzione speciale che devi implementare:

◈ Ciclo di vita di un programma MQL5 — eventi principali
OnInit()
Inizializzazione — una sola volta all'avvio
Viene chiamato una volta sola quando il programma viene caricato sul grafico. Qui inizializzi variabili, leggi i parametri di input, crei oggetti grafici, verifichi la licenza. Se restituisce un valore diverso da INIT_SUCCEEDED, il programma si ferma.
int OnInit() { /* inizializzazione */ return(INIT_SUCCEEDED); }
OnTick() / OnCalculate()
Nuovo tick — cuore del programma
OnTick() per EA — chiamato ad ogni nuovo tick di prezzo. OnCalculate() per indicatori — chiamato quando arriva un nuovo tick o si apre una nuova barra. Qui vive la logica principale del tuo sistema.
void OnTick() { /* logica EA */ } | int OnCalculate(const int rates_total, ...)
OnChartEvent()
Interazione utente — click, tastiera, oggetti
Viene chiamato quando l'utente interagisce con il grafico: click del mouse, pressione di tasti, click su pulsanti personalizzati. Oracle usa OnChartEvent() per gestire i bottoni della dashboard — cambio di timeframe, cambio di simbolo, ecc.
void OnChartEvent(const int id, const long &lparam, ...)
OnTimer()
Timer periodico — azioni programmate
Se attivato con EventSetTimer(N), viene chiamato ogni N secondi. Usato da Oracle per aggiornare la dashboard e inviare heartbeat al sistema di licenze a intervalli regolari, indipendentemente dall'arrivo di nuovi tick.
void OnTimer() { /* azioni periodiche */ }
OnDeinit()
Chiusura — pulizia prima di uscire
Viene chiamato quando il programma viene rimosso dal grafico. Qui si pulisce tutto: si eliminano gli oggetti grafici creati, si liberano le risorse, si salvano dati persistenti, si cancella il timer.
void OnDeinit(const int reason) { /* pulizia risorse */ }

La Struttura Base di un Indicatore MQL5

Vediamo la struttura completa di un indicatore MQL5 minimo ma funzionante — uno che calcola e plotta una media mobile semplice. Questo è il template da cui parte ogni indicatore personalizzato:

MQL5 · Indicatore SimpleMA_Example.mq5
// ============================================================
// SimpleMA_Example.mq5 — Template indicatore base
// Autore: Manuel Trotta · MTInvestments
// ============================================================

// --- PROPRIETÀ INDICATORE ---
#property copyright   "Manuel Trotta - MTInvestments"
#property version      "1.00"
#property indicator_chart_window          // sul grafico principale
#property indicator_buffers 1             // numero di buffer dati
#property indicator_plots   1             // numero di linee plottate

// --- PROPRIETÀ PLOT ---
#property indicator_label1  "MA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrGold
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

// --- PARAMETRI INPUT ---
input int    InpPeriod  = 14;        // Periodo MA
input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE;

// --- BUFFER DATI ---
double MABuffer[];          // array dove Oracle scrive i valori

// --- HANDLE INDICATORI BUILT-IN ---
int g_ma_handle;

// ============================================================
// OnInit — inizializzazione
// ============================================================
int OnInit()
  {
   // Collega il buffer all'array
   SetIndexBuffer(0, MABuffer, INDICATOR_DATA);
   
   // Crea handle per la MA built-in
   g_ma_handle = iMA(_Symbol, _Period, InpPeriod, 0,
                     MODE_SMA, InpPrice);
   
   if(g_ma_handle == INVALID_HANDLE)
     {
      Print("Errore creazione handle MA: ", GetLastError());
      return(INIT_FAILED);
     }
   
   IndicatorSetString(INDICATOR_SHORTNAME,
                      "MA(" + IntegerToString(InpPeriod) + ")");
   return(INIT_SUCCEEDED);
  }

// ============================================================
// OnCalculate — calcolo ad ogni tick/barra
// ============================================================
int OnCalculate(const int     rates_total,
                const int     prev_calculated,
                const datetime &time[],
                const double  &open[],
                const double  &high[],
                const double  &low[],
                const double  &close[],
                const long    &tick_volume[],
                const long    &volume[],
                const int     &spread[])
  {
   // Quante barre devo calcolare?
   int to_copy = rates_total - prev_calculated;
   if(to_copy <= 0) to_copy = 1;  // sempre almeno 1
   
   // Copia i valori MA dal handle nel buffer
   if(CopyBuffer(g_ma_handle, 0, 0, to_copy, MABuffer) < 0)
     {
      Print("CopyBuffer error: ", GetLastError());
      return(0);
     }
   
   return(rates_total);  // tutte le barre calcolate
  }

// ============================================================
// OnDeinit — pulizia
// ============================================================
void OnDeinit(const int reason)
  {
   if(g_ma_handle != INVALID_HANDLE)
      IndicatorRelease(g_ma_handle);
  }

Le Funzioni Fondamentali — Il Vocabolario di Base

MQL5 ha centinaia di funzioni built-in. Queste sono quelle che userai in ogni progetto professionale — le funzioni che appaiono decine di volte in UlcerZenith Oracle:

◈ Dati di prezzo
iClose() / iHigh() / iLow()
double iClose(symbol, timeframe, shift)
Restituisce il prezzo di chiusura (o massimo/minimo) della barra al shift specificato. shift=0 = barra corrente, shift=1 = barra precedente. In Oracle: usare sempre shift≥1 per evitare look-ahead bias.
◈ Indicatori tecnici
CopyBuffer()
int CopyBuffer(handle, buffer_idx, start, count, buffer[])
Copia N valori dal buffer di un indicatore nel tuo array. È il modo corretto di leggere gli indicatori built-in in MQL5 — prima crei l'handle con iMA(), iATR(), ecc., poi usi CopyBuffer() per leggere i valori.
◈ Gestione ordini (EA)
CTrade::Buy() / Sell()
bool Buy(volume, symbol, price, sl, tp, comment)
Apre un ordine market Long (o Short con Sell). Usa la classe CTrade dalla libreria standard — molto più robusto delle vecchie funzioni OrderSend(). Include gestione automatica del codice di errore e retry.
◈ Oggetti grafici
ObjectCreate()
bool ObjectCreate(chart_id, name, type, subwindow, ...)
Crea un oggetto grafico — rettangolo, testo, freccia, linea orizzontale. Oracle usa ObjectCreate() per costruire l'intera dashboard — centinaia di oggetti posizionati con precisione pixel per creare l'interfaccia Ferrari Luce.
◈ GlobalVariables
GlobalVariableSet() / Get()
bool GlobalVariableSet(name, double value)
Il meccanismo di comunicazione tra programmi MQL5. Una variabile globale è visibile da tutti i programmi sulla stessa istanza di MT5 — indicatori, EA, script. Oracle usa GlobalVariables per passare l'Oracle Score al ZENITH EXECUTOR EA.
◈ Alert e notifiche
SendNotification()
bool SendNotification(string text)
Invia una notifica push all'app MetaTrader sul telefono. Alternativa: WebRequest() per inviare messaggi Telegram — Oracle usa WebRequest() con l'API di Telegram per gli alert con entry, SL, TP e lotti.
◈ Strutture dati
ArraySetAsSeries()
bool ArraySetAsSeries(array[], bool flag)
Fondamentale e spesso dimenticato. Per default gli array in MQL5 hanno indice 0 = barra più vecchia. Con ArraySetAsSeries(true), indice 0 = barra più recente (come ci si aspetta intuitivamente). Oracle lo usa su tutti i price array.
◈ Informazioni account
AccountInfoDouble()
double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE)
Restituisce informazioni sull'account: balance, equity, margin, free margin. Oracle usa AccountInfoDouble(ACCOUNT_BALANCE) per calcolare i lotti dinamicamente in base al capitale corrente e alla percentuale di rischio configurata.

Template EA — Struttura Base di un Expert Advisor

Ecco il template base di un Expert Advisor MQL5 professionale — la struttura che trovi in ogni EA serio, incluso ZENITH EXECUTOR:

MQL5 · Expert Advisor EA_Template.mq5
#property copyright "Manuel Trotta - MTInvestments"
#property version   "1.00"
#include <Trade\Trade.mqh>   // Libreria ordini standard

// --- INPUT ---
input double InpRiskPercent  = 1.0;   // Rischio % per trade
input double InpSL_Pips      = 30.0;  // Stop Loss in pips
input double InpTP_RR        = 3.0;   // Take Profit RR
input double InpScoreMin     = 4.5;   // Oracle Score minimo

// --- OGGETTI GLOBALI ---
CTrade  g_trade;            // oggetto per gestire ordini
bool    g_position_open;    // flag posizione aperta
ulong   g_ticket;           // ticket dell'ordine corrente

// ============================================================
int OnInit()
  {
   g_trade.SetExpertMagicNumber(20241987);   // magic number univoco
   g_trade.SetDeviationInPoints(10);           // slippage max 1 pip
   g_position_open = false;
   Print("EA inizializzato correttamente");
   return(INIT_SUCCEEDED);
  }

// ============================================================
void OnTick()
  {
   // Lavora solo sulla chiusura di una nuova barra
   static datetime last_bar_time = 0;
   datetime current_bar = (datetime)SeriesInfoInteger(
                            _Symbol, PERIOD_H4, SERIES_LASTBAR_DATE);
   if(current_bar == last_bar_time) return; // stessa barra
   last_bar_time = current_bar;
   
   // Leggi Oracle Score dalla GlobalVariable
   double oracle_score = GlobalVariableGet("ORACLE_SCORE_EURUSD_H4");
   double oracle_dir   = GlobalVariableGet("ORACLE_DIR_EURUSD_H4");
   // +1.0 = BUY signal, -1.0 = SELL signal, 0 = no signal
   
   // Verifica condizioni di ingresso
   if(oracle_score >= InpScoreMin && !g_position_open)
     {
      double lot  = CalcLots(InpRiskPercent, InpSL_Pips);
      double ask  = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      double bid  = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double pip  = SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 10;
      
      if(oracle_dir > 0)  // BUY signal
        {
         double sl = ask - InpSL_Pips * pip;
         double tp = ask + InpSL_Pips * pip * InpTP_RR;
         if(g_trade.Buy(lot, _Symbol, ask, sl, tp, "Oracle"))
           {
            g_position_open = true;
            g_ticket = g_trade.ResultOrder();
            Print("BUY aperto · ticket: ", g_ticket,
                  " · lots: ", lot);
           }
        }
     }
  }

// ============================================================
// CalcLots — calcola lotti su % di rischio
// ============================================================
double CalcLots(double risk_pct, double sl_pips)
  {
   double balance    = AccountInfoDouble(ACCOUNT_BALANCE);
   double risk_money = balance * risk_pct / 100.0;
   double pip_value  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double lot        = risk_money / (sl_pips * pip_value * 10);
   
   // Normalizza al lotsize del broker
   double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   lot = MathMax(min_lot, MathRound(lot / lot_step) * lot_step);
   return(lot);
  }
MQL5 non è difficile — è diverso. Chi conosce C++ si trova a casa entro una settimana. Chi parte da zero ha bisogno di 2-3 mesi di pratica su progetti reali. Il trucco è sempre lo stesso: costruire qualcosa di funzionante subito, anche piccolo.

GlobalVariables — La Comunicazione tra Programmi

Le GlobalVariables sono il meccanismo con cui Oracle e ZENITH EXECUTOR EA si parlano. Sono variabili double persistenti visibili da tutti i programmi in esecuzione sulla stessa istanza di MT5. Oracle scrive i segnali nelle GlobalVariables, l'EA le legge ad ogni tick:

MQL5 · GlobalVariables ZEX-SYNC v1.0 — bridge Oracle → EA
// ============================================================
// LATO ORACLE (indicatore) — scrive il segnale
// ============================================================
void WriteSignalToGV(string symbol, string tf,
                     double score, double direction,
                     double entry, double sl, double tp)
  {
   string prefix = "ORACLE_" + symbol + "_" + tf + "_";
   
   GlobalVariableSet(prefix + "SCORE",     score);
   GlobalVariableSet(prefix + "DIRECTION",  direction); // +1=BUY -1=SELL
   GlobalVariableSet(prefix + "ENTRY",      entry);
   GlobalVariableSet(prefix + "SL",         sl);
   GlobalVariableSet(prefix + "TP",         tp);
   GlobalVariableSet(prefix + "TIMESTAMP",  (double)TimeCurrent());
  }

// ============================================================
// LATO EXECUTOR EA — legge il segnale
// ============================================================
bool ReadSignalFromGV(string symbol, string tf,
                      double &score, double &direction,
                      double &sl, double &tp)
  {
   string prefix = "ORACLE_" + symbol + "_" + tf + "_";
   
   // Verifica che il segnale esista e sia recente (<5 min)
   if(!GlobalVariableCheck(prefix + "SCORE")) return(false);
   
   double ts = GlobalVariableGet(prefix + "TIMESTAMP");
   if(TimeCurrent() - (datetime)ts > 300) return(false); // segnale stale
   
   score     = GlobalVariableGet(prefix + "SCORE");
   direction = GlobalVariableGet(prefix + "DIRECTION");
   sl        = GlobalVariableGet(prefix + "SL");
   tp        = GlobalVariableGet(prefix + "TP");
   
   return(score >= 4.5 && direction != 0.0);
  }

Vuoi vedere 12.000 righe
di MQL5 in azione?

UlcerZenith Oracle v78 — tutto quello che hai letto in questa guida, implementato.
Live gratuite: iscriviti alla prossima — Oracle sul grafico MT5 in tempo reale.

Entra nel Canale Gratuito → Costruisci il tuo indicatore →

FAQ — MQL5 e MetaTrader 5

Cos'è MQL5 e a cosa serve? ▶
MQL5 (MetaQuotes Language 5) è il linguaggio di programmazione proprietario di MetaTrader 5. Serve per creare tre tipi di programmi: indicatori personalizzati (calcolano e mostrano dati statistici sul grafico), Expert Advisor (sistemi automatici che aprono e gestiscono ordini), e Script (programmi monouso per operazioni singole). MQL5 è basato su C++ con supporto OOP completo. È il linguaggio con cui è stato costruito UlcerZenith Oracle — oltre 12.000 righe di codice produzione.
Devo conoscere la programmazione per usare MetaTrader 5? ▶
No — MT5 funziona benissimo senza scrivere codice. Puoi usare indicatori e EA già pronti dal Marketplace MQL5 o sviluppati da terzi. La programmazione serve se vuoi creare i tuoi strumenti personalizzati o capire come funzionano quelli che usi. Per usare Oracle non devi saper programmare — ricevi l'alert Telegram con entry, SL, TP e lotti già calcolati, e inserisci manualmente l'ordine in 90 secondi.
Qual è la differenza tra MQL4 e MQL5? ▶
MQL4 gira su MetaTrader 4 (piattaforma in fase di dismissione). MQL5 gira su MetaTrader 5 — più moderno, più potente. Differenze principali: MQL5 supporta OOP completa (classi, ereditarietà), backtesting su tick data reale (non solo OHLC), multi-threading, e ha una libreria standard molto più ricca. MQL4 era più semplice ma più limitato. Se stai iniziando oggi, impara direttamente MQL5 — MQL4 è legacy.
Come si impara MQL5 partendo da zero? ▶
Percorso consigliato: 1) Installa MetaTrader 5 e apri l'editor MetaEditor (F4). 2) Leggi la documentazione ufficiale su docs.mql5.com — è eccellente e in italiano. 3) Inizia con un indicatore semplice (es: media mobile personalizzata) per capire la struttura. 4) Passa a un EA con gestione ordini di base. 5) Studia il codice di progetti open source sul Marketplace. La curva di apprendimento pratica è circa 2-3 mesi per qualcuno senza esperienza di programmazione, 2-4 settimane per chi conosce già C++ o C#.
Come funziona il backtest in MQL5? ▶
Il backtesting in MQL5 si esegue tramite lo Strategy Tester di MT5 (Ctrl+R). Puoi testare su dati OHLC (più veloce) o su tick data reale (più accurato per timeframe brevi). Oracle v78 supporta backtesting completo — puoi scaricare i tick data storici direttamente da MT5 e simulare il comportamento del sistema su qualsiasi periodo. Il CSV export integrato in Oracle permette di estrarre tutti i trade del backtest con data, simbolo, entry, SL, TP e risultato per analisi statistica esterna.
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
Disclaimer: Il trading su strumenti finanziari comporta un elevato rischio di perdita del capitale investito. Il codice MQL5 presentato è a scopo educativo. Nessun contenuto costituisce consulenza finanziaria ai sensi del D.Lgs. 58/1998 (TUF). Manuel Trotta / MTInvestments P.IVA 14349331000.