The Opening Range Strategy, First 30 Minutes of New York
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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);
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
Here is the Pro NY Opening Range script:
The "Pro" Pine Script (v5)
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.")Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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;
}
}
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: The Opening Range Strategy, First 30 Minutes of New York
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.
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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.