Il Risultato — La Dashboard Oracle su MT5
Prima del codice, vediamo cosa costruiamo. Questa è la struttura della dashboard Oracle — simulata in HTML per illustrare la gerarchia degli elementi che si costruiscono con ObjectCreate in MQL5:
Ogni elemento che vedi — il titolo, le righe label/valore, la barra score, i badge colorati, i pulsanti timeframe — è un oggetto grafico separato creato con ObjectCreate() e posizionato con coordinate pixel precise. Oracle v78 ne crea oltre 200 all'inizializzazione.
I Tipi di Oggetti Grafici — Cosa Usa Oracle
| Tipo | Uso principale in Oracle | Note tecniche |
|---|---|---|
| OBJ_RECTANGLE_LABEL | Sfondi e pannelli. Il rettangolo che forma il body della dashboard, le sezioni, i badge colorati. | Posizionato con pixel assoluti. Non segue le barre del grafico. Ideale per UI fissa. |
| OBJ_LABEL | Tutti i testi. Titolo, labels, valori numerici, icone Unicode. L'80% degli oggetti Oracle è OBJ_LABEL. | Font configurabile. Supporta Wingdings per icone. Coordinate pixel assolute. |
| OBJ_BUTTON | Pulsanti interattivi. I bottoni H1/H4/D1/W1 per cambiare timeframe, bottone settings. | Genera CHARTEVENT_OBJECT_CLICK in OnChartEvent(). Ha stato pressed/unpressed. |
| OBJ_EDIT | Input utente. Non usato da Oracle nella dashboard principale — utile per campi di testo editabili. | Genera CHARTEVENT_OBJECT_ENDEDIT quando l'utente conferma il testo. |
| OBJ_BITMAP_LABEL | Immagini. Logo, icone bitmap. Richiede file .bmp in MQL5/Images/. | Meno usato — le icone Unicode su OBJ_LABEL sono più pratiche. |
Creare e Gestire un Oggetto — Pattern Base
// ============================================================ // Pattern professionale per gestione oggetti grafici // Prefix "OZ_" su tutti i nomi — facilita eliminazione in bulk // ============================================================ // ---- Helper: crea o aggiorna un OBJ_LABEL ---- // Se l'oggetto esiste già, aggiorna solo le proprietà cambiate // Evita flickering da delete+recreate ad ogni tick void SetLabel(string name, int x, int y, string text, color clr, int font_size = 9, string font = "Consolas", ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER) { // Crea solo se non esiste ancora if(ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, corner); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); } // Aggiorna sempre le proprietà visibili ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, font_size); ObjectSetString(0, name, OBJPROP_FONT, font); } // ---- Helper: crea o aggiorna un OBJ_RECTANGLE_LABEL ---- void SetRect(string name, int x, int y, int w, int h, color bg_clr, color border_clr = clrNONE, int border_width = 0) { if(ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); } ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_XSIZE, w); ObjectSetInteger(0, name, OBJPROP_YSIZE, h); ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg_clr); ObjectSetInteger(0, name, OBJPROP_COLOR, border_clr); ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, name, OBJPROP_WIDTH, border_width); } // ---- Pulizia massiva alla rimozione dell'indicatore ---- void DeleteAllDashboard() { // Elimina tutti gli oggetti che iniziano con "OZ_" for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--) { string name = ObjectName(0, i, 0, -1); if(StringFind(name, "OZ_") == 0) ObjectDelete(0, name); } ChartRedraw(); }
La Dashboard Oracle — Codice Completo
Questo è il modulo che costruisce la dashboard Oracle. Il pattern è: costruisci tutto in BuildDashboard() chiamata da OnInit(), aggiorna solo i valori dinamici in UpdateDashboard() chiamata da OnCalculate() e OnTimer():
// ============================================================ // Oracle_Dashboard.mqh — costruisce l'interfaccia su MT5 // Palette Ferrari Luce: BG #0C0C0E · Gold #C8A84B · Red #CC2200 // ============================================================ // Colori palette Ferrari Luce (come costanti MQL5) #define FL_BG C'12,12,14' // #0C0C0E background #define FL_BG2 C'16,15,20' // #100F14 pannello #define FL_GOLD C'200,168,75' // #C8A84B gold #define FL_RED C'204,34,0' // #CC2200 Ferrari red #define FL_GREEN C'0,208,132' // #00D084 green #define FL_WHITE C'242,239,232' // #F2EFE8 white #define FL_GREY2 C'106,112,128' // #6A7080 grey #define FL_GREY3 C'154,159,168' // #9A9FA8 light grey // Dimensioni pannello (in pixel) #define DASH_X 12 // distanza dal bordo sinistro #define DASH_Y 28 // distanza dal bordo superiore #define DASH_W 240 // larghezza pannello #define ROW_H 18 // altezza riga #define PAD 10 // padding interno #define PREFIX "OZ_" // prefisso oggetti // ============================================================ // BuildDashboard — crea tutti gli oggetti statici // Chiamata UNA VOLTA in OnInit() // ============================================================ void BuildDashboard() { int y = DASH_Y; // === PANNELLO PRINCIPALE (sfondo) === // Altezza totale stimata: 12 sezioni × 20px + padding SetRect(PREFIX + "bg_main", DASH_X, DASH_Y, DASH_W, 340, FL_BG2, C'30,26,14', // bordo gold scuro 1); // === HEADER BAR === SetRect(PREFIX + "bg_header", DASH_X, DASH_Y, DASH_W, 28, C'20,18,10', C'30,26,14', 1); // Icona + titolo header SetLabel(PREFIX + "lbl_title", DASH_X + PAD, DASH_Y + 7, "⚡ UlcerZenith Oracle v78", FL_GOLD, 8, "Consolas"); y = DASH_Y + 36; // === SEZIONE SCORE === SetLabel(PREFIX + "lbl_score_title", DASH_X + PAD, y, "◈ ORACLE SCORE", FL_GREY2, 7); y += 14; // Label score (valore aggiornato da UpdateDashboard) SetLabel(PREFIX + "val_score", DASH_X + PAD, y, "0.0 / 10", FL_GOLD, 16, "Oswald"); y += 24; // Barra score (sfondo + fill) SetRect(PREFIX + "bar_score_bg", DASH_X + PAD, y, DASH_W - PAD*2, 4, C'30,30,35'); SetRect(PREFIX + "bar_score_fill", DASH_X + PAD, y, 0, 4, // larghezza = 0, aggiornata da UpdateDashboard FL_GOLD); y += 12; // Label segnale SetLabel(PREFIX + "lbl_signal_k", DASH_X + PAD, y, "Segnale", FL_GREY3, 8); SetLabel(PREFIX + "val_signal", DASH_X + 80, y, "—", FL_GREY2, 8); y += ROW_H; // Regime SetLabel(PREFIX + "lbl_regime_k", DASH_X + PAD, y, "Regime", FL_GREY3, 8); SetLabel(PREFIX + "val_regime", DASH_X + 80, y, "—", FL_GREY2, 8); y += ROW_H + 6; // === SEPARATORE === SetRect(PREFIX + "sep1", DASH_X + PAD, y, DASH_W - PAD*2, 1, C'30,26,14'); y += 8; // === SEZIONE SETUP TRADE === SetLabel(PREFIX + "lbl_setup_title", DASH_X + PAD, y, "◈ TRADE SETUP", FL_GREY2, 7); y += 14; // Righe entry/SL/TP/Lotti — labels statiche string setup_keys[] = {"Entry", "Stop Loss", "Take Profit", "Lotti (1%)"}; string setup_ids[] = {"entry", "sl", "tp", "lots"}; for(int i = 0; i < 4; i++) { SetLabel(PREFIX + "lbl_" + setup_ids[i] + "_k", DASH_X + PAD, y, setup_keys[i], FL_GREY3, 8); SetLabel(PREFIX + "val_" + setup_ids[i], DASH_X + 90, y, "—", FL_WHITE, 8); y += ROW_H; } y += 6; // === PULSANTI TIMEFRAME === SetRect(PREFIX + "sep2", DASH_X + PAD, y, DASH_W - PAD*2, 1, C'30,26,14'); y += 8; SetLabel(PREFIX + "lbl_tf_title", DASH_X + PAD, y, "◈ TIMEFRAME", FL_GREY2, 7); y += 14; // 4 pulsanti TF — OBJ_BUTTON per gestire i click string tf_names[] = {"H1", "H4", "D1", "W1"}; int tf_periods[] = {60, 240, 1440, 10080}; int btn_w = 48, btn_h = 20, btn_gap = 4; for(int i = 0; i < 4; i++) { string btn_name = PREFIX + "btn_tf_" + tf_names[i]; int btn_x = DASH_X + PAD + i * (btn_w + btn_gap); if(ObjectFind(0, btn_name) < 0) { ObjectCreate(0, btn_name, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, btn_name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, btn_name, OBJPROP_SELECTABLE, false); } ObjectSetInteger(0, btn_name, OBJPROP_XDISTANCE, btn_x); ObjectSetInteger(0, btn_name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, btn_name, OBJPROP_XSIZE, btn_w); ObjectSetInteger(0, btn_name, OBJPROP_YSIZE, btn_h); ObjectSetString(0, btn_name, OBJPROP_TEXT, tf_names[i]); ObjectSetInteger(0, btn_name, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, btn_name, OBJPROP_COLOR, FL_GREY3); ObjectSetInteger(0, btn_name, OBJPROP_BGCOLOR, C'20,20,26'); ObjectSetInteger(0, btn_name, OBJPROP_BORDER_COLOR, C'40,35,18'); } // Evidenzia H4 come default attivo SetButtonActive("H4"); ChartRedraw(); } // ============================================================ // UpdateDashboard — aggiorna solo i valori dinamici // Chiamata ad ogni nuova barra e da OnTimer() // ============================================================ void UpdateDashboard(double score, double dir, double regime, double entry, double sl, double tp, double lots) { // Score numerico ObjectSetString(0, PREFIX + "val_score", OBJPROP_TEXT, DoubleToString(score, 1) + " / 10"); // Colore score in base al valore color score_clr = score >= 7.0 ? FL_GREEN : score >= 4.5 ? FL_GOLD : FL_GREY2; ObjectSetInteger(0, PREFIX + "val_score", OBJPROP_COLOR, score_clr); // Barra score — larghezza proporzionale int bar_w = (int)((DASH_W - PAD*2) * score / 10.0); ObjectSetInteger(0, PREFIX + "bar_score_fill", OBJPROP_XSIZE, bar_w); ObjectSetInteger(0, PREFIX + "bar_score_fill", OBJPROP_BGCOLOR, score_clr); // Segnale string sig_txt = dir > 0 ? "▲ BUY" : dir < 0 ? "▼ SELL" : "— FLAT"; color sig_clr = dir > 0 ? FL_GREEN : dir < 0 ? FL_RED : FL_GREY2; if(score < 4.5) { sig_txt = "— NO SIGNAL"; sig_clr = FL_GREY2; } ObjectSetString(0, PREFIX + "val_signal", OBJPROP_TEXT, sig_txt); ObjectSetInteger(0, PREFIX + "val_signal", OBJPROP_COLOR, sig_clr); // Regime string reg_txt = regime == 1 ? "📈 TREND" : regime == 2 ? "↔ RANGE" : "💥 BREAKOUT"; ObjectSetString(0, PREFIX + "val_regime", OBJPROP_TEXT, reg_txt); // Setup trade ObjectSetString(0, PREFIX+"val_entry",OBJPROP_TEXT,DoubleToString(entry,_Digits)); ObjectSetString(0, PREFIX+"val_sl", OBJPROP_TEXT,DoubleToString(sl,_Digits)); ObjectSetString(0, PREFIX+"val_tp", OBJPROP_TEXT,DoubleToString(tp,_Digits)); ObjectSetString(0, PREFIX+"val_lots", OBJPROP_TEXT,DoubleToString(lots,2)); ChartRedraw(); } // ============================================================ // SetButtonActive — evidenzia il pulsante TF attivo // ============================================================ void SetButtonActive(string active_tf) { string tfs[] = {"H1", "H4", "D1", "W1"}; for(int i = 0; i < 4; i++) { string btn_name = PREFIX + "btn_tf_" + tfs[i]; bool active = (tfs[i] == active_tf); ObjectSetInteger(0, btn_name, OBJPROP_BGCOLOR, active ? C'30,24,8' : C'20,20,26'); ObjectSetInteger(0, btn_name, OBJPROP_COLOR, active ? FL_GOLD : FL_GREY3); } }
OnChartEvent — Gestire i Click sui Pulsanti
// ============================================================ // OnChartEvent — gestisce click e resize // ============================================================ string g_active_tf = "H4"; // TF corrente selezionato void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // ---- Click su un oggetto ---- if(id == CHARTEVENT_OBJECT_CLICK) { // Pulsanti timeframe string tfs[] = {"H1", "H4", "D1", "W1"}; for(int i = 0; i < 4; i++) { if(sparam == PREFIX + "btn_tf_" + tfs[i]) { g_active_tf = tfs[i]; SetButtonActive(tfs[i]); // Reset stato pressed (OBJ_BUTTON rimane premuto senza reset) ObjectSetInteger(0, sparam, OBJPROP_STATE, false); Print("TF selezionato: ", tfs[i]); // Qui triggerare il ricalcolo Oracle per il nuovo TF ChartRedraw(); break; } } } // ---- Resize del grafico — riposizionare la dashboard ---- // Chiamato quando l'utente ridimensiona la finestra MT5 if(id == CHARTEVENT_CHART_CHANGE) { // Ricostruisce la dashboard con le nuove dimensioni del grafico // Non è necessario se usi CORNER_LEFT_UPPER con coordinate fisse — // la dashboard rimane ancorata in alto a sinistra automaticamente // Serve solo se usi coordinate relative alla dimensione del grafico BuildDashboard(); ChartRedraw(); } }
La dashboard Oracle
dal vivo ogni mattina.
Score, regime, entry, SL, TP e lotti — tutto visibile sul grafico MT5 nelle live gratuite.
— Oracle in produzione reale.
FAQ — Dashboard MT5 MQL5
if(id == CHARTEVENT_OBJECT_CLICK) { if(sparam == "OZ_btn_tf_H4") { /* gestisci */ } }. Importante: dopo aver gestito il click, resetta lo stato con ObjectSetInteger(0, sparam, OBJPROP_STATE, false) — altrimenti il pulsante rimane visivamente "premuto".EventSetTimer(1) in OnInit() e aggiorna in OnTimer() ogni secondo invece che ad ogni tick — molto meno CPU e zero flickering.ChartGetInteger(0, CHART_WIDTH_IN_PIXELS) e CHART_HEIGHT_IN_PIXELS per calcolare posizioni relative alla dimensione del grafico corrente.