Gestione Ordini MQL5: OrderSend, OrderModify e OrderClose con Codice Completo | Manuel Trotta

Gestione Ordini MQL5 — OrderSend, Modify e Close con Codice Oracle Completo

Il 90% degli EA amatoriali fallisce in produzione non per logica sbagliata, ma per gestione degli ordini fragile: nessun retry sul requote, lot size non normalizzato, SL inviato insieme all’ordine invece che dopo. Questo articolo ti mostra come Oracle UlcerZenith gestisce i 65.587 trade reali su XAUUSD H4 — codice MQL5 completo, commentato, pronto per VPS.

Il Modello di Trading MQL5: Struttura Fondamentale

Prima di scrivere una riga di codice sugli ordini, devi capire che MQL5 usa un modello completamente diverso da MQL4. In MQL4, tutto era un “ordine” — posizioni aperte e ordini pendenti convivevano nello stesso pool. In MQL5 esistono tre livelli distinti: Orders (ordini pendenti non ancora eseguiti), Positions (posizioni aperte sul mercato), e History (ordini e posizioni chiusi). Confondere questi livelli genera bug silenziosi difficilissimi da diagnosticare.

Per gestire ordini in MQL5 usi sempre due strutture: MqlTradeRequest (i parametri della richiesta) e MqlTradeResult (il risultato dell’esecuzione). La funzione OrderSend(request, result) ritorna true/false, ma il risultato vero si legge da result.retcode. Un EA che controlla solo il valore di ritorno booleano di OrderSend sta ignorando il 90% delle informazioni disponibili.

Le Cinque Azioni di Trading

MQL5 prevede cinque tipi di azione nel campo request.action:

TRADE_ACTIONDescrizioneUso Oracle
TRADE_ACTION_DEALOrdine di mercato immediatoEntry principale XAUUSD
TRADE_ACTION_PENDINGOrdine pendente (limit/stop)Setup multi-livello
TRADE_ACTION_SLTPModifica SL/TP su posizione esistenteBreakeven + Trailing ATR
TRADE_ACTION_MODIFYModifica ordine pendenteAggiornamento livelli
TRADE_ACTION_CLOSE_BYChiusura posizione con opposta (hedging)Hedge M25

OrderSend Completo: Codice Oracle per XAUUSD H4

La funzione di invio ordine di Oracle prevede calcolo del lot size basato su rischio percentuale, normalizzazione con il volume step del broker, verifica margine disponibile, e un ciclo retry per gestire requote e congestioni temporanee del server. Ecco il codice completo con commenti Oracle.

// ============================================================ // Oracle_OrderSend() — Funzione di invio ordine robusta v77 // Manuel Trotta / MTInvestments — XAUUSD H4 // ============================================================ bool Oracle_SendMarketOrder( string symbol, int direction, // ORDER_TYPE_BUY o ORDER_TYPE_SELL double sl_price, // Stop Loss assoluto double tp_price, // Take Profit assoluto double risk_pct, // es. 0.01 per 1% string comment // es. "Oracle_H4_SCORE72" ) { // --- 1. Calcolo lot size basato su rischio --------------- double balance = AccountInfoDouble(ACCOUNT_BALANCE); double risk_eur = balance * risk_pct; double entry = (direction == ORDER_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID); double sl_dist = MathAbs(entry - sl_price); double tick_val = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double tick_sz = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); // punti SL = distanza / tick_size double sl_ticks = sl_dist / tick_sz; // risk_eur / (sl_ticks * tick_value_per_lot) double lot_raw = risk_eur / (sl_ticks * tick_val); // --- 2. Normalizzazione volume step broker --------------- double vol_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double vol_min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double vol_max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); double lot_norm = MathFloor(lot_raw / vol_step) * vol_step; lot_norm = MathMax(vol_min, MathMin(vol_max, lot_norm)); lot_norm = NormalizeDouble(lot_norm, 2); // --- 3. Controllo margine disponibile -------------------- double margin_req; if(!OrderCalcMargin( (ENUM_ORDER_TYPE)direction, symbol, lot_norm, entry, margin_req)) { PrintFormat("[Oracle] ERRORE OrderCalcMargin: %d", GetLastError()); return false; } if(margin_req > AccountInfoDouble(ACCOUNT_FREEMARGIN) * 0.9) { PrintFormat("[Oracle] SKIP — margine insufficiente. Req:%.2f Free:%.2f", margin_req, AccountInfoDouble(ACCOUNT_FREEMARGIN)); return false; } // --- 4. Compilazione struttura request ------------------- MqlTradeRequest req = {}; MqlTradeResult res = {}; req.action = TRADE_ACTION_DEAL; req.symbol = symbol; req.volume = lot_norm; req.type = (ENUM_ORDER_TYPE)direction; req.price = entry; req.sl = sl_price; req.tp = tp_price; req.deviation = 30; // 30 punti slippage max XAUUSD req.magic = 77000; req.comment = comment; req.type_filling = ORDER_FILLING_IOC; // --- 5. Retry loop (max 3 tentativi) --------------------- for(int attempt = 0; attempt < 3; attempt++) { if(OrderSend(req, res)) { PrintFormat("[Oracle] ORDINE OK — Ticket:%d Lot:%.2f Entry:%.5f SL:%.5f TP:%.5f", res.order, lot_norm, entry, sl_price, tp_price); return true; } // Analisi retcode if(res.retcode == TRADE_RETCODE_REQUOTE) { PrintFormat("[Oracle] Requote tentativo %d/3 — attesa 200ms", attempt+1); req.price = (direction == ORDER_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID); Sleep(200); continue; } if(res.retcode == TRADE_RETCODE_NO_MONEY) { Print("[Oracle] ERRORE: Margine insufficiente (retcode 10019)"); return false; } if(res.retcode == TRADE_RETCODE_INVALID_STOPS) { PrintFormat("[Oracle] ERRORE: Stop non validi. SL=%.5f TP=%.5f Entry=%.5f", sl_price, tp_price, entry); return false; } // Altri errori non recuperabili PrintFormat("[Oracle] ERRORE OrderSend retcode:%d — %s", res.retcode, TradeRetcodeDescription(res.retcode)); return false; } Print("[Oracle] SKIP dopo 3 requote — setup perso"); return false; }
Formula Lot Size Oracle — XAUUSD H4
lot = (balance × risk%) ÷ (SL_ticks × tick_value)
SL_ticks = |entry − SL_price| ÷ tick_size
Esempio: €10.000 × 1% = €100 rischio
SL ATR×1.5 su XAUUSD H4 tipicamente 220–350 punti → tick_size = 0.01 → SL_ticks = 250 pips × 100 = 25.000 → tick_value XAUUSD = €0.01/0.01lot → lot = 100 / (25.000 × 0.01) = 0.40 lotti. Normalizzare sempre con MathFloor(raw/vol_step)*vol_step.

I Codici Errore MQL5 che Devi Conoscere

In MQL5 il codice errore corretto si legge sempre da result.retcode, non da GetLastError(). I due sistemi sono distinti e confonderli causa diagnosi errate. Oracle UlcerZenith categorizza gli errori in tre classi: recuperabili con retry, recuperabili con attesa, non recuperabili (skip del trade).

RetcodeNomeCausaRisposta Oracle
10004REQUOTEPrezzo cambiato nel msRetry ×3 con nuovo prezzo
10006REQUEST_REJECTEDServer occupatoSleep(500) + retry
10014INVALID_VOLUMELot non normalizzatoFix calcolo, no retry
10016INVALID_STOPSSL/TP troppo viciniLog + skip trade
10019NO_MONEYMargine insufficienteAlert + skip
10026MARKET_CLOSEDMercato chiusoAttesa riapertura
10027TRADE_DISABLEDTrading disabilitatoAlert + stop EA
10030ORDER_LOCKEDOrdine in elaborazioneSleep(200) + retry
Errore Comune 01
Usare GetLastError() invece di result.retcode
In MQL5, GetLastError() ritorna errori del runtime MQL, non del server di trading. Dopo un OrderSend fallito, GetLastError() potrebbe ritornare 0 (nessun errore) mentre result.retcode mostra 10019 (no money). Questo bug causa EA che non loggano mai gli errori reali e continuano a tentare operazioni impossibili. Regola Oracle: leggere sempre result.retcode come fonte primaria di diagnosi.
Errore Comune 02
Inviare SL/TP con ordine di mercato senza verificare distanza minima
Molti broker ECN non accettano SL/TP inclusi nell’ordine di mercato se sono troppo vicini al prezzo corrente. Il risultato è retcode 10016 INVALID_STOPS anche se la logica è corretta. Oracle separa l’invio dell’ordine di mercato dalla modifica SL/TP: prima apre la posizione (senza SL/TP), poi usa TRADE_ACTION_SLTP per settare gli stop. Due chiamate, zero reiezioni.
Errore Comune 03
Non verificare PositionSelect() prima di ogni operazione sulla posizione
Se un ordine viene chiuso manualmente o dal TP/SL mentre l’EA è in elaborazione, PositionGetDouble(POSITION_SL) ritorna il valore della posizione precedentemente selezionata nel cache — non 0 o errore. Il risultato è una modifica di SL che viene ignorata senza errore. Regola Oracle: chiamare PositionSelect(Symbol()) prima di ogni PositionGet* — se ritorna false, la posizione non esiste, uscire immediatamente.

Modifica Posizione: Breakeven e Trailing ATR

Oracle UlcerZenith implementa due livelli di gestione della posizione dopo l’apertura: il breakeven (SL portato al prezzo di apertura + buffer) quando il trade raggiunge +1R, e il trailing ATR×1.5 che segue il prezzo proteggendo i profitti. Entrambe le operazioni usano TRADE_ACTION_SLTP, non TRADE_ACTION_DEAL.

// ============================================================ // Oracle_SetBreakeven() — SL al prezzo di apertura + buffer // Attivato quando profit >= 1R (in punti) // ============================================================ bool Oracle_SetBreakeven(string symbol, double be_buffer_pts) { if(!PositionSelect(symbol)) return false; double open_price = PositionGetDouble(POSITION_PRICE_OPEN); double cur_sl = PositionGetDouble(POSITION_SL); long pos_type = PositionGetInteger(POSITION_TYPE); double tick_sz = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double buffer = be_buffer_pts * tick_sz; double new_sl; if(pos_type == POSITION_TYPE_BUY) { new_sl = open_price + buffer; if(cur_sl >= new_sl) return false; // già in BE o meglio } else { new_sl = open_price - buffer; if(cur_sl <= new_sl && cur_sl != 0) return false; } MqlTradeRequest req = {}; MqlTradeResult res = {}; req.action = TRADE_ACTION_SLTP; req.symbol = symbol; req.sl = NormalizeDouble(new_sl, (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS)); req.tp = PositionGetDouble(POSITION_TP); req.position = PositionGetInteger(POSITION_TICKET); if(OrderSend(req, res) && res.retcode == TRADE_RETCODE_DONE) { PrintFormat("[Oracle] BREAKEVEN impostato: SL=%.5f (era %.5f)", new_sl, cur_sl); return true; } PrintFormat("[Oracle] ERRORE BE retcode:%d", res.retcode); return false; } // ============================================================ // Oracle_TrailingATR() — Trailing stop basato su ATR×1.5 // Chiamata ogni tick in OnTick() dopo attivazione 1R // ============================================================ void Oracle_TrailingATR(string symbol, int atr_period, double atr_mult) { if(!PositionSelect(symbol)) return; long pos_type = PositionGetInteger(POSITION_TYPE); double cur_sl = PositionGetDouble(POSITION_SL); double cur_tp = PositionGetDouble(POSITION_TP); long ticket = PositionGetInteger(POSITION_TICKET); // ATR corrente (H4 = PERIOD_H4) double atr_val = iATR(symbol, PERIOD_H4, atr_period, 1); double trail = atr_val * atr_mult; double cur_bid = SymbolInfoDouble(symbol, SYMBOL_BID); double cur_ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double new_sl, min_dist; int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); if(pos_type == POSITION_TYPE_BUY) { new_sl = NormalizeDouble(cur_bid - trail, digits); if(new_sl <= cur_sl) return; // non migliorativo, skip } else { new_sl = NormalizeDouble(cur_ask + trail, digits); if(new_sl >= cur_sl && cur_sl != 0) return; } MqlTradeRequest req = {}; MqlTradeResult res = {}; req.action = TRADE_ACTION_SLTP; req.symbol = symbol; req.sl = new_sl; req.tp = cur_tp; req.position = ticket; if(OrderSend(req, res)) PrintFormat("[Oracle] TRAILING ATR: SL %.5f → %.5f", cur_sl, new_sl); }

Chiusura Posizione: Oracle_ClosePosition()

In MQL5 non esiste una funzione OrderClose() come in MQL4. Per chiudere una posizione aperta si usa OrderSend() con TRADE_ACTION_DEAL e un ordine opposto pari al volume della posizione. Il campo critico è request.position: deve contenere il ticket della posizione da chiudere, altrimenti apri una nuova posizione invece di chiudere quella esistente.

// ============================================================ // Oracle_ClosePosition() — Chiusura robusta posizione aperta // ============================================================ bool Oracle_ClosePosition(string symbol, string reason) { if(!PositionSelect(symbol)) { PrintFormat("[Oracle] ClosePosition: nessuna posizione su %s", symbol); return false; } double vol = PositionGetDouble(POSITION_VOLUME); long p_type = PositionGetInteger(POSITION_TYPE); long ticket = PositionGetInteger(POSITION_TICKET); // Ordine opposto alla posizione ENUM_ORDER_TYPE close_type = (p_type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY; double close_price = (close_type == ORDER_TYPE_SELL) ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK); MqlTradeRequest req = {}; MqlTradeResult res = {}; req.action = TRADE_ACTION_DEAL; req.symbol = symbol; req.volume = vol; req.type = close_type; req.price = close_price; req.deviation = 30; req.position = ticket; // CRITICO: specifica la posizione da chiudere req.magic = 77000; req.comment = reason; req.type_filling = ORDER_FILLING_IOC; for(int i = 0; i < 3; i++) { if(OrderSend(req, res) && res.retcode == TRADE_RETCODE_DONE) { PrintFormat("[Oracle] CHIUSURA OK — Ticket:%d Motivo:%s", ticket, reason); return true; } if(res.retcode == TRADE_RETCODE_REQUOTE) { req.price = (close_type == ORDER_TYPE_SELL) ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK); Sleep(200); continue; } PrintFormat("[Oracle] ERRORE chiusura retcode:%d", res.retcode); break; } return false; }
◆ Oracle UlcerZenith v78 — Dati Verificati
Architettura di Esecuzione su 65.587 Trade Reali
42,1%
Win Rate H4
1,44
Profit Factor
13,1%
Max Drawdown
+0,684R
EV per Trade

Ogni trade Oracle esegue questa sequenza: 1) Lettura GlobalVariable UZ_XAUUSD_16384_SCORE (Oracle score) e UZ_XAUUSD_16384_DIR (direzione) scritte da UlcerZenith LITE ogni candela H4. 2) Se score ≥ 65 e nessuna posizione aperta su XAUUSD, calcolo SL con ATR×1.5 e TP con SL×3 (RR 1:3). 3) Oracle_SendMarketOrder() con risk 1%. 4) Check ogni tick: se profitto ≥ 1R, chiama Oracle_SetBreakeven() una sola volta. 5) Oracle_TrailingATR() attivo da quel momento.

La robustezza dell’esecuzione (retry, normalizzazione lot, verifica margine) contribuisce all’eliminazione degli errori di esecuzione. Su 19 anni di forward test: 0 margin call, 0 ordini duplicati, 0 posizioni aperte senza SL.

Implementazione Oracle Completa: OnTick() in Produzione

L’integrazione di tutte le funzioni nell’EA Oracle prevede un flusso preciso in OnTick(). La sequenza è: lettura GlobalVariables da UlcerZenith → verifica condizioni entry → apertura se nessuna posizione → gestione posizione esistente (BE + trailing) → check segnale exit anticipata. Ogni blocco deve essere idempotente: chiamato mille volte deve produrre lo stesso risultato di una chiamata sola.

// ============================================================ // OnTick() — Flusso principale Zenith Executor Oracle // ============================================================ void OnTick() { string sym = Symbol(); // --- 1. Lettura GlobalVariables Oracle ------------------- double score = GlobalVariableGet("UZ_" + sym + "_" + (string)Period() + "_SCORE"); double dir = GlobalVariableGet("UZ_" + sym + "_" + (string)Period() + "_DIR"); double gv_sl = GlobalVariableGet("UZ_" + sym + "_" + (string)Period() + "_SL"); double gv_tp = GlobalVariableGet("UZ_" + sym + "_" + (string)Period() + "_TP"); // --- 2. Gestione posizione esistente --------------------- if(PositionSelect(sym)) { double open_p = PositionGetDouble(POSITION_PRICE_OPEN); double cur_sl = PositionGetDouble(POSITION_SL); double sl_dist = MathAbs(open_p - cur_sl); long p_type = PositionGetInteger(POSITION_TYPE); double cur_bid = SymbolInfoDouble(sym, SYMBOL_BID); // Breakeven se profitto >= 1R bool profit_1r = (p_type == POSITION_TYPE_BUY) ? (cur_bid - open_p) >= sl_dist : (open_p - cur_bid) >= sl_dist; if(profit_1r && !g_BESet) { if(Oracle_SetBreakeven(sym, 10)) g_BESet = true; } // Trailing ATR attivo dopo BE if(g_BESet) Oracle_TrailingATR(sym, 14, 1.5); // Exit anticipata: score invertito if(dir != 0 && ((p_type == POSITION_TYPE_BUY && dir < 0) || (p_type == POSITION_TYPE_SELL && dir > 0))) { Oracle_ClosePosition(sym, "Oracle_ExitSignal_ScoreInv"); g_BESet = false; } return; // posizione aperta: non aprire nuovi ordini } // --- 3. Nuova candela: controllo entry signal ------------ static datetime last_bar = 0; datetime cur_bar = (datetime)SeriesInfoInteger(sym, PERIOD_H4, SERIES_LASTBAR_DATE); if(cur_bar == last_bar) return; // non è nuova candela H4 last_bar = cur_bar; // Score minimo 65 e SL/TP validi da GV if(score < 65 || gv_sl == 0 || gv_tp == 0) return; int order_dir = (dir > 0) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; if(Oracle_SendMarketOrder(sym, order_dir, gv_sl, gv_tp, 0.01, "Oracle_H4_SCORE" + (string)(int)score)) { g_BESet = false; // reset flag BE per nuova posizione } }

Best Practice per EA in Produzione su VPS

Il codice corretto è condizione necessaria ma non sufficiente. Un EA che funziona perfettamente in tester può collassare in produzione per cause ambientali: disconnessioni, restart del terminale, cambio di ora del broker. Oracle UlcerZenith è progettato per sopravvivere a qualsiasi interruzione.

Best Practice 01
OnInit() deve ricostruire lo stato senza assumere sessione continua
All’avvio, controllare se esiste già una posizione aperta su Symbol(). Se sì, recuperare il ticket, il prezzo di apertura, e impostare g_BESet correttamente in base al profitto attuale. Non assumere che l’EA stia partendo da zero. Un restart del VPS alle 03:00 deve trovare la posizione aperta e continuare la gestione seamlessly.
Best Practice 02
Magic number univoco per EA e simbolo
Se hai più istanze di Zenith Executor su simboli diversi, usa magic number distinti: 77001 per EURUSD, 77002 per XAUUSD, 77003 per USDJPY. Il filtro PositionGetInteger(POSITION_MAGIC) == magic in ogni funzione di gestione garantisce che ogni EA gestisca solo le sue posizioni.
Best Practice 03
Loggare ogni operazione con timestamp e motivo
Ogni chiamata OrderSend deve loggare: timestamp, simbolo, tipo, volume, prezzo, SL, TP, retcode, commento. Questo log è l’unica fonte di diagnosi dopo un problema in produzione. Su Oracle: ogni log include il score Oracle al momento dell’entry, il valore ATR, e il motivo della decisione. Senza questo, diagnosticare un bug su 500 trade è impossibile.
Best Practice 04
Evitare operazioni di rete in OnTick()
OnTick() viene chiamato migliaia di volte al giorno su XAUUSD. Operazioni lente (file I/O, GlobalVariableSet inutili, Print() excessivo) degradano le prestazioni. Oracle usa un flag g_NewBar per eseguire il codice Oracle-heavy solo all’apertura di ogni candela H4, riducendo l’overhead del 99%.
Best Practice 05
Usare ORDER_FILLING_IOC su broker ECN
Molti broker ECN non supportano ORDER_FILLING_FOK (Fill or Kill) per ordini di mercato su forex/oro. Il retcode 10030 (ORDER_FILLING_NOT_ALLOWED) sparisce quasi sempre settando req.type_filling = ORDER_FILLING_IOC. Verificare il tipo di filling supportato con SymbolInfoInteger(SYMBOL, SYMBOL_FILLING_MODE) nell’OnInit().

Confronto: EA Amatoriale vs EA Oracle

AspettoEA Amatoriale TipicoOracle UlcerZenith v78
Gestione requoteNessuna — ordine fallisce silenziosamenteRetry ×3 con prezzo aggiornato
Lot sizeFisso o non normalizzatoRisk% + normalizzazione vol_step
SL/TP su entryInviati con ordine (10016 su ECN)Separati con TRADE_ACTION_SLTP
Restart VPSPerde stato, apre posizione doppiaOnInit() ricostruisce stato
Log erroriGetLastError() fuori contestoresult.retcode con descrizione
BreakevenSettato infinite volte (spam server)Flag g_BESet: una sola volta
Verifica margineOrderSend() fallisce con 10019OrderCalcMargin() preventivo
Multi-simboloMagic 0: gestisce tutte le posizioniMagic univoco per simbolo
Un EA con logica mediocre ma esecuzione robusta batte un EA con logica brillante ma gestione fragile. Ho visto sistemi con WR 55% collassare in produzione per un lot size non normalizzato che generava errore 10014 su ogni entry. — Manuel Trotta, 19 anni di sviluppo Oracle su MQL4/MQL5

Vedi Oracle in Azione — Live Ogni Giorno

— XAUUSD H4 in diretta, codice aperto, 0 fantasia. Rossella ti manda il link su WhatsApp.

SEGUI LA LIVE GRATUITA WHATSAPP ROSSELLA

FAQ — Gestione Ordini MQL5

Qual è la differenza tra OrderSend in MQL4 e MQL5?►
In MQL4, OrderSend() gestisce sia ordini di mercato che pendenti con un’unica funzione. In MQL5 il modello di trading è completamente diverso: si usa una struttura MqlTradeRequest per definire i parametri e MqlTradeResult per ricevere il risultato. La funzione OrderSend() ritorna true/false, ma il risultato reale si legge da result.retcode. Le posizioni sono gestite con PositionSelect/PositionGetDouble, non con OrderSelect/OrderGetDouble. Questo rende MQL5 più robusto ma richiede più codice boilerplate.
Come si gestisce il requote in MQL5?►
Il requote (TRADE_RETCODE_REQUOTE = 10004) si gestisce con un ciclo retry. Il pattern standard Oracle prevede massimo 3 tentativi con Sleep(200) tra un tentativo e l’altro, aggiornando req.price con il prezzo corrente a ogni tentativo. Se il requote persiste dopo 3 tentativi, si logga e si skippa il trade — meglio nessun trade che un trade a prezzo deteriorato.
Come si calcola il lot size corretto per Oracle su XAUUSD H4?►
Formula Oracle: lot = (balance × risk%) ÷ (SL_ticks × tick_value). Con SL ATR×1.5 tipicamente 220–350 punti su XAUUSD H4, rischio 1% su €10.000 = €100. Se SL = 250 punti (0.01 tick size → 25.000 ticks), tick_value XAUUSD ≈ €0.01/0.01lot → lot = 100/(25000×0.01) = 0.40 lotti. Normalizzare sempre con MathFloor(raw/vol_step)*vol_step e verificare con OrderCalcMargin() prima di inviare.
Cosa fare quando OrderSend ritorna false in MQL5?►
Leggere result.retcode per il codice errore specifico. I più comuni: 10004 (requote → retry), 10014 (invalid volume → correggere lot size), 10016 (invalid stops → SL/TP troppo vicini), 10019 (no money → verificare margine), 10027 (trade disabled → alert). Non usare mai GetLastError() come sostituto — in MQL5 il retcode nella struttura result è il riferimento corretto.
Posso aprire più ordini contemporaneamente con Oracle?►
Oracle UlcerZenith LITE gestisce una posizione per strumento per volta. Se PositionSelect(Symbol()) ritorna true, la posizione esiste già e non si apre un nuovo ordine. L’architettura multi-istanza (più EA su simboli diversi) usa GlobalVariables separate per simbolo garantendo isolamento completo.
Come funziona il trailing stop ATR in MQL5?►
Il trailing stop ATR si implementa calcolando il valore ATR corrente con iATR(), moltiplicandolo per il fattore Oracle (1.5), e confrontando il nuovo SL con quello attuale. Si modifica solo se il nuovo SL è migliore di quello esistente. Su Oracle XAUUSD H4, il trailing ATR×1.5 si attiva solo dopo che il prezzo ha raggiunto 1R di profitto e il breakeven è già impostato.
Perché usare una VPS per EA MQL5 con Oracle?►
Una VPS garantisce esecuzione continua 24/5. Per Oracle H4 su XAUUSD, i segnali arrivano all’apertura della candela H4 — un PC spento o connessione caduta in quel momento fa perdere il setup. Latenza VPS Equinix NY4: 1–3ms vs MetaQuotes server. PC domestico: 30–150ms. Su 65.587 trade, la differenza in slippage tra VPS e PC domestico vale circa 0.8–1.2% di PF annuo.
Qual è il modo corretto di modificare SL in breakeven in MQL5?►
Usare TRADE_ACTION_SLTP con il ticket della posizione. Prima verificare con PositionSelect() che la posizione esiste, leggere il prezzo di apertura, calcolare il nuovo SL con buffer (10 punti su XAUUSD), poi inviare. Fondamentale: usare un flag g_BESet per evitare di inviare la stessa modifica mille volte per tick. Il breakeven si setta una volta sola.
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