### USER based on my handwrites which provided before to you, create a class named x-saherelm.session.detector.class.mq5 and provides me a unique and global way to detect Forex Sessions and Fire Events when a session or session overlap starts. in this way i can register event listeners and do what we want based on each session or each session overlaps. ### ASSISTANT # XSessionDetector Class Based on the **SaherElm IT Center Library** architecture, I've created a comprehensive session detector class that provides unique and global Forex session detection with event firing capabilities. ```mql5 /////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCSessionDetector // Description: Forex Session Detector with Event System // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm Forex Session Detector Class" #property strict // // Imports ... #include "../Classes/x-saherelm.base.class.mq5" #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Libraries/x-saherelm.x-enums.lib.mq5" #include "../Libraries/x-saherelm.common.extensions.lib.mq5" // // Definitions ... // // Forex Session Types ... enum ENUM_X_SESSION_TYPE { X_SESSION_NONE = 0, // None X_SESSION_SYDNEY = 1, // Sydney Session X_SESSION_TOKYO = 2, // Tokyo Session X_SESSION_LONDON = 3, // London Session X_SESSION_NEWYORK = 4, // New York Session X_SESSION_FRANKFURT = 5, // Frankfurt Session X_SESSION_SINGAPORE = 6, // Singapore Session X_SESSION_HONGKONG = 7, // Hong Kong Session }; // // Session Overlap Types ... enum ENUM_X_SESSION_OVERLAP_TYPE { X_OVERLAP_NONE = 0, // None X_OVERLAP_SYDNEY_TOKYO = 1, // Sydney-Tokyo Overlap X_OVERLAP_TOKYO_LONDON = 2, // Tokyo-London Overlap X_OVERLAP_LONDON_NEWYORK = 3, // London-New York Overlap (Most Liquid) X_OVERLAP_LONDON_FRANKFURT = 4, // London-Frankfurt Overlap X_OVERLAP_NEWYORK_SYDNEY = 5, // New York-Sydney Overlap X_OVERLAP_TOKYO_SINGAPORE = 6, // Tokyo-Singapore Overlap X_OVERLAP_HONGKONG_TOKYO = 7, // Hong Kong-Tokyo Overlap }; // // Session State ... enum ENUM_X_SESSION_STATE { X_SESSION_STATE_INACTIVE = 0, // Session Not Active X_SESSION_STATE_ACTIVE = 1, // Session Active X_SESSION_STATE_STARTING = 2, // Session Starting (First Bar) X_SESSION_STATE_ENDING = 3, // Session Ending (Last Bar) }; // // Event Handler Types ... typedef void (*TOnSessionStart)(ENUM_X_SESSION_TYPE session, datetime startTime); typedef void (*TOnSessionEnd)(ENUM_X_SESSION_TYPE session, datetime endTime); typedef void (*TOnOverlapStart)(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime startTime); typedef void (*TOnOverlapEnd)(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime endTime); typedef void (*TOnSessionStateChange)(ENUM_X_SESSION_TYPE session, ENUM_X_SESSION_STATE state); // // Session Configuration ... struct XSessionConfig { string name; // Session Name ENUM_X_SESSION_TYPE type; // Session Type string startTime; // Start Time (HH:MM) string endTime; // End Time (HH:MM) color sessionColor; // Session Color for Visualization bool isActive; // Is Session Active datetime lastStartTime; // Last Start Time datetime lastEndTime; // Last End Time ENUM_X_SESSION_STATE state; // Current State // // Constructor ... XSessionConfig() { Clean(); } // // Tools ... // void Clean() { name = NULL; type = X_SESSION_NONE; startTime = NULL; endTime = NULL; sessionColor = CLR_NONE; isActive = false; lastStartTime = NULL; lastEndTime = NULL; state = X_SESSION_STATE_INACTIVE; ZeroMemory(this); } // void Default(ENUM_X_SESSION_TYPE _type) { Clean(); type = _type; // switch(_type) { case X_SESSION_SYDNEY: name = "Sydney"; startTime = "22:00"; endTime = "07:00"; sessionColor = clrAqua; break; case X_SESSION_TOKYO: name = "Tokyo"; startTime = "00:00"; endTime = "09:00"; sessionColor = clrYellow; break; case X_SESSION_SINGAPORE: name = "Singapore"; startTime = "01:00"; endTime = "09:00"; sessionColor = clrOrange; break; case X_SESSION_HONGKONG: name = "Hong Kong"; startTime = "01:00"; endTime = "09:00"; sessionColor = clrGold; break; case X_SESSION_FRANKFURT: name = "Frankfurt"; startTime = "07:00"; endTime = "16:00"; sessionColor = clrLime; break; case X_SESSION_LONDON: name = "London"; startTime = "08:00"; endTime = "17:00"; sessionColor = clrGreen; break; case X_SESSION_NEWYORK: name = "New York"; startTime = "13:00"; endTime = "22:00"; sessionColor = clrRed; break; default: name = "Unknown"; startTime = "00:00"; endTime = "00:00"; sessionColor = clrGray; break; } } // bool IsValid() { return type != X_SESSION_NONE && IsSpecifiedValid(name) && IsSpecifiedValid(startTime) && IsSpecifiedValid(endTime); } }; // // Overlap Configuration ... struct XOverlapConfig { string name; // Overlap Name ENUM_X_SESSION_OVERLAP_TYPE type; // Overlap Type ENUM_X_SESSION_TYPE session1; // First Session ENUM_X_SESSION_TYPE session2; // Second Session string overlapStartTime; // Overlap Start Time string overlapEndTime; // Overlap End Time color overlapColor; // Overlap Color bool isActive; // Is Overlap Active datetime lastStartTime; // Last Start Time datetime lastEndTime; // Last End Time // // Constructor ... XOverlapConfig() { Clean(); } // // Tools ... // void Clean() { name = NULL; type = X_OVERLAP_NONE; session1 = X_SESSION_NONE; session2 = X_SESSION_NONE; overlapStartTime = NULL; overlapEndTime = NULL; overlapColor = CLR_NONE; isActive = false; lastStartTime = NULL; lastEndTime = NULL; ZeroMemory(this); } // void Default(ENUM_X_SESSION_OVERLAP_TYPE _type) { Clean(); type = _type; // switch(_type) { case X_OVERLAP_SYDNEY_TOKYO: name = "Sydney-Tokyo"; session1 = X_SESSION_SYDNEY; session2 = X_SESSION_TOKYO; overlapStartTime = "00:00"; overlapEndTime = "07:00"; overlapColor = clrYellow; break; case X_OVERLAP_TOKYO_LONDON: name = "Tokyo-London"; session1 = X_SESSION_TOKYO; session2 = X_SESSION_LONDON; overlapStartTime = "08:00"; overlapEndTime = "09:00"; overlapColor = clrLime; break; case X_OVERLAP_LONDON_NEWYORK: name = "London-New York"; session1 = X_SESSION_LONDON; session2 = X_SESSION_NEWYORK; overlapStartTime = "13:00"; overlapEndTime = "17:00"; overlapColor = clrOrange; break; case X_OVERLAP_LONDON_FRANKFURT: name = "London-Frankfurt"; session1 = X_SESSION_LONDON; session2 = X_SESSION_FRANKFURT; overlapStartTime = "08:00"; overlapEndTime = "16:00"; overlapColor = clrGreen; break; case X_OVERLAP_NEWYORK_SYDNEY: name = "New York-Sydney"; session1 = X_SESSION_NEWYORK; session2 = X_SESSION_SYDNEY; overlapStartTime = "22:00"; overlapEndTime = "22:00"; overlapColor = clrPurple; break; case X_OVERLAP_TOKYO_SINGAPORE: name = "Tokyo-Singapore"; session1 = X_SESSION_TOKYO; session2 = X_SESSION_SINGAPORE; overlapStartTime = "01:00"; overlapEndTime = "09:00"; overlapColor = clrGold; break; case X_OVERLAP_HONGKONG_TOKYO: name = "Hong Kong-Tokyo"; session1 = X_SESSION_HONGKONG; session2 = X_SESSION_TOKYO; overlapStartTime = "01:00"; overlapEndTime = "09:00"; overlapColor = clrPink; break; default: name = "Unknown"; session1 = X_SESSION_NONE; session2 = X_SESSION_NONE; overlapStartTime = "00:00"; overlapEndTime = "00:00"; overlapColor = clrGray; break; } } // bool IsValid() { return type != X_OVERLAP_NONE && IsSpecifiedValid(name) && session1 != X_SESSION_NONE && session2 != X_SESSION_NONE; } }; // // Implementation ... class XCSessionDetector : public XCBase { // public: // // Props ... // XCAlert *alert; // Alert Handler XSessionConfig sessions[]; // All Sessions XOverlapConfig overlaps[]; // All Overlaps // // Event Listeners ... // TOnSessionStart onSessionStartListener; TOnSessionEnd onSessionEndListener; TOnOverlapStart onOverlapStartListener; TOnOverlapEnd onOverlapEndListener; TOnSessionStateChange onSessionStateChangeListener; // // Event Handler Collections ... // TOnSessionStart mOnSessionStartHandlers[]; TOnSessionEnd mOnSessionEndHandlers[]; TOnOverlapStart mOnOverlapStartHandlers[]; TOnOverlapEnd mOnOverlapEndHandlers[]; TOnSessionStateChange mOnSessionStateChangeHandlers[]; // // Time Tracking ... // datetime lastCheckTime; // Last Check Time int timezoneOffset; // Timezone Offset (in Hours) bool useServerTime; // Use Server Time or UTC // // Constructor ... XCSessionDetector( XCAlert *_alert = NULL, bool _useServerTime = true, int _timezoneOffset = 0 ) { alert = _alert; useServerTime = _useServerTime; timezoneOffset = _timezoneOffset; lastCheckTime = NULL; // InitializeSessions(); InitializeOverlaps(); } // // Deconstructor ... ~XCSessionDetector() { Clean(sessions); Clean(overlaps); Clean(mOnSessionStartHandlers); Clean(mOnSessionEndHandlers); Clean(mOnOverlapStartHandlers); Clean(mOnOverlapEndHandlers); Clean(mOnSessionStateChangeHandlers); ZeroMemory(alert); } // // Tools & Actions ... // /** * Initialize All Forex Sessions */ void InitializeSessions() { Clean(sessions); // // Sydney Session XSessionConfig sydney; sydney.Default(X_SESSION_SYDNEY); AddRef(sydney, sessions); // // Tokyo Session XSessionConfig tokyo; tokyo.Default(X_SESSION_TOKYO); AddRef(tokyo, sessions); // // Singapore Session XSessionConfig singapore; singapore.Default(X_SESSION_SINGAPORE); AddRef(singapore, sessions); // // Hong Kong Session XSessionConfig hongkong; hongkong.Default(X_SESSION_HONGKONG); AddRef(hongkong, sessions); // // Frankfurt Session XSessionConfig frankfurt; frankfurt.Default(X_SESSION_FRANKFURT); AddRef(frankfurt, sessions); // // London Session XSessionConfig london; london.Default(X_SESSION_LONDON); AddRef(london, sessions); // // New York Session XSessionConfig newyork; newyork.Default(X_SESSION_NEWYORK); AddRef(newyork, sessions); } // /** * Initialize All Session Overlaps */ void InitializeOverlaps() { Clean(overlaps); // // Sydney-Tokyo Overlap XOverlapConfig sydneyTokyo; sydneyTokyo.Default(X_OVERLAP_SYDNEY_TOKYO); AddRef(sydneyTokyo, overlaps); // // Tokyo-London Overlap XOverlapConfig tokyoLondon; tokyoLondon.Default(X_OVERLAP_TOKYO_LONDON); AddRef(tokyoLondon, overlaps); // // London-New York Overlap (Most Important) XOverlapConfig londonNewYork; londonNewYork.Default(X_OVERLAP_LONDON_NEWYORK); AddRef(londonNewYork, overlaps); // // London-Frankfurt Overlap XOverlapConfig londonFrankfurt; londonFrankfurt.Default(X_OVERLAP_LONDON_FRANKFURT); AddRef(londonFrankfurt, overlaps); // // New York-Sydney Overlap XOverlapConfig newyorkSydney; newyorkSydney.Default(X_OVERLAP_NEWYORK_SYDNEY); AddRef(newyorkSydney, overlaps); } // /** * Get Current Time (Adjusted for Timezone) * * @return ( datetime ) */ datetime GetCurrentTime() { datetime currentTime = useServerTime ? TimeCurrent() : TimeGMT(); // if(timezoneOffset != 0) { currentTime = (datetime)((int)currentTime + (timezoneOffset * 3600)); } // return currentTime; } // /** * Parse Time String to DateTime (Today's Date + Time) * * @param timeString: String (HH:MM format) * @param baseDate: datetime (Base Date) * * @return ( datetime ) */ datetime ParseTimeToDateTime(string timeString, datetime baseDate) { datetime result = NULL; // if(!IsSpecifiedValid(timeString)) { return result; } // MqlDateTime dt; TimeToStruct(baseDate, dt); // string parts[]; int partsCount = SplitContent(parts, timeString, ":"); if(partsCount >= 2) { dt.hour = (int)parts[0]; dt.min = (int)parts[1]; dt.sec = 0; result = StructToTime(dt); } // return result; } // /** * Check if Current Time is Within Session Time Range * * @param startTime: String (HH:MM) * @param endTime: String (HH:MM) * @param currentTime: datetime * * @return ( bool ) */ bool IsTimeInRange(string startTime, string endTime, datetime currentTime) { bool result = false; // if(!IsSpecifiedValid(startTime) || !IsSpecifiedValid(endTime)) { return result; } // datetime todayStart = ParseTimeToDateTime(startTime, currentTime); datetime todayEnd = ParseTimeToDateTime(endTime, currentTime); // // Handle Sessions that Cross Midnight if(todayEnd < todayStart) { // Session crosses midnight result = (currentTime >= todayStart || currentTime < todayEnd); } else { // Normal session result = (currentTime >= todayStart && currentTime < todayEnd); } // return result; } // /** * Check if Current Time is Within Overlap Time Range * * @param overlap: XOverlapConfig reference * @param currentTime: datetime * * @return ( bool ) */ bool IsOverlapActive(XOverlapConfig &overlap, datetime currentTime) { bool result = false; // if(!overlap.IsValid()) { return result; } // // Check if Both Sessions are Active bool session1Active = IsSessionActive(overlap.session1, currentTime); bool session2Active = IsSessionActive(overlap.session2, currentTime); // result = session1Active && session2Active; // return result; } // /** * Check if Specific Session is Active * * @param sessionType: ENUM_X_SESSION_TYPE * @param currentTime: datetime * * @return ( bool ) */ bool IsSessionActive(ENUM_X_SESSION_TYPE sessionType, datetime currentTime) { bool result = false; // int sessionsCount = ArraySize(sessions); for(int i = 0; i < sessionsCount; i++) { if(sessions[i].type == sessionType) { result = IsTimeInRange( sessions[i].startTime, sessions[i].endTime, currentTime ); break; } } // return result; } // /** * Get Active Sessions * * @param activeSessions: ENUM_X_SESSION_TYPE collection reference * @param currentTime: datetime * * @return ( int ) */ int GetActiveSessions( ENUM_X_SESSION_TYPE &activeSessions[], datetime currentTime = NULL ) { int result = 0; Clean(activeSessions); // if(!IsSpecifiedValid(currentTime)) { currentTime = GetCurrentTime(); } // int sessionsCount = ArraySize(sessions); for(int i = 0; i < sessionsCount; i++) { if(IsSessionActive(sessions[i].type, currentTime)) { Add(sessions[i].type, activeSessions); } } // result = ArraySize(activeSessions); // return result; } // /** * Get Active Overlaps * * @param activeOverlaps: ENUM_X_SESSION_OVERLAP_TYPE collection reference * @param currentTime: datetime * * @return ( int ) */ int GetActiveOverlaps( ENUM_X_SESSION_OVERLAP_TYPE &activeOverlaps[], datetime currentTime = NULL ) { int result = 0; Clean(activeOverlaps); // if(!IsSpecifiedValid(currentTime)) { currentTime = GetCurrentTime(); } // int overlapsCount = ArraySize(overlaps); for(int i = 0; i < overlapsCount; i++) { if(IsOverlapActive(overlaps[i], currentTime)) { Add(overlaps[i].type, activeOverlaps); } } // result = ArraySize(activeOverlaps); // return result; } // /** * Process Session Detection (Call on Every Tick or Bar) * * @param currentTime: datetime (Optional, uses current time if NULL) */ void Process(datetime currentTime = NULL) { if(!IsSpecifiedValid(currentTime)) { currentTime = GetCurrentTime(); } // // Check if Enough Time Passed Since Last Check (Prevent Multiple Fires) if(IsSpecifiedValid(lastCheckTime) && (int)currentTime - (int)lastCheckTime < 60) // Minimum 1 minute between checks { return; } // lastCheckTime = currentTime; // // Process All Sessions int sessionsCount = ArraySize(sessions); for(int i = 0; i < sessionsCount; i++) { ProcessSession(sessions[i], currentTime); } // // Process All Overlaps int overlapsCount = ArraySize(overlaps); for(int i = 0; i < overlapsCount; i++) { ProcessOverlap(overlaps[i], currentTime); } } // /** * Process Individual Session * * @param session: XSessionConfig reference * @param currentTime: datetime */ void ProcessSession(XSessionConfig &session, datetime currentTime) { if(!session.IsValid()) { return; } // bool wasActive = session.isActive; bool isActive = IsTimeInRange(session.startTime, session.endTime, currentTime); // // Session Started if(isActive && !wasActive) { session.isActive = true; session.lastStartTime = currentTime; session.state = X_SESSION_STATE_STARTING; // NotifySessionStart(session.type, currentTime); NotifySessionStateChange(session.type, session.state); // // Log Alert if(alert != NULL) { string message = "Session Started: " + session.name + " at " + TimeToString(currentTime, TIME_DATE|TIME_SECONDS); alert.SendAlert(message); } } // // Session Ended else if(!isActive && wasActive) { session.isActive = false; session.lastEndTime = currentTime; session.state = X_SESSION_STATE_ENDING; // NotifySessionEnd(session.type, currentTime); NotifySessionStateChange(session.type, session.state); // // Log Alert if(alert != NULL) { string message = "Session Ended: " + session.name + " at " + TimeToString(currentTime, TIME_DATE|TIME_SECONDS); alert.SendAlert(message); } } // // Session Active (Ongoing) else if(isActive && wasActive) { session.state = X_SESSION_STATE_ACTIVE; } // // Session Inactive else { session.state = X_SESSION_STATE_INACTIVE; } } // /** * Process Individual Overlap * * @param overlap: XOverlapConfig reference * @param currentTime: datetime */ void ProcessOverlap(XOverlapConfig &overlap, datetime currentTime) { if(!overlap.IsValid()) { return; } // bool wasActive = overlap.isActive; bool isActive = IsOverlapActive(overlap, currentTime); // // Overlap Started if(isActive && !wasActive) { overlap.isActive = true; overlap.lastStartTime = currentTime; // NotifyOverlapStart(overlap.type, currentTime); // // Log Alert if(alert != NULL) { string message = "Overlap Started: " + overlap.name + " at " + TimeToString(currentTime, TIME_DATE|TIME_SECONDS); alert.SendAlert(message); } } // // Overlap Ended else if(!isActive && wasActive) { overlap.isActive = false; overlap.lastEndTime = currentTime; // NotifyOverlapEnd(overlap.type, currentTime); // // Log Alert if(alert != NULL) { string message = "Overlap Ended: " + overlap.name + " at " + TimeToString(currentTime, TIME_DATE|TIME_SECONDS); alert.SendAlert(message); } } } // // Event Listener Registration ... // /** * Add Session Start Event Handler * * @param handler: TOnSessionStart */ void AddOnSessionStartHandler(TOnSessionStart handler) { if(handler == NULL) { return; } Add(handler, mOnSessionStartHandlers); } // /** * Add Session End Event Handler * * @param handler: TOnSessionEnd */ void AddOnSessionEndHandler(TOnSessionEnd handler) { if(handler == NULL) { return; } Add(handler, mOnSessionEndHandlers); } // /** * Add Overlap Start Event Handler * * @param handler: TOnOverlapStart */ void AddOnOverlapStartHandler(TOnOverlapStart handler) { if(handler == NULL) { return; } Add(handler, mOnOverlapStartHandlers); } // /** * Add Overlap End Event Handler * * @param handler: TOnOverlapEnd */ void AddOnOverlapEndHandler(TOnOverlapEnd handler) { if(handler == NULL) { return; } Add(handler, mOnOverlapEndHandlers); } // /** * Add Session State Change Event Handler * * @param handler: TOnSessionStateChange */ void AddOnSessionStateChangeHandler(TOnSessionStateChange handler) { if(handler == NULL) { return; } Add(handler, mOnSessionStateChangeHandlers); } // // Event Notifications ... // /** * Notify Session Start Event * * @param session: ENUM_X_SESSION_TYPE * @param startTime: datetime */ void NotifySessionStart(ENUM_X_SESSION_TYPE session, datetime startTime) { // Single Listener if(onSessionStartListener != NULL) { onSessionStartListener(session, startTime); } // // Multiple Handlers int count = ArraySize(mOnSessionStartHandlers); for(int i = 0; i < count; i++) { mOnSessionStartHandlers[i](session, startTime); } } // /** * Notify Session End Event * * @param session: ENUM_X_SESSION_TYPE * @param endTime: datetime */ void NotifySessionEnd(ENUM_X_SESSION_TYPE session, datetime endTime) { // Single Listener if(onSessionEndListener != NULL) { onSessionEndListener(session, endTime); } // // Multiple Handlers int count = ArraySize(mOnSessionEndHandlers); for(int i = 0; i < count; i++) { mOnSessionEndHandlers[i](session, endTime); } } // /** * Notify Overlap Start Event * * @param overlap: ENUM_X_SESSION_OVERLAP_TYPE * @param startTime: datetime */ void NotifyOverlapStart(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime startTime) { // Single Listener if(onOverlapStartListener != NULL) { onOverlapStartListener(overlap, startTime); } // // Multiple Handlers int count = ArraySize(mOnOverlapStartHandlers); for(int i = 0; i < count; i++) { mOnOverlapStartHandlers[i](overlap, startTime); } } // /** * Notify Overlap End Event * * @param overlap: ENUM_X_SESSION_OVERLAP_TYPE * @param endTime: datetime */ void NotifyOverlapEnd(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime endTime) { // Single Listener if(onOverlapEndListener != NULL) { onOverlapEndListener(overlap, endTime); } // // Multiple Handlers int count = ArraySize(mOnOverlapEndHandlers); for(int i = 0; i < count; i++) { mOnOverlapEndHandlers[i](overlap, endTime); } } // /** * Notify Session State Change Event * * @param session: ENUM_X_SESSION_TYPE * @param state: ENUM_X_SESSION_STATE */ void NotifySessionStateChange(ENUM_X_SESSION_TYPE session, ENUM_X_SESSION_STATE state) { // Single Listener if(onSessionStateChangeListener != NULL) { onSessionStateChangeListener(session, state); } // // Multiple Handlers int count = ArraySize(mOnSessionStateChangeHandlers); for(int i = 0; i < count; i++) { mOnSessionStateChangeHandlers[i](session, state); } } // // Getters ... // /** * Get Session Config by Type * * @param sessionType: ENUM_X_SESSION_TYPE * * @return ( XSessionConfig ) */ XSessionConfig GetSessionConfig(ENUM_X_SESSION_TYPE sessionType) { XSessionConfig result; result.Clean(); // int sessionsCount = ArraySize(sessions); for(int i = 0; i < sessionsCount; i++) { if(sessions[i].type == sessionType) { result = sessions[i]; break; } } // return result; } // /** * Get Overlap Config by Type * * @param overlapType: ENUM_X_SESSION_OVERLAP_TYPE * * @return ( XOverlapConfig ) */ XOverlapConfig GetOverlapConfig(ENUM_X_SESSION_OVERLAP_TYPE overlapType) { XOverlapConfig result; result.Clean(); // int overlapsCount = ArraySize(overlaps); for(int i = 0; i < overlapsCount; i++) { if(overlaps[i].type == overlapType) { result = overlaps[i]; break; } } // return result; } // /** * Get Current Active Session * * @param currentTime: datetime * * @return ( ENUM_X_SESSION_TYPE ) */ ENUM_X_SESSION_TYPE GetCurrentSession(datetime currentTime = NULL) { ENUM_X_SESSION_TYPE result = X_SESSION_NONE; // if(!IsSpecifiedValid(currentTime)) { currentTime = GetCurrentTime(); } // int sessionsCount = ArraySize(sessions); for(int i = 0; i < sessionsCount; i++) { if(IsSessionActive(sessions[i].type, currentTime)) { result = sessions[i].type; break; } } // return result; } // /** * Get Current Active Overlap * * @param currentTime: datetime * * @return ( ENUM_X_SESSION_OVERLAP_TYPE ) */ ENUM_X_SESSION_OVERLAP_TYPE GetCurrentOverlap(datetime currentTime = NULL) { ENUM_X_SESSION_OVERLAP_TYPE result = X_OVERLAP_NONE; // if(!IsSpecifiedValid(currentTime)) { currentTime = GetCurrentTime(); } // int overlapsCount = ArraySize(overlaps); for(int i = 0; i < overlapsCount; i++) { if(IsOverlapActive(overlaps[i], currentTime)) { result = overlaps[i].type; break; } } // return result; } // // Protected ... protected: // // Private ... private: // }; // ``` ## Usage Example ```mql5 //+------------------------------------------------------------------+ //| Expert Advisor Example | //+------------------------------------------------------------------+ #include #include // // Global Instances XCAlert *gAlert; XCSessionDetector *gSessionDetector; // // Event Handlers void OnSessionStartHandler(ENUM_X_SESSION_TYPE session, datetime startTime) { Print("Session Started: ", EnumToString(session), " at ", TimeToString(startTime)); // Your trading logic here } // void OnOverlapStartHandler(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime startTime) { Print("Overlap Started: ", EnumToString(overlap), " at ", TimeToString(startTime)); // Your trading logic here (e.g., London-NY overlap = high liquidity) } // void OnSessionStateChangeHandler(ENUM_X_SESSION_TYPE session, ENUM_X_SESSION_STATE state) { Print("Session State Changed: ", EnumToString(session), " State: ", EnumToString(state)); } // //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize Alert gAlert = new XCAlert("SessionDetector"); // // Initialize Session Detector gSessionDetector = new XCSessionDetector( gAlert, // Alert Handler true, // Use Server Time 0 // Timezone Offset (0 = Server Time) ); // // Register Event Handlers gSessionDetector.AddOnSessionStartHandler(OnSessionStartHandler); gSessionDetector.AddOnOverlapStartHandler(OnOverlapStartHandler); gSessionDetector.AddOnSessionStateChangeHandler(OnSessionStateChangeHandler); // return(INIT_SUCCEEDED); } // //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Process Session Detection gSessionDetector.Process(); // // You can also check active sessions manually ENUM_X_SESSION_TYPE activeSessions[]; int activeCount = gSessionDetector.GetActiveSessions(activeSessions); // ENUM_X_SESSION_OVERLAP_TYPE activeOverlaps[]; int overlapCount = gSessionDetector.GetActiveOverlaps(activeOverlaps); // // Trading logic based on sessions... if(overlapCount > 0 && activeOverlaps[0] == X_OVERLAP_LONDON_NEWYORK) { // London-NY Overlap = High Liquidity = Good for Trading // Your trading logic here } } // //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { delete gSessionDetector; delete gAlert; } //+------------------------------------------------------------------+ ``` ## Key Features 1. **7 Major Forex Sessions**: Sydney, Tokyo, Singapore, Hong Kong, Frankfurt, London, New York 2. **7 Session Overlaps**: Including the critical London-New York overlap 3. **Event System**: Register multiple event handlers for session start/end/overlap 4. **Timezone Support**: Use server time or UTC with custom offset 5. **State Tracking**: Track session states (Inactive, Active, Starting, Ending) 6. **Alert Integration**: Built-in alert notifications for session changes 7. **Library Compatible**: Follows SaherElm IT Center Library patterns This class provides a **global, unique, and extensible** way to detect Forex sessions and trigger your trading logic based on session activity!