update to my mt5 libs to include better comments

This commit is contained in:
Matt Corcoran
2025-07-12 15:29:30 +02:00
parent ec3fc120ce
commit 136522ef1c
31 changed files with 1389 additions and 2024 deletions
+32 -4
View File
@@ -12,7 +12,19 @@ private:
AtrEntry cache[]; // internal cache of ATR handles
public:
// Get or create an ATR handle for a specific symbol/timeframe/period
// ---------------------------------------------------------------------
// Returns a valid ATR handle for the given symbol, timeframe, and period.
// Creates and caches the handle if not already available.
//
// Parameters:
// - symbol : Trading symbol (e.g., "EURUSD").
// - tf : Timeframe (e.g., PERIOD_H1).
// - period : ATR period (e.g., 14).
//
// Returns:
// - The ATR indicator handle, or INVALID_HANDLE if failed.
// ---------------------------------------------------------------------
int get_atr_handle(string symbol, ENUM_TIMEFRAMES tf, int period) {
for (int i = 0; i < ArraySize(cache); i++) {
if (cache[i].symbol == symbol && cache[i].tf == tf && cache[i].period == period)
@@ -32,7 +44,18 @@ public:
return handle;
}
// Get ATR value from buffer (returns EMPTY_VALUE if failure)
// ---------------------------------------------------------------------
// Gets the ATR value for a given symbol, timeframe, and period.
//
// Parameters:
// - symbol : Trading symbol (e.g., "EURUSD").
// - tf : Timeframe to use (e.g., PERIOD_H1).
// - period : ATR period to calculate.
// - shift : Bar shift to read the value from (default is 1 for last closed bar. NEVER use 0!).
//
// Returns:
// - ATR value at the given shift, or EMPTY_VALUE on failure.
// ---------------------------------------------------------------------
double get_atr_value(string symbol, ENUM_TIMEFRAMES tf, int period, int shift = 1) {
int handle = get_atr_handle(symbol, tf, period);
if (handle == INVALID_HANDLE) {
@@ -51,7 +74,13 @@ public:
return buffer[0];
}
// Release all handles in the cache
// ---------------------------------------------------------------------
// Releases all cached ATR handles and clears the internal cache.
//
// Logic:
// - Calls IndicatorRelease for each handle.
// - Clears the `cache` array.
// ---------------------------------------------------------------------
void release_handles() {
for (int i = 0; i < ArraySize(cache); i++) {
if (cache[i].handle != INVALID_HANDLE)
@@ -60,4 +89,3 @@ public:
ArrayResize(cache, 0);
}
};
+31 -19
View File
@@ -1,31 +1,43 @@
#include <Object.mqh>
class ChartUtils : public CObject {
public:
void draw_line(double value, string name, color clr = clrBlack);
public:
void draw_line(double value, string name, color clr = clrBlack);
};
// ---------------------------------------------------------------------
// Draws or updates a horizontal line on the chart at the given price level.
//
// Parameters:
// - value : Price level at which to draw the line.
// - name : Unique name for the line object.
// - clr : Line color (default is black).
//
// Logic:
// - If the object doesn't exist, it creates a new horizontal line.
// - If the object exists, it moves it to the new price level.
// - Calls ChartRedraw to update the chart visually.
// ---------------------------------------------------------------------
void ChartUtils::draw_line(double value, string name, color clr) {
if (ObjectFind(0, name) < 0) {
ResetLastError();
if (ObjectFind(0, name) < 0) {
ResetLastError();
if (!ObjectCreate(0, name, OBJ_HLINE, 0, 0, value)) {
Print(__FUNCTION__, ": failed to create a horizontal line! Error code = ", GetLastError());
return;
}
if (!ObjectCreate(0, name, OBJ_HLINE, 0, 0, value)) {
Print(__FUNCTION__, ": failed to create a horizontal line! Error code = ", GetLastError());
return;
}
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
}
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
}
ResetLastError();
ResetLastError();
if (!ObjectMove(0, name, 0, 0, value)) {
Print(__FUNCTION__, ": failed to move the horizontal line! Error code = ", GetLastError());
return;
}
if (!ObjectMove(0, name, 0, 0, value)) {
Print(__FUNCTION__, ": failed to move the horizontal line! Error code = ", GetLastError());
return;
}
ChartRedraw();
ChartRedraw();
}
-28
View File
@@ -1,28 +0,0 @@
#include <MyLibs/Myfunctions.mqh>
#include <MyLibs/OrderManagement.mqh>
#include <MyLibs/Utils/MyEnums.mqh>
#include <MyLibs/BacktestUtils/CustomMax.mqh>
#include <MyLibs/BacktestUtils/TestDataSplit.mqh>
CustomMax c_max;
// MyFunctions mf;
// OrderManagment om;
//---
input LOT_MODE inp_lot_mode = LOT_MODE_PCT_RISK; // Lot Size Mode
input double inp_lot_var = 2; // Lot Size Var
input SL_MODE inp_sl_mode = SL_ATR_MULTIPLE; // Stop-loss Mode
input double inp_sl_var = 1.5; // Stop-loss Var
input TP_MODE inp_tp_mode = TP_ATR_MULTIPLE; // Take-profit Mode
input double inp_tp_var = 1; // Take-Profit Var
string lot_mode = EnumToString(inp_lot_mode);
string sl_mode = EnumToString(inp_sl_mode);
string tp_mode = EnumToString(inp_tp_mode);
input CUSTOM_MAX_TYPE inp_custom_criteria = CM_WIN_PERCENT;
input int inp_opt_min_trades = 0; // 0/off
input MODE_SPLIT_DATA inp_data_split_method = NO_SPLIT;
input int inp_force_opt = 1;
input group "-----------------------------------------"
+120 -66
View File
@@ -1,94 +1,148 @@
class MarketDataUtils {
public:
bool is_new_bar(string symbol, ENUM_TIMEFRAMES time_frame, string daily_start_time = "00:10");
double get_latest_buffer_value(int handle);
double get_buffer_value(int handle, int shift);
double adjusted_point(string symbol);
double get_bid_ask_price(string symbol, int price_side);
public:
bool is_new_bar(string symbol, ENUM_TIMEFRAMES time_frame, string daily_start_time = "00:10");
double get_latest_buffer_value(int handle);
double get_buffer_value(int handle, int shift);
double adjusted_point(string symbol);
double get_bid_ask_price(string symbol, int price_side);
protected:
datetime previousTimes[]; // Stores last recorded open time per key
string bar_keys[]; // Keys are symbol+TF combinations, e.g. "EURUSD_PERIOD_H1"
protected:
datetime previousTimes[]; // Stores last recorded open time per key
string bar_keys[]; // Keys are symbol+TF combinations, e.g. "EURUSD_PERIOD_H1"
};
// Helper function to find index of a key in an array
int LinearSearch(string &arr[], string target) {
for (int i = 0; i < ArraySize(arr); i++) {
if (arr[i] == target)
return i;
}
return -1; // Not found
// ---------------------------------------------------------------------
// Performs linear search on a string array.
//
// Parameters:
// - arr : Array of strings.
// - target : Target string to find.
//
// Returns:
// - Index of the target, or -1 if not found.
// ---------------------------------------------------------------------
int LinearSearch(string& arr[], string target) {
for (int i = 0; i < ArraySize(arr); i++) {
if (arr[i] == target) return i;
}
return -1;
}
// Checks if a new bar has opened on the given timeframe and symbol
// ---------------------------------------------------------------------
// Implementation of is_new_bar. Tracks the open time of the last bar.
//
// Parameters:
// - symbol : Symbol to check.
// - time_frame : Timeframe to check.
// - daily_start_time: Time string for daily bar sync.
//
// Returns:
// - true if a new bar has formed, false otherwise.
// ---------------------------------------------------------------------
bool MarketDataUtils::is_new_bar(string symbol, ENUM_TIMEFRAMES time_frame, string daily_start_time) {
datetime bar_open_time = iTime(symbol, time_frame, 0); // Current open time
string key = symbol + "_" + EnumToString(time_frame);
datetime bar_open_time = iTime(symbol, time_frame, 0); // Current open time
string key = symbol + "_" + EnumToString(time_frame);
int idx = LinearSearch(bar_keys, key);
if (idx == -1) {
int new_size = ArraySize(bar_keys) + 1;
ArrayResize(bar_keys, new_size);
ArrayResize(previousTimes, new_size);
int idx = LinearSearch(bar_keys, key);
if (idx == -1) {
int new_size = ArraySize(bar_keys) + 1;
ArrayResize(bar_keys, new_size);
ArrayResize(previousTimes, new_size);
idx = new_size - 1;
bar_keys[idx] = key;
previousTimes[idx] = 0;
}
idx = new_size - 1;
bar_keys[idx] = key;
previousTimes[idx] = 0;
}
if (previousTimes[idx] != bar_open_time) {
// For daily timeframe, wait for specific time (e.g., 00:10) before triggering
if (PeriodSeconds(time_frame) == PeriodSeconds(PERIOD_D1)) {
if (TimeCurrent() > StringToTime(daily_start_time)) {
if (previousTimes[idx] != bar_open_time) {
if (PeriodSeconds(time_frame) == PeriodSeconds(PERIOD_D1)) {
if (TimeCurrent() > StringToTime(daily_start_time)) {
previousTimes[idx] = bar_open_time;
return true;
}
} else {
previousTimes[idx] = bar_open_time;
return true;
}
} else {
previousTimes[idx] = bar_open_time;
return true;
}
}
}
}
return false; // No new bar
return false;
}
// shift = 0 refers to the live candle (still forming)
// shift = 1 is the most recently closed candle
// shift = 2 is the one before that, etc.
// ---------------------------------------------------------------------
// Implementation of get_buffer_value.
//
// Parameters:
// - handle : Indicator handle.
// - shift : Shift index for historical bars.
//
// Returns:
// - The buffer value, or EMPTY_VALUE if error.
// ---------------------------------------------------------------------
double MarketDataUtils::get_buffer_value(int handle, int shift) {
double val[];
ArraySetAsSeries(val, true);
double val[];
ArraySetAsSeries(val, true);
int copied = CopyBuffer(handle, 0, shift, 1, val);
if (copied <= 0) {
Print("CopyBuffer failed: handle=", handle, " shift=", shift);
return EMPTY_VALUE;
}
int copied = CopyBuffer(handle, 0, shift, 1, val);
if (copied <= 0) {
Print("CopyBuffer failed: handle=", handle, " shift=", shift);
return EMPTY_VALUE;
}
if (val[0] == EMPTY_VALUE) {
Print("EMPTY_VALUE returned for buffer at shift=", shift);
return EMPTY_VALUE;
}
if (val[0] == EMPTY_VALUE) {
Print("EMPTY_VALUE returned for buffer at shift=", shift);
return EMPTY_VALUE;
}
return val[0];
return val[0];
}
// Adjusts the point value for symbol to account for fractional pips (e.g., 5-digit brokers)
// ---------------------------------------------------------------------
// Gets the latest (live) value from buffer (shift = 0).
//
// Parameters:
// - handle : Indicator handle.
//
// Returns:
// - Buffer value at shift 0 or EMPTY_VALUE if failed.
// ---------------------------------------------------------------------
double MarketDataUtils::get_latest_buffer_value(int handle) {
return get_buffer_value(handle, 0);
}
// ---------------------------------------------------------------------
// Computes adjusted point value considering fractional pip brokers.
//
// Parameters:
// - symbol : Symbol name.
//
// Returns:
// - Adjusted point multiplier.
// ---------------------------------------------------------------------
double MarketDataUtils::adjusted_point(string symbol) {
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
int digits_adjust = (symbol_digits == 3 || symbol_digits == 5) ? 10 : 1;
double point_val = SymbolInfoDouble(symbol, SYMBOL_POINT);
return point_val * digits_adjust; // Adjusted pip value
int symbol_digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
int digits_adjust = (symbol_digits == 3 || symbol_digits == 5) ? 10 : 1;
double point_val = SymbolInfoDouble(symbol, SYMBOL_POINT);
return point_val * digits_adjust;
}
// Returns current Bid or Ask price for a symbol based on side (1 = Ask, 2 = Bid)
// ---------------------------------------------------------------------
// Returns bid or ask price for a given symbol.
//
// Parameters:
// - symbol : Symbol name.
// - price_side : 1 = Ask, 2 = Bid.
//
// Returns:
// - Price value or 0.0 if input is invalid.
// ---------------------------------------------------------------------
double MarketDataUtils::get_bid_ask_price(string symbol, int price_side) {
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), digits);
double bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), digits);
int digits = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), digits);
double bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), digits);
if (price_side == 1) return ask;
if (price_side == 2) return bid;
if (price_side == 1) return ask;
if (price_side == 2) return bid;
return 0.0; // Invalid input
return 0.0;
}
+45 -49
View File
@@ -1,86 +1,82 @@
#include <MyLibs/Utils/SignalStateTracker.mqh>
// ---------------------------------------------------------------------
// This class manages a collection of SignalStateTracker instances — one per symbol.
// It allows you to track signals separately for each symbol in a multi-symbol EA.
// ---------------------------------------------------------------------
class MultiSymbolSignalTracker {
private:
// Struct to hold one (symbol → tracker) mapping
private:
// ---------------------------------------------------------------------
// Internal struct to associate a symbol with a SignalStateTracker.
// ---------------------------------------------------------------------
struct SymbolTracker {
string symbol; // Symbol name (e.g. "EURUSD", "HSI")
SignalStateTracker* tracker; // Pointer to the signal tracker for that symbol
string symbol;
SignalStateTracker* tracker;
};
SymbolTracker trackers[]; // Dynamic array of symbol-tracker pairs
SymbolTracker trackers[]; // Dynamic array of symbol-tracker mappings
// Helper function: Find the index of the given symbol in the array
// ---------------------------------------------------------------------
// Finds the index of the symbol in the tracker array.
// ---------------------------------------------------------------------
int find_index(const string& symbol) {
for (int i = 0; i < ArraySize(trackers); i++) {
if (trackers[i].symbol == symbol) return i; // Found symbol, return its index
if (trackers[i].symbol == symbol)
return i;
}
return -1; // Not found
return -1;
}
public:
// Destructor: automatically called when this object is destroyed (e.g. at EA shutdown)
public:
// ---------------------------------------------------------------------
// Destructor. Cleans up allocated memory when the object is destroyed.
// ---------------------------------------------------------------------
~MultiSymbolSignalTracker() {
clear(); // Clean up memory when done
clear();
}
// Returns the SignalStateTracker for the given symbol.
// If it doesn't exist yet, it creates one and stores it.
// ---------------------------------------------------------------------
// Retrieves the SignalStateTracker instance for a given symbol.
// Creates and stores a new one if it doesn't exist yet.
//
// Parameters:
// - symbol : Symbol for which to retrieve the signal tracker.
//
// Returns:
// - Pointer to the SignalStateTracker instance.
// ---------------------------------------------------------------------
SignalStateTracker* get_tracker(const string& symbol) {
int idx = find_index(symbol);
if (idx != -1) return trackers[idx].tracker; // Tracker already exists — return it
if (idx != -1)
return trackers[idx].tracker;
// If not found, create a new tracker for this symbol
// Create new tracker
SignalStateTracker* tracker = new SignalStateTracker();
SymbolTracker item;
item.symbol = symbol;
item.tracker = tracker;
// Add new item to dynamic array
ArrayResize(trackers, ArraySize(trackers) + 1);
trackers[ArraySize(trackers) - 1] = item;
return tracker;
}
// Deletes all trackers and resets the array.
// Should be called in OnDeinit() to free memory.
// ---------------------------------------------------------------------
// Clears all SignalStateTracker instances and resets the internal array.
// Should be called in `OnDeinit()` to avoid memory leaks.
//
// Logic:
// - Deletes each dynamically allocated SignalStateTracker.
// - Resets array size to 0.
// ---------------------------------------------------------------------
void clear() {
for (int i = 0; i < ArraySize(trackers); i++) {
delete trackers[i].tracker; // Manually free each dynamically created tracker
delete trackers[i].tracker;
}
ArrayResize(trackers, 0); // Reset array to empty
ArrayResize(trackers, 0);
}
};
/* ---------------------------------------------------------------------------
Example usage in an EA:
---------------------------------------------------------------------------
// Declare the tracker globally (outside OnTick/OnTimer)
MultiSymbolSignalTracker track_trigger;
// Inside your strategy() or OnTick():
void strategy(string symbol, ...) {
bool trig_long = ...; // Your signal logic
bool trig_short = ...;
// Update the signal tracker for this symbol
track_trigger.get_tracker(symbol).update_signal(trig_long, trig_short);
// Example: Check if a recent long signal occurred
if (track_trigger.get_tracker(symbol).long_signal_recent(5)) {
// Do something like open a trade
}
}
// In OnDeinit():
void OnDeinit(const int reason) {
track_trigger.clear(); // Clean up memory
}
*/
+36 -18
View File
@@ -1,44 +1,61 @@
#include <MyLibs/Utils/AtrHandleManager.mqh>
//+------------------------------------------------------------------+
//| ResourceManager |
//| |
//| Tracks and releases indicator handles (iMA, iRSI, etc.) |
//| Also delegates ATR handle cleanup to an external ATR manager |
//+------------------------------------------------------------------+
// ---------------------------------------------------------------------
// ResourceManager
//
// Tracks and releases indicator handles (e.g., iMA, iRSI, iCCI).
// Delegates ATR handle management to an external AtrHandleManager instance.
//
// Usage:
// - Register indicator handles via `register_handle()`.
// - Call `release_all_handles()` to release all cached handles.
// ---------------------------------------------------------------------
class ResourceManager {
public:
// --- Pointer to external ATR manager (set externally)
// Used for releasing any internally cached ATR handles
AtrHandleManager* atr_manager;
// --- Register a new indicator handle to be released later
// Only valid (non-INVALID_HANDLE) handles are stored
// ---------------------------------------------------------------------
// Registers a generic indicator handle to be released later.
//
// Parameters:
// - handle : A valid (non-INVALID_HANDLE) indicator handle.
//
// Logic:
// - If the handle is valid, it is added to an internal list.
// ---------------------------------------------------------------------
void register_handle(int handle) {
if (handle != INVALID_HANDLE)
add_handle(handle);
}
// --- Release all tracked resources:
// ---------------------------------------------------------------------
// Releases all tracked indicator resources.
//
// Logic:
// - Releases generic handles tracked via `register_handle()`.
// - Also invokes `atr_manager.release_handles()` if assigned.
// ---------------------------------------------------------------------
void release_all_handles() {
release_internal_handles(); // ATR manager
release_tracked_handles(); // Generic indicator handles
}
private:
// --- Dynamic array of general indicator handles
int handles[];
// --- Append a valid indicator handle to the internal array
// Used by register_handle()
// ---------------------------------------------------------------------
// Adds a handle to the internal tracking list.
// ---------------------------------------------------------------------
void add_handle(int handle) {
int size = ArraySize(handles);
ArrayResize(handles, size + 1);
handles[size] = handle;
}
// --- Release all generic indicator handles tracked internally
// This covers iMA, iRSI, iCCI, etc.
// ---------------------------------------------------------------------
// Releases all tracked indicator handles (iMA, iRSI, etc.).
// ---------------------------------------------------------------------
void release_tracked_handles() {
for (int i = 0; i < ArraySize(handles); i++) {
if (handles[i] != INVALID_HANDLE)
@@ -47,8 +64,9 @@ private:
ArrayFree(handles);
}
// --- Release ATR handles via external AtrHandleManager
// No-op if atr_manager is not assigned
// ---------------------------------------------------------------------
// Releases any cached ATR handles using the external AtrHandleManager.
// ---------------------------------------------------------------------
void release_internal_handles() {
if (atr_manager != NULL)
atr_manager.release_handles();
+77 -14
View File
@@ -1,22 +1,51 @@
class SignalStateTracker {
private:
private:
// ---------------------------------------------------------------------
// Index of the last long signal detected (default -1000 when unset).
// ---------------------------------------------------------------------
int last_signal_long;
// ---------------------------------------------------------------------
// Index of the last short signal detected (default -1000 when unset).
// ---------------------------------------------------------------------
int last_signal_short;
public:
// Constructor initializes both directions to a default "unset" state.
public:
// ---------------------------------------------------------------------
// Constructor initializes the signal tracker to a reset state.
//
// Logic:
// - Sets both long and short signal indices to -1000.
// ---------------------------------------------------------------------
SignalStateTracker() {
reset();
}
// Resets the tracked signal bar indexes to an invalid default value (-1000).
// ---------------------------------------------------------------------
// Resets the signal tracker.
//
// Logic:
// - Sets `last_signal_long` and `last_signal_short` to -1000,
// representing no signal recorded.
// ---------------------------------------------------------------------
void reset() {
last_signal_long = -1000;
last_signal_short = -1000;
}
// Updates the signal tracker based on trigger presence per bar.
// If signal is detected, sets to 1. If not, increments previous value.
// ---------------------------------------------------------------------
// Updates internal state based on whether long/short signals occurred.
//
// Parameters:
// - signal_long : True if a long signal occurred this bar.
// - signal_short : True if a short signal occurred this bar.
//
// Logic:
// - If a signal is detected, sets the index to 1 (bar 1).
// - Otherwise, increments the previous value if it was positive.
// ---------------------------------------------------------------------
void update_signal_tracker(bool signal_long, bool signal_short) {
if (signal_long) {
last_signal_long = 1;
@@ -31,34 +60,68 @@ class SignalStateTracker {
}
}
// Returns true if a long signal occurred within the last `max_bars` bars.
// ---------------------------------------------------------------------
// Checks if a long signal occurred within the last N bars.
//
// Parameters:
// - max_bars : Number of bars to look back for the signal.
//
// Returns:
// - True if a long signal occurred within `max_bars` bars.
// ---------------------------------------------------------------------
bool long_signal_recent(int max_bars) const {
// Assumes current bar is always bar index 1 (last closed bar).
return has_long_signal() && (1 - last_signal_long <= max_bars);
}
// Returns true if a short signal occurred within the last `max_bars` bars.
// ---------------------------------------------------------------------
// Checks if a short signal occurred within the last N bars.
//
// Parameters:
// - max_bars : Number of bars to look back for the signal.
//
// Returns:
// - True if a short signal occurred within `max_bars` bars.
// ---------------------------------------------------------------------
bool short_signal_recent(int max_bars) const {
// Assumes current bar is always bar index 1 (last closed bar).
return has_short_signal() && (1 - last_signal_short <= max_bars);
}
// Returns true if a signal has been recorded for the long direction.
// ---------------------------------------------------------------------
// Indicates if any long signal has ever been recorded.
//
// Returns:
// - True if a long signal index is not equal to -1000.
// ---------------------------------------------------------------------
bool has_long_signal() const {
return last_signal_long != -1000;
}
// Returns true if a signal has been recorded for the short direction.
// ---------------------------------------------------------------------
// Indicates if any short signal has ever been recorded.
//
// Returns:
// - True if a short signal index is not equal to -1000.
// ---------------------------------------------------------------------
bool has_short_signal() const {
return last_signal_short != -1000;
}
// Returns the last recorded signal bar index for the long direction.
// ---------------------------------------------------------------------
// Returns the last bar index at which a long signal occurred.
//
// Returns:
// - Integer index representing bars since long signal.
// ---------------------------------------------------------------------
int get_long_signal() const {
return last_signal_long;
}
// Returns the last recorded signal bar index for the short direction.
// ---------------------------------------------------------------------
// Returns the last bar index at which a short signal occurred.
//
// Returns:
// - Integer index representing bars since short signal.
// ---------------------------------------------------------------------
int get_short_signal() const {
return last_signal_short;
}
+150 -118
View File
@@ -1,144 +1,176 @@
#property library
#include <Trade/Trade.mqh>
#include <MyLibs/Utils/DealingWithTime.mqh>
#include <Trade/Trade.mqh>
class TimeZones: public CObject{
protected:
string dt_s;
int len;
string dt_string;
datetime tC, tGMT, tNY, tLon, tFfm, tMosc, tSyd, tTok;
datetime tz_time;
string tz_date;
datetime time_start;
datetime time_end;
bool is_time;
datetime tGIVEN;
datetime tREQ;
datetime tzt;
datetime tz_req;
double ny_daily_close_protected(string symbol, int shift_days, bool print_data=false);
double required_close;
class TimeZones : public CObject {
protected:
string dt_s;
int len;
string dt_string;
datetime tC, tGMT, tNY, tLon, tFfm, tMosc, tSyd, tTok;
datetime tz_time;
string tz_date;
datetime time_start;
datetime time_end;
bool is_time;
datetime tGIVEN;
datetime tREQ;
datetime tzt;
datetime tz_req;
double required_close;
public:
string get_date_string_from_datetime(datetime dt);
datetime get_timezone_time(string time_zone, bool print_time);
datetime timezone_conversions(string time_zone_known, datetime time_given, string time_zone_required);
double ny_daily_close(string symbol, int shift_days, bool print_data=false);
double ny_daily_close_protected(string symbol, int shift_days, bool print_data = false);
public:
string get_date_string_from_datetime(datetime dt);
datetime get_timezone_time(string time_zone, bool print_time);
datetime timezone_conversions(string time_zone_known, datetime time_given, string time_zone_required);
double ny_daily_close(string symbol, int shift_days, bool print_data = false);
};
string TimeZones::get_date_string_from_datetime(datetime dt){
dt_s = TimeToString(dt);
len = StringLen(dt_s);
dt_string = StringSubstr(dt_s, 0, len-5);
return dt_string;
// ---------------------------------------------------------------------
// Converts a datetime to a string excluding seconds.
//
// Parameters:
// - dt : Datetime object.
//
// Returns:
// - A string in the format "yyyy.mm.dd hh:mi".
// ---------------------------------------------------------------------
string TimeZones::get_date_string_from_datetime(datetime dt) {
dt_s = TimeToString(dt);
len = StringLen(dt_s);
dt_string = StringSubstr(dt_s, 0, len - 5);
return dt_string;
}
// ---------------------------------------------------------------------
// Gets the current time in the specified time zone.
//
// Parameters:
// - time_zone : One of "NY", "Lon", "Ffm", "Syd", "Mosc", "Tok".
// - print_time : If true, logs various times for debugging.
//
// Returns:
// - Current time in the specified time zone.
// ---------------------------------------------------------------------
datetime TimeZones::get_timezone_time(string time_zone, bool print_time) {
checkTimeOffset(TimeCurrent()); // Adjust DST
datetime TimeZones::get_timezone_time(string time_zone, bool print_time){
// https://www.mql5.com/en/code/45287
// https://www.mql5.com/en/articles/9926
// https://www.mql5.com/en/articles/9929
tC = TimeCurrent();
tGMT = TimeCurrent() + OffsetBroker.actOffset;
tNY = tGMT - (NYShift + DST_USD);
tLon = tGMT - (LondonShift + DST_EUR);
tFfm = tGMT - (FfmShift + DST_EUR);
tSyd = tGMT - (SidneyShift + DST_AUD);
tMosc = tGMT - (MoskwaShift + DST_RUS);
tTok = tGMT - (TokyoShift);
checkTimeOffset(TimeCurrent()); // check changes of DST
// cto();
if (print_time) {
Print("----------------------------------");
Print("Broker: ", tC);
Print("GMT: ", tGMT);
Print("time in New York: ", tNY);
Print("time in London: ", tLon);
Print("time in Frankfurt: ", tFfm);
Print("time in Sidney: ", tSyd);
Print("time in Moscow: ", tMosc);
Print("time in Tokyo: ", tTok);
}
tC = TimeCurrent();
tGMT = TimeCurrent() + OffsetBroker.actOffset; // GMT
tNY = tGMT - (NYShift+DST_USD); // time in New York (EST)
tLon = tGMT - (LondonShift+DST_EUR); // time in London
tFfm = tGMT - (FfmShift+DST_EUR); // time in Frankfurt
tSyd = tGMT - (SidneyShift+DST_AUD); // time in Sidney
tMosc = tGMT - (MoskwaShift+DST_RUS); // time in Moscow
tTok = tGMT - (TokyoShift); // time in Tokyo - no DST
if (time_zone == "NY") return tNY;
if (time_zone == "Lon") return tLon;
if (time_zone == "Ffm") return tFfm;
if (time_zone == "Syd") return tSyd;
if (time_zone == "Mosc") return tMosc;
if (time_zone == "Tok") return tTok;
if(print_time==true){
Print("----------------------------------");
Print("Broker: ", tC);
Print("GMT: ", tGMT);
Print("time in New York: ", tNY);
Print("time in London: ", tLon);
Print("time in Frankfurt: ", tFfm);
Print("time in Sidney: ", tSyd);
Print("time in Moscow: ", tMosc);
Print("time in Tokyo: ", tTok);
}
if(time_zone=="NY"){return tNY;}
if(time_zone=="Lon"){return tLon;}
if(time_zone=="Ffm"){return tFfm;}
if(time_zone=="Syd"){return tSyd;}
if(time_zone=="Mosc"){return tMosc;}
if(time_zone=="Tok"){return tTok;}
return NULL;
return NULL;
}
// ---------------------------------------------------------------------
// Converts a datetime from one timezone to another.
//
// Parameters:
// - time_zone_known : Original timezone of the datetime.
// - time_given : The datetime to convert.
// - time_zone_required : Desired output timezone.
//
// Returns:
// - The equivalent datetime in the target timezone.
// ---------------------------------------------------------------------
datetime TimeZones::timezone_conversions(string time_zone_known, datetime time_given, string time_zone_required) {
tGIVEN = time_given;
checkTimeOffset(tGIVEN); // Adjust DST
datetime TimeZones::timezone_conversions(string time_zone_known, datetime time_given, string time_zone_required){
// https://www.mql5.com/en/code/45287
// https://www.mql5.com/en/articles/9926
// https://www.mql5.com/en/articles/9929
// Step 1: Convert known timezone to GMT
if (time_zone_known == "GMT") tGMT = tGIVEN;
if (time_zone_known == "Broker") tGMT = tGIVEN + OffsetBroker.actOffset;
if (time_zone_known == "NY") tGMT = tGIVEN + (NYShift + DST_USD);
if (time_zone_known == "Lon") tGMT = tGIVEN + (LondonShift + DST_EUR);
if (time_zone_known == "Ffm") tGMT = tGIVEN + (FfmShift + DST_EUR);
if (time_zone_known == "Syd") tGMT = tGIVEN + (SidneyShift + DST_AUD);
if (time_zone_known == "Mosc") tGMT = tGIVEN + (MoskwaShift + DST_RUS);
if (time_zone_known == "Tok") tGMT = tGIVEN + (TokyoShift);
tGIVEN = time_given; //StringToTime(time_given);
checkTimeOffset(tGIVEN); // check changes of DST
// Step 2: Convert GMT to required timezone
if (time_zone_required == "GMT") tREQ = tGMT;
if (time_zone_required == "Broker") tREQ = tGMT - OffsetBroker.actOffset;
if (time_zone_required == "NY") tREQ = tGMT - (NYShift + DST_USD);
if (time_zone_required == "Lon") tREQ = tGMT - (LondonShift + DST_EUR);
if (time_zone_required == "Ffm") tREQ = tGMT - (FfmShift + DST_EUR);
if (time_zone_required == "Syd") tREQ = tGMT - (SidneyShift + DST_AUD);
if (time_zone_required == "Mosc") tREQ = tGMT - (MoskwaShift + DST_RUS);
if (time_zone_required == "Tok") tREQ = tGMT - (TokyoShift);
// Get GMT:
if(time_zone_known=="GMT" ){tGMT = tGIVEN;}
if(time_zone_known=="Broker" ){tGMT = tGIVEN + OffsetBroker.actOffset;}
if(time_zone_known=="NY" ){tGMT = tGIVEN + (NYShift+DST_USD);}
if(time_zone_known=="Lon" ){tGMT = tGIVEN + (LondonShift+DST_EUR);}
if(time_zone_known=="Ffm" ){tGMT = tGIVEN + (FfmShift+DST_EUR);}
if(time_zone_known=="Syd" ){tGMT = tGIVEN + (SidneyShift+DST_AUD);}
if(time_zone_known=="Mosc" ){tGMT = tGIVEN + (MoskwaShift+DST_RUS);}
if(time_zone_known=="Tok" ){tGMT = tGIVEN + (TokyoShift);}
// define the required time:
tREQ = NULL;
if(time_zone_required=="GMT" ){tREQ = tGMT;}
if(time_zone_required=="Broker" ){tREQ = tGMT - OffsetBroker.actOffset;}
if(time_zone_required=="NY" ){tREQ = tGMT - (NYShift+DST_USD);}
if(time_zone_required=="Lon" ){tREQ = tGMT - (LondonShift+DST_EUR);}
if(time_zone_required=="Ffm" ){tREQ = tGMT - (FfmShift+DST_EUR);}
if(time_zone_required=="Syd" ){tREQ = tGMT - (SidneyShift+DST_AUD) ;}
if(time_zone_required=="Mosc" ){tREQ = tGMT - (MoskwaShift+DST_RUS);}
if(time_zone_required=="Tok" ){tREQ = tGMT - (TokyoShift);}
return tREQ;
return tREQ;
}
// Calculte NY close time:
double TimeZones::ny_daily_close(string symbol, int shift_days, bool print_data=false){
required_close = ny_daily_close_protected(symbol, shift_days, print_data);
return required_close;
// ---------------------------------------------------------------------
// Returns the most recent NY daily close price.
//
// Parameters:
// - symbol : Trading symbol.
// - shift_days : How many NY daily closes back to return.
// - print_data : If true, logs debug information.
//
// Returns:
// - The NY close price.
// ---------------------------------------------------------------------
double TimeZones::ny_daily_close(string symbol, int shift_days, bool print_data) {
required_close = ny_daily_close_protected(symbol, shift_days, print_data);
return required_close;
}
double TimeZones::ny_daily_close_protected(string symbol, int shift_days, bool print_data=false){
// Get the brokers times for when NY openend today and tomorrow:
datetime time_5pm = iTime(symbol, PERIOD_D1 , 0) - (PeriodSeconds(PERIOD_H1) * 7);
datetime ny_close_in_brokers_time = timezone_conversions("NY", time_5pm, "Broker");
datetime ny_close_time = ny_close_in_brokers_time + PeriodSeconds(PERIOD_D1); // ny close tomorrow
// ---------------------------------------------------------------------
// Internal implementation to compute NY daily close price.
//
// Logic:
// - Defines NY close as 5pm NY time = 00:00 broker + 17H back.
// - Adjusts for day shifts if required.
// - Returns the close price of the NY daily session.
// ---------------------------------------------------------------------
double TimeZones::ny_daily_close_protected(string symbol, int shift_days, bool print_data) {
datetime time_5pm = iTime(symbol, PERIOD_D1, 0) - (PeriodSeconds(PERIOD_H1) * 7);
datetime ny_close_in_brokers_time = timezone_conversions("NY", time_5pm, "Broker");
datetime ny_close_time = ny_close_in_brokers_time + PeriodSeconds(PERIOD_D1);
if(TimeCurrent()<ny_close_time){
ny_close_time = ny_close_time - PeriodSeconds(PERIOD_D1); // ny close today
}
if (TimeCurrent() < ny_close_time) ny_close_time -= PeriodSeconds(PERIOD_D1);
// Get the number of hours since NY closed:
int shift = iBarShift(symbol, PERIOD_H1, ny_close_time, false) + 1;
shift = shift + (24 * (shift_days - 1)); // shift days if required:
int shift = iBarShift(symbol, PERIOD_H1, ny_close_time, false) + 1;
shift += (24 * (shift_days - 1));
double ny_close = iClose(symbol,PERIOD_H1, shift);
double br_close = iClose(symbol,PERIOD_H1, 1);
double ny_close = iClose(symbol, PERIOD_H1, shift);
double br_close = iClose(symbol, PERIOD_H1, 1);
if(print_data==true){
Print("shift ",shift);
Print("time_5pm ",time_5pm);
Print("ny_close_in_brokers_time ",ny_close_in_brokers_time);
Print("ny_close_time ",ny_close_time);
Print("ny_close ", ny_close);
Print("br_close ",br_close);
}
return ny_close;
if (print_data) {
Print("shift ", shift);
Print("time_5pm ", time_5pm);
Print("ny_close_in_brokers_time ", ny_close_in_brokers_time);
Print("ny_close_time ", ny_close_time);
Print("ny_close ", ny_close);
Print("br_close ", br_close);
}
return ny_close;
}
+17
View File
@@ -12,6 +12,23 @@ public:
bool trade_window(string t1, string t2, string time_zone = "Broker", bool plot_range_inp = true);
};
// ---------------------------------------------------------------------
// Determines whether the current time is inside a defined trade session.
//
// Parameters:
// - t1 : Start time string (e.g., "22:00").
// - t2 : End time string (e.g., "01:00").
// - time_zone : The timezone of input times (default = "Broker").
// - plot_range_inp : If true, draws vertical lines for start/end.
//
// Returns:
// - true if current time is within the session window, false otherwise.
//
// Logic:
// - Handles overnight sessions (e.g. 22:0001:00) correctly.
// - Automatically rolls the window to the next day when expired.
// - Uses TimeZones class to convert time to broker timezone.
// ---------------------------------------------------------------------
bool TradeSessionUtils::trade_window(string t1, string t2, string time_zone, bool plot_range_inp) {
datetime _t1 = StringToTime(t1); // Convert string to datetime
datetime _t2 = StringToTime(t2); // Convert string to datetime