Files
MQL5Data/X121XKIEA/Documents/SessionDetector.md
T
2026-02-27 01:46:11 +03:30

1213 lines
30 KiB
Markdown

### 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 <Classes/x-saherelm.x-alert.class.mq5>
#include <Classes/x-saherelm.session.detector.class.mq5>
//
// 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!