//+------------------------------------------------------------------+ //| ForexSessionHighLowIndicator.mq5 | //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" #property version "1.00" #property indicator_chart_window #property indicator_buffers 8 #property indicator_plots 4 // Session times (in broker time) input string SydneyStart = "22:00"; // Sydney session start (GMT+10 when DST) input string SydneyEnd = "07:00"; // Sydney session end input string TokyoStart = "00:00"; // Tokyo session start (GMT+9) input string TokyoEnd = "09:00"; // Tokyo session end input string LondonStart = "08:00"; // London session start (GMT+0) input string LondonEnd = "17:00"; // London session end input string NewYorkStart = "13:00"; // New York session start (GMT-4/5) input string NewYorkEnd = "22:00"; // New York session end input color SydneyColor = clrDodgerBlue; // Sydney session color input color TokyoColor = clrMediumSeaGreen; // Tokyo session color input color LondonColor = clrGold; // London session color input color NewYorkColor = clrTomato; // New York session color input int LineWidth = 1; // Line width input bool ShowLabels = true; // Show session labels input bool ShowHighLow = true; // Show high/low prices // Buffers for session high/low double SydneyHighBuffer[]; double SydneyLowBuffer[]; double TokyoHighBuffer[]; double TokyoLowBuffer[]; double LondonHighBuffer[]; double LondonLowBuffer[]; double NewYorkHighBuffer[]; double NewYorkLowBuffer[]; // Global variables int SydneyStartHour, SydneyStartMin; int SydneyEndHour, SydneyEndMin; int TokyoStartHour, TokyoStartMin; int TokyoEndHour, TokyoEndMin; int LondonStartHour, LondonStartMin; int LondonEndHour, LondonEndMin; int NewYorkStartHour, NewYorkStartMin; int NewYorkEndHour, NewYorkEndMin; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { // Parse session times ParseTime(SydneyStart, SydneyStartHour, SydneyStartMin); ParseTime(SydneyEnd, SydneyEndHour, SydneyEndMin); ParseTime(TokyoStart, TokyoStartHour, TokyoStartMin); ParseTime(TokyoEnd, TokyoEndHour, TokyoEndMin); ParseTime(LondonStart, LondonStartHour, LondonStartMin); ParseTime(LondonEnd, LondonEndHour, LondonEndMin); ParseTime(NewYorkStart, NewYorkStartHour, NewYorkStartMin); ParseTime(NewYorkEnd, NewYorkEndHour, NewYorkEndMin); // Set indicator properties SetIndexBuffer(0, SydneyHighBuffer, INDICATOR_DATA); SetIndexBuffer(1, SydneyLowBuffer, INDICATOR_DATA); SetIndexBuffer(2, TokyoHighBuffer, INDICATOR_DATA); SetIndexBuffer(3, TokyoLowBuffer, INDICATOR_DATA); SetIndexBuffer(4, LondonHighBuffer, INDICATOR_DATA); SetIndexBuffer(5, LondonLowBuffer, INDICATOR_DATA); SetIndexBuffer(6, NewYorkHighBuffer, INDICATOR_DATA); SetIndexBuffer(7, NewYorkLowBuffer, INDICATOR_DATA); // Set drawing styles PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE); PlotIndexSetInteger(0, PLOT_LINE_COLOR, SydneyColor); PlotIndexSetInteger(0, PLOT_LINE_WIDTH, LineWidth); PlotIndexSetString(0, PLOT_LABEL, "Sydney High"); PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE); PlotIndexSetInteger(1, PLOT_LINE_COLOR, SydneyColor); PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_DOT); PlotIndexSetInteger(1, PLOT_LINE_WIDTH, LineWidth); PlotIndexSetString(1, PLOT_LABEL, "Sydney Low"); PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_LINE); PlotIndexSetInteger(2, PLOT_LINE_COLOR, TokyoColor); PlotIndexSetInteger(2, PLOT_LINE_WIDTH, LineWidth); PlotIndexSetString(2, PLOT_LABEL, "Tokyo High"); PlotIndexSetInteger(3, PLOT_DRAW_TYPE, DRAW_LINE); PlotIndexSetInteger(3, PLOT_LINE_COLOR, TokyoColor); PlotIndexSetInteger(3, PLOT_LINE_STYLE, STYLE_DOT); PlotIndexSetInteger(3, PLOT_LINE_WIDTH, LineWidth); PlotIndexSetString(3, PLOT_LABEL, "Tokyo Low"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 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[]) { // Check if we have enough data if(rates_total < 2) return(0); // Set all buffers to EMPTY_VALUE initially ArrayInitialize(SydneyHighBuffer, EMPTY_VALUE); ArrayInitialize(SydneyLowBuffer, EMPTY_VALUE); ArrayInitialize(TokyoHighBuffer, EMPTY_VALUE); ArrayInitialize(TokyoLowBuffer, EMPTY_VALUE); ArrayInitialize(LondonHighBuffer, EMPTY_VALUE); ArrayInitialize(LondonLowBuffer, EMPTY_VALUE); ArrayInitialize(NewYorkHighBuffer, EMPTY_VALUE); ArrayInitialize(NewYorkLowBuffer, EMPTY_VALUE); // Calculate start position int start = (prev_calculated == 0) ? 0 : prev_calculated - 1; // Main calculation loop for(int i = start; i < rates_total; i++) { MqlDateTime dt; TimeToStruct(time[i], dt); // Check if current time is within any session bool inSydney = IsInSession(dt.hour, dt.min, SydneyStartHour, SydneyStartMin, SydneyEndHour, SydneyEndMin); bool inTokyo = IsInSession(dt.hour, dt.min, TokyoStartHour, TokyoStartMin, TokyoEndHour, TokyoEndMin); bool inLondon = IsInSession(dt.hour, dt.min, LondonStartHour, LondonStartMin, LondonEndHour, LondonEndMin); bool inNewYork = IsInSession(dt.hour, dt.min, NewYorkStartHour, NewYorkStartMin, NewYorkEndHour, NewYorkEndMin); // Find session boundaries and calculate high/low if(inSydney) { CalculateSessionHighLow(i, rates_total, time, high, low, SydneyHighBuffer, SydneyLowBuffer, SydneyStartHour, SydneyStartMin, SydneyEndHour, SydneyEndMin); } if(inTokyo) { CalculateSessionHighLow(i, rates_total, time, high, low, TokyoHighBuffer, TokyoLowBuffer, TokyoStartHour, TokyoStartMin, TokyoEndHour, TokyoEndMin); } if(inLondon) { CalculateSessionHighLow(i, rates_total, time, high, low, LondonHighBuffer, LondonLowBuffer, LondonStartHour, LondonStartMin, LondonEndHour, LondonEndMin); } if(inNewYork) { CalculateSessionHighLow(i, rates_total, time, high, low, NewYorkHighBuffer, NewYorkLowBuffer, NewYorkStartHour, NewYorkStartMin, NewYorkEndHour, NewYorkEndMin); } // Add labels if enabled if(ShowLabels && i == rates_total - 1) { AddSessionLabels(time[rates_total-1], high[rates_total-1], low[rates_total-1]); } } return(rates_total); } //+------------------------------------------------------------------+ //| Parse time string into hours and minutes | //+------------------------------------------------------------------+ void ParseTime(string timeStr, int &hour, int &min) { string parts[]; StringSplit(timeStr, ':', parts); hour = (int)StringToInteger(parts[0]); min = (ArraySize(parts) > 1) ? (int)StringToInteger(parts[1]) : 0; } //+------------------------------------------------------------------+ //| Check if current time is within a session | //+------------------------------------------------------------------+ bool IsInSession(int currentHour, int currentMin, int startHour, int startMin, int endHour, int endMin) { int currentTime = currentHour * 100 + currentMin; int sessionStart = startHour * 100 + startMin; int sessionEnd = endHour * 100 + endMin; // Handle sessions that cross midnight if(sessionStart > sessionEnd) { return(currentTime >= sessionStart || currentTime < sessionEnd); } else { return(currentTime >= sessionStart && currentTime < sessionEnd); } } //+------------------------------------------------------------------+ //| Calculate session high and low | //+------------------------------------------------------------------+ void CalculateSessionHighLow(int index, int rates_total, const datetime &time[], const double &high[], const double &low[], double &highBuffer[], double &lowBuffer[], int startHour, int startMin, int endHour, int endMin) { // Find the start of the current session MqlDateTime currentDt, sessionStartDt; TimeToStruct(time[index], currentDt); TimeToStruct(time[index], sessionStartDt); sessionStartDt.hour = startHour; sessionStartDt.min = startMin; sessionStartDt.sec = 0; datetime sessionStartTime = StructToTime(sessionStartDt); // If session crosses midnight, adjust the start time int sessionStart = startHour * 100 + startMin; int sessionEnd = endHour * 100 + endMin; if(sessionStart > sessionEnd) { // Session crosses midnight, check if we need to use previous day int currentTime = currentDt.hour * 100 + currentDt.min; if(currentTime < sessionEnd) { sessionStartTime -= 86400; // Subtract one day } } // Find the bar index for the session start int sessionStartIndex = iBarShift(NULL, 0, sessionStartTime); if(sessionStartIndex < 0) sessionStartIndex = 0; // Calculate high and low for the session double sessionHigh = high[sessionStartIndex]; double sessionLow = low[sessionStartIndex]; for(int j = sessionStartIndex; j <= index; j++) { if(j >= rates_total) continue; if(high[j] > sessionHigh) sessionHigh = high[j]; if(low[j] < sessionLow) sessionLow = low[j]; } // Store the values in buffers highBuffer[index] = sessionHigh; lowBuffer[index] = sessionLow; // If ShowHighLow is enabled, draw the levels if(ShowHighLow && index == rates_total - 1) { string sessionName = ""; color sessionClr = clrNONE; if(startHour == SydneyStartHour && startMin == SydneyStartMin) { sessionName = "Sydney"; sessionClr = SydneyColor; } else if(startHour == TokyoStartHour && startMin == TokyoStartMin) { sessionName = "Tokyo"; sessionClr = TokyoColor; } else if(startHour == LondonStartHour && startMin == LondonStartMin) { sessionName = "London"; sessionClr = LondonColor; } else if(startHour == NewYorkStartHour && startMin == NewYorkStartMin) { sessionName = "NewYork"; sessionClr = NewYorkColor; } if(sessionName != "") { string highLabel = sessionName + " High: " + DoubleToString(sessionHigh, _Digits); string lowLabel = sessionName + " Low: " + DoubleToString(sessionLow, _Digits); ObjectCreate(0, highLabel, OBJ_HLINE, 0, 0, sessionHigh); ObjectSetInteger(0, highLabel, OBJPROP_COLOR, sessionClr); ObjectSetInteger(0, highLabel, OBJPROP_WIDTH, LineWidth); ObjectSetInteger(0, highLabel, OBJPROP_BACK, true); ObjectCreate(0, lowLabel, OBJ_HLINE, 0, 0, sessionLow); ObjectSetInteger(0, lowLabel, OBJPROP_COLOR, sessionClr); ObjectSetInteger(0, lowLabel, OBJPROP_WIDTH, LineWidth); ObjectSetInteger(0, lowLabel, OBJPROP_STYLE, STYLE_DOT); ObjectSetInteger(0, lowLabel, OBJPROP_BACK, true); } } } //+------------------------------------------------------------------+ //| Add session labels to the chart | //+------------------------------------------------------------------+ void AddSessionLabels(datetime currentTime, double currentHigh, double currentLow) { MqlDateTime dt; TimeToStruct(currentTime, dt); // Remove previous labels ObjectsDeleteAll(0, "SessionLabel_"); if(IsInSession(dt.hour, dt.min, SydneyStartHour, SydneyStartMin, SydneyEndHour, SydneyEndMin)) { ObjectCreate(0, "SessionLabel_Sydney", OBJ_TEXT, 0, currentTime, currentHigh + 10 * _Point); ObjectSetString(0, "SessionLabel_Sydney", OBJPROP_TEXT, "Sydney Session"); ObjectSetInteger(0, "SessionLabel_Sydney", OBJPROP_COLOR, SydneyColor); ObjectSetInteger(0, "SessionLabel_Sydney", OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); } if(IsInSession(dt.hour, dt.min, TokyoStartHour, TokyoStartMin, TokyoEndHour, TokyoEndMin)) { ObjectCreate(0, "SessionLabel_Tokyo", OBJ_TEXT, 0, currentTime, currentHigh + 20 * _Point); ObjectSetString(0, "SessionLabel_Tokyo", OBJPROP_TEXT, "Tokyo Session"); ObjectSetInteger(0, "SessionLabel_Tokyo", OBJPROP_COLOR, TokyoColor); ObjectSetInteger(0, "SessionLabel_Tokyo", OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); } if(IsInSession(dt.hour, dt.min, LondonStartHour, LondonStartMin, LondonEndHour, LondonEndMin)) { ObjectCreate(0, "SessionLabel_London", OBJ_TEXT, 0, currentTime, currentHigh + 30 * _Point); ObjectSetString(0, "SessionLabel_London", OBJPROP_TEXT, "London Session"); ObjectSetInteger(0, "SessionLabel_London", OBJPROP_COLOR, LondonColor); ObjectSetInteger(0, "SessionLabel_London", OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); } if(IsInSession(dt.hour, dt.min, NewYorkStartHour, NewYorkStartMin, NewYorkEndHour, NewYorkEndMin)) { ObjectCreate(0, "SessionLabel_NewYork", OBJ_TEXT, 0, currentTime, currentHigh + 40 * _Point); ObjectSetString(0, "SessionLabel_NewYork", OBJPROP_TEXT, "New York Session"); ObjectSetInteger(0, "SessionLabel_NewYork", OBJPROP_COLOR, NewYorkColor); ObjectSetInteger(0, "SessionLabel_NewYork", OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); } } //+------------------------------------------------------------------+