Page 2 of 2

Re: Timeframe Should Match Your Reaction Speed, Not Your Ambition

Posted: Tue Sep 22, 2026 6:59 pm
by PTScalper
1. MetaTrader 5 (MQL5) Version

Save as an Indicator (.mq5). It uses MT5's PeriodSeconds() and iTime structure for precise real-time state management.

Code: Select all

//+------------------------------------------------------------------+
//|                                          ExecutionAnchor_MT5.mq5 |
//|                                     Mindful Scalping UI Overlay  |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 0

//--- Inputs
input color InpColorFast   = clrMaroon;
input color InpColorOpt    = clrTeal;
input color InpColorMacro  = clrNavy;
input color InpColorText   = clrWhite;

//--- Object Names
string obj_bg = "ExecAnchor_BG";
string obj_header = "ExecAnchor_Header";
string obj_timer = "ExecAnchor_Timer";
string obj_body1 = "ExecAnchor_Body1";
string obj_body2 = "ExecAnchor_Body2";
string obj_body3 = "ExecAnchor_Body3";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   EventSetTimer(1); // 1-second tick for the timer
   CreateUI();
   UpdateDashboard();
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
   ObjectsDeleteAll(0, "ExecAnchor_");
   ChartRedraw();
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
  {
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   UpdateDashboard();
  }

//+------------------------------------------------------------------+
//| Core Logic & UI Updates                                          |
//+------------------------------------------------------------------+
void UpdateDashboard()
  {
   int tfMinutes = PeriodSeconds(_Period) / 60;
   color stateColor = InpColorMacro;
   
   string headerStr = "";
   string b1 = "", b2 = "", b3 = "";

   // Determine State
   if(tfMinutes < 5)
     {
      stateColor = InpColorFast;
      headerStr = "⚠️ RUSHED EXECUTION ZONE (" + EnumToString(_Period) + ")";
      b1 = "There is no prize for the fastest timeframe.";
      b2 = "If you are second-guessing entries or missing closes,";
      b3 = "drop to a slower chart where you can think clearly.";
     }
   else if(tfMinutes >= 5 && tfMinutes <= 15)
     {
      stateColor = InpColorOpt;
      headerStr = "✅ CLEAN EXECUTION ZONE (" + EnumToString(_Period) + ")";
      b1 = "Match execution to actual processing speed.";
      b2 = "Focus on clean, consistent decisions without";
      b3 = "the rushed pressure of micro-timeframes.";
     }
   else
     {
      stateColor = InpColorMacro;
      headerStr = "📘 MACRO CONTEXT ZONE (" + EnumToString(_Period) + ")";
      b1 = "Higher timeframes dictate structural bias.";
      b2 = "Ensure your execution timeframe aligns with";
      b3 = "your demonstrated reaction speed.";
     }

   // Timer Calculation
   datetime currentCandleOpen = iTime(_Symbol, _Period, 0);
   datetime nextCandleOpen = currentCandleOpen + PeriodSeconds(_Period);
   int secondsRemaining = (int)(nextCandleOpen - TimeCurrent());
   
   string timerStr = "Market Closed";
   if(secondsRemaining > 0)
     {
      int h = secondsRemaining / 3600;
      int m = (secondsRemaining % 3600) / 60;
      int s = secondsRemaining % 60;
      timerStr = StringFormat("Candle Close: %02d:%02d:%02d", h, m, s);
     }

   // Update Objects
   ObjectSetInteger(0, obj_bg, OBJPROP_BGCOLOR, stateColor);
   ObjectSetString(0, obj_header, OBJPROP_TEXT, headerStr);
   ObjectSetString(0, obj_timer, OBJPROP_TEXT, timerStr);
   ObjectSetString(0, obj_body1, OBJPROP_TEXT, b1);
   ObjectSetString(0, obj_body2, OBJPROP_TEXT, b2);
   ObjectSetString(0, obj_body3, OBJPROP_TEXT, b3);
   
   ChartRedraw();
  }

//+------------------------------------------------------------------+
//| UI Generation                                                    |
//+------------------------------------------------------------------+
void CreateUI()
  {
   int x = 20, y = 20;
   
   // Background
   ObjectCreate(0, obj_bg, OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, obj_bg, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
   ObjectSetInteger(0, obj_bg, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, obj_bg, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, obj_bg, OBJPROP_XSIZE, 350);
   ObjectSetInteger(0, obj_bg, OBJPROP_YSIZE, 110);
   ObjectSetInteger(0, obj_bg, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, obj_bg, OBJPROP_BACK, true);

   // Text Creation Macro
   CreateText(obj_header, x + 10, y + 80, 10, true);
   CreateText(obj_timer, x + 10, y + 60, 10, true);
   CreateText(obj_body1, x + 10, y + 40, 8, false);
   CreateText(obj_body2, x + 10, y + 25, 8, false);
   CreateText(obj_body3, x + 10, y + 10, 8, false);
  }

void CreateText(string name, int x, int y, int fontSize, bool isBold)
  {
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(0, name, OBJPROP_FONT, "Consolas");
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, name, OBJPROP_COLOR, InpColorText);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
  }

Re: Timeframe Should Match Your Reaction Speed, Not Your Ambition

Posted: Tue Sep 22, 2026 7:00 pm
by PTScalper
2. MetaTrader 4 (MQL4) Version

Save as an Indicator (.mq4). MT4 requires Period() (which returns minutes natively) and slightly different parameter signatures for ObjectCreate().

Code: Select all

//+------------------------------------------------------------------+
//|                                          ExecutionAnchor_MT4.mq4 |
//|                                     Mindful Scalping UI Overlay  |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict

//--- Inputs
input color InpColorFast   = clrMaroon;
input color InpColorOpt    = clrTeal;
input color InpColorMacro  = clrNavy;
input color InpColorText   = clrWhite;

//--- Object Names
string obj_bg = "ExecAnchor_BG";
string obj_header = "ExecAnchor_Header";
string obj_timer = "ExecAnchor_Timer";
string obj_body1 = "ExecAnchor_Body1";
string obj_body2 = "ExecAnchor_Body2";
string obj_body3 = "ExecAnchor_Body3";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   EventSetTimer(1); 
   CreateUI();
   UpdateDashboard();
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   EventKillTimer();
   ObjectsDeleteAll(0, "ExecAnchor_");
   WindowRedraw();
  }

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[])
  {
   return(rates_total);
  }

void OnTimer()
  {
   UpdateDashboard();
  }

//+------------------------------------------------------------------+
//| Core Logic & UI Updates                                          |
//+------------------------------------------------------------------+
void UpdateDashboard()
  {
   int tfMinutes = Period(); // Returns exactly minutes in MT4
   color stateColor = InpColorMacro;
   
   string headerStr = "";
   string b1 = "", b2 = "", b3 = "";

   // Determine State
   if(tfMinutes < 5)
     {
      stateColor = InpColorFast;
      headerStr = "⚠️ RUSHED EXECUTION (" + IntegerToString(tfMinutes) + "M)";
      b1 = "There is no prize for the fastest timeframe.";
      b2 = "If you are second-guessing entries or missing closes,";
      b3 = "drop to a slower chart where you can think clearly.";
     }
   else if(tfMinutes >= 5 && tfMinutes <= 15)
     {
      stateColor = InpColorOpt;
      headerStr = "✅ CLEAN EXECUTION (" + IntegerToString(tfMinutes) + "M)";
      b1 = "Match execution to actual processing speed.";
      b2 = "Focus on clean, consistent decisions without";
      b3 = "the rushed pressure of micro-timeframes.";
     }
   else
     {
      stateColor = InpColorMacro;
      headerStr = "📘 MACRO CONTEXT (" + IntegerToString(tfMinutes) + "M)";
      b1 = "Higher timeframes dictate structural bias.";
      b2 = "Ensure your execution timeframe aligns with";
      b3 = "your demonstrated reaction speed.";
     }

   // Timer Calculation
   datetime currentCandleOpen = iTime(Symbol(), Period(), 0);
   datetime nextCandleOpen = currentCandleOpen + (Period() * 60);
   int secondsRemaining = (int)(nextCandleOpen - TimeCurrent());
   
   string timerStr = "Market Closed";
   if(secondsRemaining > 0)
     {
      int h = secondsRemaining / 3600;
      int m = (secondsRemaining % 3600) / 60;
      int s = secondsRemaining % 60;
      timerStr = StringFormat("Candle Close: %02d:%02d:%02d", h, m, s);
     }

   // Update Objects
   ObjectSetInteger(0, obj_bg, OBJPROP_BGCOLOR, stateColor);
   ObjectSetString(0, obj_header, OBJPROP_TEXT, headerStr);
   ObjectSetString(0, obj_timer, OBJPROP_TEXT, timerStr);
   ObjectSetString(0, obj_body1, OBJPROP_TEXT, b1);
   ObjectSetString(0, obj_body2, OBJPROP_TEXT, b2);
   ObjectSetString(0, obj_body3, OBJPROP_TEXT, b3);
   
   WindowRedraw();
  }

//+------------------------------------------------------------------+
//| UI Generation                                                    |
//+------------------------------------------------------------------+
void CreateUI()
  {
   int x = 20, y = 20;
   
   ObjectCreate(0, obj_bg, OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, obj_bg, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
   ObjectSetInteger(0, obj_bg, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, obj_bg, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, obj_bg, OBJPROP_XSIZE, 350);
   ObjectSetInteger(0, obj_bg, OBJPROP_YSIZE, 110);
   ObjectSetInteger(0, obj_bg, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, obj_bg, OBJPROP_BACK, true);

   CreateText(obj_header, x + 10, y + 80, 10);
   CreateText(obj_timer, x + 10, y + 60, 10);
   CreateText(obj_body1, x + 10, y + 40, 8);
   CreateText(obj_body2, x + 10, y + 25, 8);
   CreateText(obj_body3, x + 10, y + 10, 8);
  }

void CreateText(string name, int x, int y, int fontSize)
  {
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(0, name, OBJPROP_FONT, "Consolas");
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, name, OBJPROP_COLOR, InpColorText);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
  }

Re: Timeframe Should Match Your Reaction Speed, Not Your Ambition

Posted: Tue Sep 22, 2026 7:01 pm
by PTScalper
For cTrader, indicators use C# and natively support UI overlays via the Chart.CreateUIElement() panel architecture or direct canvas drawing.

This professional cTrader Indicator (ExecutionAnchor.cs) builds a clean, hardware-accelerated WPF-style control panel directly on your chart canvas. It includes dynamic color states, real-time candle close countdowns, and updates smoothly every second using timer events.

cTrader Indicator (C# / cBot & Indicator API)

Create a new Indicator in cTrader Automate, paste this code, and compile:

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ExecutionAnchor : Indicator
    {
        [Parameter("Position", DefaultValue = ControlPosition.BottomRight)]
        public ControlPosition DashboardPosition { get; set; }

        [Parameter("Danger Zone Color (< 5m)", DefaultValue = "Maroon")]
        public string ColorFast { get; set; }

        [Parameter("Optimal Zone Color (5m - 15m)", DefaultValue = "Teal")]
        public string ColorOpt { get; set; }

        [Parameter("Macro Zone Color (> 15m)", DefaultValue = "Navy")]
        public string ColorMacro { get; set; }

        private Border _mainBorder;
        private TextBlock _headerText;
        private TextBlock _timerText;
        private TextBlock _bodyText1;
        private TextBlock _bodyText2;
        private TextBlock _bodyText3;

        protected override void Initialize()
        {
            // Build Panel Layout Container
            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                Spacing = 4,
                Margin = new Thickness(10)
            };

            _headerText = new TextBlock
            {
                FontWeight = FontWeight.Bold,
                FontSize = 11,
                ForegroundColor = Color.White
            };

            _timerText = new TextBlock
            {
                FontWeight = FontWeight.Bold,
                FontSize = 11,
                ForegroundColor = Color.Cyan
            };

            _bodyText1 = new TextBlock { FontSize = 10, ForegroundColor = Color.LightGray };
            _bodyText2 = new TextBlock { FontSize = 10, ForegroundColor = Color.LightGray };
            _bodyText3 = new TextBlock { FontSize = 10, ForegroundColor = Color.LightGray };

            panel.AddChild(_headerText);
            panel.AddChild(_timerText);
            panel.AddChild(new TextBlock { Text = "" }); // Spacer
            panel.AddChild(_bodyText1);
            panel.AddChild(_bodyText2);
            panel.AddChild(_bodyText3);

            _mainBorder = new Border
            {
                Child = panel,
                BackgroundColor = Color.FromHex(ColorMacro),
                Opacity = 0.85,
                Padding = new Thickness(10),
                CornerRadius = new CornerRadius(4),
                HorizontalAlignment = HorizontalAlignment.Right,
                VerticalAlignment = VerticalAlignment.Bottom
            };

            // Bind to Chart UI
            Chart.AddControl(_mainBorder);
            
            // Register Timer for 1-second interval countdown updates
            Timer.Start(1);
        }

        public override void Calculate(int index)
        {
            // Only update logic on the last bar or tick equivalent
            if (index == Bars.Count - 1)
            {
                UpdateDashboardData();
            }
        }

        protected override void OnTimer()
        {
            UpdateDashboardData();
        }

        private void UpdateDashboardData()
        {
            // Determine Timeframe Duration in Minutes
            int tfMinutes = 1;
            var tf = TimeFrame;
            
            if (tf == TimeFrame.Minute) tfMinutes = 1;
            else if (tf == TimeFrame.Minute2) tfMinutes = 2;
            else if (tf == TimeFrame.Minute3) tfMinutes = 3;
            else if (tf == TimeFrame.Minute4) tfMinutes = 4;
            else if (tf == TimeFrame.Minute5) tfMinutes = 5;
            else if (tf == TimeFrame.Minute10) tfMinutes = 10;
            else if (tf == TimeFrame.Minute15) tfMinutes = 15;
            else if (tf == TimeFrame.Minute30) tfMinutes = 30;
            else if (tf == TimeFrame.Hour) tfMinutes = 60;
            else if (tf == TimeFrame.Hour4) tfMinutes = 240;
            else if (tf == TimeFrame.Daily) tfMinutes = 1440;
            else tfMinutes = (int)tf.ToTimeSpan().TotalMinutes;

            string tfName = tf.ToString();
            
            // State Logic
            if (tfMinutes < 5)
            {
                _mainBorder.BackgroundColor = Color.FromHex("#8B0000"); // Dark Red / Maroon
                _headerText.Text = $"⚠️ RUSHED EXECUTION ZONE ({tfName})";
                _bodyText1.Text = "There is no prize for the fastest timeframe.";
                _bodyText2.Text = "If you are second-guessing entries or missing closes,";
                _bodyText3.Text = "drop to a slower chart where you can think clearly.";
            }
            else if (tfMinutes >= 5 && tfMinutes <= 15)
            {
                _mainBorder.BackgroundColor = Color.FromHex("#008080"); // Teal
                _headerText.Text = $"✅ CLEAN EXECUTION ZONE ({tfName})";
                _bodyText1.Text = "Match execution to actual processing speed.";
                _bodyText2.Text = "Focus on clean, consistent decisions without";
                _bodyText3.Text = "the rushed pressure of micro-timeframes.";
            }
            else
            {
                _mainBorder.BackgroundColor = Color.FromHex("#000080"); // Navy
                _headerText.Text = $"📘 MACRO CONTEXT ZONE ({tfName})";
                _bodyText1.Text = "Higher timeframes dictate structural bias.";
                _bodyText2.Text = "Ensure your execution timeframe aligns with";
                _bodyText3.Text = "your demonstrated reaction speed.";
            }

            // Real-time Candle Close Countdown Calculation
            DateTime currentBarOpenTime = Bars.OpenTimes[Bars.Count - 1];
            DateTime nextBarOpenTime = currentBarOpenTime.Add(tf.ToTimeSpan());
            TimeSpan timeRemaining = nextBarOpenTime - Server.Time;

            if (timeRemaining.TotalSeconds > 0)
            {
                _timerText.Text = $"Candle Close: {timeRemaining.Hours:D2}:{timeRemaining.Minutes:D2}:{timeRemaining.Seconds:D2}";
            }
            else
            {
                _timerText.Text = "Candle Close: Synchronizing...";
            }
        }

        protected override void OnStop()
        {
            if (_mainBorder != null)
            {
                Chart.RemoveControl(_mainBorder);
            }
        }
    }
}

Re: Timeframe Should Match Your Reaction Speed, Not Your Ambition

Posted: Tue Sep 22, 2026 7:02 pm
by PTScalper
Architectural Highlights:

Native WPF Layout Engine: cTrader handles containers (StackPanel, Border) natively, ensuring crisp text rendering that scales cleanly without artifacts during chart panning or zooming.

Dual Update Lifecycle: Combines standard indicator calculation triggers with a robust Timer.Start(1) thread hook, ensuring the candle close countdown updates every single second even on illiquid instruments or flat markets.