
showMidPoint (default: false)
Plots a line at the exact center of the opening range. The midpoint often acts as a pivot level and can be used for mean reversion strategies.
showShadedBox (default: true)
Draws a filled rectangle over the opening range period, providing clear visual identification of the ORB zone.
Color Customization
shadeColor (default: clrTeal)
Sets the color for the shaded opening range rectangle.
orb50Color (default: clrPurple)
Color for the 50% profit target lines.
orb100Color (default: clrBlue)
Color for the 100% profit target lines.
orbOtherColor (default: clrTeal)
Color for all extended profit targets (150% through 450%).
Time Settings
sORBStartTime (default: "0930-0945")
Custom time override in 24-hour format (HHMM-HHMM). This parameter is only used when sOpeningRangeMinutes is set to 0, allowing complete flexibility in defining the opening range period.
sTimeZone (default: "EST")
Reference timezone for the opening range calculation. While the parameter accepts different timezone abbreviations, the indicator calculates times based on the broker's server time.
Label Formatting
labelOffsetBars (default: 5)
Horizontal spacing in bars between the current price action and the label position. Positive values move labels to the right.
labelOffsetPips (default: 0)
Vertical spacing in pips for label positioning. This helps prevent labels from overlapping with price action or other chart elements.
labelFontSize (default: 8)
Font size for all text labels on the chart. Adjust based on screen resolution and personal preference.
labelAnchor (default: ANCHOR_LEFT)
Determines the anchor point for label positioning. Options include ANCHOR_LEFT, ANCHOR_RIGHT, ANCHOR_CENTER, etc.
maxLineBars (default: 500)
Maximum length in bars for ORB level lines. This prevents the indicator from drawing excessively long lines on historical data, improving performance.
How the Indicator Works
Opening Range Calculation
The indicator identifies the opening range by monitoring the specified time period and recording the highest high and lowest low during that window. For example, with a 15-minute setting, it captures the range between 9:30 and 9:45.
Once the opening range period ends, the high and low levels are locked and extended forward as horizontal lines for the remainder of the trading session.
Price Target Calculation
All profit targets are calculated as multiples of the opening range size. If the opening range is 20 points, the 50% target would be 10 points beyond the ORB high (for long trades) or below the ORB low (for short trades). The 100% target would be 20 points, 150% would be 30 points, and so on.
This dynamic scaling ensures profit targets adjust automatically to market volatility, with larger ranges producing wider targets and smaller ranges producing tighter targets.
Breakout Detection Logic
The indicator employs sophisticated multi-bar confirmation for breakout signals. A valid upside breakout requires price to close above the ORB high on one bar, then continue higher on the next bar with the low remaining above the ORB high level. This filters out false breakouts where price briefly spikes through the level but immediately reverses.
Similarly, downside breakouts require closes below the ORB low followed by continuation with highs remaining below the level.
Retest Identification
After a confirmed breakout, the indicator monitors for pullbacks to the broken level. A valid retest occurs when price returns to touch the ORB level but closes on the correct side, confirming the level has flipped from resistance to support (or vice versa).
Failed retests are flagged when price breaks back through the ORB level in the opposite direction, invalidating the original breakout signal.
Interpretation and Trading Applications
Breakout Trading Strategy
The primary application is identifying high-probability breakout trades. When price breaks out of the opening range with volume and momentum, traders can enter in the direction of the breakout, placing stops below the ORB low (for long trades) or above the ORB high (for short trades).
The first profit target is typically the 50% level, where partial profits can be taken. The remaining position targets the 100% level or beyond in strongly trending conditions.
Retest Entry Method
Conservative traders prefer waiting for a retest after the initial breakout. The "Breakout - Wait for Retest" label signals this opportunity. When price pulls back to test the broken level and finds support (or resistance), it provides a lower-risk entry point with a tighter stop loss.
This approach improves the risk-reward ratio significantly compared to chasing the initial breakout.
Range-Bound Trading
When price remains contained within the opening range, traders can employ mean reversion strategies, buying near the ORB low and selling near the ORB high. The midpoint line serves as a reference for neutral positioning.
Multi-Timeframe Analysis
The indicator can be applied to multiple timeframes simultaneously. Some traders use a 5-minute ORB for scalping, a 15-minute ORB for day trading, and a 30-minute ORB for swing trading, creating a comprehensive view of potential support and resistance zones.
Recommended Symbols and Timeframes
Optimal Timeframes
The indicator works best on 1-minute (M1) through 15-minute (M15) charts, where intraday price action is clearly visible. For detailed analysis of entry timing, the M5 timeframe provides an excellent balance between noise reduction and responsiveness.
Suitable Instruments
The ORB strategy is particularly effective on liquid instruments with clear opening sessions:
- Forex pairs: EURUSD, GBPUSD, USDJPY during their respective regional opens
- Gold (XAUUSD): Highly responsive to opening range breakouts due to strong directional moves
- Stock indices: US30, NAS100, SPX500 during the New York session open
- Cryptocurrencies: BTCUSD, ETHUSD during periods of high volume
The indicator performs best on instruments with defined trading sessions rather than 24-hour markets without clear opening times.
Performance Optimization
The indicator includes several performance optimizations for smooth chart operation. Buffer initialization to EMPTY_VALUE prevents unnecessary line drawing, while the maxLineBars parameter limits historical line length. The rectangle drawing logic waits until the session concludes before rendering, reducing computational overhead during active trading periods.
Object naming conventions use unique identifiers based on day of year, preventing conflicts when multiple ORB sessions are displayed simultaneously.
Alert System
The notification system provides real-time alerts through MetaTrader 5's built-in alert mechanism. Alerts can be configured for simple level crossings or restricted to confirmed breakouts only. When a breakout occurs, the alert message specifies whether it's above the ORB high or below the ORB low, allowing traders to quickly assess the opportunity without watching the chart continuously.
Visual Presentation
All chart elements follow professional formatting standards with customizable colors. The default color scheme uses lime for ORB high, red for ORB low, purple for 50% targets, blue for 100% targets, and teal for extended targets and the shaded range box. This color-coding system allows for rapid visual identification of key levels even on busy charts.
The shaded rectangle provides an intuitive visual reference for the opening range period, making it immediately obvious when price is trading within or outside the established range.
Conclusion
The Open Range Breakout indicator is a comprehensive trading tool that combines automatic range calculation, multiple profit targets, breakout detection, and retest identification into a single, easy-to-use package. Its flexibility through extensive input parameters allows traders to adapt the indicator to various trading styles, from aggressive breakout trading to conservative retest entries.
The indicator's clean visual presentation and logical alert system make it suitable for both discretionary traders and those developing automated trading systems. By focusing on the critical opening range period, it helps traders identify the most significant support and resistance levels for each trading session.
//+------------------------------------------------------------------+ //| Open Range Breakout-H-Max.mq5 | //| By Hieronymos Starch - Quotesy of The Nevek Ratio | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Hieronymos Starch - arete2077@gmail.com - +263785974079 " #property link "https://www.mql5.com" #property version "9.00" #property indicator_chart_window #property indicator_buffers 22 #property indicator_plots 22 // Plot buffers #property indicator_label1 "ORB High" #property indicator_type1 DRAW_LINE #property indicator_color1 clrLime #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #property indicator_label2 "ORB Low" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 2 #property indicator_label3 "ORB Mid Point" #property indicator_type3 DRAW_LINE #property indicator_color3 clrGray #property indicator_style3 STYLE_SOLID #property indicator_width3 1 #property indicator_label4 "ORB High PT 0.5" #property indicator_type4 DRAW_LINE #property indicator_color4 clrPurple #property indicator_style4 STYLE_SOLID #property indicator_width4 2 #property indicator_label5 "ORB High PT 1.0" #property indicator_type5 DRAW_LINE #property indicator_color5 clrBlue #property indicator_style5 STYLE_SOLID #property indicator_width5 2 #property indicator_label6 "ORB Low PT 0.5" #property indicator_type6 DRAW_LINE #property indicator_color6 clrPurple #property indicator_style6 STYLE_SOLID #property indicator_width6 2 #property indicator_label7 "ORB Low PT 1.0" #property indicator_type7 DRAW_LINE #property indicator_color7 clrBlue #property indicator_style7 STYLE_SOLID #property indicator_width7 2 // Extended targets #property indicator_label8 "ORB High PT 1.5" #property indicator_type8 DRAW_LINE #property indicator_color8 clrTeal #property indicator_label9 "ORB High PT 2.0" #property indicator_type9 DRAW_LINE #property indicator_color9 clrTeal #property indicator_label10 "ORB High PT 2.5" #property indicator_type10 DRAW_LINE #property indicator_color10 clrTeal #property indicator_label11 "ORB High PT 3.0" #property indicator_type11 DRAW_LINE #property indicator_color11 clrTeal #property indicator_label12 "ORB High PT 3.5" #property indicator_type12 DRAW_LINE #property indicator_color12 clrTeal #property indicator_label13 "ORB High PT 4.0" #property indicator_type13 DRAW_LINE #property indicator_color13 clrTeal #property indicator_label14 "ORB High PT 4.5" #property indicator_type14 DRAW_LINE #property indicator_color14 clrTeal #property indicator_label15 "ORB High PT 5.0" #property indicator_type15 DRAW_LINE #property indicator_color15 clrTeal #property indicator_label16 "ORB Low PT 1.5" #property indicator_type16 DRAW_LINE #property indicator_color16 clrTeal #property indicator_label17 "ORB Low PT 2.0" #property indicator_type17 DRAW_LINE #property indicator_color17 clrTeal #property indicator_label18 "ORB Low PT 2.5" #property indicator_type18 DRAW_LINE #property indicator_color18 clrTeal #property indicator_label19 "ORB Low PT 3.0" #property indicator_type19 DRAW_LINE #property indicator_color19 clrTeal #property indicator_label20 "ORB Low PT 3.5" #property indicator_type20 DRAW_LINE #property indicator_color20 clrTeal #property indicator_label21 "ORB Low PT 4.0" #property indicator_type21 DRAW_LINE #property indicator_color21 clrTeal #property indicator_label22 "ORB Low PT 4.5" #property indicator_type22 DRAW_LINE #property indicator_color22 clrTeal // Input parameters input string sOpeningRangeMinutes = "15"; // Period (minutes): 5,15,30,0 input bool alertBreakoutsOnly = false; // Alert only on ORB breakouts (not price ticks) input bool showLabels = true; // Show ORB labels input bool showPreviousDayORBs = true; // Show ORB ranges on previous days input bool showEntries = true; // Show potential ORB Breakouts and Retests (BRB) input bool showPriceTargets = true; // Show Default Price Targets (50%, 100%) input bool showPriceTargetsExtended = false; // Show Extended Price Targets (150%, 200%) input bool showMidPoint = false; // Show ORB Mid Point input bool showShadedBox = true; // Shade the ORB Range input color shadeColor = clrTeal; // Shaded ORB Range Color input color orb50Color = clrPurple; // ORB 50 Price Target input color orb100Color = clrBlue; // ORB 100 Price Target input color orbOtherColor = clrTeal; // All Other ORB Price Targets input string sORBStartTime = "0930-0945"; // Time Override (Format: 0930-0945) input string sTimeZone = "EST"; // Timezone input int labelOffsetBars = 5; // Label Horizontal Offset (bars) input int labelOffsetPips = 0; // Label Vertical Offset (pips) input int labelFontSize = 8; // Label Font Size input ENUM_ANCHOR_POINT labelAnchor = ANCHOR_LEFT; // Label Anchor Point input int maxLineBars = 500; // Maximum Line Length (bars) // Indicator buffers double OrbHighBuffer[]; double OrbLowBuffer[]; double OrbMidBuffer[]; double OrbHigh50Buffer[]; double OrbHigh100Buffer[]; double OrbLow50Buffer[]; double OrbLow100Buffer[]; double OrbHigh150Buffer[]; double OrbHigh200Buffer[]; double OrbHigh250Buffer[]; double OrbHigh300Buffer[]; double OrbHigh350Buffer[]; double OrbHigh400Buffer[]; double OrbHigh450Buffer[]; double OrbHigh500Buffer[]; double OrbLow150Buffer[]; double OrbLow200Buffer[]; double OrbLow250Buffer[]; double OrbLow300Buffer[]; double OrbLow350Buffer[]; double OrbLow400Buffer[]; double OrbLow450Buffer[]; // Global variables struct ORBData { double orbHighPrice; double orbLowPrice; datetime orbStartTime; datetime orbEndTime; bool isActive; string boxName; int dayOfYear; int sessionStartBar; int sessionEndBar; }; ORBData currentORB; bool inBreakout = false; int openingRangeMinutes; int sessionStartHour, sessionStartMin; int sessionEndHour, sessionEndMin; string orbTitle; double pointMultiplier; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { openingRangeMinutes = (int)StringToInteger(sOpeningRangeMinutes); pointMultiplier = (_Point * 10); // Determine session times if(openingRangeMinutes == 5) { sessionStartHour = 9; sessionStartMin = 30; sessionEndHour = 9; sessionEndMin = 35; } else if(openingRangeMinutes == 15) { sessionStartHour = 9; sessionStartMin = 30; sessionEndHour = 9; sessionEndMin = 45; } else if(openingRangeMinutes == 30) { sessionStartHour = 9; sessionStartMin = 30; sessionEndHour = 10; sessionEndMin = 0; } else if(openingRangeMinutes == 0) { string parts[]; if(StringSplit(sORBStartTime, '-', parts) == 2) { string startTime = parts[0]; string endTime = parts[1]; sessionStartHour = (int)StringToInteger(StringSubstr(startTime, 0, 2)); sessionStartMin = (int)StringToInteger(StringSubstr(startTime, 2, 2)); sessionEndHour = (int)StringToInteger(StringSubstr(endTime, 0, 2)); sessionEndMin = (int)StringToInteger(StringSubstr(endTime, 2, 2)); } } else { sessionStartHour = 9; sessionStartMin = 30; sessionEndHour = 9; sessionEndMin = 45; } orbTitle = "ORB" + IntegerToString(openingRangeMinutes); // Initialize ORB data currentORB.orbHighPrice = 0.0; currentORB.orbLowPrice = 0.0; currentORB.isActive = false; currentORB.boxName = ""; currentORB.dayOfYear = 0; currentORB.sessionStartBar = -1; currentORB.sessionEndBar = -1; // Set indicator buffers SetIndexBuffer(0, OrbHighBuffer, INDICATOR_DATA); SetIndexBuffer(1, OrbLowBuffer, INDICATOR_DATA); SetIndexBuffer(2, OrbMidBuffer, INDICATOR_DATA); SetIndexBuffer(3, OrbHigh50Buffer, INDICATOR_DATA); SetIndexBuffer(4, OrbHigh100Buffer, INDICATOR_DATA); SetIndexBuffer(5, OrbLow50Buffer, INDICATOR_DATA); SetIndexBuffer(6, OrbLow100Buffer, INDICATOR_DATA); SetIndexBuffer(7, OrbHigh150Buffer, INDICATOR_DATA); SetIndexBuffer(8, OrbHigh200Buffer, INDICATOR_DATA); SetIndexBuffer(9, OrbHigh250Buffer, INDICATOR_DATA); SetIndexBuffer(10, OrbHigh300Buffer, INDICATOR_DATA); SetIndexBuffer(11, OrbHigh350Buffer, INDICATOR_DATA); SetIndexBuffer(12, OrbHigh400Buffer, INDICATOR_DATA); SetIndexBuffer(13, OrbHigh450Buffer, INDICATOR_DATA); SetIndexBuffer(14, OrbHigh500Buffer, INDICATOR_DATA); SetIndexBuffer(15, OrbLow150Buffer, INDICATOR_DATA); SetIndexBuffer(16, OrbLow200Buffer, INDICATOR_DATA); SetIndexBuffer(17, OrbLow250Buffer, INDICATOR_DATA); SetIndexBuffer(18, OrbLow300Buffer, INDICATOR_DATA); SetIndexBuffer(19, OrbLow350Buffer, INDICATOR_DATA); SetIndexBuffer(20, OrbLow400Buffer, INDICATOR_DATA); SetIndexBuffer(21, OrbLow450Buffer, INDICATOR_DATA); // Set colors PlotIndexSetInteger(3, PLOT_LINE_COLOR, orb50Color); PlotIndexSetInteger(4, PLOT_LINE_COLOR, orb100Color); PlotIndexSetInteger(5, PLOT_LINE_COLOR, orb50Color); PlotIndexSetInteger(6, PLOT_LINE_COLOR, orb100Color); for(int i = 7; i < 22; i++) PlotIndexSetInteger(i, PLOT_LINE_COLOR, orbOtherColor); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0, "ORB_"); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total < 10) return(0); int start = MathMax(1, prev_calculated); if(start == 1) start = 0; for(int i = start; i < rates_total; i++) { InitializeBuffers(i); MqlDateTime dt; TimeToStruct(time[i], dt); bool inSession = IsInSession(dt); bool isFirstBar = IsFirstBarOfSession(time, i, dt); bool newDayStart = IsNewDay(time, i); bool isToday = IsToday(time[i]); bool drawOrbs = showPreviousDayORBs || (!showPreviousDayORBs && isToday); // Start new ORB session if(isFirstBar && inSession) { currentORB.orbHighPrice = high[i]; currentORB.orbLowPrice = low[i]; currentORB.orbStartTime = time[i]; currentORB.sessionStartBar = i; currentORB.isActive = true; currentORB.dayOfYear = dt.day_of_year; inBreakout = false; // Calculate session end time MqlDateTime sessionEnd = dt; sessionEnd.hour = sessionEndHour; sessionEnd.min = sessionEndMin; currentORB.orbEndTime = StructToTime(sessionEnd); currentORB.boxName = "ORB_Box_" + IntegerToString(dt.day_of_year); } // Update ORB levels during session if(inSession && currentORB.isActive) { if(high[i] > currentORB.orbHighPrice) currentORB.orbHighPrice = high[i]; if(low[i] < currentORB.orbLowPrice) currentORB.orbLowPrice = low[i]; } // Mark end of session if(!inSession && currentORB.isActive && i > 0) { MqlDateTime prevDt; TimeToStruct(time[i-1], prevDt); if(IsInSession(prevDt)) { currentORB.sessionEndBar = i - 1; currentORB.isActive = false; // Draw the rectangle now that session is complete if(showShadedBox) DrawORBRectangle(); } } // Plot ORB levels and targets if(currentORB.orbHighPrice > 0 && currentORB.orbLowPrice > 0) { bool shouldPlot = false; if(!inSession && drawOrbs) { // Limit line length int barsFromSessionEnd = (currentORB.sessionEndBar > 0) ? i - currentORB.sessionEndBar : 0; if(barsFromSessionEnd <= maxLineBars) shouldPlot = true; } if(shouldPlot) { double orbRange = currentORB.orbHighPrice - currentORB.orbLowPrice; // Always show ORB High and Low OrbHighBuffer[i] = currentORB.orbHighPrice; OrbLowBuffer[i] = currentORB.orbLowPrice; if(showMidPoint && showPriceTargets) OrbMidBuffer[i] = currentORB.orbLowPrice + (orbRange * 0.5); if(showPriceTargets) PlotPriceTargets(i, orbRange); // Draw labels only for today and only once if(isToday && showLabels && i == rates_total - 1) DrawPriceTargetLabels(time[i], orbRange); } } // Handle breakout detection if(!inSession && i > 2 && currentORB.orbHighPrice > 0) ProcessBreakouts(time, high, low, close, i, isToday); } return(rates_total); } //+------------------------------------------------------------------+ //| Initialize all buffers to EMPTY_VALUE | //+------------------------------------------------------------------+ void InitializeBuffers(int index) { OrbHighBuffer[index] = EMPTY_VALUE; OrbLowBuffer[index] = EMPTY_VALUE; OrbMidBuffer[index] = EMPTY_VALUE; OrbHigh50Buffer[index] = EMPTY_VALUE; OrbHigh100Buffer[index] = EMPTY_VALUE; OrbLow50Buffer[index] = EMPTY_VALUE; OrbLow100Buffer[index] = EMPTY_VALUE; OrbHigh150Buffer[index] = EMPTY_VALUE; OrbHigh200Buffer[index] = EMPTY_VALUE; OrbHigh250Buffer[index] = EMPTY_VALUE; OrbHigh300Buffer[index] = EMPTY_VALUE; OrbHigh350Buffer[index] = EMPTY_VALUE; OrbHigh400Buffer[index] = EMPTY_VALUE; OrbHigh450Buffer[index] = EMPTY_VALUE; OrbHigh500Buffer[index] = EMPTY_VALUE; OrbLow150Buffer[index] = EMPTY_VALUE; OrbLow200Buffer[index] = EMPTY_VALUE; OrbLow250Buffer[index] = EMPTY_VALUE; OrbLow300Buffer[index] = EMPTY_VALUE; OrbLow350Buffer[index] = EMPTY_VALUE; OrbLow400Buffer[index] = EMPTY_VALUE; OrbLow450Buffer[index] = EMPTY_VALUE; } //+------------------------------------------------------------------+ //| Plot price targets | //+------------------------------------------------------------------+ void PlotPriceTargets(int index, double orbRange) { OrbHigh50Buffer[index] = currentORB.orbHighPrice + (orbRange * 0.5); OrbHigh100Buffer[index] = currentORB.orbHighPrice + (orbRange * 1.0); OrbLow50Buffer[index] = currentORB.orbLowPrice + (orbRange * -0.5); OrbLow100Buffer[index] = currentORB.orbLowPrice + (orbRange * -1.0); if(showPriceTargetsExtended) { OrbHigh150Buffer[index] = currentORB.orbHighPrice + (orbRange * 1.5); OrbHigh200Buffer[index] = currentORB.orbHighPrice + (orbRange * 2.0); OrbHigh250Buffer[index] = currentORB.orbHighPrice + (orbRange * 2.5); OrbHigh300Buffer[index] = currentORB.orbHighPrice + (orbRange * 3.0); OrbHigh350Buffer[index] = currentORB.orbHighPrice + (orbRange * 3.5); OrbHigh400Buffer[index] = currentORB.orbHighPrice + (orbRange * 4.0); OrbHigh450Buffer[index] = currentORB.orbHighPrice + (orbRange * 4.5); OrbHigh500Buffer[index] = currentORB.orbHighPrice + (orbRange * 5.0); OrbLow150Buffer[index] = currentORB.orbLowPrice + (orbRange * -1.5); OrbLow200Buffer[index] = currentORB.orbLowPrice + (orbRange * -2.0); OrbLow250Buffer[index] = currentORB.orbLowPrice + (orbRange * -2.5); OrbLow300Buffer[index] = currentORB.orbLowPrice + (orbRange * -3.0); OrbLow350Buffer[index] = currentORB.orbLowPrice + (orbRange * -3.5); OrbLow400Buffer[index] = currentORB.orbLowPrice + (orbRange * -4.0); OrbLow450Buffer[index] = currentORB.orbLowPrice + (orbRange * -4.5); } } //+------------------------------------------------------------------+ //| Draw price target labels | //+------------------------------------------------------------------+ void DrawPriceTargetLabels(datetime time, double orbRange) { if(!showLabels) return; string prefix = "ORB_Label_" + IntegerToString(currentORB.dayOfYear); ObjectsDeleteAll(0, prefix); datetime labelTime = time + labelOffsetBars * PeriodSeconds(); double pipOffset = labelOffsetPips * pointMultiplier; // Basic ORB levels CreatePriceLabel(labelTime, currentORB.orbHighPrice + pipOffset + (20 * _Point), orbTitle + " HIGH", clrLime); CreatePriceLabel(labelTime, currentORB.orbLowPrice + pipOffset - (20 * _Point), orbTitle + " LOW", clrRed); if(showPriceTargets) { CreatePriceLabel(labelTime, currentORB.orbHighPrice + (orbRange * 0.5) + pipOffset, "PT 50%", orb50Color); CreatePriceLabel(labelTime, currentORB.orbHighPrice + (orbRange * 1.0) + pipOffset, "PT 100%", orb100Color); CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * -0.5) + pipOffset, "PT 50%", orb50Color); CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * -1.0) + pipOffset, "PT 100%", orb100Color); if(showPriceTargetsExtended) { CreatePriceLabel(labelTime, currentORB.orbHighPrice + (orbRange * 1.5) + pipOffset, "PT 150%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbHighPrice + (orbRange * 2.0) + pipOffset, "PT 200%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbHighPrice + (orbRange * 2.5) + pipOffset, "PT 250%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbHighPrice + (orbRange * 3.0) + pipOffset, "PT 300%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * -1.5) + pipOffset, "PT 150%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * -2.0) + pipOffset, "PT 200%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * -2.5) + pipOffset, "PT 250%", orbOtherColor); CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * -3.0) + pipOffset, "PT 300%", orbOtherColor); } if(showMidPoint) { CreatePriceLabel(labelTime, currentORB.orbLowPrice + (orbRange * 0.5) + pipOffset, "MIDPOINT", clrGray); } } } //+------------------------------------------------------------------+ //| Create price label | //+------------------------------------------------------------------+ void CreatePriceLabel(datetime time, double price, string text, color clr) { string labelName = "ORB_Label_" + IntegerToString(currentORB.dayOfYear) + "_" + text; if(ObjectCreate(0, labelName, OBJ_TEXT, 0, time, price)) { ObjectSetString(0, labelName, OBJPROP_TEXT, text); ObjectSetInteger(0, labelName, OBJPROP_COLOR, clr); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, labelFontSize); ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, labelAnchor); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial"); } } //+------------------------------------------------------------------+ //| Process breakout detection | //+------------------------------------------------------------------+ void ProcessBreakouts(const datetime &time[], const double &high[], const double &low[], const double &close[], int i, bool isToday) { bool highCrossBO = CheckHighBreakout(high, low, close, i); bool lowCrossBO = CheckLowBreakout(high, low, close, i); if(showEntries) { if(highCrossBO) { CreateBreakoutLabel(time[i], high[i], "Breakout\nWait for Retest", clrGreen, true); inBreakout = true; } if(lowCrossBO) { CreateBreakoutLabel(time[i], low[i], "Breakout\nWait for Retest", clrGreen, false); inBreakout = true; } if(inBreakout) { bool isRetestHigh = close[i-1] > currentORB.orbHighPrice && low[i] <= currentORB.orbHighPrice && close[i] >= currentORB.orbHighPrice; bool isRetestLow = close[i-1] < currentORB.orbLowPrice && high[i] >= currentORB.orbLowPrice && close[i] <= currentORB.orbLowPrice; bool failedRetest = (close[i-1] > currentORB.orbHighPrice && close[i] < currentORB.orbHighPrice) || (close[i-1] < currentORB.orbLowPrice && close[i] > currentORB.orbLowPrice); if(isRetestHigh || isRetestLow) { CreateBreakoutLabel(time[i], high[i], "Retest", clrGreen, true); inBreakout = false; } else if(failedRetest) { CreateBreakoutLabel(time[i], high[i], "Failed Retest", clrRed, true); inBreakout = false; } } } if(isToday) { if(!alertBreakoutsOnly) { bool highCross = CheckCross(close, i, currentORB.orbHighPrice); bool lowCross = CheckCross(close, i, currentORB.orbLowPrice); if(highCross) SendNotification("Price crossing ORB High Level"); if(lowCross) SendNotification("Price crossing ORB Low Level"); } else { if(highCrossBO) SendNotification("Price breaking out of ORB High Level, Look for Retest"); if(lowCrossBO) SendNotification("Price breaking out of ORB Low Level, Look for Retest"); } } } //+------------------------------------------------------------------+ //| Create breakout label | //+------------------------------------------------------------------+ void CreateBreakoutLabel(datetime time, double price, string text, color clr, bool above) { string labelName = "ORB_Breakout_" + TimeToString(time) + "_" + DoubleToString(price, 5); double adjustedPrice = above ? price + (50 * _Point) : price - (50 * _Point); if(ObjectCreate(0, labelName, OBJ_TEXT, 0, time, adjustedPrice)) { ObjectSetString(0, labelName, OBJPROP_TEXT, text); ObjectSetInteger(0, labelName, OBJPROP_COLOR, clr); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, above ? ANCHOR_LOWER : ANCHOR_UPPER); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial"); } } //+------------------------------------------------------------------+ //| Draw ORB Rectangle | //+------------------------------------------------------------------+ void DrawORBRectangle() { if(!showShadedBox || currentORB.boxName == "" || currentORB.sessionStartBar < 0 || currentORB.sessionEndBar < 0) return; ObjectDelete(0, currentORB.boxName); if(ObjectCreate(0, currentORB.boxName, OBJ_RECTANGLE, 0, currentORB.orbStartTime, currentORB.orbHighPrice, currentORB.orbEndTime, currentORB.orbLowPrice)) { ObjectSetInteger(0, currentORB.boxName, OBJPROP_COLOR, shadeColor); ObjectSetInteger(0, currentORB.boxName, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, currentORB.boxName, OBJPROP_WIDTH, 2); ObjectSetInteger(0, currentORB.boxName, OBJPROP_BACK, true); ObjectSetInteger(0, currentORB.boxName, OBJPROP_FILL, true); ObjectSetInteger(0, currentORB.boxName, OBJPROP_BGCOLOR, shadeColor); } } //+------------------------------------------------------------------+ //| Helper functions | //+------------------------------------------------------------------+ bool IsInSession(MqlDateTime &dt) { int currentMinutes = dt.hour * 60 + dt.min; int sessionStart = sessionStartHour * 60 + sessionStartMin; int sessionEnd = sessionEndHour * 60 + sessionEndMin; return (currentMinutes >= sessionStart && currentMinutes < sessionEnd); } bool IsFirstBarOfSession(const datetime &time[], int i, MqlDateTime &dt) { if(i == 0) return false; MqlDateTime prevDt; TimeToStruct(time[i-1], prevDt); bool inSession = IsInSession(dt); bool wasInSession = IsInSession(prevDt); return (inSession && !wasInSession); } bool IsNewDay(const datetime &time[], int i) { if(i == 0) return true; MqlDateTime dt, prevDt; TimeToStruct(time[i], dt); TimeToStruct(time[i-1], prevDt); return (dt.day != prevDt.day); } bool IsToday(datetime barTime) { MqlDateTime dt, currentDt; TimeToStruct(barTime, dt); TimeToStruct(TimeCurrent(), currentDt); return (dt.year == currentDt.year && dt.day_of_year == currentDt.day_of_year); } bool CheckHighBreakout(const double &high[], const double &low[], const double &close[], int i) { return (low[i-2] < currentORB.orbHighPrice && close[i-2] > currentORB.orbHighPrice && low[i-1] > currentORB.orbHighPrice && close[i-1] > currentORB.orbHighPrice && close[i] > low[i-1] && low[i] > currentORB.orbHighPrice); } bool CheckLowBreakout(const double &high[], const double &low[], const double &close[], int i) { return (high[i-2] > currentORB.orbLowPrice && close[i-2] < currentORB.orbLowPrice && high[i-1] < currentORB.orbLowPrice && close[i-1] < currentORB.orbLowPrice && close[i] < high[i-1] && high[i] < currentORB.orbLowPrice); } bool CheckCross(const double &close[], int i, double level) { if(i == 0) return false; return ((close[i-1] <= level && close[i] > level) || (close[i-1] >= level && close[i] < level)); }