Analisi · 2026-04-15
OnCalculate MQL5:
la Funzione Principale
degli Indicatori Custom.
OnCalculate è la funzione obbligatoria di ogni indicatore custom MQL5. È l’equivalente di OnTick per gli EA: viene chiamata ad ogni nuova barra o ad ogni tick. Capire il meccanismo dei parametri rates_total, prev_calculated e il calcolo incrementale è essenziale per costruire indicatori efficienti come l’Ulcer Index di Oracle v78.
·
15 Aprile 2026
·
Aggiornato in tempo reale
·
~14 min lettura
1. Struttura di un Indicatore Custom MQL5
Un indicatore custom MQL5 ha una struttura diversa da un Expert Advisor. Non usa OnTick o OnInit (sebbene OnInit esista anche negli indicatori per l’inizializzazione). La funzione principale è OnCalculate, che viene chiamata ogni volta che c’è un nuovo dato da elaborare — ad ogni nuova barra o ad ogni nuovo tick, secondo la modalità dell’indicatore.
struttura_indicatore.mq5MQL5
// Dichiarazioni obbligatorie
#property indicator_chart_window // Mostra l'indicatore nel grafico principale
// oppure: #property indicator_separate_window // Finestra separata sotto il grafico
#property indicator_buffers 1 // Numero di buffer di output
#property indicator_plots 1 // Numero di linee da disegnare
// Dichiarazione del buffer
double BufferUlcer[]; // Array che contiene i valori dell'indicatore
// OnInit: configurazione del buffer
int OnInit()
{
SetIndexBuffer(0, BufferUlcer, INDICATOR_DATA);
PlotIndexSetString(0, PLOT_LABEL, "Ulcer Index");
PlotIndexSetInteger(0, PLOT_COLOR, clrOrange);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
IndicatorSetString(INDICATOR_SHORTNAME, "UlcerIndex(14)");
return INIT_SUCCEEDED;
}
// OnCalculate: logica di calcolo (vedi sezione 2)
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[])
{
// ... logica di calcolo ...
return rates_total; // FONDAMENTALE: indica quante barre sono state elaborate
}
2. La Firma di OnCalculate: i 4 Parametri Chiave
OnCalculate riceve 10 parametri, ma 4 sono critici per capire il meccanismo di aggiornamento efficiente dell’indicatore:
rates_total: il numero totale di barre disponibili nel grafico in questo momento. Cambia ogni volta che si aggiunge una nuova barra (tipicamente una volta ogni 4 ore su H4).
prev_calculated: il numero di barre calcolate durante la chiamata precedente di OnCalculate. Questo è il parametro più importante per il calcolo incrementale: se prev_calculated == rates_total, nessuna nuova barra è stata aggiunta e non c’è nulla da ricalcolare. Se prev_calculated < rates_total, ci sono (rates_total − prev_calculated) barre nuove da calcolare.
close[], high[], low[], open[]: array con i prezzi di tutte le barre. L’indice 0 è la barra più recente (la corrente in formazione), l’indice rates_total−1 è la barra più vecchia.
3. Calcolo Incrementale: Come Evitare Ricalcoli Inutili
Il calcolo incrementale è la tecnica più importante per gli indicatori custom efficienti. Senza di essa, l’indicatore ricalcola tutti i valori storici ad ogni tick — inutilmente e molto lentamente. Con il calcolo incrementale, ricalcola solo le barre nuove.
calcolo_incrementale.mq5MQL5
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[])
{
int PERIOD = 14; // Periodo dell'indicatore
// Prima barra da calcolare: logica incrementale
int pos_first;
if(prev_calculated == 0)
{
// Primo calcolo: elabora dall'inizio (barra PERIOD-1 per avere storia sufficiente)
pos_first = PERIOD - 1;
// Inizializza le barre precedenti a EMPTY_VALUE (non mostrate sul grafico)
for(int i = 0; i < pos_first; i++)
BufferUlcer[i] = EMPTY_VALUE;
}
else
{
// Calcolo incrementale: ricomincia una barra prima dell'ultima elaborata
// (-1 per includere la barra corrente in formazione che potrebbe essere aggiornata)
pos_first = prev_calculated - 1;
}
// Calcola il valore per ogni nuova barra
for(int i = pos_first; i < rates_total; i++)
{
if(i < PERIOD - 1) { BufferUlcer[i] = EMPTY_VALUE; continue; }
// Calcola massimo degli ultimi PERIOD periodi
double max_c = close[i];
for(int j = i - PERIOD + 1; j <= i; j++)
if(close[j] > max_c) max_c = close[j];
// Somma quadrati dei drawdown
double sum_sq = 0;
for(int j = i - PERIOD + 1; j <= i; j++)
{
double dd = (max_c - close[j]) / max_c * 100.0;
sum_sq += dd * dd;
}
BufferUlcer[i] = MathSqrt(sum_sq / PERIOD);
}
return rates_total; // Fondamentale per il meccanismo incrementale
}
4. Buffer di Output: Come Mostrare i Valori sul Grafico
I buffer di output sono array dichiarati globalmente e collegati ai plot visivi tramite SetIndexBuffer(). MT5 usa questi array come fonte dei dati da disegnare sul grafico. Regole fondamentali: usa EMPTY_VALUE (8.988×10307 in MQL5) per i valori che non devono essere mostrati (barre con storia insufficiente). Non assegnare mai 0 ai valori mancanti: 0 verrà disegnato sul grafico come una linea a zero.
5. Costruire l’Ulcer Index come Indicatore Custom
L’Ulcer Index di Peter Martin (1987) misura il drawdown percentuale dal massimo recente. È la metrica alla base di Oracle v78. Il codice di OnCalculate nella sezione 3 implementa già l’Ulcer Index completo. Una volta compilato e installato in MT5, l’indicatore mostra la curva dell’Ulcer Index su qualsiasi grafico. La soglia dell’80° percentile storico — usata da Oracle v78 come gate — è aggiunta come linea orizzontale dinamica calcolata negli ultimi 100 periodi.
6. Richiamare l’Indicatore da un EA con iCustom
icustom_ulcer.mq5MQL5
// Legge il valore dell'Ulcer Index dall'indicatore custom
// "UlcerIndex" deve essere il nome del file .ex5 nella cartella Indicators/
// Richiama l'indicatore con periodo 14, legge buffer 0, shift 1 (ultima barra chiusa)
double ulcer_value = iCustom(_Symbol, PERIOD_H4,
"UlcerIndex", // nome file
14, // parametro input: periodo
0, // indice buffer
1); // shift: 1 = ultima barra chiusa
// Calcola il percentile su 100 periodi storici
int count_below = 0;
for(int i = 2; i <= 101; i++) // shift da 2 a 101 = 100 valori storici
{
double hist_val = iCustom(_Symbol, PERIOD_H4, "UlcerIndex", 14, 0, i);
if(hist_val < ulcer_value) count_below++;
}
double percentile = (double)count_below / 100.0 * 100.0;
Print("Ulcer corrente: ", ulcer_value, " | Percentile: ", percentile, "%");
💡 Questa è la chiamata iCustom che Oracle v78 usa internamente. L’EA non ricalcola l’Ulcer Index da zero — richiama l’indicatore custom già calcolato da MT5, rendendo il codice modulare e più semplice da mantenere.
7. Errori Comuni in OnCalculate
Errore 1: Non ritornare rates_total. Se OnCalculate ritorna un valore diverso da rates_total (es. 0 o prev_calculated), MT5 non aggiorna correttamente il contatore per il calcolo incrementale. La prossima chiamata avrà prev_calculated=0 e ricalcolerà tutto daccapo.
Errore 2: Accedere a indici fuori range. Se l’indicatore usa una finestra di 14 periodi, le prime 13 barre (indici 0–12) non hanno storia sufficiente. Assegna EMPTY_VALUE per quelle barre invece di calcolare con dati insufficienti.
Errore 3: Usare shift=0 in iCustom da un EA. La barra corrente (shift=0) è in formazione: il suo valore dell’Ulcer Index cambia ad ogni tick. Per segnali stabili usa sempre shift=1 in iCustom.
8. Come Oracle v78 Usa gli Indicatori Custom
Oracle v78 usa iCustom per richiamare l’Ulcer Index percentile calcolato dall’indicatore custom dedicato. Questo design modulare ha un vantaggio preciso: l’indicatore custom è calcolato una volta sola da MT5 e il suo buffer è condiviso tra tutti gli EA e indicatori che lo richiedono sullo stesso grafico. Se Oracle UI e Oracle Scanner richiedono entrambi l’Ulcer Index, MT5 calcola il buffer una volta sola e lo restituisce a entrambi — nessun ricalcolo doppio.
Domande Frequenti
Cosa fa la funzione OnCalculate in MQL5? ▼
OnCalculate è la funzione principale di ogni indicatore custom MQL5. Viene chiamata ogni volta che c’è un nuovo dato da elaborare (nuovo tick o nuova barra). Riceve i prezzi di tutte le barre come parametri, calcola i valori dell’indicatore e li scrive nei buffer di output che MT5 usa per disegnare le linee sul grafico. È l’equivalente di OnTick per gli EA.
Cosa sono rates_total e prev_calculated? ▼
rates_total è il numero totale di barre disponibili nel grafico. prev_calculated è il numero di barre già elaborate nella chiamata precedente. La differenza (rates_total − prev_calculated) indica quante nuove barre devono essere calcolate. Questo meccanismo permette il calcolo incrementale: si calcolano solo le barre nuove invece di ricalcolare tutto lo storico ad ogni tick.
Come si chiama un indicatore custom da un EA in MQL5? ▼
Tramite la funzione iCustom(). Sintassi: iCustom(_Symbol, PERIOD_H4, "NomeFile", param1, param2, buffer_index, shift). Il nome file è il nome dell’.ex5 nella cartella Indicators/. buffer_index indica quale buffer leggere (0 per il primo). shift indica quale barra leggere (1 = ultima chiusa, 0 = corrente in formazione).
9. OnCalculate con Array di Prezzo: la Versione Breve
Esiste una seconda firma di OnCalculate, più concisa, usata quando l’indicatore opera su un singolo array di prezzi (tipicamente i prezzi di chiusura):
oncalculate_short.mq5MQL5
// Versione breve: riceve direttamente l'array dei prezzi
// Utile per indicatori su un solo prezzo (es. RSI custom, Ulcer su close)
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin, // Primo indice valido dell'array
const double &price[]) // Array prezzi (configurato in OnInit)
{
int pos_first = (prev_calculated == 0) ? begin + 14 : prev_calculated - 1;
for(int i = pos_first; i < rates_total; i++)
{
if(i < 14) { Buffer[i] = EMPTY_VALUE; continue; }
// Calcola massimo degli ultimi 14 periodi
double max_p = price[i];
for(int j = i - 13; j <= i; j++)
if(price[j] > max_p) max_p = price[j];
// Ulcer Index
double sum = 0;
for(int j = i - 13; j <= i; j++)
{
double dd = (max_p > 0) ? (max_p - price[j]) / max_p * 100 : 0;
sum += dd * dd;
}
Buffer[i] = MathSqrt(sum / 14.0);
}
return rates_total;
}
💡 In OnInit configura quale prezzo ricevere: PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 14) e usa #property indicator_applied_price PRICE_CLOSE. La versione breve è più leggibile per indicatori mono-prezzo.
10. Performance: Quanto È Veloce OnCalculate?
La velocità di OnCalculate è critica per indicatori usati come input di EA attivi. Su un hardware moderno (i5/i7) su Windows:
| Tipo di calcolo | Barre | Tempo tipico | Impatto su MT5 |
| MA20 semplice | 10.000 | <1ms | Trascurabile |
| Ulcer Index(14) incrementale | Solo nuove barre (1–3) | <1ms per aggiornamento | Trascurabile |
| Ulcer Index(14) full recalc | 10.000 barre | ~50–200ms | Lento al primo caricamento |
| Ulcer Index con O(n²) per barra | 10.000 barre | ~5–20 secondi | Blocca MT5 |
Il calcolo incrementale (solo nuove barre) è essenziale per gli indicatori usati in produzione. Il ricalcolo completo avviene solo al primo caricamento dell’indicatore o quando si cambia il timeframe del grafico — accetta che richieda qualche secondo. Per i tick successivi, il calcolo incrementale è praticamente istantaneo.
11. Debug di un Indicatore Custom: Tecniche Pratiche
Il debug degli indicatori custom è più complesso degli EA perché non si può avviare un indicatore con il debugger standard durante l’esecuzione live. Le tecniche più efficaci:
- Print() durante il calcolo: aggiungi
Print("i=", i, " ulcer=", BufferUlcer[i]); dentro OnCalculate. I valori appaiono nel Journal di MT5. Rimuovi i Print() prima di andare in produzione.
- Secondo buffer di debug: crea un secondo buffer (es.
double DebugBuffer[]) e scrivi valori intermedi per verificarli visivamente sul grafico.
- Confronto con Python: calcola lo stesso indicatore in Python su dati storici e confronta i valori barra per barra. Le discrepanze indicano errori nell’implementazione.
- Strategy Tester con visual mode: avvia l’EA che chiama l’indicatore nel Strategy Tester con visual mode attiva — puoi fermare l’esecuzione su una barra specifica e ispezionare il valore dell’indicatore in quel momento.
✔ Il pattern di sviluppo di Oracle v78
L’Ulcer Index custom di Oracle v78 è stato validato confrontando i valori barra per barra con l’implementazione Python per 3.000 barre H4. Le prime versioni avevano discrepanze nell’edge handling (prime N barre con storia insufficiente). La versione finale corrisponde all’implementazione Python con differenza massima <0.001% — puramente floating point.
Implicazioni Pratiche: dal Concetto al Sistema Operativo
La distanza tra la teoria statistica e il trading operativo è colmata solo dall’implementazione sistematica. Un trader può conoscere perfettamente la definizione di Profit Factor, Ulcer Index, edge statistico e mean reversion — ma se queste conoscenze non si traducono in regole operative codificate e rispettate meccanicamente, rimangono concetti accademici senza impatto sulla performance.
Oracle v78 rappresenta il punto di arrivo di questo processo: anni di ricerca statistica (in Python su dati XAUUSD H4), validazione su campioni out-of-sample separati, implementazione in MQL5 (8.293 righe di codice), e infine esecuzione meccanica su 65.587 trade reali senza deroghe alle regole. Il sistema ha una risposta precisa a ogni condizione di mercato: score sopra soglia + Ulcer Index > 80° percentile = apri il trade con 1% di rischio. Score sotto soglia = non operare. Non c’è spazio per l’interpretazione soggettiva.
Questo approccio sistematico ha un costo: la flessibilità di adattamento in tempo reale è zero. Oracle v78 non “sente” che il mercato è cambiato e non modifica il suo comportamento finché i parametri non vengono aggiornati attraverso un processo formale di ri-ottimizzazione. Questo è un vantaggio, non uno svantaggio: i trader discrezionali che “adattano” il loro sistema in tempo reale stanno quasi sempre razionalizzando bias comportamentali, non rispondendo a cambiamenti strutturali del mercato.
Il percorso consigliato per chi vuole passare dal trading discrezionale al trading sistematico: inizia usando Oracle v78 come strumento educativo — osserva come il sistema identifica le condizioni di ingresso, come gestisce le posizioni, come rispetta sistematicamente lo stop loss e il take profit. Poi, se ti interessa costruire il tuo sistema, applica gli stessi principi statistici (edge misurabile, validazione out-of-sample, position sizing fisso) al tuo strumento e timeframe preferiti. La differenza tra un trader sistematico e uno discrezionale non è nel mercato che tratta — è nel processo decisionale che usa.
La live gratuita su oracle.mtinvestments.it mostra Oracle v78 in operazione su MetaTrader 5 in tempo reale. Non è una presentazione: è il conto MT5 live con il sistema attivo, i trade aperti, lo storico completo e tutte le metriche visibili. È l’unico modo per verificare in modo indipendente quello che questo articolo descrive.
Conclusioni: la Statistica Come Bussola nel Mercato
I mercati finanziari sono uno dei pochi ambienti in cui intuizioni, esperienze passate e capacità analitiche individuali sono costantemente sfidate dall’incertezza fondamentale dei prezzi futuri. Nessun trader — sistemático o discrezionale — può eliminare questa incertezza. Ma è possibile costruire un processo decisionale che la gestisca in modo statisticamente coerente, che riduca i bias comportamentali e che crei un edge misurabile nel lungo periodo.
Oracle v78 con 65.587 trade reali non è la prova che il futuro sarà identico al passato. È la prova che un sistema con fondamento statistico solido, implementato correttamente e rispettato meccanicamente, può generare rendimenti positivi aggiustati per il rischio su un orizzonte temporale sufficientemente lungo. Il CAGR 14,3% con MDD 13,1% su 19 anni di dati reali è un risultato che si ottiene non per fortuna, ma per la combinazione di edge statistico genuino e disciplina esecutiva assoluta.
Il passo successivo è verificare questi dati in prima persona. La live gratuita su oracle.mtinvestments.it è aperta: nessun costo, nessun deposito richiesto, solo il sistema in azione su MT5 in tempo reale. Scrivi “ORACLE” su WhatsApp a Rossella (+39 380 635 8296) per ricevere la guida completa e iniziare il percorso di verifica.
Considerazioni Finali sul Trading Sistematico
Il trading sistematico richiede un cambiamento di prospettiva fondamentale: non si tratta di trovare il “segreto del mercato” o di avere intuizioni brillanti. Si tratta di costruire un processo statisticamente robusto, implementarlo in modo rigoroso e mantenerlo operativo con disciplina assoluta nel lungo periodo. Questi concetti — edge statistico, EV positivo, Profit Factor, win rate condizionato, position sizing fisso — non sono sofisticati nel senso di “difficili da capire”. Sono sofisticati nel senso di “richiedono di abbandonare le intuizioni naturali su come funzionano i mercati”.
L’intuizione naturale dice che bisogna avere ragione la maggior parte delle volte. La statistica dice che basta avere ragione abbastanza spesso rispetto al rapporto rischio/rendimento. L’intuizione naturale dice che più si analizza, meglio si capisce il mercato. La statistica dice che più si analizza senza un framework ipotetico, più si è esposti al data-snooping bias. L’intuizione naturale dice che i pattern tecnici visibili sul grafico sono significativi. La statistica dice che la maggior parte dei pattern tecnici non supera un test statistico formale su un campione adeguato.
Oracle v78 è il risultato di 19 anni di lavoro che ha progressivamente sostituito l’intuizione con la statistica: dall’analisi dell’Ulcer Index di Peter Martin (1987), alla scoperta del gate condizionale su XAUUSD H4, all’implementazione in MQL5, fino ai 65.587 trade reali verificabili. Non è un sistema perfetto — può avere drawdown del 13%, può avere periodi di lateralità di settimane, può perdere trade in sequenza. Ma ha edge statistico documentato, e con edge statistico positivo e gestione del rischio corretta, il lungo periodo è sempre favorevole.
Per chi vuole iniziare questo percorso: entra nella live gratuita su oracle.mtinvestments.it. Non per comprare qualcosa, ma per vedere con i propri occhi come si presenta un sistema con dati reali e metriche trasparenti. Confrontalo con ciò che il mercato degli “educatori trading” propone normalmente — segnali senza statistiche, rendimenti senza drawdown, promesse senza dati verificabili. La differenza sarà immediatamente evidente.
⚡ Oracle v78 — 65.587 trade reali MT5
Dalla Teoria
al Sistema Verificabile.
WR 42,1%, PF 1,44, CAGR 14,3%, MDD 13,1% su 65.587 trade reali XAUUSD H4. La live gratuita mostra il sistema in azione — schermata MT5 live, nessuna slide.
65.587 trade realiWR 42,1% PF 1,44CAGR 14,3% MDD 13,1%Zenith Zero · il sistema completo
ENTRA NELLA LIVE GRATUITA →
Scrivi “SERIO” a Rossella su WhatsApp
Nessun costo. Risposta entro 2 ore. P.IVA IT14349331000