| //+------------------------------------------------------------------+
|
| //| ForexSessionsPanel.mq5 |
|
| //| Sydney / Tokyo / London / New York sessions with automatic DST |
|
| //| Chart boxes + info panel | Bilingual (FA/EN) inputs |
|
| //+------------------------------------------------------------------+
|
| #property copyright "Forex Sessions Panel"
|
| #property version "2.00"
|
| #property description "Forex sessions (Sydney, Tokyo, London, New York) with automatic DST detection."
|
| #property description "Session times are entered in each market's LOCAL time; UTC conversion is automatic."
|
| #property indicator_chart_window
|
| #property indicator_buffers 0
|
| #property indicator_plots 0
|
|
|
| #define PREFIX "FSP_"
|
|
|
| //--- DST rule ids
|
| #define RULE_NONE 0
|
| #define RULE_US 1
|
| #define RULE_EU 2
|
| #define RULE_AU 3
|
|
|
| //--- enums (the comment after each item is shown in the dropdown)
|
| enum ENUM_SERVER_MODE
|
| {
|
| SRV_AUTO_US = 0, // Auto - US DST rule (recommended) | خودکار - قانون ساعت تابستانی آمریکا (پیشنهادی)
|
| SRV_AUTO_EU = 1, // Auto - EU DST rule | خودکار - قانون ساعت تابستانی اروپا
|
| SRV_DETECT = 2, // Live detect from terminal | تشخیص زنده از ترمینال (فقط چارت زنده)
|
| SRV_FIXED = 3 // Fixed, no DST | ثابت و بدون تغییر ساعت
|
| };
|
|
|
| enum ENUM_DISPLAY_TZ
|
| {
|
| TZ_SERVER = 0, // Broker server time | ساعت سرور بروکر
|
| TZ_UTC = 1, // UTC / GMT | ساعت جهانی UTC
|
| TZ_LOCAL = 2 // My computer time | ساعت کامپیوتر من
|
| };
|
|
|
| //+==================================================================+
|
| //| INPUTS |
|
| //+==================================================================+
|
| input group "██ بخش ۱ ▪ تنظیمات زمان و ساعت تابستانی ▪ SECTION 1 · TIME & DST ██"
|
| input ENUM_SERVER_MODE InpServerMode = SRV_AUTO_US; // حالت ساعت سرور بروکر | Broker server time mode
|
| input double InpServerWinterGMT = 2.0; // اختلاف سرور با GMT در زمستان (ساعت) | Server GMT offset in winter (h)
|
| input bool InpAutoSessionDST = true; // تغییر خودکار ساعت تابستانی سشنها | Auto DST for sessions
|
| input ENUM_DISPLAY_TZ InpDisplayTZ = TZ_SERVER; // منطقه زمانی نمایش در جدول | Panel time zone
|
|
|
| input group "██ بخش ۲ ▪ تنظیمات نمایش سشنها ▪ SECTION 2 · DISPLAY OPTIONS ██"
|
| input int InpDaysBack = 5; // تعداد روزهای گذشته روی چارت | Days of history on chart
|
| input bool InpSkipWeekends = true; // حذف سشنهای زمان تعطیلی بازار | Skip market-closed sessions
|
|
|
| input group "██ بخش ۳ ▪ سشن سیدنی (ساعت محلی سیدنی) ▪ SECTION 3 · SYDNEY (local) ██"
|
| input bool InpSydShow = true; // نمایش این سشن | Show session
|
| input int InpSydSH = 8; // ساعت شروع | Start hour
|
| input int InpSydSM = 0; // دقیقه شروع | Start minute
|
| input int InpSydEH = 17; // ساعت پایان | End hour
|
| input int InpSydEM = 0; // دقیقه پایان | End minute
|
| input color InpSydClr = C'30,60,110'; // رنگ سشن | Session color
|
|
|
| input group "██ بخش ۴ ▪ سشن آسیا - توکیو (ساعت محلی ژاپن) ▪ SECTION 4 · ASIA / TOKYO (local) ██"
|
| input bool InpTokShow = true; // نمایش این سشن | Show session
|
| input int InpTokSH = 9; // ساعت شروع | Start hour
|
| input int InpTokSM = 0; // دقیقه شروع | Start minute
|
| input int InpTokEH = 18; // ساعت پایان | End hour
|
| input int InpTokEM = 0; // دقیقه پایان | End minute
|
| input color InpTokClr = C'110,45,45'; // رنگ سشن | Session color
|
|
|
| input group "██ بخش ۵ ▪ سشن لندن (ساعت محلی لندن) ▪ SECTION 5 · LONDON (local) ██"
|
| input bool InpLonShow = true; // نمایش این سشن | Show session
|
| input int InpLonSH = 8; // ساعت شروع | Start hour
|
| input int InpLonSM = 0; // دقیقه شروع | Start minute
|
| input int InpLonEH = 17; // ساعت پایان | End hour
|
| input int InpLonEM = 0; // دقیقه پایان | End minute
|
| input color InpLonClr = C'30,95,50'; // رنگ سشن | Session color
|
|
|
| input group "██ بخش ۶ ▪ سشن نیویورک (ساعت محلی نیویورک) ▪ SECTION 6 · NEW YORK (local) ██"
|
| input bool InpNYShow = true; // نمایش این سشن | Show session
|
| input int InpNYSH = 8; // ساعت شروع | Start hour
|
| input int InpNYSM = 0; // دقیقه شروع | Start minute
|
| input int InpNYEH = 17; // ساعت پایان | End hour
|
| input int InpNYEM = 0; // دقیقه پایان | End minute
|
| input color InpNYClr = C'120,90,20'; // رنگ سشن | Session color
|
|
|
| input group "██ بخش ۷ ▪ ظاهر چارت ▪ SECTION 7 · CHART APPEARANCE ██"
|
| input bool InpFillBoxes = true; // پر کردن باکسها | Fill session boxes
|
| input bool InpShowLabels = true; // نمایش نام سشن روی چارت | Show session names
|
|
|
| input group "██ بخش ۸ ▪ پنل اطلاعات ▪ SECTION 8 · INFO PANEL ██"
|
| input bool InpShowPanel = true; // نمایش پنل | Show panel
|
| input bool InpShowOverlap = true; // نمایش جدول همپوشانی همه سشنها | Show all-sessions overlap table
|
| input int InpPanelX = 10; // فاصله از چپ (پیکسل) | X offset (px)
|
| input int InpPanelY = 20; // فاصله از بالا (پیکسل) | Y offset (px)
|
| input int InpFontSize = 9; // اندازه فونت | Font size
|
| input color InpPanelBg = C'25,25,30'; // رنگ پسزمینه پنل | Panel background
|
| input color InpTextClr = clrWhite; // رنگ متن | Text color
|
|
|
| //+------------------------------------------------------------------+
|
| struct SSession
|
| {
|
| string name;
|
| bool show;
|
| int sMin; // start minute of day, market LOCAL time
|
| int eMin; // end minute of day, market LOCAL time
|
| color clr;
|
| int stdOff; // standard (winter) UTC offset in hours
|
| int rule; // DST rule
|
| };
|
|
|
| SSession g_s[4];
|
| int g_tick = 0;
|
|
|
| //+==================================================================+
|
| //| DATE / DST HELPERS |
|
| //+==================================================================+
|
| datetime MakeDT(int y, int m, int d, int h)
|
| {
|
| MqlDateTime t;
|
| t.year = y; t.mon = m; t.day = d; t.hour = h; t.min = 0; t.sec = 0;
|
| return StructToTime(t);
|
| }
|
| //+------------------------------------------------------------------+
|
| int DayOfWeekOf(int y, int m, int d)
|
| {
|
| MqlDateTime t;
|
| t.year = y; t.mon = m; t.day = d; t.hour = 12; t.min = 0; t.sec = 0;
|
| datetime dt = StructToTime(t);
|
| TimeToStruct(dt, t);
|
| return t.day_of_week; // 0 = Sunday
|
| }
|
| //+------------------------------------------------------------------+
|
| int DaysInMonth(int y, int m)
|
| {
|
| int dm[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
| bool leap = ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0));
|
| if(m == 2 && leap) return 29;
|
| return dm[m - 1];
|
| }
|
| //+------------------------------------------------------------------+
|
| int NthSunday(int y, int m, int n)
|
| {
|
| int dow = DayOfWeekOf(y, m, 1);
|
| int first = (dow == 0) ? 1 : (8 - dow);
|
| return first + 7 * (n - 1);
|
| }
|
| //+------------------------------------------------------------------+
|
| int LastSunday(int y, int m)
|
| {
|
| int dim = DaysInMonth(y, m);
|
| int dow = DayOfWeekOf(y, m, dim);
|
| return dim - dow;
|
| }
|
| //+------------------------------------------------------------------+
|
| int YearOf(datetime u)
|
| {
|
| MqlDateTime t;
|
| TimeToStruct(u, t);
|
| return t.year;
|
| }
|
| //+------------------------------------------------------------------+
|
| // US: 2nd Sunday of March 07:00 UTC -> 1st Sunday of November 06:00 UTC
|
| bool IsUSDST(datetime u)
|
| {
|
| int y = YearOf(u);
|
| datetime s = MakeDT(y, 3, NthSunday(y, 3, 2), 7);
|
| datetime e = MakeDT(y, 11, NthSunday(y, 11, 1), 6);
|
| return (u >= s && u < e);
|
| }
|
| //+------------------------------------------------------------------+
|
| // EU/UK: last Sunday of March 01:00 UTC -> last Sunday of October 01:00 UTC
|
| bool IsEUDST(datetime u)
|
| {
|
| int y = YearOf(u);
|
| datetime s = MakeDT(y, 3, LastSunday(y, 3), 1);
|
| datetime e = MakeDT(y, 10, LastSunday(y, 10), 1);
|
| return (u >= s && u < e);
|
| }
|
| //+------------------------------------------------------------------+
|
| // Australia (Sydney): 1st Sunday of October -> 1st Sunday of April
|
| bool IsAUDST(datetime u)
|
| {
|
| int y = YearOf(u);
|
| datetime s = (datetime)(MakeDT(y, 10, NthSunday(y, 10, 1), 0) - 8 * 3600);
|
| datetime e = (datetime)(MakeDT(y, 4, NthSunday(y, 4, 1), 0) - 8 * 3600);
|
| return (u >= s || u < e);
|
| }
|
| //+------------------------------------------------------------------+
|
| bool ZoneDST(int rule, datetime u)
|
| {
|
| switch(rule)
|
| {
|
| case RULE_US: return IsUSDST(u);
|
| case RULE_EU: return IsEUDST(u);
|
| case RULE_AU: return IsAUDST(u);
|
| }
|
| return false;
|
| }
|
| //+------------------------------------------------------------------+
|
| long ZoneOffset(int s, datetime u)
|
| {
|
| long o = (long)g_s[s].stdOff * 3600;
|
| if(InpAutoSessionDST && ZoneDST(g_s[s].rule, u)) o += 3600;
|
| return o;
|
| }
|
| //+------------------------------------------------------------------+
|
| long ServerOffsetSec(datetime u)
|
| {
|
| long base = (long)MathRound(InpServerWinterGMT * 3600.0);
|
| switch(InpServerMode)
|
| {
|
| case SRV_AUTO_US: return base + (IsUSDST(u) ? 3600 : 0);
|
| case SRV_AUTO_EU: return base + (IsEUDST(u) ? 3600 : 0);
|
| case SRV_DETECT:
|
| {
|
| long d = (long)(TimeTradeServer() - TimeGMT());
|
| return (long)MathRound((double)d / 900.0) * 900;
|
| }
|
| }
|
| return base;
|
| }
|
| //+------------------------------------------------------------------+
|
| datetime NowUtc()
|
| {
|
| datetime s = TimeTradeServer();
|
| long base = (long)MathRound(InpServerWinterGMT * 3600.0);
|
| long off = ServerOffsetSec((datetime)(s - base));
|
| return (datetime)(s - off);
|
| }
|
| //+------------------------------------------------------------------+
|
| long DisplayOffsetSec(datetime u)
|
| {
|
| if(InpDisplayTZ == TZ_UTC) return 0;
|
| if(InpDisplayTZ == TZ_LOCAL)
|
| {
|
| long d = (long)(TimeLocal() - TimeGMT());
|
| return (long)MathRound((double)d / 900.0) * 900;
|
| }
|
| return ServerOffsetSec(u);
|
| }
|
| //+------------------------------------------------------------------+
|
| string FmtT(datetime utc)
|
| {
|
| datetime t = (datetime)(utc + DisplayOffsetSec(utc));
|
| MqlDateTime m;
|
| TimeToStruct(t, m);
|
| return StringFormat("%02d:%02d", m.hour, m.min);
|
| }
|
| //+------------------------------------------------------------------+
|
| string SecToHMS(long sec)
|
| {
|
| if(sec < 0) sec = 0;
|
| return StringFormat("%02d:%02d:%02d", (int)(sec / 3600), (int)((sec % 3600) / 60), (int)(sec % 60));
|
| }
|
| //+------------------------------------------------------------------+
|
| // Forex market closed: Friday 17:00 New York -> Sunday 17:00 New York
|
| bool MarketClosed(datetime utc)
|
| {
|
| long off = -5 * 3600 + (IsUSDST(utc) ? 3600 : 0);
|
| MqlDateTime t;
|
| TimeToStruct((datetime)(utc + off), t);
|
| if(t.day_of_week == 6) return true;
|
| if(t.day_of_week == 5 && t.hour >= 17) return true;
|
| if(t.day_of_week == 0 && t.hour < 17) return true;
|
| return false;
|
| }
|
| //+==================================================================+
|
| //| SESSION INSTANCES |
|
| //+==================================================================+
|
| // d = day offset relative to the market's own "today" (0 = today, -1 = yesterday ...)
|
| void Instance(int s, int d, datetime nowUtc, datetime &st, datetime &en)
|
| {
|
| long o0 = ZoneOffset(s, nowUtc);
|
| datetime lnow = (datetime)(nowUtc + o0);
|
| datetime ld0 = (datetime)(lnow - (lnow % 86400));
|
| datetime L = (datetime)(ld0 + (long)d * 86400 + (long)g_s[s].sMin * 60);
|
|
|
| long o1 = ZoneOffset(s, (datetime)(L - o0));
|
| st = (datetime)(L - o1);
|
| long o2 = ZoneOffset(s, st);
|
| st = (datetime)(L - o2);
|
|
|
| int dur = (g_s[s].eMin > g_s[s].sMin) ? (g_s[s].eMin - g_s[s].sMin)
|
| : (g_s[s].eMin + 1440 - g_s[s].sMin);
|
| en = (datetime)(st + (long)dur * 60);
|
| }
|
| //+------------------------------------------------------------------+
|
| bool InstValid(datetime a, datetime b)
|
| {
|
| return !MarketClosed((datetime)(a + (b - a) / 2));
|
| }
|
| //+------------------------------------------------------------------+
|
| // Current (or next) instance of a session
|
| void SessionState(int s, datetime nowUtc, bool &open, bool &found, datetime &st, datetime &en)
|
| {
|
| open = false; found = false; st = 0; en = 0;
|
| bool closedNow = MarketClosed(nowUtc);
|
|
|
| for(int d = -1; d <= 4; d++)
|
| {
|
| datetime a, b;
|
| Instance(s, d, nowUtc, a, b);
|
| if(!InstValid(a, b)) continue;
|
|
|
| if(a <= nowUtc && nowUtc < b)
|
| {
|
| open = !closedNow;
|
| found = true; st = a; en = b;
|
| return;
|
| }
|
| if(a > nowUtc && (!found || a < st))
|
| {
|
| found = true; st = a; en = b;
|
| }
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|
| // Current or next overlap between two sessions (s1 < s2)
|
| bool PairOverlap(int s1, int s2, datetime nowUtc, datetime &os, datetime &oe, bool &active)
|
| {
|
| bool found = false;
|
| active = false;
|
| os = 0; oe = 0;
|
| for(int d1 = -1; d1 <= 4; d1++)
|
| {
|
| datetime a1, b1;
|
| Instance(s1, d1, nowUtc, a1, b1);
|
| if(!InstValid(a1, b1)) continue;
|
| for(int d2 = -1; d2 <= 4; d2++)
|
| {
|
| datetime a2, b2;
|
| Instance(s2, d2, nowUtc, a2, b2);
|
| if(!InstValid(a2, b2)) continue;
|
| datetime a = (a1 > a2) ? a1 : a2;
|
| datetime b = (b1 < b2) ? b1 : b2;
|
| if(b > a && b > nowUtc && (!found || a < os))
|
| {
|
| os = a; oe = b; found = true;
|
| }
|
| }
|
| }
|
| if(found)
|
| active = (os <= nowUtc && nowUtc < oe && !MarketClosed(nowUtc));
|
| return found;
|
| }
|
| //+==================================================================+
|
| //| PANEL |
|
| //+==================================================================+
|
| void CreateLabel(const string name, int x, int y, string text, color clr, int size, bool bold = false)
|
| {
|
| if(text == "") text = " ";
|
| string n = PREFIX + name;
|
| if(ObjectFind(0, n) < 0)
|
| {
|
| ObjectCreate(0, n, OBJ_LABEL, 0, 0, 0);
|
| ObjectSetInteger(0, n, OBJPROP_CORNER, CORNER_LEFT_UPPER);
|
| ObjectSetInteger(0, n, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
|
| ObjectSetInteger(0, n, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, n, OBJPROP_HIDDEN, true);
|
| ObjectSetInteger(0, n, OBJPROP_ZORDER, 10);
|
| }
|
| ObjectSetInteger(0, n, OBJPROP_XDISTANCE, x);
|
| ObjectSetInteger(0, n, OBJPROP_YDISTANCE, y);
|
| ObjectSetString(0, n, OBJPROP_FONT, bold ? "Consolas Bold" : "Consolas");
|
| ObjectSetInteger(0, n, OBJPROP_FONTSIZE, size);
|
| ObjectSetInteger(0, n, OBJPROP_COLOR, clr);
|
| ObjectSetString(0, n, OBJPROP_TEXT, text);
|
| }
|
| //+------------------------------------------------------------------+
|
| string GMTText(long offSec)
|
| {
|
| double h = (double)offSec / 3600.0;
|
| string s = DoubleToString(MathAbs(h), (MathMod(MathAbs((double)offSec), 3600.0) == 0.0) ? 0 : 1);
|
| return "GMT" + (h < 0 ? "-" : "+") + s;
|
| }
|
| //+------------------------------------------------------------------+
|
| void UpdatePanel()
|
| {
|
| if(!InpShowPanel) return;
|
|
|
| const int rowH = 20;
|
| const int w = 460;
|
| int x0 = InpPanelX, y0 = InpPanelY;
|
|
|
| datetime nowSrv = TimeTradeServer();
|
| datetime nowUtc = NowUtc();
|
| long srvOff = ServerOffsetSec(nowUtc);
|
|
|
| // --- collect overlaps of all session pairs, sorted by overlap start time
|
| string shortN[4] = {"SYD", "TOK", "LDN", "NY"};
|
| int ovCnt = 0;
|
| int ovA[6], ovB[6], idx[6];
|
| datetime ovS[6], ovE[6];
|
| bool ovAct[6];
|
| if(InpShowOverlap)
|
| {
|
| for(int a = 0; a < 4; a++)
|
| for(int b = a + 1; b < 4; b++)
|
| {
|
| if(!g_s[a].show || !g_s[b].show) continue;
|
| datetime os, oe;
|
| bool act;
|
| if(PairOverlap(a, b, nowUtc, os, oe, act))
|
| {
|
| ovA[ovCnt] = a; ovB[ovCnt] = b;
|
| ovS[ovCnt] = os; ovE[ovCnt] = oe; ovAct[ovCnt] = act;
|
| idx[ovCnt] = ovCnt;
|
| ovCnt++;
|
| }
|
| }
|
| for(int i = 0; i < ovCnt - 1; i++)
|
| for(int j = 0; j < ovCnt - 1 - i; j++)
|
| if(ovS[idx[j]] > ovS[idx[j + 1]])
|
| {
|
| int tmp = idx[j]; idx[j] = idx[j + 1]; idx[j + 1] = tmp;
|
| }
|
| }
|
|
|
| int rows = 8 + (ovCnt > 0 ? ovCnt + 1 : 0);
|
|
|
| // background
|
| string bg = PREFIX + "PanelBG";
|
| if(ObjectFind(0, bg) < 0)
|
| {
|
| ObjectCreate(0, bg, OBJ_RECTANGLE_LABEL, 0, 0, 0);
|
| ObjectSetInteger(0, bg, OBJPROP_CORNER, CORNER_LEFT_UPPER);
|
| ObjectSetInteger(0, bg, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, bg, OBJPROP_HIDDEN, true);
|
| ObjectSetInteger(0, bg, OBJPROP_BORDER_TYPE, BORDER_FLAT);
|
| ObjectSetInteger(0, bg, OBJPROP_ZORDER, 0);
|
| }
|
| ObjectSetInteger(0, bg, OBJPROP_XDISTANCE, x0);
|
| ObjectSetInteger(0, bg, OBJPROP_YDISTANCE, y0);
|
| ObjectSetInteger(0, bg, OBJPROP_XSIZE, w);
|
| ObjectSetInteger(0, bg, OBJPROP_YSIZE, rowH * rows + 10);
|
| ObjectSetInteger(0, bg, OBJPROP_BGCOLOR, InpPanelBg);
|
| ObjectSetInteger(0, bg, OBJPROP_COLOR, C'70,70,80');
|
|
|
| string tzName = (InpDisplayTZ == TZ_SERVER ? "Server" : (InpDisplayTZ == TZ_UTC ? "UTC" : "Local"));
|
| int cx[5] = {10, 115, 185, 255, 345};
|
| int y = y0 + 5;
|
|
|
| CreateLabel("T_Title", x0 + 10, y, "FOREX SESSIONS", clrGold, InpFontSize + 1, true);
|
| y += rowH;
|
|
|
| CreateLabel("T_Clock", x0 + 10, y,
|
| StringFormat("Server %s | UTC %s | Shown: %s",
|
| TimeToString(nowSrv, TIME_MINUTES | TIME_SECONDS),
|
| TimeToString(nowUtc, TIME_MINUTES | TIME_SECONDS),
|
| tzName),
|
| clrSilver, InpFontSize);
|
| y += rowH;
|
|
|
| string dst;
|
| if(InpAutoSessionDST)
|
| dst = StringFormat("%s | DST AU:%s UK:%s US:%s", GMTText(srvOff),
|
| IsAUDST(nowUtc) ? "ON" : "OFF",
|
| IsEUDST(nowUtc) ? "ON" : "OFF",
|
| IsUSDST(nowUtc) ? "ON" : "OFF");
|
| else
|
| dst = StringFormat("%s | Session DST: disabled", GMTText(srvOff));
|
| CreateLabel("T_DST", x0 + 10, y, dst, clrKhaki, InpFontSize);
|
| y += rowH;
|
|
|
| string hdr[5] = {"Session", "Start", "End", "Status", "Remaining"};
|
| for(int c = 0; c < 5; c++)
|
| CreateLabel("H_" + IntegerToString(c), x0 + cx[c], y, hdr[c], clrDeepSkyBlue, InpFontSize, true);
|
| y += rowH;
|
|
|
| bool closedNow = MarketClosed(nowUtc);
|
|
|
| for(int i = 0; i < 4; i++)
|
| {
|
| string id = IntegerToString(i);
|
| bool open, found;
|
| datetime st, en;
|
| SessionState(i, nowUtc, open, found, st, en);
|
|
|
| string status, remTxt = "--:--:--", sTxt = "--:--", eTxt = "--:--";
|
| color sc;
|
|
|
| if(found)
|
| {
|
| sTxt = FmtT(st);
|
| eTxt = FmtT(en);
|
| }
|
|
|
| if(open)
|
| {
|
| status = "OPEN"; sc = clrLime;
|
| remTxt = "ends " + SecToHMS((long)(en - nowUtc));
|
| }
|
| else
|
| {
|
| status = closedNow ? "WEEKEND" : "CLOSED";
|
| sc = closedNow ? clrDimGray : clrTomato;
|
| if(found)
|
| remTxt = (st <= nowUtc) ? "soon" : ("in " + SecToHMS((long)(st - nowUtc)));
|
| }
|
|
|
| color nameClr = g_s[i].show ? g_s[i].clr : clrGray;
|
| color txt = (color)(nameClr | 0x606060);
|
|
|
| CreateLabel("R" + id + "_0", x0 + cx[0], y, g_s[i].name, txt, InpFontSize, true);
|
| CreateLabel("R" + id + "_1", x0 + cx[1], y, sTxt, InpTextClr, InpFontSize);
|
| CreateLabel("R" + id + "_2", x0 + cx[2], y, eTxt, InpTextClr, InpFontSize);
|
| CreateLabel("R" + id + "_3", x0 + cx[3], y, status, sc, InpFontSize, true);
|
| CreateLabel("R" + id + "_4", x0 + cx[4], y, remTxt, InpTextClr, InpFontSize);
|
| y += rowH;
|
| }
|
|
|
| // Overlap table (all session pairs, chronological)
|
| if(ovCnt > 0)
|
| {
|
| CreateLabel("OVT", x0 + 10, y, "SESSION OVERLAPS (chronological)", clrGold, InpFontSize, true);
|
| y += rowH;
|
| for(int k = 0; k < ovCnt; k++)
|
| {
|
| int n = idx[k];
|
| string kid = IntegerToString(k);
|
| string rem = ovAct[n] ? ("ends " + SecToHMS((long)(ovE[n] - nowUtc)))
|
| : ("in " + SecToHMS((long)(ovS[n] - nowUtc)));
|
| CreateLabel("OV" + kid + "_0", x0 + cx[0], y, shortN[ovA[n]] + "/" + shortN[ovB[n]], clrOrange, InpFontSize, true);
|
| CreateLabel("OV" + kid + "_1", x0 + cx[1], y, FmtT(ovS[n]), InpTextClr, InpFontSize);
|
| CreateLabel("OV" + kid + "_2", x0 + cx[2], y, FmtT(ovE[n]), InpTextClr, InpFontSize);
|
| CreateLabel("OV" + kid + "_3", x0 + cx[3], y, ovAct[n] ? "OVERLAP" : "WAIT", ovAct[n] ? clrLime : clrDimGray, InpFontSize, true);
|
| CreateLabel("OV" + kid + "_4", x0 + cx[4], y, rem, InpTextClr, InpFontSize);
|
| y += rowH;
|
| }
|
| }
|
| else
|
| ObjectDelete(0, PREFIX + "OVT");
|
|
|
| // remove stale overlap rows
|
| for(int k = ovCnt; k < 6; k++)
|
| for(int c = 0; c < 5; c++)
|
| ObjectDelete(0, PREFIX + "OV" + IntegerToString(k) + "_" + IntegerToString(c));
|
| }
|
| //+==================================================================+
|
| //| CHART BOXES |
|
| //+==================================================================+
|
| void DrawSessions()
|
| {
|
| datetime nowSrv = TimeTradeServer();
|
| datetime nowUtc = NowUtc();
|
|
|
| for(int i = 0; i < 4; i++)
|
| {
|
| for(int d = 1; d >= -InpDaysBack; d--)
|
| {
|
| int j = 1 - d;
|
| string rn = StringFormat("%sBox_%d_%d", PREFIX, i, j);
|
| string ln = StringFormat("%sLbl_%d_%d", PREFIX, i, j);
|
|
|
| datetime st, en;
|
| Instance(i, d, nowUtc, st, en);
|
|
|
| bool skip = (!g_s[i].show || st > nowUtc);
|
| if(!skip && InpSkipWeekends && !InstValid(st, en)) skip = true;
|
|
|
| datetime stS = (datetime)(st + ServerOffsetSec(st));
|
| datetime enS = (datetime)(en + ServerOffsetSec(en));
|
|
|
| double hi = 0, lo = 0;
|
| if(!skip)
|
| {
|
| datetime endCalc = (enS > nowSrv) ? nowSrv : enS;
|
| if(endCalc <= stS)
|
| skip = true;
|
| else
|
| {
|
| double ha[], la[];
|
| int c1 = CopyHigh(_Symbol, PERIOD_M15, stS, endCalc, ha);
|
| int c2 = CopyLow(_Symbol, PERIOD_M15, stS, endCalc, la);
|
| if(c1 <= 0 || c2 <= 0)
|
| skip = true;
|
| else
|
| {
|
| hi = ha[ArrayMaximum(ha)];
|
| lo = la[ArrayMinimum(la)];
|
| }
|
| }
|
| }
|
|
|
| if(skip)
|
| {
|
| ObjectDelete(0, rn);
|
| ObjectDelete(0, ln);
|
| continue;
|
| }
|
|
|
| if(ObjectFind(0, rn) < 0)
|
| {
|
| ObjectCreate(0, rn, OBJ_RECTANGLE, 0, stS, hi, enS, lo);
|
| ObjectSetInteger(0, rn, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, rn, OBJPROP_HIDDEN, true);
|
| ObjectSetInteger(0, rn, OBJPROP_BACK, true);
|
| }
|
| ObjectSetInteger(0, rn, OBJPROP_TIME, 0, stS);
|
| ObjectSetDouble(0, rn, OBJPROP_PRICE, 0, hi);
|
| ObjectSetInteger(0, rn, OBJPROP_TIME, 1, enS);
|
| ObjectSetDouble(0, rn, OBJPROP_PRICE, 1, lo);
|
| ObjectSetInteger(0, rn, OBJPROP_COLOR, g_s[i].clr);
|
| ObjectSetInteger(0, rn, OBJPROP_FILL, InpFillBoxes);
|
| ObjectSetString(0, rn, OBJPROP_TOOLTIP,
|
| StringFormat("%s | %s - %s (server)", g_s[i].name,
|
| TimeToString(stS, TIME_DATE | TIME_MINUTES),
|
| TimeToString(enS, TIME_DATE | TIME_MINUTES)));
|
|
|
| if(InpShowLabels)
|
| {
|
| if(ObjectFind(0, ln) < 0)
|
| {
|
| ObjectCreate(0, ln, OBJ_TEXT, 0, stS, hi);
|
| ObjectSetInteger(0, ln, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, ln, OBJPROP_HIDDEN, true);
|
| ObjectSetInteger(0, ln, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
|
| ObjectSetInteger(0, ln, OBJPROP_FONTSIZE, 8);
|
| }
|
| ObjectSetInteger(0, ln, OBJPROP_TIME, 0, stS);
|
| ObjectSetDouble(0, ln, OBJPROP_PRICE, 0, hi);
|
| ObjectSetInteger(0, ln, OBJPROP_COLOR, (color)(g_s[i].clr | 0x808080));
|
| ObjectSetString(0, ln, OBJPROP_TEXT, g_s[i].name);
|
| }
|
| else
|
| ObjectDelete(0, ln);
|
| }
|
| }
|
| }
|
| //+==================================================================+
|
| //| EVENT HANDLERS |
|
| //+==================================================================+
|
| int OnInit()
|
| {
|
| g_s[0].name = "Sydney"; g_s[0].show = InpSydShow; g_s[0].sMin = InpSydSH * 60 + InpSydSM; g_s[0].eMin = InpSydEH * 60 + InpSydEM; g_s[0].clr = InpSydClr; g_s[0].stdOff = 10; g_s[0].rule = RULE_AU;
|
| g_s[1].name = "Tokyo"; g_s[1].show = InpTokShow; g_s[1].sMin = InpTokSH * 60 + InpTokSM; g_s[1].eMin = InpTokEH * 60 + InpTokEM; g_s[1].clr = InpTokClr; g_s[1].stdOff = 9; g_s[1].rule = RULE_NONE;
|
| g_s[2].name = "London"; g_s[2].show = InpLonShow; g_s[2].sMin = InpLonSH * 60 + InpLonSM; g_s[2].eMin = InpLonEH * 60 + InpLonEM; g_s[2].clr = InpLonClr; g_s[2].stdOff = 0; g_s[2].rule = RULE_EU;
|
| g_s[3].name = "New York"; g_s[3].show = InpNYShow; g_s[3].sMin = InpNYSH * 60 + InpNYSM; g_s[3].eMin = InpNYEH * 60 + InpNYEM; g_s[3].clr = InpNYClr; g_s[3].stdOff = -5; g_s[3].rule = RULE_US;
|
|
|
| ObjectsDeleteAll(0, PREFIX);
|
| IndicatorSetString(INDICATOR_SHORTNAME, "Forex Sessions Panel");
|
| EventSetTimer(1);
|
| DrawSessions();
|
| UpdatePanel();
|
| ChartRedraw();
|
| return INIT_SUCCEEDED;
|
| }
|
| //+------------------------------------------------------------------+
|
| void OnDeinit(const int reason)
|
| {
|
| EventKillTimer();
|
| ObjectsDeleteAll(0, PREFIX);
|
| ChartRedraw();
|
| }
|
| //+------------------------------------------------------------------+
|
| void OnTimer()
|
| {
|
| UpdatePanel();
|
| g_tick++;
|
| if(g_tick % 5 == 0)
|
| DrawSessions();
|
| ChartRedraw();
|
| }
|
| //+------------------------------------------------------------------+
|
| 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(prev_calculated == 0)
|
| {
|
| DrawSessions();
|
| UpdatePanel();
|
| }
|
| return rates_total;
|
| }
|
| //+------------------------------------------------------------------+
|