MT5 Strategy Tester: Cannot Close Daily Trade at EOD in Netting Mode (M1 OHLC)

 

I am having trouble creating a snippet of code to sit within in a EA to close all trades at the end of the day.

MT5 build number 5.00 build 5260

Account type Netting

Tester settings Model: 1-minute OHLC

My expectation To close the trade as close to EOD as possible, and on Fridays must close before end of day

What actually happens Closes next day, between 1 and 7 minutes into the day


My question:
What am I missing in netting + 1-minute OHLC mode that prevents PositionClose(_Symbol) (and even the fallback opposite order) from closing the trade at 23:59 daily?

Any insight into known tester limitations, or what extra step is needed to force the tester to flatten the net position at the desired time?


My code:

#property strict
#include <Trade\Trade.mqh>
CTrade trade;

input double LotSize    = 0.10; // one trade per day
input int    OpenHour   = 22;   // open at HH:00
input int    CloseHour  = 23;   // close at 23:59 (Mon–Fri)
input int    CloseMin   = 59;

datetime lastBar=0;
bool     openedToday=false;
int      oy=0, om=0, od=0; // open day (calendar)

bool SameDate(const MqlDateTime &a, const MqlDateTime &b)
{ return (a.year==b.year && a.mon==b.mon && a.day==b.day); }

void RecordOpenDate(const MqlDateTime &bt){ oy=bt.year; om=bt.mon; od=bt.day; }

bool ForceFlat()
{
   if(!PositionSelect(_Symbol)) return true;
   if(trade.PositionClose(_Symbol))
   {
      if(!PositionSelect(_Symbol)) return true;
   }
   // fallback: opposite order (netting-safe)
   if(PositionSelect(_Symbol))
   {
      double vol  = PositionGetDouble(POSITION_VOLUME);
      long   type = PositionGetInteger(POSITION_TYPE);
      bool ok=false;
      if(vol>0)
      {
         if(type==POSITION_TYPE_BUY)  ok=trade.Sell(vol,_Symbol);
         if(type==POSITION_TYPE_SELL) ok=trade.Buy(vol,_Symbol);
      }
      Print("Fallback opposite order sent vol=",vol," ok=",ok," err=",GetLastError());
   }
   return !PositionSelect(_Symbol);
}

void OnTick()
{
   datetime btTime=iTime(_Symbol,PERIOD_M1,0);
   if(btTime==lastBar) return;
   lastBar=btTime;

   MqlDateTime bt; TimeToStruct(btTime,bt);

   // ENTRY: once per day at HH:00 if flat
   if(!openedToday && bt.hour==OpenHour && bt.min==0)
   {
      if(!PositionSelect(_Symbol))
      {
         bool ok=trade.Buy(LotSize,_Symbol);
         Print("Open try ",TimeToString(btTime,TIME_DATE|TIME_SECONDS)," ok=",ok," err=",GetLastError());
         if(ok){ openedToday=true; RecordOpenDate(bt); }
      }
   }

   // EXIT: at 23:59 same calendar day as open
   if(openedToday && PositionSelect(_Symbol))
   {
      if(bt.year==oy && bt.mon==om && bt.day==od && bt.hour==CloseHour && bt.min==CloseMin)
      {
         Print("Close trigger @ ",TimeToString(btTime,TIME_DATE|TIME_SECONDS));
         bool flat=ForceFlat();
         Print("Flat=",flat," err=",GetLastError());
         if(flat){ openedToday=false; oy=om=od=0; }
      }
      // Safety: if date rolled without closing, flatten immediately
      if(!(bt.year==oy && bt.mon==om && bt.day==od))
      {
         Print("Safety rollover close @ ",TimeToString(btTime,TIME_DATE|TIME_SECONDS));
         bool flat=ForceFlat();
         Print("Flat=",flat," err=",GetLastError());
         openedToday=false; oy=om=od=0;
      }
   }
}
 
Your topic has been moved to the section: Expert Advisors and Automated Trading
Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
 

Closing at 23:59 hours is not reliable because your broker usually will not allow opening/closing because of swap/rollover period. You can also check the times when your broker actually allows you to trade the symbol with ctrl M. 

For min you can see that I get quotes for EURUSD from  00:00 to 23:57 but I can't actually trade until 4 mins after open and I can't trade three mins before close. Also why would you want to close at exactly these times? The spread is incredibly crazy