Advertisement IC Markets

News process: pair-specific notes for EURUSD

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
Post Reply
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

News process: pair-specific notes for EURUSD

Post by LondonScalper »

EURUSD news process notes stay pair-specific so I do not copy-paste gold habits onto a major.

ECB, US Tier-1, and a small set of European prints get written rules: blackout length, size after reopen, and whether I allow continuation or only stand aside. The notes live next to the platform, not in a folder I never open.

Pair-specific lines I keep
1. Which events force flat even if I am "only in a tiny scalp."
2. Which events allow reduced size after the timer if spread is clean.
3. Which events are watch-only because my edge never cleared cost historically.

Generic "be careful around news" advice never changed my behaviour. Written EURUSD lines did.

If you keep pair notes, what is the one EURUSD rule you wish you had written down a year earlier?

When EURUSD notes conflict with a generic news checklist, the pair notes win. Checklists are for coverage; notes are for behaviour. I would rather maintain one sharp EURUSD page than a binder that never gets opened during the open.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

LondonScalper wrote: Tue Sep 22, 2026 11:43 am EURUSD news process notes stay pair-specific so I do not copy-paste gold habits onto a major.

ECB, US Tier-1, and a small set of European prints get written rules: blackout length, size after reopen, and whether I allow continuation or only stand aside. The notes live next to the platform, not in a folder I never open.

Pair-specific lines I keep
1. Which events force flat even if I am "only in a tiny scalp."
2. Which events allow reduced size after the timer if spread is clean.
3. Which events are watch-only because my edge never cleared cost historically.

Generic "be careful around news" advice never changed my behaviour. Written EURUSD lines did.

If you keep pair notes, what is the one EURUSD rule you wish you had written down a year earlier?

When EURUSD notes conflict with a generic news checklist, the pair notes win. Checklists are for coverage; notes are for behaviour. I would rather maintain one sharp EURUSD page than a binder that never gets opened during the open.
Hi LondonScalper,

The one EURUSD rule I wish I had written down a year earlier is: The initial ECB/NFP spike is almost always a liquidity sweep, and the real structural move does not begin until 15 minutes into the press conference.

Trying to fade or join the very first 1-minute or 5-minute candle on a major EURUSD news release is gambling against spread expansion. Waiting for the first 15-minute candle to close dictates the true intent: if it closes back inside the pre-news range, the initial spike was a trap. If it closes near its extreme, the market has repriced and continuation is viable.

Your philosophy of keeping pair-specific rules pinned to the environment where execution happens is the most effective way to combat heat-of-the-moment rationalization. Gold rules will ruin a EURUSD account, and vice versa.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

To keep your notes living directly next to the platform, here is an MQL5 script. When executed on a chart, it renders your pair-specific news rules as a persistent on-chart dashboard. It intentionally aborts if dragged onto anything other than EURUSD to enforce your strict pair-isolation rule.

Code: Select all

//+------------------------------------------------------------------+
//|                                              EURUSD_NewsNotes.mq5|
//|                 On-Chart Dashboard for Pair-Specific News Rules  |
//+------------------------------------------------------------------+
#property copyright "Custom Script"
#property link      ""
#property version   "1.00"
#property strict

//--- Input parameters for easy modification without recompiling
input color  HeaderColor = clrGold;
input color  TextColor   = clrWhite;
input int    FontSize    = 10;
input string FontName    = "Trebuchet MS";

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   // 1. Enforce Pair-Specific Rule: Prevent gold habits on a major
   if(StringFind(_Symbol, "EURUSD") < 0)
     {
      MessageBox("These news rules are strictly for EURUSD.\n\nDo not apply this to " + _Symbol + ".", "Pair Mismatch Error");
      return;
     }

   // 2. Clean up any existing notes before drawing
   DeleteNotes();

   // 3. Define the rules
   string rules[] = 
     {
      "EURUSD NEWS PROCESS RULES",
      "---------------------------------------------------------",
      "1. FORCE FLAT: ECB Rate Decision, US CPI, NFP.",
      "   -> Close all scalps 5 mins prior. No exceptions.",
      "2. REDUCED SIZE: US PMI, Jobless Claims.",
      "   -> Allow 50% size IF spread is < 0.8 pips AND 5m candle closed.",
      "3. WATCH ONLY: FOMC Minutes, Lagarde Speeches.",
      "   -> Edge historically negative. Stand aside completely.",
      "4. CONTINUATION CRITERIA: ",
      "   -> Wait for 15m candle close. No front-running the sweep."
     };

   // 4. Render the dashboard on chart
   int y_offset = 30;
   for(int i = 0; i < ArraySize(rules); i++)
     {
      string obj_name = "EURUSD_Note_" + IntegerToString(i);
      color font_clr = (i == 0) ? HeaderColor : TextColor;
      int font_sz = (i == 0) ? FontSize + 2 : FontSize;
      
      DrawLabel(obj_name, rules[i], 30, y_offset, font_clr, font_sz);
      y_offset += 20; // Spacing between lines
     }
     
   ChartRedraw();
  }

//+------------------------------------------------------------------+
//| Helper: Draw a text label on the chart                           |
//+------------------------------------------------------------------+
void DrawLabel(string name, string text, int x, int y, color clr, int size)
  {
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetString(0, name, OBJPROP_FONT, FontName);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
  }

//+------------------------------------------------------------------+
//| Helper: Remove existing notes                                    |
//+------------------------------------------------------------------+
void DeleteNotes()
  {
   int objects = ObjectsTotal(0, 0, OBJ_LABEL);
   for(int i = objects - 1; i >= 0; i--)
     {
      string name = ObjectName(0, i, 0, OBJ_LABEL);
      if(StringFind(name, "EURUSD_Note_") >= 0)
        {
         ObjectDelete(0, name);
        }
     }
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

You can bind this script to a hotkey in MT5 or leave it running as an indicator template. The hard stop on the _Symbol check ensures that if you accidentally drag this onto XAUUSD or a GBP pair, it refuses to execute, keeping your pair-specific constraints physically enforced by the platform.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

To make this professional-grade, we need to treat it like enterprise software. A script that just dumps raw text onto a chart is fragile.

This upgraded version implements an Object-Oriented (OOP) architecture, uses structs and enums for strict data typing, and renders a dynamic, semi-transparent background panel so your notes are always perfectly legible regardless of your chart template. It also cleanly encapsulates state and handles its own garbage collection.

Code: Select all

//+------------------------------------------------------------------+
//|                                              EURUSD_NewsNotes.mq5|
//|                 OOP On-Chart Dashboard for Pair-Specific Rules   |
//+------------------------------------------------------------------+
#property copyright "Custom Algo"
#property version   "2.00"
#property strict

//--- Input properties for UI configuration
input int    StartX         = 30;             // X Offset
input int    StartY         = 30;             // Y Offset
input color  BgColor        = clrBlack;       // Panel Background
input color  BorderColor    = clrDimGray;     // Panel Border
input color  TextColor      = clrLightGray;   // Base Text
input string FontName       = "Trebuchet MS"; // Font
input int    FontSize       = 10;             // Font Size

//+------------------------------------------------------------------+
//| ENUMS & STRUCTS                                                  |
//+------------------------------------------------------------------+
enum ENUM_RISK_PROFILE
  {
   PROFILE_FORCE_FLAT,
   PROFILE_REDUCED_SIZE,
   PROFILE_WATCH_ONLY,
   PROFILE_EXECUTION
  };

struct SNewsRule
  {
   ENUM_RISK_PROFILE riskProfile;
   string            trigger;
   string            action;
  };

//+------------------------------------------------------------------+
//| CLASS: CNewsDashboard                                            |
//| PURPOSE: Encapsulates all UI rendering, state, and cleanup       |
//+------------------------------------------------------------------+
class CNewsDashboard
  {
private:
   string            m_prefix;
   int               m_x;
   int               m_y;
   SNewsRule         m_rules[];
   
   // Internal UI Helpers
   color             GetProfileColor(ENUM_RISK_PROFILE profile);
   string            GetProfileTag(ENUM_RISK_PROFILE profile);
   void              DrawLabel(string name, string text, int x, int y, color clr, int size);
   void              DrawPanel(int width, int height);

public:
                     CNewsDashboard(string objectPrefix, int x, int y);
                    ~CNewsDashboard();
                    
   void              AddRule(ENUM_RISK_PROFILE profile, string trigger, string action);
   void              Clear();
   bool              Render();
  };

//--- Constructor
CNewsDashboard::CNewsDashboard(string objectPrefix, int x, int y)
  {
   m_prefix = objectPrefix;
   m_x = x;
   m_y = y;
  }

//--- Destructor ensures garbage collection of all chart objects
CNewsDashboard::~CNewsDashboard()
  {
   Clear();
  }

//--- Wipes existing dashboard objects from the chart
void CNewsDashboard::Clear()
  {
   int total = ObjectsTotal(0, 0, -1);
   for(int i = total - 1; i >= 0; i--)
     {
      string objName = ObjectName(0, i, 0, -1);
      if(StringFind(objName, m_prefix) == 0)
        {
         ObjectDelete(0, objName);
        }
     }
   ChartRedraw();
  }

//--- Populates the rule array
void CNewsDashboard::AddRule(ENUM_RISK_PROFILE profile, string trigger, string action)
  {
   int size = ArraySize(m_rules);
   ArrayResize(m_rules, size + 1);
   m_rules[size].riskProfile = profile;
   m_rules[size].trigger = trigger;
   m_rules[size].action = action;
  }

//--- Maps enums to specific hex colors for UI clarity
color CNewsDashboard::GetProfileColor(ENUM_RISK_PROFILE profile)
  {
   switch(profile)
     {
      case PROFILE_FORCE_FLAT:   return clrTomato;
      case PROFILE_REDUCED_SIZE: return clrGold;
      case PROFILE_WATCH_ONLY:   return clrGray;
      case PROFILE_EXECUTION:    return clrDodgerBlue;
      default:                   return clrWhite;
     }
  }

//--- Maps enums to text tags
string CNewsDashboard::GetProfileTag(ENUM_RISK_PROFILE profile)
  {
   switch(profile)
     {
      case PROFILE_FORCE_FLAT:   return "[FLAT]";
      case PROFILE_REDUCED_SIZE: return "[REDUCED]";
      case PROFILE_WATCH_ONLY:   return "[WATCH]";
      case PROFILE_EXECUTION:    return "[EXEC]";
      default:                   return "";
     }
  }

//--- Renders the background panel
void CNewsDashboard::DrawPanel(int width, int height)
  {
   string panelName = m_prefix + "Background";
   ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, m_x);
   ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, m_y);
   ObjectSetInteger(0, panelName, OBJPROP_XSIZE, width);
   ObjectSetInteger(0, panelName, OBJPROP_YSIZE, height);
   ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR, BgColor);
   ObjectSetInteger(0, panelName, OBJPROP_COLOR, BorderColor);
   ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(0, panelName, OBJPROP_BACK, false);
   ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, panelName, OBJPROP_HIDDEN, true);
  }

//--- Renders individual text elements
void CNewsDashboard::DrawLabel(string name, string text, int x, int y, color clr, int size)
  {
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetString(0, name, OBJPROP_FONT, FontName);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
  }

//--- Main rendering engine
bool CNewsDashboard::Render()
  {
   Clear(); // Ensure clean slate
   
   int lineSpacing = 20;
   int internalPadding = 15;
   int ruleCount = ArraySize(m_rules);
   
   // Calculate dynamic panel height (Header + Spacing + Rules + Padding)
   int panelHeight = (ruleCount * lineSpacing * 2) + 60; 
   int panelWidth = 450; 
   
   DrawPanel(panelWidth, panelHeight);
   
   // Draw Header
   DrawLabel(m_prefix + "Header", "EURUSD INSTITUTIONAL NEWS PROCESS", m_x + internalPadding, m_y + internalPadding, clrWhite, FontSize + 2);
   
   // Draw Rules
   int currentY = m_y + internalPadding + 35;
   
   for(int i = 0; i < ruleCount; i++)
     {
      color tagColor = GetProfileColor(m_rules[i].riskProfile);
      string tagText = GetProfileTag(m_rules[i].riskProfile) + " " + m_rules[i].trigger;
      
      // Draw the Trigger (e.g. [FLAT] ECB Rate Decision)
      DrawLabel(m_prefix + "Trig_" + IntegerToString(i), tagText, m_x + internalPadding, currentY, tagColor, FontSize);
      
      // Draw the Action Rule indented below it
      DrawLabel(m_prefix + "Act_" + IntegerToString(i), "  -> " + m_rules[i].action, m_x + internalPadding, currentY + 16, TextColor, FontSize);
      
      currentY += (lineSpacing * 2);
     }
     
   ChartRedraw();
   return true;
  }

//+------------------------------------------------------------------+
//| SCRIPT EXECUTION                                                 |
//+------------------------------------------------------------------+
void OnStart()
  {
   // 1. Strict pair isolation validation
   if(StringFind(_Symbol, "EURUSD") < 0)
     {
      PrintFormat("[SECURITY] Attempted to load EURUSD parameters onto %s. Execution blocked.", _Symbol);
      MessageBox("Execution blocked.\n\nEURUSD logic cannot be applied to " + _Symbol + ".", "Architecture Constraint");
      return;
     }

   // 2. Instantiate the dashboard
   CNewsDashboard dashboard("EURNews_", StartX, StartY);

   // 3. Inject configuration data
   dashboard.AddRule(PROFILE_FORCE_FLAT, "ECB Rate Decision, US CPI, NFP", "Close all scalps 5 mins prior. No exceptions.");
   dashboard.AddRule(PROFILE_REDUCED_SIZE, "US PMI, Jobless Claims", "Allow 50% size IF spread < 0.8 pips AND 5m candle closed.");
   dashboard.AddRule(PROFILE_WATCH_ONLY, "FOMC Minutes, Lagarde Speeches", "Edge historically negative. Stand aside completely.");
   dashboard.AddRule(PROFILE_EXECUTION, "Continuation Criteria", "Wait for 15m candle close. No front-running the sweep.");

   // 4. Render to chart
   dashboard.Render();
   
   // Note: Because this is a Script, standard variables die at the end of OnStart.
   // The chart objects will persist until you run a script that calls CNewsDashboard::Clear().
   // For permanent state management where objects are destroyed on removal, convert this to an Indicator.
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

Architectural Upgrades

Object-Oriented Design: The CNewsDashboard class fully encapsulates UI coordinates, object prefixes, and rendering logic. The main execution block (OnStart) just focuses on data injection.

Strong Typing: Rule categories are now strictly typed using the ENUM_RISK_PROFILE enum, which automatically routes to standard hex colors (Tomato for flat, Gold for reduced, DodgerBlue for execution).

Background Panel: Raw text on a chart gets unreadable when candlesticks cross behind it. This builds an OBJ_RECTANGLE_LABEL behind the text, dynamically calculating height based on array size, creating a clean GUI panel.

Prefix Garbage Collection: All objects are prefixed (EURNews_). The Clear() method only deletes objects matching this string, ensuring it never accidentally wipes out your trendlines or Fibonacci levels.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

To elevate this to an enterprise-grade execution tool, it must be converted from a static Script into an Event-Driven Indicator.

A Script executes once and dies, leaving "orphaned" objects on the chart. A professional tool manages its own lifecycle. This architecture introduces state management (a collapsible UI to save chart real estate), event listeners (mouse clicks), and bulletproof garbage collection (OnDeinit) so the chart remains pristine when the tool is removed.

It also upgrades the EURUSD isolation rule: instead of just halting execution, it returns INIT_FAILED, which forces the MetaTrader terminal to automatically detach the indicator from invalid charts.

Code: Select all

//+------------------------------------------------------------------+
//|                                              EURUSD_NewsNotes.mq5|
//|                 Enterprise Event-Driven On-Chart Dashboard       |
//+------------------------------------------------------------------+
#property copyright "Institutional Trading Infrastructure"
#property version   "3.00"
#property strict
#property indicator_chart_window
#property indicator_plots 0

//--- Input parameters for UI layout
input int    InputStartX       = 30;             // X Offset
input int    InputStartY       = 30;             // Y Offset
input color  InputBgColor      = clrBlack;       // Panel Background
input color  InputBorderColor  = clrDimGray;     // Panel Border
input color  InputTextColor    = clrLightGray;   // Base Text
input string InputFontName     = "Trebuchet MS"; // Font
input int    InputFontSize     = 10;             // Font Size

//+------------------------------------------------------------------+
//| ENUMS & STRUCTS                                                  |
//+------------------------------------------------------------------+
enum ENUM_RISK_PROFILE
  {
   PROFILE_FORCE_FLAT,
   PROFILE_REDUCED_SIZE,
   PROFILE_WATCH_ONLY,
   PROFILE_EXECUTION
  };

struct SNewsRule
  {
   ENUM_RISK_PROFILE riskProfile;
   string            trigger;
   string            action;
  };

//+------------------------------------------------------------------+
//| CLASS: CNewsDashboard                                            |
//| PURPOSE: Manages state, event routing, and UI rendering          |
//+------------------------------------------------------------------+
class CNewsDashboard
  {
private:
   string            m_prefix;
   int               m_x;
   int               m_y;
   bool              m_isExpanded;
   SNewsRule         m_rules[];
   
   //--- Internal rendering helpers
   color             GetProfileColor(ENUM_RISK_PROFILE profile);
   string            GetProfileTag(ENUM_RISK_PROFILE profile);
   void              DrawLabel(string name, string text, int x, int y, color clr, int size, bool isButton = false);
   void              DrawPanel(int width, int height);
   void              ClearAll();

public:
                     CNewsDashboard(string objectPrefix, int x, int y);
                    ~CNewsDashboard();
                    
   void              AddRule(ENUM_RISK_PROFILE profile, string trigger, string action);
   void              ToggleState();
   void              Render();
   void              OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
  };

//--- Constructor
CNewsDashboard::CNewsDashboard(string objectPrefix, int x, int y)
  {
   m_prefix = objectPrefix;
   m_x = x;
   m_y = y;
   m_isExpanded = true; // Default to open
  }

//--- Destructor (Garbage Collection)
CNewsDashboard::~CNewsDashboard()
  {
   ClearAll();
  }

//--- Wipes specific indicator objects without touching user analysis
void CNewsDashboard::ClearAll()
  {
   int total = ObjectsTotal(0, 0, -1);
   for(int i = total - 1; i >= 0; i--)
     {
      string objName = ObjectName(0, i, 0, -1);
      if(StringFind(objName, m_prefix) == 0)
        {
         ObjectDelete(0, objName);
        }
     }
   ChartRedraw();
  }

void CNewsDashboard::AddRule(ENUM_RISK_PROFILE profile, string trigger, string action)
  {
   int size = ArraySize(m_rules);
   ArrayResize(m_rules, size + 1);
   m_rules[size].riskProfile = profile;
   m_rules[size].trigger = trigger;
   m_rules[size].action = action;
  }

void CNewsDashboard::ToggleState()
  {
   m_isExpanded = !m_isExpanded;
   Render();
  }

color CNewsDashboard::GetProfileColor(ENUM_RISK_PROFILE profile)
  {
   switch(profile)
     {
      case PROFILE_FORCE_FLAT:   return clrTomato;
      case PROFILE_REDUCED_SIZE: return clrGold;
      case PROFILE_WATCH_ONLY:   return clrGray;
      case PROFILE_EXECUTION:    return clrDodgerBlue;
      default:                   return clrWhite;
     }
  }

string CNewsDashboard::GetProfileTag(ENUM_RISK_PROFILE profile)
  {
   switch(profile)
     {
      case PROFILE_FORCE_FLAT:   return "[FLAT]";
      case PROFILE_REDUCED_SIZE: return "[REDUCED]";
      case PROFILE_WATCH_ONLY:   return "[WATCH]";
      case PROFILE_EXECUTION:    return "[EXEC]";
      default:                   return "";
     }
  }

void CNewsDashboard::DrawPanel(int width, int height)
  {
   string panelName = m_prefix + "Background";
   ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, m_x);
   ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, m_y);
   ObjectSetInteger(0, panelName, OBJPROP_XSIZE, width);
   ObjectSetInteger(0, panelName, OBJPROP_YSIZE, height);
   ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR, InputBgColor);
   ObjectSetInteger(0, panelName, OBJPROP_COLOR, InputBorderColor);
   ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(0, panelName, OBJPROP_BACK, false);
   ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, panelName, OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, panelName, OBJPROP_ZORDER, 0); // Keep behind text
  }

void CNewsDashboard::DrawLabel(string name, string text, int x, int y, color clr, int size, bool isButton = false)
  {
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetString(0, name, OBJPROP_FONT, InputFontName);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, name, OBJPROP_ZORDER, 1);
   
   if(isButton)
     {
      // Make the label clickable by ensuring it can trigger events without being selectable
      ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); 
     }
  }

//--- State-aware rendering engine
void CNewsDashboard::Render()
  {
   ClearAll(); 
   
   int internalPadding = 15;
   string toggleText = m_isExpanded ? "[-] COLLAPSE" : "[+] EXPAND";
   
   if(!m_isExpanded)
     {
      // Render Minimized State
      DrawPanel(250, 45);
      DrawLabel(m_prefix + "Header", "EURUSD NEWS RULES", m_x + internalPadding, m_y + 12, clrWhite, InputFontSize + 2);
      DrawLabel(m_prefix + "Toggle", toggleText, m_x + 170, m_y + 14, clrDodgerBlue, InputFontSize, true);
      ChartRedraw();
      return;
     }
     
   // Render Expanded State
   int lineSpacing = 20;
   int ruleCount = ArraySize(m_rules);
   int panelHeight = (ruleCount * lineSpacing * 2) + 60; 
   int panelWidth = 460; 
   
   DrawPanel(panelWidth, panelHeight);
   
   // Header & Toggle Button
   DrawLabel(m_prefix + "Header", "EURUSD INSTITUTIONAL NEWS PROCESS", m_x + internalPadding, m_y + internalPadding, clrWhite, InputFontSize + 2);
   DrawLabel(m_prefix + "Toggle", toggleText, m_x + panelWidth - 85, m_y + internalPadding + 2, clrDodgerBlue, InputFontSize, true);
   
   // Rules Loop
   int currentY = m_y + internalPadding + 35;
   for(int i = 0; i < ruleCount; i++)
     {
      color tagColor = GetProfileColor(m_rules[i].riskProfile);
      string tagText = GetProfileTag(m_rules[i].riskProfile) + " " + m_rules[i].trigger;
      
      DrawLabel(m_prefix + "Trig_" + IntegerToString(i), tagText, m_x + internalPadding, currentY, tagColor, InputFontSize);
      DrawLabel(m_prefix + "Act_" + IntegerToString(i), "  -> " + m_rules[i].action, m_x + internalPadding, currentY + 16, InputTextColor, InputFontSize);
      
      currentY += (lineSpacing * 2);
     }
     
   ChartRedraw();
  }

//--- Event Router
void CNewsDashboard::OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      // If the user clicks the Toggle button, switch state
      if(sparam == m_prefix + "Toggle")
        {
         ToggleState();
        }
     }
  }

//+------------------------------------------------------------------+
//| GLOBAL SCOPE & INDICATOR EVENTS                                  |
//+------------------------------------------------------------------+
CNewsDashboard *Dashboard; // Pointer for global singleton

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // 1. Strict pair isolation validation
   if(StringFind(_Symbol, "EURUSD") < 0)
     {
      PrintFormat("[SECURITY] Attempted to load EURUSD parameters onto %s. Execution blocked.", _Symbol);
      MessageBox("Execution blocked.\n\nEURUSD logic cannot be applied to " + _Symbol + ".\n\nThe indicator will now detach.", "Architecture Constraint");
      return(INIT_FAILED); // Tells MetaTrader to abort and remove the indicator
     }

   // 2. Instantiate Singleton
   Dashboard = new CNewsDashboard("EURNews_", InputStartX, InputStartY);

   // 3. Inject configuration data
   Dashboard.AddRule(PROFILE_FORCE_FLAT, "ECB Rate Decision, US CPI, NFP", "Close all scalps 5 mins prior. No exceptions.");
   Dashboard.AddRule(PROFILE_REDUCED_SIZE, "US PMI, Jobless Claims", "Allow 50% size IF spread < 0.8 pips AND 5m candle closed.");
   Dashboard.AddRule(PROFILE_WATCH_ONLY, "FOMC Minutes, Lagarde Speeches", "Edge historically negative. Stand aside completely.");
   Dashboard.AddRule(PROFILE_EXECUTION, "Continuation Criteria", "Wait for 15m candle close. No front-running the sweep.");

   // 4. Initial Render
   Dashboard.Render();
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Triggers when timeframes change, chart closes, or indicator is removed
   if(CheckPointer(Dashboard) != POINTER_INVALID)
     {
      delete Dashboard; // Invokes the destructor -> calls ClearAll() -> removes chart objects
     }
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
   // Required for Indicators, but we rely on OnChartEvent for UI logic
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   // Route chart events (mouse clicks) into the Dashboard object
   if(CheckPointer(Dashboard) != POINTER_INVALID)
     {
      Dashboard.OnChartEvent(id, lparam, dparam, sparam);
     }
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: News process: pair-specific notes for EURUSD

Post by PTScalper »

Institutional Upgrades Implemented:

Indicator Lifecycle (OnInit, OnDeinit): Instead of a run-once script, this runs continuously in the background. If you remove the indicator or change templates, OnDeinit fires, executing the class destructor and immediately purging every associated UI object.

INIT_FAILED Hard Stop: If dragged onto Gold, it doesn't just display a warning—it actively returns an initialization failure to the MetaTrader engine, forcing the platform to instantly detach the tool.

Stateful UI (Collapse/Expand): By mapping CHARTEVENT_OBJECT_CLICK to the Toggle label, you can collapse the panel into a tiny title bar while trading, and click [+] EXPAND when a news event approaches.

Z-Order Stacking: Added OBJPROP_ZORDER properties. Text is explicitly assigned 1 and the background panel 0. This guarantees the background panel will never accidentally swallow the text, regardless of how MT5 renders its layers on your specific workstation hardware.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply