Page 2 of 3

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:09 pm
by PTScalper
Because MetaTrader 4 (MT4) and MetaTrader 5 (MT5) use fundamentally different programming languages (MQL4 and MQL5), they require separate scripts.

Before using these, you must understand the Golden Rule of MetaTrader Time: MT4 and MT5 do not have built-in timezone converters like TradingView or cTrader. They run strictly on your Broker's Server Time.

Example: If your broker is in Cyprus (GMT+2) and New York (EST) is GMT-5, there is a 7-hour difference. You would need to input 16:30 as the start time instead of 09:30. Check your broker's time (Market Watch window) to calculate the offset.

Here is the code for both platforms.

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:11 pm
by PTScalper
1. MetaTrader 4 (MQL4) Code

Installation: Open MT4 -> Click F4 to open MetaEditor -> In the Navigator, right-click Indicators -> New -> Custom Indicator -> Name it NYOpeningRange -> Finish. Delete all the default code, paste the code below, and click Compile.

Code: Select all

//+------------------------------------------------------------------+
//|                                               NYOpeningRange.mq4 |
//+------------------------------------------------------------------+
#property copyright "Opening Range Breakout"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color1 SeaGreen
#property indicator_color2 Crimson
#property indicator_color3 SeaGreen
#property indicator_color4 Crimson
#property indicator_color5 DodgerBlue
#property indicator_color6 DarkOrange

#property indicator_width1 2
#property indicator_width2 2

//--- Inputs (Must be set to Broker Server Time)
input int OR_Start_Hour = 9;
input int OR_Start_Minute = 30;
input int OR_End_Hour = 10;
input int OR_End_Minute = 0;
input int Session_End_Hour = 16;
input int Session_End_Minute = 0;
input int ArrowOffsetPips = 5;

//--- Buffers
double ExtHighBuffer[];
double ExtLowBuffer[];
double ExtBOUpBuffer[];
double ExtBODnBuffer[];
double ExtFOUpBuffer[];
double ExtFODnBuffer[];

int OnInit()
{
    SetIndexBuffer(0, ExtHighBuffer); SetIndexStyle(0, DRAW_LINE); SetIndexLabel(0, "OR High");
    SetIndexBuffer(1, ExtLowBuffer); SetIndexStyle(1, DRAW_LINE); SetIndexLabel(1, "OR Low");
    
    SetIndexBuffer(2, ExtBOUpBuffer); SetIndexStyle(2, DRAW_ARROW); SetIndexArrow(2, 233); SetIndexLabel(2, "BO Up");
    SetIndexBuffer(3, ExtBODnBuffer); SetIndexStyle(3, DRAW_ARROW); SetIndexArrow(3, 234); SetIndexLabel(3, "BO Down");
    
    SetIndexBuffer(4, ExtFOUpBuffer); SetIndexStyle(4, DRAW_ARROW); SetIndexArrow(4, 225); SetIndexLabel(4, "FO Up");
    SetIndexBuffer(5, ExtFODnBuffer); SetIndexStyle(5, DRAW_ARROW); SetIndexArrow(5, 226); SetIndexLabel(5, "FO Down");

    return(INIT_SUCCEEDED);
}

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[])
{
    int limit = rates_total - prev_calculated;
    if (prev_calculated == 0) limit = rates_total - 1;
    
    int start_mins = OR_Start_Hour * 60 + OR_Start_Minute;
    int end_mins = OR_End_Hour * 60 + OR_End_Minute;
    int session_end_mins = Session_End_Hour * 60 + Session_End_Minute;
    
    double pips = Point;
    if (Digits == 3 || Digits == 5) pips *= 10;
    
    static int last_day = -1;
    static double or_high = 0;
    static double or_low = 999999;

    // MT4 loops from oldest (rates_total-1) down to newest (0)
    for(int i = limit; i >= 0; i--) 
    {
        int bar_day = TimeDay(Time[i]);
        int time_mins = TimeHour(Time[i]) * 60 + TimeMinute(Time[i]);
        
        // Reset variables for a new day
        if (bar_day != last_day) {
            last_day = bar_day;
            or_high = 0;
            or_low = 999999;
        }
        
        ExtHighBuffer[i] = EMPTY_VALUE;
        ExtLowBuffer[i] = EMPTY_VALUE;
        ExtBOUpBuffer[i] = EMPTY_VALUE;
        ExtBODnBuffer[i] = EMPTY_VALUE;
        ExtFOUpBuffer[i] = EMPTY_VALUE;
        ExtFODnBuffer[i] = EMPTY_VALUE;

        // 1. Establish the Range
        if (time_mins >= start_mins && time_mins < end_mins) {
            if (high[i] > or_high) or_high = high[i];
            if (low[i] < or_low) or_low = low[i];
        }
        
        // 2. Project Lines and Detect Signals
        if (time_mins >= end_mins && time_mins <= session_end_mins) {
            if (or_high > 0 && or_low < 999999) {
                ExtHighBuffer[i] = or_high;
                ExtLowBuffer[i] = or_low;
                
                // Read previous candle (older index in MT4 is i+1)
                double prev_close = (i < rates_total - 1) ? close[i+1] : close[i];
                
                // Breakouts
                if (close[i] > or_high && prev_close <= or_high) ExtBOUpBuffer[i] = low[i] - (ArrowOffsetPips * pips);
                if (close[i] < or_low && prev_close >= or_low) ExtBODnBuffer[i] = high[i] + (ArrowOffsetPips * pips);
                
                // Fakeouts (Sweeps)
                if (low[i] < or_low && close[i] > or_low && prev_close >= or_low) ExtFOUpBuffer[i] = low[i] - ((ArrowOffsetPips * 2) * pips);
                if (high[i] > or_high && close[i] < or_high && prev_close <= or_high) ExtFODnBuffer[i] = high[i] + ((ArrowOffsetPips * 2) * pips);
            }
        }
    }
    return(rates_total);
}

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:12 pm
by PTScalper
2. MetaTrader 5 (MQL5) Code

Installation: Open MT5 -> Click F4 to open MetaEditor -> In Navigator, right-click Indicators -> New -> Custom Indicator -> Name it NYOpeningRange -> Finish. Delete everything, paste this code, and click Compile.

Code: Select all

//+------------------------------------------------------------------+
//|                                               NYOpeningRange.mq5 |
//+------------------------------------------------------------------+
#property copyright "Opening Range Breakout"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   6

// Plot Properties
#property indicator_label1  "OR High"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_width1  2

#property indicator_label2  "OR Low"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrCrimson
#property indicator_width2  2

#property indicator_label3  "Breakout Up"
#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrSeaGreen

#property indicator_label4  "Breakout Down"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrCrimson

#property indicator_label5  "Fakeout Up"
#property indicator_type5   DRAW_ARROW
#property indicator_color5  clrDodgerBlue

#property indicator_label6  "Fakeout Down"
#property indicator_type6   DRAW_ARROW
#property indicator_color6  clrDarkOrange

//--- Inputs (Must be set to Broker Server Time)
input int OR_Start_Hour = 9;
input int OR_Start_Minute = 30;
input int OR_End_Hour = 10;
input int OR_End_Minute = 0;
input int Session_End_Hour = 16;
input int Session_End_Minute = 0;
input int ArrowOffsetPips = 5;

double ExtHighBuffer[];
double ExtLowBuffer[];
double ExtBOUpBuffer[];
double ExtBODnBuffer[];
double ExtFOUpBuffer[];
double ExtFODnBuffer[];

int OnInit()
{
    SetIndexBuffer(0, ExtHighBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, ExtLowBuffer, INDICATOR_DATA);
    
    SetIndexBuffer(2, ExtBOUpBuffer, INDICATOR_DATA); PlotIndexSetInteger(2, PLOT_ARROW, 233);
    SetIndexBuffer(3, ExtBODnBuffer, INDICATOR_DATA); PlotIndexSetInteger(3, PLOT_ARROW, 234);
    
    SetIndexBuffer(4, ExtFOUpBuffer, INDICATOR_DATA); PlotIndexSetInteger(4, PLOT_ARROW, 225);
    SetIndexBuffer(5, ExtFODnBuffer, INDICATOR_DATA); PlotIndexSetInteger(5, PLOT_ARROW, 226);

    // Set Empty Values so lines don't drop to 0 outside session times
    for(int i=0; i<6; i++) PlotIndexSetDouble(i, PLOT_EMPTY_VALUE, 0.0);
    
    return(INIT_SUCCEEDED);
}

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[])
{
    if(rates_total < 2) return 0;
    
    // MT5 arrays default to normal indexing (0 is oldest, rates_total-1 is newest)
    int start = prev_calculated;
    if(start == 0) start = 1; 
    else start = start - 1; 
    
    int start_mins = OR_Start_Hour * 60 + OR_Start_Minute;
    int end_mins = OR_End_Hour * 60 + OR_End_Minute;
    int session_end_mins = Session_End_Hour * 60 + Session_End_Minute;
    
    double pips = _Point;
    if (_Digits == 3 || _Digits == 5) pips *= 10;
    
    static int last_day = -1;
    static double or_high = 0;
    static double or_low = 999999;
    
    for(int i = start; i < rates_total; i++) 
    {
        MqlDateTime dt;
        TimeToStruct(time[i], dt);
        
        int bar_day = dt.day;
        int time_mins = dt.hour * 60 + dt.min;
        
        if (bar_day != last_day) {
            last_day = bar_day;
            or_high = 0;
            or_low = 999999;
        }
        
        ExtHighBuffer[i] = 0.0;
        ExtLowBuffer[i] = 0.0;
        ExtBOUpBuffer[i] = 0.0;
        ExtBODnBuffer[i] = 0.0;
        ExtFOUpBuffer[i] = 0.0;
        ExtFODnBuffer[i] = 0.0;
        
        if (time_mins >= start_mins && time_mins < end_mins) {
            if (high[i] > or_high) or_high = high[i];
            if (low[i] < or_low) or_low = low[i];
        }
        
        if (time_mins >= end_mins && time_mins <= session_end_mins) {
            if (or_high > 0 && or_low < 999999) { 
                ExtHighBuffer[i] = or_high;
                ExtLowBuffer[i] = or_low;
                
                // Read previous candle (older index in MT5 is i-1)
                double prev_close = close[i-1];
                
                // Breakouts
                if (close[i] > or_high && prev_close <= or_high) ExtBOUpBuffer[i] = low[i] - (ArrowOffsetPips * pips);
                if (close[i] < or_low && prev_close >= or_low) ExtBODnBuffer[i] = high[i] + (ArrowOffsetPips * pips);
                
                // Fakeouts (Sweeps)
                if (low[i] < or_low && close[i] > or_low && prev_close >= or_low) ExtFOUpBuffer[i] = low[i] - ((ArrowOffsetPips * 2) * pips);
                if (high[i] > or_high && close[i] < or_high && prev_close <= or_high) ExtFODnBuffer[i] = high[i] + ((ArrowOffsetPips * 2) * pips);
            }
        }
    }
    
    return(rates_total);
}

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:13 pm
by PTScalper
To upgrade this to a "Pro" level, we need to move away from basic line plots and incorporate the features that institutional and professional retail traders use.

A professional TradingView script requires:

Object-Based Visuals: Using cleanly drawn Boxes and Lines instead of standard plots to prevent chart clutter and "staircasing" across days.

A Live Dashboard (Table): Real-time data showing the range size in points/pips, comparing it to the Daily ATR (if the range is too wide, the daily fuel is gone).

Advanced Filtering: A volume filter (breakouts are only valid if volume is higher than the 20-period moving average).

Risk-to-Reward Targets: Automatically plotting 1:1 and 1:2 expansion targets based on the size of the 30-minute range.

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:14 pm
by PTScalper
Here is the Pro NY Opening Range script:

The "Pro" Pine Script (v5)

Code: Select all

//@version=5
indicator("Pro NY Opening Range (OR) [Advanced]", overlay=true, max_boxes_count=100, max_lines_count=200, max_labels_count=100)

// =========================================================================
// 1. SETTINGS & INPUTS
// =========================================================================
grp_time = "Session Settings"
orSession = input.session("0930-1000", title="OR Time (EST)", group=grp_time)
tradeSession = input.session("1000-1600", title="Trading Session", group=grp_time)
tz = input.string("America/New_York", title="Timezone", group=grp_time)

grp_filters = "Filters & Targets"
useVol = input.bool(true, title="Require Volume Spike for Breakouts?", group=grp_filters, tooltip="Breakout candle must have volume higher than the 20-SMA of volume.")
showTargets = input.bool(true, title="Show 1R & 2R Expansion Targets?", group=grp_filters)

grp_ui = "UI & Dashboard"
showDash = input.bool(true, title="Show Data Dashboard", group=grp_ui)
boxColor = input.color(color.new(color.gray, 85), title="OR Box Color", group=grp_ui)

// =========================================================================
// 2. CORE SESSION LOGIC & DATA
// =========================================================================
inOrSession = time(timeframe.period, orSession, tz)
inTradeSession = time(timeframe.period, tradeSession, tz)

isNewOr = inOrSession and not inOrSession[1]
isTradeStart = inTradeSession and not inTradeSession[1]

var float orHigh = na
var float orLow = na
var int orStartBar = na

// ATR for Exhaustion checking
dailyATR = request.security(syminfo.tickerid, "D", ta.atr(14))
volSMA = ta.sma(volume, 20)
volSpike = volume > volSMA

// Update Range
if isNewOr
    orHigh := high
    orLow := low
    orStartBar := bar_index
else if inOrSession
    orHigh := math.max(orHigh, high)
    orLow := math.min(orLow, low)

float rangeSize = orHigh - orLow

// =========================================================================
// 3. PRO VISUALS (BOXES & LINES)
// =========================================================================
var box orBox = na
var line highLine = na
var line lowLine = na
var line t1Up = na
var line t1Dn = na

if isNewOr
    // Create new drawing objects for the day
    orBox := box.new(left=bar_index, top=orHigh, bottom=orLow, right=bar_index, bgcolor=boxColor, border_color=color.new(color.gray, 50))

if inOrSession
    // Expand box while forming
    box.set_top(orBox, orHigh)
    box.set_bottom(orBox, orLow)
    box.set_right(orBox, bar_index)

if isTradeStart
    // Draw horizontal projection lines at the start of trade session
    highLine := line.new(x1=orStartBar, y1=orHigh, x2=bar_index, y2=orHigh, color=color.green, style=line.style_solid, width=2)
    lowLine := line.new(x1=orStartBar, y1=orLow, x2=bar_index, y2=orLow, color=color.red, style=line.style_solid, width=2)
    
    if showTargets
        t1Up := line.new(x1=orStartBar, y1=orHigh + rangeSize, x2=bar_index, y2=orHigh + rangeSize, color=color.new(color.green, 50), style=line.style_dashed)
        t1Dn := line.new(x1=orStartBar, y1=orLow - rangeSize, x2=bar_index, y2=orLow - rangeSize, color=color.new(color.red, 50), style=line.style_dashed)

if inTradeSession
    // Extend lines forward with price action
    line.set_x2(highLine, bar_index)
    line.set_x2(lowLine, bar_index)
    if showTargets
        line.set_x2(t1Up, bar_index)
        line.set_x2(t1Dn, bar_index)

// =========================================================================
// 4. SIGNALS (WITH VOLUME FILTER)
// =========================================================================
// Breakouts
validBOUp = inTradeSession and close > orHigh and close[1] <= orHigh and (useVol ? volSpike : true)
validBODn = inTradeSession and close < orLow and close[1] >= orLow and (useVol ? volSpike : true)

// Sweeps / Fakeouts
validFOUp = inTradeSession and low < orLow and close > orLow and close[1] >= orLow
validFODn = inTradeSession and high > orHigh and close < orHigh and close[1] <= orHigh

plotshape(validBOUp, title="BO Up", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
plotshape(validBODn, title="BO Down", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
plotshape(validFOUp, title="Sweep Bottom", style=shape.arrowup, location=location.belowbar, color=color.blue, size=size.small)
plotshape(validFODn, title="Sweep Top", style=shape.arrowdown, location=location.abovebar, color=color.orange, size=size.small)

// =========================================================================
// 5. PROFESSIONAL DASHBOARD
// =========================================================================
var table dash = table.new(position.top_right, 2, 4, bgcolor=color.new(color.black, 20), border_width=1, border_color=color.gray)

if showDash and barstate.islast
    // Calculate how much fuel is left
    float rangePips = syminfo.mintick == 0.00001 ? rangeSize * 10000 : rangeSize / syminfo.mintick
    float atrPips = syminfo.mintick == 0.00001 ? dailyATR * 10000 : dailyATR / syminfo.mintick
    float exhaustionPct = (rangeSize / dailyATR) * 100
    color exhColor = exhaustionPct > 50 ? color.red : color.green // If OR is > 50% of ATR, breakouts are dangerous

    table.cell(dash, 0, 0, "NY OR Status", text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 0, inOrSession ? "Forming..." : inTradeSession ? "Active" : "Closed", text_color=inOrSession ? color.yellow : color.white, text_size=size.small)
    
    table.cell(dash, 0, 1, "Range Size", text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 1, str.tostring(rangePips, "#.1") + " pts", text_color=color.white, text_size=size.small)
    
    table.cell(dash, 0, 2, "Daily ATR", text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 2, str.tostring(atrPips, "#.1") + " pts", text_color=color.white, text_size=size.small)
    
    table.cell(dash, 0, 3, "Exhaustion", text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 3, str.tostring(exhaustionPct, "#.1") + "%", text_color=exhColor, text_size=size.small)

// =========================================================================
// 6. ALERTS
// =========================================================================
alertcondition(validBOUp, "Pro OR Breakout UP", "Bullish Breakout: Valid volume and close above OR High.")
alertcondition(validBODn, "Pro OR Breakout DOWN", "Bearish Breakout: Valid volume and close below OR Low.")
alertcondition(validFOUp, "Pro OR Sweep BOTTOM", "Bullish Fakeout: Price swept the OR Low and rejected.")
alertcondition(validFODn, "Pro OR Sweep TOP", "Bearish Fakeout: Price swept the OR High and rejected.")

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:14 pm
by PTScalper
What makes this version "Pro":

Smart Money Aesthetics (Boxes & Lines): Instead of drawing infinite clunky lines across your whole chart, this script draws a precise shaded box during the 9:30–10:00 AM formation. At 10:00 AM, it projects crisp lines forward that only extend up to the current live candle.

Live Data Dashboard (Top Right): It features a real-time table evaluating the condition of the market:

It measures the current size of the 30-minute range.

It compares it against the Daily ATR (Average True Range).

The Pro Edge: If the 30-minute range has already consumed more than 50% of the daily ATR, the text turns Red. This warns you that a breakout trade is highly dangerous because the market is mathematically exhausted. You should only look for Fakeout/Sweep trades when this happens.

Volume Filtration: By default, it will ignore breakouts if they happen on low volume. The breakout candle must have a volume spike higher than the 20-period moving average to trigger a green/red triangle signal (this filters out midday chop traps). You can toggle this on/off in the settings.

Automatic Expansion Targets: It calculates the total size of the Opening Range and projects a dashed line exactly 1x that size above and below the range. This acts as a mechanical Take Profit 1 (TP1) level for breakout trades.

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:15 pm
by PTScalper
Here is the completely upgraded Pro version for cTrader.

cTrader is built on C# (.NET), which allows us to create a truly professional, institutional-grade visual interface directly on the chart.

This upgraded cAlgo script includes:

A Live WPF-style Dashboard Panel: Calculates real-time Range Size, Daily ATR (by silently pulling Daily timeframe data in the background), and mathematical Exhaustion.

Smart Money Visuals: Instead of clunky infinite lines, it draws a shaded ChartRectangle (Box) while the range forms, and clean ChartTrendLine projections that update dynamically.

Automatic Targets: Automatically projects 1R Expansion targets above and below the range.

Volume Filtration: Uses cTrader’s SimpleMovingAverage on Tick Volume to ignore breakouts that lack institutional momentum.

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:16 pm
by PTScalper
The cTrader C# Source Code (Pro Version)

Code: Select all

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.EasternStandardTime, AccessRights = AccessRights.None)]
    public class ProNYOpeningRange : Indicator
    {
        // --- SETTINGS ---
        [Parameter("OR Start Time (EST)", Group = "Session Settings", DefaultValue = "09:30")]
        public string OrStartTimeStr { get; set; }

        [Parameter("OR End Time (EST)", Group = "Session Settings", DefaultValue = "10:00")]
        public string OrEndTimeStr { get; set; }

        [Parameter("Trade Session End (EST)", Group = "Session Settings", DefaultValue = "16:00")]
        public string SessionEndTimeStr { get; set; }

        [Parameter("Require Volume Spike?", Group = "Filters & Targets", DefaultValue = true)]
        public bool UseVolumeFilter { get; set; }

        [Parameter("Show 1R Expansion Targets?", Group = "Filters & Targets", DefaultValue = true)]
        public bool ShowTargets { get; set; }

        // --- INTERNAL VARIABLES ---
        private TimeSpan _orStart, _orEnd, _sessionEnd;
        private double _orHigh, _orLow;
        private DateTime _orStartDate;
        
        private Bars _dailyBars;
        private AverageTrueRange _dailyAtr;
        private SimpleMovingAverage _volSma;

        // --- UI ELEMENTS ---
        private TextBlock _valStatus, _valRange, _valAtr, _valExhaustion;

        protected override void Initialize()
        {
            // Parse Times
            TimeSpan.TryParse(OrStartTimeStr, out _orStart);
            TimeSpan.TryParse(OrEndTimeStr, out _orEnd);
            TimeSpan.TryParse(SessionEndTimeStr, out _sessionEnd);

            // Initialize Indicators for Filters & Dashboard
            _dailyBars = MarketData.GetBars(TimeFrame.Daily);
            _dailyAtr = Indicators.AverageTrueRange(_dailyBars, 14, MovingAverageType.Simple);
            _volSma = Indicators.SimpleMovingAverage(Bars.TickVolumes, 20);

            // Build Professional Dashboard Panel
            BuildDashboard();
        }

        public override void Calculate(int index)
        {
            var barTime = Bars.OpenTimes[index];
            var timeOfDay = barTime.TimeOfDay;

            // 1. FORMING THE RANGE
            if (timeOfDay >= _orStart && timeOfDay < _orEnd)
            {
                if (barTime.Date != _orStartDate.Date || timeOfDay == _orStart)
                {
                    _orHigh = Bars.HighPrices[index];
                    _orLow = Bars.LowPrices[index];
                    _orStartDate = barTime;
                }
                else
                {
                    _orHigh = Math.Max(_orHigh, Bars.HighPrices[index]);
                    _orLow = Math.Min(_orLow, Bars.LowPrices[index]);
                }

                // Draw Shaded Box for the Opening Range window
                string boxName = "OR_Box_" + _orStartDate.ToString("yyyyMMdd");
                Chart.DrawRectangle(boxName, _orStartDate.Add(_orStart), _orHigh, barTime.AddMinutes(Bars.TimeFrame.Minute), _orLow, Color.FromArgb(40, Color.Gray));
            }

            // 2. ACTIVE TRADING SESSION (Lines, Targets & Signals)
            if (timeOfDay >= _orEnd && timeOfDay <= _sessionEnd && _orStartDate.Date == barTime.Date)
            {
                string dateKey = _orStartDate.ToString("yyyyMMdd");
                double rangeSize = _orHigh - _orLow;

                // Draw dynamic lines that stop at the current candle
                Chart.DrawTrendLine("OR_High_" + dateKey, _orStartDate.Add(_orStart), _orHigh, barTime, _orHigh, Color.SeaGreen, 2, LineStyle.Solid);
                Chart.DrawTrendLine("OR_Low_" + dateKey, _orStartDate.Add(_orStart), _orLow, barTime, _orLow, Color.Crimson, 2, LineStyle.Solid);

                // Draw 1R Targets
                if (ShowTargets)
                {
                    Chart.DrawTrendLine("Target_Up_" + dateKey, _orStartDate.Add(_orStart), _orHigh + rangeSize, barTime, _orHigh + rangeSize, Color.FromArgb(120, Color.SeaGreen), 1, LineStyle.Lines);
                    Chart.DrawTrendLine("Target_Dn_" + dateKey, _orStartDate.Add(_orStart), _orLow - rangeSize, barTime, _orLow - rangeSize, Color.FromArgb(120, Color.Crimson), 1, LineStyle.Lines);
                }

                // Signal Detection
                double close = Bars.ClosePrices[index];
                double prevClose = Bars.ClosePrices[index - 1];
                double high = Bars.HighPrices[index];
                double low = Bars.LowPrices[index];
                double volume = Bars.TickVolumes[index];
                double volAvg = _volSma.Result[index];

                bool volSpike = !UseVolumeFilter || volume > volAvg;

                // --- BREAKOUT SIGNALS (With Volume Filter) ---
                if (close > _orHigh && prevClose <= _orHigh && volSpike)
                    Chart.DrawIcon("BO_Up_" + index, ChartIconType.UpTriangle, index, low - (Symbol.PipSize * 5), Color.SeaGreen);
                
                if (close < _orLow && prevClose >= _orLow && volSpike)
                    Chart.DrawIcon("BO_Down_" + index, ChartIconType.DownTriangle, index, high + (Symbol.PipSize * 5), Color.Crimson);

                // --- FAKEOUT (SWEEP) SIGNALS ---
                if (low < _orLow && close > _orLow && prevClose >= _orLow)
                    Chart.DrawIcon("FO_Bot_" + index, ChartIconType.UpArrow, index, low - (Symbol.PipSize * 10), Color.DodgerBlue);
                
                if (high > _orHigh && close < _orHigh && prevClose <= _orHigh)
                    Chart.DrawIcon("FO_Top_" + index, ChartIconType.DownArrow, index, high + (Symbol.PipSize * 10), Color.DarkOrange);
            }

            // 3. UPDATE LIVE DASHBOARD (Only on the newest tick to save CPU)
            if (IsLastBar)
            {
                UpdateDashboard(timeOfDay);
            }
        }

        private void BuildDashboard()
        {
            var grid = new Grid(4, 2) { Margin = new Thickness(10) };
            
            // Add row styling and labels
            string[] labels = { "NY OR Status:", "Range Size:", "Daily ATR:", "Exhaustion:" };
            for (int i = 0; i < 4; i++)
            {
                grid.AddChild(new TextBlock { Text = labels[i], Foreground = Color.DarkGray, Margin = new Thickness(0, 0, 15, 5), FontWeight = FontWeight.Bold }, i, 0);
            }

            _valStatus = new TextBlock { Text = "-", Foreground = Color.White, Margin = new Thickness(0, 0, 0, 5) };
            _valRange = new TextBlock { Text = "-", Foreground = Color.White, Margin = new Thickness(0, 0, 0, 5) };
            _valAtr = new TextBlock { Text = "-", Foreground = Color.White, Margin = new Thickness(0, 0, 0, 5) };
            _valExhaustion = new TextBlock { Text = "-", Foreground = Color.White, Margin = new Thickness(0, 0, 0, 5), FontWeight = FontWeight.ExtraBold };

            grid.AddChild(_valStatus, 0, 1);
            grid.AddChild(_valRange, 1, 1);
            grid.AddChild(_valAtr, 2, 1);
            grid.AddChild(_valExhaustion, 3, 1);

            var border = new Border
            {
                BackgroundColor = Color.FromArgb(220, 20, 20, 20),
                BorderColor = Color.DimGray,
                BorderThickness = new Thickness(1),
                CornerRadius = new CornerRadius(5),
                HorizontalAlignment = HorizontalAlignment.Right,
                VerticalAlignment = VerticalAlignment.Top,
                Margin = new Thickness(20),
                Child = grid
            };

            Chart.AddControl(border);
        }

        private void UpdateDashboard(TimeSpan timeOfDay)
        {
            // Status update
            if (timeOfDay >= _orStart && timeOfDay < _orEnd) { _valStatus.Text = "Forming..."; _valStatus.Foreground = Color.Gold; }
            else if (timeOfDay >= _orEnd && timeOfDay <= _sessionEnd) { _valStatus.Text = "Active"; _valStatus.Foreground = Color.LimeGreen; }
            else { _valStatus.Text = "Closed"; _valStatus.Foreground = Color.Gray; }

            // Math calculations for Pips
            double rangeSizePips = Math.Round((_orHigh - _orLow) / Symbol.PipSize, 1);
            double dailyAtrPips = Math.Round(_dailyAtr.Result.LastValue / Symbol.PipSize, 1);
            
            // Exhaustion calculation
            double exhaustionPct = dailyAtrPips > 0 ? Math.Round((rangeSizePips / dailyAtrPips) * 100, 1) : 0;

            _valRange.Text = rangeSizePips.ToString("0.0") + " pips";
            _valAtr.Text = dailyAtrPips.ToString("0.0") + " pips";
            _valExhaustion.Text = exhaustionPct.ToString("0.0") + "%";
            
            // If Range has consumed > 50% of Daily ATR, warn the user by turning red
            _valExhaustion.Foreground = exhaustionPct >= 50 ? Color.Crimson : Color.LimeGreen;
        }
    }
}

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:16 pm
by PTScalper
Installation Guide for cTrader

1.) Open cTrader desktop and click the Automate tab on the left.

2.) In the left panel, click the Indicators tab, then click + New.

3.) Name it ProNYOpeningRange.

4.) Delete the template code, paste the C# script above, and click the Build button (or press Ctrl+B / Cmd+B).

5.) Go back to the Trade tab.

6.) Right-click your chart (best used on a 5M or 15M timeframe) -> Indicators -> Custom -> select ProNYOpeningRange.

What Makes This Implementation "Pro"?

Clean Memory / Graphics: It uses Chart.DrawRectangle to physically shade the 30-minute block so you can visualize the accumulation phase, rather than just plotting lines into infinity.

WPF Dashboard Integration: Because cTrader allows custom UI controls, we generated a floating dashboard. When the text next to Exhaustion turns Red (meaning the 30-minute range was larger than 50% of the daily ATR), you immediately know that the market has mathematically stretched too far. Avoid breakouts on these days and strictly trade the blue/orange Fakeout arrows.

Multi-Timeframe Engine: The script silently pulls the MarketData.GetBars(TimeFrame.Daily) data in the background to calculate the Daily ATR without you having to switch charts or apply a second indicator.

Re: The Opening Range Strategy, First 30 Minutes of New York

Posted: Fri Oct 02, 2026 4:18 pm
by PTScalper
Here is the Pro version built natively for both MetaTrader 4 and MetaTrader 5.

To achieve the "Pro" level in MetaTrader, this code introduces:

On-Chart Live Dashboard: Creates a dynamic graphical UI in the top-right corner tracking the Range Size, Daily ATR, and Exhaustion percentage.

Smart Box Visuals: Instead of drawing lines all over your chart, it creates an actual shaded graphical Rectangle (OBJ_RECTANGLE) specifically over the 30-minute formation period.

Volume Filtration: Calculates a rolling 20-period Moving Average of Tick Volume to filter out false breakouts.

1R Expansion Targets: Automatically projects dashed Target 1 lines above and below the range.