How to check 'Market is closed' befor opening a position? - page 3

 
Zsolt Haromszeki:

Dear Coders!

I started a backtest. My expert advisor is trying to open a position immediately at time 00:00. I get 'Market is closed' (TRADE_RETCODE_MARKET_CLOSED, error code: 10018) message, because the trading is start only at time 00:01:


How can I check in advance if it is possible to open a position?

I tried unsuccessfully with this code:

Please help me, how can I check the allowed trading periods.

Thank you in advance.

Zsolt

Try the below code, currently in script, but easy enough to incorporate in an EA.

Also I assume you use some sort of version of the IsNewBar function, this market open I beliwve needs to be incorporated to the IsNewBar function

ENUM_DAY_OF_WEEK day_of_week;
//+------------------------------------------------------------------+
//| Script                                                           |
//+------------------------------------------------------------------+
void OnStart()
  {
   Print("Trade Session Open: ", trade_session());
  }
//+------------------------------------------------------------------+
//| Function: Check if trade session is open and excl. Sat and Sun   |
//+------------------------------------------------------------------+
bool trade_session()
  {
   datetime time_now = TimeCurrent();
   MqlDateTime time;
   TimeToStruct(time_now, time);
   uint week_day_now = time.day_of_week;
   uint seconds_now = (time.hour * 3600) + (time.min * 60) + time.sec;
   if(week_day_now == 0)
      day_of_week = SUNDAY;
   if(week_day_now == 1)
      day_of_week = MONDAY;
   if(week_day_now == 2)
      day_of_week = TUESDAY;
   if(week_day_now == 3)
      day_of_week = WEDNESDAY;
   if(week_day_now == 4)
      day_of_week = THURSDAY;
   if(week_day_now == 5)
      day_of_week = FRIDAY;
   if(week_day_now == 6)
      day_of_week = SATURDAY;
   datetime from, to;
   uint session = 0;
   while(SymbolInfoSessionTrade(_Symbol, day_of_week, session, from, to))
     {
      session++;
     }
   uint trade_session_open_seconds = uint(from);
   uint trade_session_close_seconds = uint(to);
   if(trade_session_open_seconds < seconds_now && trade_session_close_seconds > seconds_now && week_day_now >= 1 && week_day_now <= 5)
      return(true);
   return(false);
  }
 
Centaur #:

Thank you.

 
Dominik Egert #:

Here is my function to solve the issue:


There is a bug in the implementation of this function.

Here is the corrected version:

//+------------------------------------------------------------------+
//| SymbolInfoQuerySessionTimes()                                    |
//+------------------------------------------------------------------+
const bool SymbolInfoQuerySessionTimes(const string symbol, datetime& session_begin, datetime& session_end, datetime& next_session, const bool quote_sessions = false, const datetime reference_time = NULL)
{
    // Local cache

        static  datetime    c_begin     = NULL;
        static  datetime    c_end       = NULL;
        static  datetime    c_next      = NULL;
        static  bool        c_quotes    = false;
        static  string      c_symbol    = NULL;


    // Cache update

        if( (c_symbol == symbol)
         && (c_quotes == quote_sessions)
         && (c_begin < reference_time)
         && (c_end > reference_time) )
        {
            session_begin   = c_begin;
            session_end     = c_end;
            next_session    = c_next;
            return(true);
        }
        c_symbol    = symbol;
        c_quotes    = quote_sessions;


    // Pre init

        MqlDateTime     mql_time        = {};
        const datetime  time_current    = (reference_time == NULL) ? ::TimeTradeServer(mql_time) : reference_time;
        if( (time_current > NULL)
         && (!::TimeToStruct(time_current, mql_time)) )
        {
            session_begin   = 0xFFFFFFFFFFFFFFFF;
            session_end     = 0xFFFFFFFFFFFFFFFF;
            next_session    = 0xFFFFFFFFFFFFFFFF;
            return(false);
        }


    // Local init

        datetime    start           = NULL;
        datetime    finish          = NULL;
        datetime    day_start       = time_current - (time_current % 0x0000000000015180) - 0x0000000000015180;
        int         session_index   = NULL;
                    session_begin   = NULL;
                    session_end     = NULL;
                    next_session    = NULL;


    // Loop search

        for(ulong cnt = NULL; (cnt < 0x08) && !_StopFlag; cnt++)
        {
            // Current time offset
            day_start      += 0x0000000000015180;
            session_index   = NULL;

            // Switch type of evaluation
            switch((uint)cnt)
            {
                // Find current session if any
                case 0x00:
                    if(quote_sessions)
                    {
                        while( ((day_start + finish) <= time_current)
                            && (mqlplus::SymbolInfoSessionQuote(symbol, mqlplus::DayOfWeekToEnum(mql_time.day_of_week + cnt), (int)(session_index++), start, finish))
                            && !_StopFlag);
                    }
                    else
                    {
                        while( ((day_start + finish) <= time_current)
                            && (mqlplus::SymbolInfoSessionTrade(symbol, mqlplus::DayOfWeekToEnum(mql_time.day_of_week + cnt), (int)(session_index++), start, finish))
                            && !_StopFlag);
                    }

                    // Check results
                    if( ((day_start + start) <= time_current)
                     && ((day_start + finish) > time_current))
                    {
                        session_begin           = (day_start + start);
                        session_end             = (day_start + finish);
                    }

                    // Search for beginning of session
                    if(session_begin > NULL)
                    {
                        // Init loop
                        int         session_index1  = NULL;
                        int         max_count       = NULL;
                        datetime    local_begin     = NULL;
                        datetime    local_end       = NULL;

                        // Loop search
                        for(int cnt1 = (day_start == session_begin); (cnt1 < 0x08) && !_StopFlag; cnt1++)
                        {
                            // Init search loop
                            day_start      -= 0x0000000000015180 * ((cnt1 > NULL) && (session_index1 == NULL));
                            session_index1  = NULL;
                            local_end       = NULL;

                            // Loop backwards
                            if(quote_sessions)
                            {
                                while( ((session_index1 < max_count) || (max_count == NULL))
                                    && (mqlplus::SymbolInfoSessionQuote(symbol, mqlplus::DayOfWeekToEnum(mql_time.day_of_week - cnt1), session_index1++, start, finish))
                                    && ((day_start + finish) <= session_begin)
                                    && !_StopFlag)
                                {
                                    local_begin = (day_start + start);
                                    local_end   = (day_start + finish);
                                }
                                session_index1--;
                            }
                            else
                            {
                                while( ((session_index1 < max_count) || (max_count == NULL))
                                    && (mqlplus::SymbolInfoSessionTrade(symbol, mqlplus::DayOfWeekToEnum(mql_time.day_of_week - cnt1), session_index1++, start, finish))
                                    && ((day_start + finish) <= session_begin)
                                    && !_StopFlag)
                                {
                                    local_begin = (day_start + start);
                                    local_end   = (day_start + finish);
                                }
                                session_index1--;
                            }

                            // Repeat search on same day if more than one session
                            if(session_begin == local_end)
                            {
                                session_begin   = local_begin;
                                cnt1           -= 1 * (session_index1 > 0x01);
                                session_index1 -= (session_index1 == 0x01);
                                max_count       = session_index1;
                            }

                            cnt1 |= 0xFF * (session_begin > local_end);
                        }

                        // Reset day_start variable
                        day_start = time_current - (time_current % 0x0000000000015180);
                    }

                    // Check for multiple sessions
                    if( ((day_start + start) > session_end)
                     && (finish > NULL))
                    {
                        next_session            = (day_start + start);
                        c_begin                 = session_begin;
                        c_end                   = session_end;
                        c_next                  = next_session;
                        return(true);
                    }


                // Find next session
                default:
                    if(quote_sessions)
                    {
                        if(!mqlplus::SymbolInfoSessionQuote(symbol, mqlplus::DayOfWeekToEnum(mql_time.day_of_week + cnt), (int)(session_index++), start, finish))
                        { continue; }
                    }
                    else
                    {
                        if(!mqlplus::SymbolInfoSessionTrade(symbol, mqlplus::DayOfWeekToEnum(mql_time.day_of_week + cnt), (int)(session_index++), start, finish))
                        { continue; }
                    }

                    // Next found session
                    next_session                = (day_start + start) * (session_end < (long)(day_start + start));
                    session_end                 = ((session_end * (next_session > NULL)) + (((finish > NULL) ? day_start + finish : session_end) * (next_session == NULL)));
            }

            if(next_session > NULL)
            {
                c_begin = session_begin;
                c_end   = session_end;
                c_next  = next_session;
                return(true);
            }
        }


    // Clear to zero as 24/7 sessions

        session_begin   = NULL;
        session_end     = NULL;
        next_session    = NULL;
        c_begin         = session_begin;
        c_end           = session_end;
        c_next          = next_session;

    // Return
    return(!_StopFlag);
}



namespace mqlplus
{
    //+------------------------------------------------------------------+
    //| SymbolInfoSessionQuote()                                         |
    //+------------------------------------------------------------------+
    bool SymbolInfoSessionQuote(const string symbol, const ENUM_DAY_OF_WEEK day, const int session_index, datetime& start, datetime& finish)
    {
        start   = NULL;
        finish  = NULL;
        return(::SymbolInfoSessionQuote(symbol, day, session_index, start, finish));
    }


    //+------------------------------------------------------------------+
    //| SymbolInfoSessionTrade()                                         |
    //+------------------------------------------------------------------+
    bool SymbolInfoSessionTrade(const string symbol, const ENUM_DAY_OF_WEEK day, const int session_index, datetime& start, datetime& finish)
    {
        start   = NULL;
        finish  = NULL;
        return(::SymbolInfoSessionTrade(symbol, day, session_index, start, finish));
    }


    //+------------------------------------------------------------------+
    //| DayOfWeekToEnum()                                                |
    //+------------------------------------------------------------------+
    template <typename T>
    const ENUM_DAY_OF_WEEK DayOfWeekToEnum(const T day_of_week, const bool first_day_monday = false)
    {
        switch((((uchar)day_of_week) + ((uchar)(first_day_monday))) % 7)
        {
            case 0x01:  return(MONDAY);
            case 0x02:  return(TUESDAY);
            case 0x03:  return(WEDNESDAY);
            case 0x04:  return(THURSDAY);
            case 0x05:  return(FRIDAY);
            case 0x06:  return(SATURDAY);
            default:    return(SUNDAY);
        }
    }

}; // END namespace mqlplus
 
Control_Trade_Sessions
Control_Trade_Sessions
  • www.mql5.com
Библиотека для контроля торговой сессии. При запуске считает время торговых сессий за все 7 дней недели (в сб и вс может быть торговля по криптовалютам), до 10 сессий в день. Затем в OnTick() можно делать проверки, и если тик пришел вне торговой сессии, то можно выйти из дальнейшей его обработки.
 
Dominik Egert #:

There is a bug in the implementation of this function.

Here is the corrected version:

Many thanks, Dominik! As always, very much appreciated.

Thanks.

 
Fernando Carreiro #:

Your code should verify the trade session times using SymbolInfoSessionTrade(), as trading will not be disabled, just temporarily closed:

Is it showing GMT, Server time or Local time ?   I can probably find out by letting the EA print those alternative timestamps to the log in the moment of a TRADE_RETCODE_MARKET_CLOSED situation.
 
You also might sometimes want to avoid leaving a trade open after the market closes (especially if it's in a loss and not a "smart" trade). I made a function which will close any trade that's in a certain loss just before the market would close.
 
Conor Mcnamara #:
You also might sometimes want to avoid leaving a trade open after the market closes (especially if it's in a loss and not a "smart" trade). I made a function which will close any trade that's in a certain loss just before the market would close.
That is one of the things I try to implement. For now I will try to base my calculations on SymbolInfoSessionTrade responses. I have not concluded fully if market open hours are expressed in some particular time zone format. What I have seen looks GMT to me. I assume if I do historical backtesting that such queries will reflect settings in effect at that time.  
 
Dominik Egert #:

There is a bug in the implementation of this function.

Here is the corrected version:

just to clarify, the way we use it 
if (SymbolInfoQuerySessionTimes() == true) { open_a_position(); }

?

I still get 2024.01.04 00:42:43   failed buy limit 0.15 XAUUSD.PRO_xx3b at 2039.41 [Market closed]

Granted I didn't check this on a live (demo) account, only in the strategy tester. Does this function work in the strategy tester?

2024.01.04 it's a Thursday. 

in my tester I have : 


Just checking, any input appreciated @Dominik Egert



 

I found this thread while I was on the search for almost the same issue. But I mostly wanted something to confirm that my code below will do as I want it to. If anyone can read my code and tell me that I am bonkers or if "great minds think alike". please.

My goal is...

1. to make my ea to "return" when the day changes, and also the minute is 1 or 2;

2. Each day, i want my ea to "return" when the hour is 23, and also, the minute is 57, 58, 59.

Here's my code... (my fingers are crossed, and face is grimacing, ready to take the flack)

Note my code is below OnTick; first lines in the OnTick.

If it is wrong, please explain why or give sources for me to read. I'd rather teach myself than to simply copy and paste.

   datetime time_now = TimeCurrent();
   MqlDateTime time;
   TimeToStruct(time_now, time);
   static uint week_day_now ; // = time.day_of_week;

   if(time.day_of_week!=week_day_now || (time.hour==23 && time.min>56))
     {
      if(time.min<3 || (time.hour==23 && time.min>56))
         return;
      week_day_now = time.day_of_week;
     }