Open MT5 -> Open MetaEditor (F4) -> New -> Custom Indicator -> Name it ProNYOpeningRange. Paste this code and click Compile.
Code: Select all
//+------------------------------------------------------------------+
//| ProNYOpeningRange.mq5 |
//+------------------------------------------------------------------+
#property copyright "Pro Opening Range"
#property indicator_chart_window
#property indicator_buffers 8
#property indicator_plots 8
#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 "1R Target Up"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrSeaGreen
#property indicator_style3 STYLE_DASH
#property indicator_label4 "1R Target Down"
#property indicator_type4 DRAW_LINE
#property indicator_color4 clrCrimson
#property indicator_style4 STYLE_DASH
#property indicator_label5 "BO Up"
#property indicator_type5 DRAW_ARROW
#property indicator_color5 clrSeaGreen
#property indicator_label6 "BO Down"
#property indicator_type6 DRAW_ARROW
#property indicator_color6 clrCrimson
#property indicator_label7 "FO Up"
#property indicator_type7 DRAW_ARROW
#property indicator_color7 clrDodgerBlue
#property indicator_label8 "FO Down"
#property indicator_type8 DRAW_ARROW
#property indicator_color8 clrDarkOrange
//--- Inputs
input string _time_settings = "--- Time Settings (Use Broker 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 string _filter_settings = "--- Filters & UI ---";
input bool UseVolumeFilter = true;
input bool ShowTargets = true;
input bool ShowDashboard = true;
input int ArrowOffsetPips = 5;
//--- Buffers
double ExtHigh[], ExtLow[], ExtT1Up[], ExtT1Dn[];
double ExtBOUp[], ExtBODn[], ExtFOUp[], ExtFODn[];
int atr_handle;
double atr_buffer[];
int OnInit()
{
SetIndexBuffer(0, ExtHigh, INDICATOR_DATA);
SetIndexBuffer(1, ExtLow, INDICATOR_DATA);
SetIndexBuffer(2, ExtT1Up, INDICATOR_DATA);
SetIndexBuffer(3, ExtT1Dn, INDICATOR_DATA);
SetIndexBuffer(4, ExtBOUp, INDICATOR_DATA); PlotIndexSetInteger(4, PLOT_ARROW, 233);
SetIndexBuffer(5, ExtBODn, INDICATOR_DATA); PlotIndexSetInteger(5, PLOT_ARROW, 234);
SetIndexBuffer(6, ExtFOUp, INDICATOR_DATA); PlotIndexSetInteger(6, PLOT_ARROW, 225);
SetIndexBuffer(7, ExtFODn, INDICATOR_DATA); PlotIndexSetInteger(7, PLOT_ARROW, 226);
for(int i=0; i<8; i++) PlotIndexSetDouble(i, PLOT_EMPTY_VALUE, 0.0);
atr_handle = iATR(_Symbol, PERIOD_D1, 14);
ArraySetAsSeries(atr_buffer, true);
return(INIT_SUCCEEDED);
}
void DrawText(string name, string text, int x, int y, color clr, int fontSize, bool bold=false)
{
if(ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetString(0, name, OBJPROP_FONT, bold ? "Arial Bold" : "Arial");
}
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 < 22) return 0;
// Reverse arrays to match MT4 logic (i=0 is newest bar)
ArraySetAsSeries(time, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(tick_volume, true);
int limit = rates_total - prev_calculated;
if (prev_calculated == 0) limit = rates_total - 22;
if (limit < 0) limit = 0;
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, or_low = 999999;
static datetime start_time = 0;
for(int i = limit; i >= 0; 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;
start_time = 0;
}
ExtHigh[i]=0.0; ExtLow[i]=0.0; ExtT1Up[i]=0.0; ExtT1Dn[i]=0.0;
ExtBOUp[i]=0.0; ExtBODn[i]=0.0; ExtFOUp[i]=0.0; ExtFODn[i]=0.0;
// 1. Establish the Range & Draw the Shaded Box
if (time_mins >= start_mins && time_mins < end_mins) {
if(start_time == 0) start_time = time[i];
if (high[i] > or_high) or_high = high[i];
if (low[i] < or_low) or_low = low[i];
if(time[i] >= TimeCurrent() - (30 * 86400)) {
string rectName = "OR_Box_" + IntegerToString(bar_day);
if(ObjectFind(0, rectName) < 0) {
ObjectCreate(0, rectName, OBJ_RECTANGLE, 0, start_time, or_high, time[i], or_low);
ObjectSetInteger(0, rectName, OBJPROP_COLOR, clrDarkGray);
ObjectSetInteger(0, rectName, OBJPROP_BACK, true);
} else {
ObjectSetDouble(0, rectName, OBJPROP_PRICE1, or_high);
ObjectSetDouble(0, rectName, OBJPROP_PRICE2, or_low);
ObjectSetInteger(0, rectName, OBJPROP_TIME2, time[i]);
}
}
}
// 2. Project Lines and Detect Signals
if (time_mins >= end_mins && time_mins <= session_end_mins) {
if (or_high > 0 && or_low < 999999) {
double range_size = or_high - or_low;
ExtHigh[i] = or_high;
ExtLow[i] = or_low;
if(ShowTargets) {
ExtT1Up[i] = or_high + range_size;
ExtT1Dn[i] = or_low - range_size;
}
double prev_close = close[i+1];
// Volume Filter
double vol_sum = 0;
for(int v=1; v<=20; v++) vol_sum += (double)tick_volume[i+v];
double vol_avg = vol_sum / 20.0;
bool vol_spike = (!UseVolumeFilter) || ((double)tick_volume[i] > vol_avg);
// Signals
if (close[i] > or_high && prev_close <= or_high && vol_spike) ExtBOUp[i] = low[i] - (ArrowOffsetPips * pips);
if (close[i] < or_low && prev_close >= or_low && vol_spike) ExtBODn[i] = high[i] + (ArrowOffsetPips * pips);
if (low[i] < or_low && close[i] > or_low && prev_close >= or_low) ExtFOUp[i] = low[i] - ((ArrowOffsetPips * 2) * pips);
if (high[i] > or_high && close[i] < or_high && prev_close <= or_high) ExtFODn[i] = high[i] + ((ArrowOffsetPips * 2) * pips);
}
}
// 3. Update Dashboard on Current Tick
if (i == 0 && ShowDashboard) {
CopyBuffer(atr_handle, 0, 0, 1, atr_buffer);
double atr = atr_buffer[0];
double range_pips = (or_high - or_low) / pips;
double atr_pips = atr / pips;
double exh_pct = (atr_pips > 0) ? (range_pips / atr_pips) * 100.0 : 0;
string status = "Closed"; color statusClr = clrGray;
if (time_mins >= start_mins && time_mins < end_mins) { status = "Forming..."; statusClr = clrGold; }
else if (time_mins >= end_mins && time_mins <= session_end_mins) { status = "Active"; statusClr = clrLimeGreen; }
DrawText("dashLbl1", "NY OR Status:", 160, 20, clrDarkGray, 10, true);
DrawText("dashVal1", status, 20, 20, statusClr, 10, true);
DrawText("dashLbl2", "Range Size:", 160, 40, clrDarkGray, 10, true);
DrawText("dashVal2", DoubleToString(range_pips, 1) + " pips", 20, 40, clrWhite, 10, false);
DrawText("dashLbl3", "Daily ATR:", 160, 60, clrDarkGray, 10, true);
DrawText("dashVal3", DoubleToString(atr_pips, 1) + " pips", 20, 60, clrWhite, 10, false);
DrawText("dashLbl4", "Exhaustion:", 160, 80, clrDarkGray, 10, true);
DrawText("dashVal4", DoubleToString(exh_pct, 1) + "%", 20, 80, exh_pct > 50 ? clrRed : clrLimeGreen, 10, true);
}
}
return(rates_total);
}