//+------------------------------------------------------------------+ //| iForexSessions.mq5 | //| Copyright © 2018, Amr Ali | //| https://www.mql5.com/en/users/amrali | //+------------------------------------------------------------------+ #property copyright "Copyright © 2018, Amr Ali" #property link "https://www.mql5.com/en/users/amrali" #property version "1.99" #property description "Forex Sessions indicator" #property description "Highlights the Forex Market Sessions" #property description "The indicator assumes local \"wall clock\" trading hours of 8:00 AM - 5:00 PM in " #property description "each Forex market, except in Sydney it is 7:00 AM - 4:00 PM or 9:00 AM - 6:00 PM." #property indicator_chart_window #property indicator_buffers 0 #property indicator_plots 0 #include #include "SessionHours.mqh" //+------------------------------------------------------------------+ //--- input parameters input int InpNumDays = 35; // Number of days to display input color InpColorSydney = clrPurple; // Sydney session color input color InpColorTokyo = clrTeal; // Tokyo session color input color InpColorLondon = clrMaroon; // London session color input color InpColorNewYork = clrDarkBlue; // NewYork session color input bool InpShowLabels = true; // Show session labels input bool InpShowVLines = true; // Show sydney-session start lines input bool InpShowClock = true; // Show broker's clock (left lower corner) input bool InpShowGrid = false; // Show grid in the chart input bool InpUseGoldSymbol = true; // Load XAUUSD symbol for estimation of the server's TZ/DST //+------------------------------------------------------------------+ //--- global variables string obj_name_prefix=MQLInfoString(MQL_PROGRAM_NAME); int WidthScreen; int HeightScreen; CCanvas canv; bool canv_on=false; bool ready_H1=false; bool chart_grid; enum ENUM_SESSIONS { SYD = 0, TOK = 1, LON = 2, NYC = 3 }; struct SBrokerSession { datetime BeginBroker; // session time begin in broker time datetime EndBroker; // session time end in broker time }; SBrokerSession Sessions[][4]; // 2d array of 4 sessions for n days //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { if(Period()>PERIOD_H4) { Alert("This indicator works only on H4 charts and lower"); } //--- timer if(InpShowClock) { EventSetTimer(1); } //--- remember chart grid flag ChartGetInteger(0,CHART_SHOW_GRID,chart_grid); //--- set chart grid flag ChartSetInteger(0,CHART_SHOW_GRID,InpShowGrid); ChartRedraw(); //--- create canvas to output debug info WidthScreen =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); HeightScreen=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); ChartSetInteger(0,CHART_FOREGROUND,false); if(!canv.CreateBitmapLabel(0,0,"Canvas07",0,0,WidthScreen,HeightScreen,COLOR_FORMAT_ARGB_NORMALIZE)) Print("Error creating canvas: ",GetLastError()); canv.FontSet("Courier New",18); canv.FontFlagsSet(FW_SEMIBOLD); ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true); //--- set the option of using Gold symbol for estimation of the server's TZ/DST CTimeZoneInfo::SetUsingGoldSymbol(InpUseGoldSymbol); //--- Initialization completed successfully return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- delete timer EventKillTimer(); //--- delete canvas canv.Destroy(); //---- restore chart grid ChartSetInteger(0,CHART_SHOW_GRID,chart_grid); //--- delete objects ObjectsDeleteAll(0,obj_name_prefix); ChartRedraw(); } //+------------------------------------------------------------------+ //| 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[]) { ENUM_TIMEFRAMES P=Period(); if(P > PERIOD_H4) return(0); //--- make sure that H1 timeframe is loaded. datetime timeH1=iTime(NULL,PERIOD_H1,0); if(timeH1==0) { datetime times[]; if(CopyTime(Symbol(),PERIOD_H1,time[0],1,times)<=0) { ChartSetSymbolPeriod(0,NULL,P); // emulate a tick } ready_H1=false; return(0); } ready_H1=true; //--- draw only if a new hourly bar has arrived static datetime prevtime; if(timeH1 == prevtime) return(0); else prevtime=timeH1; //--- GetForexSessions(Sessions,InpNumDays); DrawSessions(Sessions); ChartRedraw(); //--- return(0); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_CHART_CHANGE) { if(ready_H1) { GetForexSessions(Sessions,InpNumDays); DrawSessions(Sessions); ChartRedraw(); } WidthScreen =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); HeightScreen=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); canv.Resize(WidthScreen,HeightScreen); } if(id==CHARTEVENT_MOUSE_MOVE) { //--- moving the mouse on a chart while the "Ctrl" key is pressed if(TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL)) { int x =(int)lparam; int y =(int)dparam; datetime time =0; double price =0; int window=0; //--- convert the X and Y coordinates in terms of time/price if(ChartXYToTimePrice(0,x,y,window,time,price)) { int i1=iBarShift(_Symbol,_Period,time); datetime bartime = iTime(_Symbol,_Period,i1); bool dst = CTimeZoneInfo::IsDaylightSavingsTime(ZONE_ID_BROKER, bartime); //--- ChartTimePriceToXY(0,window,bartime,price,x,y); canv.Erase(0); canv.LineVertical(x,HeightScreen-1,0,ColorToARGB(clrRed)); canv.TextOut(WidthScreen-600,HeightScreen-170,"bar #"+IntegerToString(i1),ColorToARGB(dst ? clrYellow: clrOrange)); canv.TextOut(WidthScreen-600,HeightScreen-150,CTimeZoneInfo::FormatTimeForPlace(bartime, ZONE_ID_BROKER),ColorToARGB(dst ? clrYellow: clrOrange)); //--- ENUM_ZONE_ID ids[]= {ZONE_ID_SYDNEY, ZONE_ID_TOKYO, ZONE_ID_LONDON, ZONE_ID_NEWYORK}; for(int i = 0; i < ArraySize(ids); i++) { ENUM_ZONE_ID id = ids[i]; datetime converted = CTimeZoneInfo::ConvertTimeForPlace(bartime, ZONE_ID_BROKER, id); dst = CTimeZoneInfo::IsDaylightSavingsTime(id, converted); //PrintFormat("bar #%d | %s | %s", i1, CTimeZoneInfo::FormatTimeForPlace(bartime, ZONE_ID_BROKER), CTimeZoneInfo::FormatTimeForPlace(converted, id)); canv.TextOut(WidthScreen-600,HeightScreen-130+i*20,CTimeZoneInfo::FormatTimeForPlace(converted, id),ColorToARGB(dst ? clrYellow: clrOrange)); } canv.Update(); canv_on=true; } } //--- moving the mouse on a chart while the "Ctrl" key is released else if(canv_on) { canv.Erase(0); canv.Update(); canv_on=false; } } } //+------------------------------------------------------------------+ //| Custom indicator timer function | //+------------------------------------------------------------------+ void OnTimer() { UpdateBrokerClock(); ChartRedraw(); } //+------------------------------------------------------------------+ //| Get forex market sessions for the specified num of days. | //+------------------------------------------------------------------+ int GetForexSessions(SBrokerSession &BrokerSessions[][4], int numDays=9) { ArrayFree(BrokerSessions); if(numDays <= 0) return(0); ArrayResize(BrokerSessions,numDays); //--- Forex pairs start at 17:00 NY. Gold starts an hour later. string beginNYC = "17:00"; if(StringSubstr(Symbol(),0,3)=="XAU"||StringSubstr(Symbol(),0,4)=="GOLD") { beginNYC = "18:00"; } int day = 0; int bars = iBars(NULL,PERIOD_H1); for(int i = 0; i < bars; i++) { datetime bartime = iTime(NULL,PERIOD_H1,i); datetime tNYC = CTimeZoneInfo::ConvertTimeForPlace(bartime, ZONE_ID_BROKER, ZONE_ID_NEWYORK); if(TimeToString(tNYC,TIME_MINUTES) == beginNYC) // find the H1 bar matching Fx opening in NY. { //--- server time corresponding to forex opening at 5 pm in New York (or 6 pm for gold) BrokerSessions[day][SYD].BeginBroker = bartime; BrokerSessions[day][SYD].EndBroker = bartime + 9*PeriodSeconds(PERIOD_H1); //--- set session hours to 8:00 am - 5:00 pm local time datetime beginlocal = StringToTime(TimeToString(tNYC+PeriodSeconds(PERIOD_D1), TIME_DATE) + " " + "08:00"); datetime endlocal = StringToTime(TimeToString(tNYC+PeriodSeconds(PERIOD_D1), TIME_DATE) + " " + "17:00"); //--- conversion to broker time BrokerSessions[day][TOK].BeginBroker = CTimeZoneInfo::ConvertTimeForPlace(beginlocal, ZONE_ID_TOKYO, ZONE_ID_BROKER); BrokerSessions[day][TOK].EndBroker = CTimeZoneInfo::ConvertTimeForPlace(endlocal, ZONE_ID_TOKYO, ZONE_ID_BROKER); BrokerSessions[day][LON].BeginBroker = CTimeZoneInfo::ConvertTimeForPlace(beginlocal, ZONE_ID_LONDON, ZONE_ID_BROKER); BrokerSessions[day][LON].EndBroker = CTimeZoneInfo::ConvertTimeForPlace(endlocal, ZONE_ID_LONDON, ZONE_ID_BROKER); BrokerSessions[day][NYC].BeginBroker = CTimeZoneInfo::ConvertTimeForPlace(beginlocal, ZONE_ID_NEWYORK, ZONE_ID_BROKER); BrokerSessions[day][NYC].EndBroker = CTimeZoneInfo::ConvertTimeForPlace(endlocal, ZONE_ID_NEWYORK, ZONE_ID_BROKER); //--- if(++day>=numDays) break; } } numDays = MathMin(numDays,day); ArrayResize(BrokerSessions,numDays); // ArrayPrint(BrokerSessions); //--- return(numDays); } //+------------------------------------------------------------------+ //| Create vertical lines and colored rectangles for forex sessions | //+------------------------------------------------------------------+ void DrawSessions(SBrokerSession &BrokerSessions[][4]) { string obj_name, tooltip; datetime time1, time2; double price1, price2; color sColor; double high[]; double dayhigh; bool weekstart; //--- string session_names[]= {"Sydney","Tokyo","London","NewYork"}; string session_labels[]= {"SYD","TOK","LON","NYC"}; color session_colors[4]; session_colors[0]=InpColorSydney; session_colors[1]=InpColorTokyo; session_colors[2]=InpColorLondon; session_colors[3]=InpColorNewYork; //--- find the highest and lowest values of the chart double max_price=ChartGetDouble(0,CHART_PRICE_MAX); double min_price=ChartGetDouble(0,CHART_PRICE_MIN); double height=(max_price-min_price)/70; //--- delete objects ObjectsDeleteAll(0,obj_name_prefix); //--- for(int i = 0; i < ArrayRange(BrokerSessions, 0); i++) { if(InpShowVLines) { //--- Show sydney-session start lines time1 = BrokerSessions[i][SYD].BeginBroker; obj_name = obj_name_prefix+": "+CTimeZoneInfo::FormatTimeForPlace(time1, ZONE_ID_BROKER, false, false); weekstart = (i+1 < ArrayRange(BrokerSessions, 0)) && (time1 - BrokerSessions[i+1][SYD].BeginBroker > 24*3600); sColor = weekstart ? clrDarkOrange : clrWheat; VLineCreate(obj_name,time1,sColor,STYLE_DASHDOTDOT); //--- Show day of week text label int shift = iBarShift(Symbol(),0,time1); double low = iLow(Symbol(),0,shift); string wkday = EnumToString((ENUM_DAY_OF_WEEK)(((uint)time1 / 86400 + 4) % 7)); TextCreate(obj_name+"_wkday",wkday,time1,low-50*_Point,sColor); } int copied=CopyHigh(Symbol(),PERIOD_H1,BrokerSessions[i][SYD].BeginBroker,BrokerSessions[i][NYC].EndBroker,high); if(copied<=0) continue; dayhigh=high[ArrayMaximum(high)]; for(int s = 0; s < ArraySize(session_names); s++) { obj_name = obj_name_prefix+session_names[s]+"Rect"+(string)i; time1 = BrokerSessions[i][s].BeginBroker; time2 = BrokerSessions[i][s].EndBroker; price1 = dayhigh + (height*1.3)*(4-s); price2 = price1 - height; sColor = session_colors[s]; tooltip = session_names[s]+" session from "+TimeToString(time1,TIME_MINUTES)+" to "+TimeToString(time2,TIME_MINUTES)+" (server time)"; RectangleCreate(obj_name,time1,price1,time2,price2,sColor,tooltip); //--- if(InpShowLabels) { obj_name = obj_name_prefix+session_names[s]+"Text"+(string)i; tooltip = session_labels[s]+" "+TimeToString(time1,TIME_MINUTES); TextCreate(obj_name,tooltip,time1,price1-(height/2),clrWheat); } } } //--- } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void UpdateBrokerClock() { string obj_name, text; int x_, y_; color sColor; //--- int sec = CSessionHours::SecRemainingForex(); datetime forexCloseTime = CSessionHours::ForexCloseTime(); int shiftInSeconds = CheckTimeSync(); //--- string brokers_labels[4][2] = { {"Server Time : ", CTimeZoneInfo::FormatTimeForPlace(TimeTradeServer(), ZONE_ID_BROKER)}, {"Closing Time : ", CTimeZoneInfo::FormatTimeForPlace(forexCloseTime, ZONE_ID_BROKER)}, {"Remaining sec : ", StringFormat("%i sec = %s %s", sec, CSessionHours::SecondsToString(sec), sec ? sec >= 7200 ? "" : " (closing soon)" : " (market closed)")}, {"PC Time sync : ", shiftInSeconds < 30 ? "Ok" : StringFormat("Shift of pc time is %i sec - Check www.time.is", shiftInSeconds)} }; //--- for(int i = 0; i < ArrayRange(brokers_labels,0); i++) for(int j = 0; j < ArrayRange(brokers_labels,1); j++) { obj_name = obj_name_prefix+"BrokerLabel_"+(string)(i+4*j); text = brokers_labels[i][j]; x_ = 12+112*j; y_ = 72-14*i; sColor = sec != 0 ? clrWheat : clrDarkGray; LabelCreate(obj_name,text,x_,y_,sColor); } } //+------------------------------------------------------------------+ //| Check the time synchronization of the local computer. | //+------------------------------------------------------------------+ int CheckTimeSync() { static datetime current, before; static int shiftInSeconds = 0; before = current; current = TimeCurrent(); //--- if it is the first call of the function if(before == 0) return(0); //--- if the server is not "frozen" due to weekends/holidays if(current != before) { shiftInSeconds = (int)(TimeTradeServer() - current); } return(shiftInSeconds); } //+------------------------------------------------------------------+ //| Create the vertical line | //+------------------------------------------------------------------+ void VLineCreate(string name, datetime time, color clr, ENUM_LINE_STYLE style=STYLE_SOLID, int width=1) { ObjectCreate(0,name,OBJ_VLINE,0,time,0); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); ObjectSetInteger(0,name,OBJPROP_STYLE,style); ObjectSetInteger(0,name,OBJPROP_WIDTH,width); ObjectSetInteger(0,name,OBJPROP_BACK,false); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,name,OBJPROP_SELECTED,false); } //+------------------------------------------------------------------+ //| Create rectangle by the given coordinates | //+------------------------------------------------------------------+ void RectangleCreate(string name, datetime time1, double price1, datetime time2, double price2, color clr, string tooltip) { ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2); ObjectSetString(0,name,OBJPROP_TOOLTIP,tooltip); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); ObjectSetInteger(0,name,OBJPROP_WIDTH,1); ObjectSetInteger(0,name,OBJPROP_FILL,true); ObjectSetInteger(0,name,OBJPROP_BACK,true); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,name,OBJPROP_SELECTED,false); } //+------------------------------------------------------------------+ //| Creating Text object | //+------------------------------------------------------------------+ void TextCreate(string name, string text, datetime time, double price, color clr=clrWhiteSmoke) { ObjectCreate(0,name,OBJ_TEXT,0,time,price); ObjectSetString(0,name,OBJPROP_TEXT,text); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT); ObjectSetDouble(0,name,OBJPROP_ANGLE,0.00); ObjectSetString(0,name,OBJPROP_FONT,"Lucida Console"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,name,OBJPROP_BACK,true); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,name,OBJPROP_SELECTED,false); } //+------------------------------------------------------------------+ //| Create a text label | //+------------------------------------------------------------------+ void LabelCreate(string name, string text, int x, int y, color clr=clrWhiteSmoke) { ObjectCreate(0,name,OBJ_LABEL,0,0,0); ObjectSetString(0,name,OBJPROP_TEXT,text); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_LOWER); ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT); ObjectSetDouble(0,name,OBJPROP_ANGLE,0.00); ObjectSetString(0,name,OBJPROP_FONT,"Lucida Console"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8); ObjectSetInteger(0,name,OBJPROP_BACK,false); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,name,OBJPROP_SELECTED,false); } //+------------------------------------------------------------------+