680 lines
28 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| 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;
| |||
}
| |||
//+------------------------------------------------------------------+
|