691 lines
No EOL
27 KiB
MQL5
691 lines
No EOL
27 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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));
|
|
} |