Spread Monitor and Filter

Indicators MetaTrader 5 Free
//+——————————————————————+
//|                                            SpreadMonitorDemo.mq5 |
//|                                        Copyright 2026, Algosphere |
//|                                      https://algosphere-quant.com |
//+——————————————————————+
#property copyright “Copyright 2026, Algosphere”
#property link      “https://algosphere-quant.com”
#property version   “1.00”
#property description “Demo indicator for SpreadMonitor Library”
#property description “Displays real-time spread statistics and alerts”
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   0
//+——————————————————————+
//| Includes                                                         |
//+——————————————————————+
#include “SpreadMonitor.mqh”
//+——————————————————————+
//| Input parameters                                                 |
//+——————————————————————+
input group              “=== Display Settings ===”
input int                InpPanelX=10;              // Panel X Position
input int                InpPanelY=30;              // Panel Y Position
input color              InpBackgroundColor=C’32,32,32′;  // Background Color
input color              InpTextColor=clrWhite;    // Text Color
input group              “=== Spread Thresholds (Pips) ===”
input double             InpLowThreshold=1.0;      // Low Spread Threshold
input double             InpNormalThreshold=2.0;   // Normal Spread Threshold  
input double             InpHighThreshold=5.0;     // High Spread Threshold
input group              “=== Filter Settings ===”
input double             InpMaxSpread=3.0;         // Maximum Acceptable Spread
input int                InpHistorySize=500;       // History Size (samples)
input group              “=== Alert Settings ===”
input bool               InpAlertOnHigh=true;      // Alert on High Spread
input bool               InpAlertOnExtreme=true;   // Alert on Extreme Spread
//+——————————————————————+
//| Defines                                                          |
//+——————————————————————+
#define PREFIX           “SPM_”
#define PANEL_WIDTH      200
#define PANEL_HEIGHT     230
#define ROW_SPACING      18
//+——————————————————————+
//| Global variables                                                 |
//+——————————————————————+
CSpreadMonitor           g_spread_monitor;
double                   g_spread_buffer[];
ENUM_SPREAD_CONDITION    g_last_condition=SPREAD_LOW;
datetime                 g_last_alert_time=0;
//+——————————————————————+
//| Custom indicator initialization function                         |
//+——————————————————————+
int OnInit()
  {
//— Initialize spread monitor
   if(!g_spread_monitor.Init(_Symbol,InpHistorySize,
                              InpLowThreshold,InpNormalThreshold,InpHighThreshold))
     {
      Print(“Error: Failed to initialize SpreadMonitor”);
      return(INIT_FAILED);
     }
//— Set indicator buffer (not plotted, just for data storage)
   SetIndexBuffer(0,g_spread_buffer,INDICATOR_CALCULATIONS);
//— Create panel
   CreatePanel();
   
//— Initial update
   g_spread_monitor.Update();
   UpdatePanel();
//— Set timer for frequent updates
   EventSetMillisecondTimer(250);
   return(INIT_SUCCEEDED);
  }
//+——————————————————————+
//| Custom indicator deinitialization function                       |
//+——————————————————————+
void OnDeinit(const int reason)
  {
   EventKillTimer();
   ObjectsDeleteAll(0,PREFIX);
  }
//+——————————————————————+
//| Timer function – updates spread display                          |
//+——————————————————————+
void OnTimer()
  {
//— Record spread sample
   g_spread_monitor.Update();
   
//— Update display
   UpdatePanel();
   
//— Check for alerts
   CheckAlerts();
  }
//+——————————————————————+
//| 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[])
  {
//— Store current spread
   if(rates_total>0)
      g_spread_buffer[rates_total-1]=g_spread_monitor.GetCurrentSpread();
      
   return(rates_total);
  }
//+——————————————————————+
//| Check and trigger alerts                                         |
//+——————————————————————+
void CheckAlerts()
  {
   ENUM_SPREAD_CONDITION current_condition=g_spread_monitor.GetSpreadCondition();
   
//— Only alert on condition change to avoid spam
   if(current_condition==g_last_condition)
      return;
      
//— Check if enough time passed since last alert (30 seconds)
   if(TimeCurrent()-g_last_alert_time<30)
      return;
//— Alert on high spread
   if(InpAlertOnHigh && current_condition==SPREAD_HIGH && g_last_condition<SPREAD_HIGH)
     {
      Alert(_Symbol,” – HIGH SPREAD: “,DoubleToString(g_spread_monitor.GetCurrentSpread(),1),” pips”);
      g_last_alert_time=TimeCurrent();
     }
//— Alert on extreme spread
   if(InpAlertOnExtreme && current_condition==SPREAD_EXTREME && g_last_condition<SPREAD_EXTREME)
     {
      Alert(_Symbol,” – EXTREME SPREAD: “,DoubleToString(g_spread_monitor.GetCurrentSpread(),1),” pips!”);
      g_last_alert_time=TimeCurrent();
     }
   g_last_condition=current_condition;
  }
//+——————————————————————+
//| Create information panel                                         |
//+——————————————————————+
void CreatePanel()
  {
   int x=InpPanelX;
   int y=InpPanelY;
//— Background
   CreateRectangleLabel(PREFIX+”Background”,x,y,PANEL_WIDTH,PANEL_HEIGHT,
                        InpBackgroundColor,C’60,60,60′);
//— Title
   CreateTextLabel(PREFIX+”Title”,x+10,y+8,”SPREAD MONITOR”,
                   InpTextColor,11,”Arial Bold”);
//— Symbol
   CreateTextLabel(PREFIX+”Symbol”,x+PANEL_WIDTH-60,y+10,_Symbol,
                   clrDodgerBlue,9,”Arial”);
//— Separator
   CreateRectangleLabel(PREFIX+”Sep1″,x+10,y+30,PANEL_WIDTH-20,1,
                        clrDimGray,clrDimGray);
   int row_y=y+40;
//— Current spread (large display)
   CreateTextLabel(PREFIX+”LblCurrent”,x+15,row_y,”Current:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValCurrent”,x+80,row_y,”0.0″,clrLime,14,”Arial Bold”);
   CreateTextLabel(PREFIX+”UnitCurrent”,x+130,row_y,”pips”,clrGray,9,”Arial”);
   row_y+=24;
//— Condition
   CreateTextLabel(PREFIX+”LblCondition”,x+15,row_y,”Status:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValCondition”,x+80,row_y,”LOW”,clrLime,10,”Arial Bold”);
   row_y+=ROW_SPACING+5;
//— Separator
   CreateRectangleLabel(PREFIX+”Sep2″,x+10,row_y,PANEL_WIDTH-20,1,
                        clrDimGray,clrDimGray);
   row_y+=10;
//— Statistics section
   CreateTextLabel(PREFIX+”LblStats”,x+15,row_y,”Statistics”,clrWhite,9,”Arial Bold”);
   row_y+=ROW_SPACING;
   CreateTextLabel(PREFIX+”LblAvg”,x+15,row_y,”Average:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValAvg”,x+100,row_y,”0.0 pips”,InpTextColor,9,”Arial”);
   row_y+=ROW_SPACING;
   CreateTextLabel(PREFIX+”LblMin”,x+15,row_y,”Minimum:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValMin”,x+100,row_y,”0.0 pips”,clrLime,9,”Arial”);
   row_y+=ROW_SPACING;
   CreateTextLabel(PREFIX+”LblMax”,x+15,row_y,”Maximum:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValMax”,x+100,row_y,”0.0 pips”,clrOrange,9,”Arial”);
   row_y+=ROW_SPACING;
//— Separator
   CreateRectangleLabel(PREFIX+”Sep3″,x+10,row_y+5,PANEL_WIDTH-20,1,
                        clrDimGray,clrDimGray);
   row_y+=15;
//— Filter status
   CreateTextLabel(PREFIX+”LblFilter”,x+15,row_y,”Trade Filter:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValFilter”,x+100,row_y,”ALLOW”,clrLime,9,”Arial Bold”);
   row_y+=ROW_SPACING;
//— Samples
   CreateTextLabel(PREFIX+”LblSamples”,x+15,row_y,”Samples:”,clrGray,9,”Arial”);
   CreateTextLabel(PREFIX+”ValSamples”,x+100,row_y,”0″,clrGray,9,”Arial”);
   ChartRedraw();
  }
//+——————————————————————+
//| Update panel values                                              |
//+——————————————————————+
void UpdatePanel()
  {
//— Get statistics
   SSpreadStats stats=g_spread_monitor.GetStatistics();
//— Update current spread
   ObjectSetString(0,PREFIX+”ValCurrent”,OBJPROP_TEXT,
                   DoubleToString(stats.current,1));
   ObjectSetInteger(0,PREFIX+”ValCurrent”,OBJPROP_COLOR,
                    g_spread_monitor.GetConditionColor(stats.condition));
//— Update condition
   ObjectSetString(0,PREFIX+”ValCondition”,OBJPROP_TEXT,
                   g_spread_monitor.GetConditionName(stats.condition));
   ObjectSetInteger(0,PREFIX+”ValCondition”,OBJPROP_COLOR,
                    g_spread_monitor.GetConditionColor(stats.condition));
//— Update statistics
   ObjectSetString(0,PREFIX+”ValAvg”,OBJPROP_TEXT,
                   DoubleToString(stats.average,1)+” pips”);
   ObjectSetString(0,PREFIX+”ValMin”,OBJPROP_TEXT,
                   DoubleToString(stats.minimum,1)+” pips”);
   ObjectSetString(0,PREFIX+”ValMax”,OBJPROP_TEXT,
                   DoubleToString(stats.maximum,1)+” pips”);
//— Update filter status
   bool acceptable=g_spread_monitor.IsSpreadAcceptable(InpMaxSpread);
   ObjectSetString(0,PREFIX+”ValFilter”,OBJPROP_TEXT,
                   acceptable ? “ALLOW” : “BLOCK”);
   ObjectSetInteger(0,PREFIX+”ValFilter”,OBJPROP_COLOR,
                    acceptable ? clrLime : clrRed);
//— Update samples count
   ObjectSetString(0,PREFIX+”ValSamples”,OBJPROP_TEXT,
                   IntegerToString(stats.sample_count));
   ChartRedraw();
  }
//+——————————————————————+
//| Create text label                                                |
//+——————————————————————+
void CreateTextLabel(const string name,
                     const int x,
                     const int y,
                     const string text,
                     const color clr,
                     const int font_size,
                     const string font_name)
  {
   if(ObjectFind(0,name)>=0)
      ObjectDelete(0,name);
   if(!ObjectCreate(0,name,OBJ_LABEL,0,0,0))
      return;
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_UPPER);
   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_name);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
  }
//+——————————————————————+
//| Create rectangle label                                           |
//+——————————————————————+
void CreateRectangleLabel(const string name,
                          const int x,
                          const int y,
                          const int width,
                          const int height,
                          const color bg_color,
                          const color border_color)
  {
   if(ObjectFind(0,name)>=0)
      ObjectDelete(0,name);
   if(!ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0))
      return;
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,width);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,height);
   ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_UPPER);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bg_color);
   ObjectSetInteger(0,name,OBJPROP_BORDER_COLOR,border_color);
   ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
  }
//+——————————————————————+