How to Set Trading Time in MQL5?

Importance of Controlling Trading Hours

Effective algorithmic trading often hinges on precision, and this includes when your Expert Advisor (EA) operates. Controlling trading hours is paramount for several reasons:

  • Aligning with Market Liquidity: Trading during peak liquidity hours (e.g., session overlaps) can reduce slippage and improve execution.
  • Strategy Specificity: Many strategies are designed for specific market conditions prevalent during certain trading sessions (e.g., breakout strategies during London open, range trading during Asian session).
  • Risk Management: Avoiding trading during highly volatile news releases or periods of low liquidity (like weekends or holidays) can protect capital.
  • Resource Optimization: Prevents the EA from analyzing markets or attempting trades when conditions are unfavorable or trading is disabled by the broker.

Overview of MQL5 Functions for Time Management

MQL5 provides a robust set of functions for time management. Key functions include:

  • TimeCurrent(): Retrieves the current server time of the broker. This is the most crucial time for trading logic.
  • TimeLocal(): Gets the local time of the computer where the terminal is running.
  • TimeToStruct(datetime time, MqlDateTime& dt_struct): Converts a datetime value into a MqlDateTime structure, making it easy to access individual components like hour, minute, day of the week, etc.
  • StructToTime(MqlDateTime& dt_struct): Performs the reverse operation of TimeToStruct.
  • EventSetTimer() / EventKillTimer(): Manages timer events for scheduled tasks.

Using TimeCurrent() and TimeLocal() Functions

Understanding the Difference Between Server and Local Time

A common pitfall for developers is confusing server time with local time.

  • TimeCurrent() (Server Time): This function returns the last known server time, which is the time at the broker’s trade server. All trading operations, historical data timestamps, and server-side events are based on this time. For all trading logic, TimeCurrent() should be the primary source.
  • TimeLocal() (Local Time): This function returns the time of the operating system on the computer where your MetaTrader 5 terminal is running. It can be useful for logging or UI elements specific to the user’s timezone, but it should not be used for making trading decisions due to potential discrepancies with server time and its irrelevance to trade execution timing.

The difference, TimeCurrent() - TimeLocal(), can be used to find the offset, but this offset can change (e.g., due to Daylight Saving Time changes on either the server or local machine) and is generally not needed if you consistently use TimeCurrent().

Retrieving Current Time Information

Both TimeCurrent() and TimeLocal() return a datetime value, which represents the number of seconds elapsed since 00:00 January 1, 1970. To work with this information in a more human-readable format, we use the MqlDateTime structure and the TimeToStruct() function.

void OnTick() {
    // Retrieve server time
    datetime serverTime = TimeCurrent();
    MqlDateTime srvTimeStruct;
    TimeToStruct(serverTime, srvTimeStruct);

    PrintFormat("Server Time: %04u.%02u.%02u %02u:%02u:%02u (Day of Week: %d)",
                srvTimeStruct.year, srvTimeStruct.mon, srvTimeStruct.day,
                srvTimeStruct.hour, srvTimeStruct.min, srvTimeStruct.sec,
                srvTimeStruct.day_of_week);

    // Retrieve local time
    datetime localTime = TimeLocal();
    MqlDateTime locTimeStruct;
    TimeToStruct(localTime, locTimeStruct);

    PrintFormat("Local Time: %04u.%02u.%02u %02u:%02u:%02u (Day of Week: %d)",
                locTimeStruct.year, locTimeStruct.mon, locTimeStruct.day,
                locTimeStruct.hour, locTimeStruct.min, locTimeStruct.sec,
                locTimeStruct.day_of_week);
}

Note: srvTimeStruct.day_of_week will be 0 for Sunday, 1 for Monday, …, 6 for Saturday.

Implementing Trading Hour Restrictions

Checking if the Current Time is Within Allowed Trading Hours

To restrict trading to specific hours, you need to extract the hour and minute from the current server time and compare them against your desired trading window.

// Input parameters for the EA
input int StartTradingHour = 9;    // e.g., 9 AM
input int StartTradingMinute = 0;
input int EndTradingHour = 17;     // e.g., 5 PM (trades will not be placed at 17:00 or later)
input int EndTradingMinute = 0;

bool IsWithinTradingHours() {
    MqlDateTime currentTimeStruct;
    TimeToStruct(TimeCurrent(), currentTimeStruct);

    int currentTotalMinutes = currentTimeStruct.hour * 60 + currentTimeStruct.min;
    int startTotalMinutes = StartTradingHour * 60 + StartTradingMinute;
    int endTotalMinutes = EndTradingHour * 60 + EndTradingMinute;

    // Case 1: Normal period (e.g., 09:00 - 17:00)
    if (startTotalMinutes <= endTotalMinutes) {
        return (currentTotalMinutes >= startTotalMinutes && currentTotalMinutes < endTotalMinutes);
    }
    // Case 2: Overnight period (e.g., 22:00 - 05:00)
    else {
        return (currentTotalMinutes >= startTotalMinutes || currentTotalMinutes < endTotalMinutes);
    }
}

void OnTick() {
    if (!IsWithinTradingHours()) {
        Print("Outside of configured trading hours. No new trades.");
        return;
    }
    // Proceed with trading logic
    Print("Within trading hours. Evaluating trading signals...");
}

The condition currentTotalMinutes < endTotalMinutes ensures that trading stops before the EndTradingHour:EndTradingMinute. If you want to include trades exactly at the end minute, you might adjust logic or input expectations.

Creating Functions to Define Trading Sessions

For clarity and reusability, encapsulate session checking logic into functions. You might have multiple sessions, e.g., Asian, London, New York.

// Structure to define a trading session
struct TradingSession {
    string name;
    int startHour;
    int startMinute;
    int endHour;
    int endMinute;
    bool isActive; // To easily enable/disable sessions via inputs

    bool IsTimeWithin(const MqlDateTime &dt) const {
        int currentTotalMinutes = dt.hour * 60 + dt.min;
        int startTotalMinutes = startHour * 60 + startMinute;
        int endTotalMinutes = endHour * 60 + endMinute;

        if (startTotalMinutes <= endTotalMinutes) {
            return (currentTotalMinutes >= startTotalMinutes && currentTotalMinutes < endTotalMinutes);
        } else {
            return (currentTotalMinutes >= startTotalMinutes || currentTotalMinutes < endTotalMinutes);
        }
    }
};

// Example usage:
TradingSession londonSession = {"London", 10, 0, 18, 0, true}; // Assuming broker time +2 UTC, London opens 8 AM UTC (10:00 broker)

void OnTick() {
    MqlDateTime currentTimeStruct;
    TimeToStruct(TimeCurrent(), currentTimeStruct);

    if (londonSession.isActive && londonSession.IsTimeWithin(currentTimeStruct)) {
        Print(londonSession.name, " session is active.");
        // London session trading logic
    } else {
        Print(londonSession.name, " session is inactive or outside hours.");
    }
}

Handling Weekend Restrictions

Most markets are closed on weekends. It’s crucial to prevent your EA from attempting to trade during these times.

bool IsWeekend(datetime time) {
    MqlDateTime dtStruct;
    TimeToStruct(time, dtStruct);
    return (dtStruct.day_of_week == SUNDAY || dtStruct.day_of_week == SATURDAY); // 0 for Sunday, 6 for Saturday
}

void OnTick() {
    if (IsWeekend(TimeCurrent())) {
        Print("Market closed (Weekend). No trading.");
        return;
    }

    // ... rest of your trading logic
}

Advanced Techniques for Time-Based Trading

Utilizing EventSetTimer() for Scheduled Operations

Sometimes you need actions performed at specific intervals or times, independent of incoming ticks. EventSetTimer() creates a timer that will generate OnTimer() events.

// In OnInit()
int OnInit() {
    // Set a timer to trigger every minute
    EventSetTimer(60); // Parameter is in seconds
    return(INIT_SUCCEEDED);
}

// In OnDeinit()
void OnDeinit(const int reason) {
    EventKillTimer();
}

// Timer event handler
void OnTimer() {
    // This code will execute every 60 seconds
    MqlDateTime now;
    TimeToStruct(TimeCurrent(), now);

    // Example: Check if it's 5 minutes before market close to flatten positions
    // This is a simplified example; precise closing logic might vary.
    // if (now.hour == EndTradingHour && now.min == (EndTradingMinute - 5 + 60) % 60 ) { 
    //     CloseAllPositions();
    //     Print("Approaching end of trading day, preparing to close positions.");
    // }

    // Another example: Perform a check at the start of every hour
    if (now.min == 0 && now.sec < 5) { // Check within the first few seconds of the hour
        PrintFormat("Hourly check at %02u:00", now.hour);
        // Perform hourly tasks
    }
}

EventSetTimer is powerful for tasks like periodic checks, data downloads, or time-based order modifications without relying on OnTick.

Calculating Time to Next Trading Session

Knowing when the next trading session begins can be useful for an EA to manage its state or provide information to the user. The general approach involves:

  1. Determining the target start time (hour, minute) for the session.
  2. Getting the current server time (TimeCurrent()) and converting it to an MqlDateTime structure.
  3. Creating an MqlDateTime structure for today’s session start time by setting the hour and minute, keeping the current date.
  4. Converting both current time and target session start time to datetime timestamps (seconds since epoch).
  5. If the current time is already past today’s session start time, the next session will be on a subsequent day. You would then calculate the timestamp for the session start on the next valid trading day (e.g., adding 24*60*60 seconds for the next day, and ensuring to skip weekends).
  6. The difference between the next session start timestamp and the current timestamp gives the seconds remaining. This can be formatted into hours/minutes/seconds.

This calculation requires careful handling of date rollovers (day, month, year) and skipping non-trading days (weekends, holidays). For many EAs, a simpler approach is to periodically check (e.g., via OnTimer or OnTick) if the current time is within an allowed session and remain idle otherwise, rather than calculating precise countdowns.

Implementing Dynamic Trading Schedules

For sophisticated strategies, trading hours might not be static. They could depend on:

  • Day of the week: Different hours for Monday vs. Friday.
  • Volatility conditions: Only trade if ATR is above a certain level during specific general hours.
  • News events: Pausing trading around major news releases. This typically requires an external news calendar integration or a manual input mechanism.

Implementing this involves adding more layers of conditional logic to your IsTradingAllowed() function or equivalent checks, potentially using arrays of TradingSession structs and selecting the active one based on day_of_week or other criteria.

// Example: Different closing hours for Friday
// (Assumes StartTradingHour, StartTradingMinute, EndTradingHour, EndTradingMinute are global or inputs)
input int FridayEndHour = 15;
input int FridayEndMinute = 0;

bool IsWithinTradingHoursDynamic() {
    MqlDateTime currentTimeStruct;
    TimeToStruct(TimeCurrent(), currentTimeStruct);

    int effectiveEndHour = EndTradingHour;       // Default end hour
    int effectiveEndMinute = EndTradingMinute;   // Default end minute

    if (currentTimeStruct.day_of_week == FRIDAY) {
        effectiveEndHour = FridayEndHour;
        effectiveEndMinute = FridayEndMinute;
    }

    int currentTotalMinutes = currentTimeStruct.hour * 60 + currentTimeStruct.min;
    int startTotalMinutes = StartTradingHour * 60 + StartTradingMinute;
    int endTotalMinutes = effectiveEndHour * 60 + effectiveEndMinute;

    if (startTotalMinutes <= endTotalMinutes) { // Normal period
        return (currentTotalMinutes >= startTotalMinutes && currentTotalMinutes < endTotalMinutes);
    } else { // Overnight period
        return (currentTotalMinutes >= startTotalMinutes || currentTotalMinutes < endTotalMinutes);
    }
}

Practical Examples and Considerations

Example: Trading only during London and New York sessions

This requires defining multiple time windows and checking if the current time falls into any of them. Broker server time is key. Assume your broker server is GMT+2 (this is an example, verify your broker’s time).

  • London Actual Open: 8:00 AM GMT -> If broker is GMT+2, this is 10:00 AM Broker Time.
  • New York Actual Open: 1:00 PM GMT (13:00) -> If broker is GMT+2, this is 3:00 PM Broker Time (15:00).

Set your EA inputs based on the broker’s server time.

// Inputs for London Session (Broker Time)
input int LonStartHour = 10; input int LonStartMin = 0; // Example: 10:00 broker time
input int LonEndHour = 18;   input int LonEndMin = 0;   // Example: 18:00 broker time

// Inputs for New York Session (Broker Time)
input int NYStartHour = 15;  input int NYStartMin = 0;  // Example: 15:00 broker time
input int NYEndHour = 23;    input int NYEndMin = 0;    // Example: 23:00 broker time

// Reusable function to check if current time is in a given session's hours
bool IsTimeInSession(const MqlDateTime &dt, int sH, int sM, int eH, int eM) {
    int currentTotalMinutes = dt.hour * 60 + dt.min;
    int startTotalMinutes = sH * 60 + sM;
    int endTotalMinutes = eH * 60 + eM;

    if (startTotalMinutes <= endTotalMinutes) {
        return (currentTotalMinutes >= startTotalMinutes && currentTotalMinutes < endTotalMinutes);
    } else { // Handles overnight sessions, though not typical for Lon/NY individually
        return (currentTotalMinutes >= startTotalMinutes || currentTotalMinutes < endTotalMinutes);
    }
}

void OnTick() {
    if (IsWeekend(TimeCurrent())) {
        Print("Market closed (Weekend).");
        return;
    }

    MqlDateTime currentTimeStruct;
    TimeToStruct(TimeCurrent(), currentTimeStruct);

    bool isLondonActive = IsTimeInSession(currentTimeStruct, LonStartHour, LonStartMin, LonEndHour, LonEndMin);
    bool isNYActive = IsTimeInSession(currentTimeStruct, NYStartHour, NYStartMin, NYEndHour, NYEndMin);

    if (isLondonActive || isNYActive) {
        string activeSessions = "";
        if (isLondonActive) activeSessions += "London ";
        if (isNYActive) activeSessions += "New York";
        PrintFormat("%s session(s) active. Trade logic enabled.", StringTrim(activeSessions));

        // --- Your core trading logic here ---

    } else {
        Print("Outside of specified London/NY trading sessions.");
    }
}

Dealing with Broker Time Zone Differences

The fundamental rule is: always base your trading times on TimeCurrent() (broker’s server time). Your EA’s input parameters for start and end hours must be relative to this server time.

  • DST (Daylight Saving Time): Most brokers adjust their server time for DST if their server’s locality observes it. This means TimeCurrent() automatically reflects these changes. If your strategy targets specific UTC times (e.g., London open always at 8:00 UTC), you must be aware of your broker’s current UTC offset and how it changes with DST. Some brokers maintain a fixed offset (e.g., GMT+2 always), while others shift (e.g., GMT+2 in winter, GMT+3 in summer for European brokers).
    • To make an EA robust to broker DST changes when targeting absolute UTC times, you’d ideally need to know the broker’s current UTC offset. MQL5 doesn’t have a direct function like BrokerGMTOffset(). You might compare TimeCurrent() with TimeGMT() (available in MqlDateTime from TimeToStruct(TimeCurrent(), dt); dt.gmt_ofs; – but this is client’s interpretation of GMT offset for TimeCurrent() not necessarily broker’s base definition). A common, robust method is to use an input parameter for the broker’s current base UTC offset, which you update manually if necessary.
    • Often, it’s simpler to define session times in broker server hours in your EA’s inputs. You would then manually adjust these inputs if the broker’s DST changes shift their server time relative to the true market session times you are targeting (e.g., London open at 8 AM UTC).

Best Practices for Reliable Time Management in MQL5

  • Exclusively Use TimeCurrent(): For all trading logic, time-based conditions, and historical data alignment, rely solely on the broker’s server time.
  • MqlDateTime is Your Friend: Convert datetime values to the MqlDateTime structure using TimeToStruct() for easy and reliable access to hours, minutes, day of the week, etc.
  • Parameterize Trading Hours: Use input variables for start/end hours and minutes. This makes the EA flexible, testable, and configurable without code modification.
  • Handle Overnight Sessions Correctly: If your defined trading window spans midnight (e.g., 22:00 server time to 05:00 server time), ensure your comparison logic (currentTime >= startTime || currentTime < endTime) is correctly implemented using total minutes or consistent hour/minute comparisons.
  • Weekend and Holiday Handling: Always include logic to prevent trading on weekends (day_of_week == SATURDAY || day_of_week == SUNDAY). For market holidays, MQL5 does not provide a built-in calendar; this requires a manual list, external data feed, or user input.
  • Thorough Testing in Strategy Tester: Test your time-based logic extensively, especially across date ranges that include DST transitions for your broker’s server time zone. Test with different brokers (demo accounts) if you plan to use the EA widely, as server time configurations can vary.
  • Consider OnTimer for Precise Timed Actions: If an action must occur at a very specific time (e.g., closing all positions at 16:59:59 server time), using EventSetTimer() and the OnTimer() event handler is more reliable than OnTick, as ticks are not guaranteed to arrive at every second.
  • Keep it Server-Centric: Always think and code in terms of the broker’s server time. If your strategy says

Leave a Reply