Features of the mql5 language, subtleties and tricks - page 209

 

Another to the previously published (one,two) ways of determining the GMT offset of a trading server.

#define  HOUR 3600
#define  DAY (24 * HOUR)
#define  WEEK 7

bool GetWeekSession( const string Symb, datetime &From, datetime &To )
{
  datetime Tmp;
  
  From = 0;
  To = 0;
  
  for (int i = 0; i < 7; i++)
    if (::SymbolInfoSessionQuote(Symb, (ENUM_DAY_OF_WEEK)i, 0, From, Tmp) && (From != Tmp))
    {
      From += (i + WEEK - 1) * DAY;
      
      break;
    }

  for (int i = 6; i >= 0; i--)
    if (::SymbolInfoSessionQuote(Symb, (ENUM_DAY_OF_WEEK)i, 0, Tmp, To) && (To != Tmp))
    {
      To += ((i + WEEK - 1) % WEEK) * DAY;
      
      break;
    }
  
  return(From != To);
}

// Аналог по серверному времени - https://www.mql5.com/ru/docs/dateandtime/timegmtoffset
// Работает для FOREX-символов.
int TimeServerGMTOffset( void )
{
  const datetime Sunday = (WEEK - 1) * DAY;
  
  datetime From;
  datetime To;        
  
  return(GetWeekSession(_Symbol, From, To) ? ((int)::MathRound((double)::MathMin(Sunday - DAY - To, Sunday + DAY - From) / HOUR) - 3) * HOUR : 0);
}

A symbiosis of all three methods gives a very high probability of getting the correct result.

 

A continuation of the theme of rollovers. Trying to identify the time of the rollover on the M1-history.

#define  HOUR 3600
#define  HOURS 24
#define  DAY (HOURS * HOUR)
#define  WEEK 7
#define  MINUTE 60

ENUM_DAY_OF_WEEK TimeDayOfWeek( const datetime time )
{
  return((ENUM_DAY_OF_WEEK)((time / DAY + THURSDAY) % WEEK));
}

datetime GetTimeDayOfWeek( const datetime time, const ENUM_DAY_OF_WEEK Day = SUNDAY )
{
  const datetime Res = time / DAY * DAY;
  
  return(Res - (((WEEK + (TimeDayOfWeek(Res) - Day)) % WEEK)) * DAY);
}

#define  GETHOUR(A) (int)((A.time / HOUR) % HOURS)
#define  GETMINUTE(A) (int)((A.time / MINUTE) % MINUTE)

int GetTimePos( const MqlRates &Rates[], const datetime time )
{
  int Left = 0;
  int Right = ArraySize(Rates) - 1;  
      
  while (Right > Left)
  {            
    const int Middle = (Left + Right) >> 1;  
        
    if (Rates[Middle].time < time)
      Left = Middle + 1;
    else
      Right = Middle - 1;
  }
  
  return(Left);
}

int GetRolloverInterval( const MqlRates &Rates[], const datetime From, const datetime To, const bool MQL4Method = false )
{
  double Hours[HOURS];  
  ArrayInitialize(Hours, 0);
        
  const int FromPos = GetTimePos(Rates, From);
  const int ToPos = GetTimePos(Rates, To);
  
  for (int i = FromPos; i < ToPos; i++)
  {
  const int HourNow = GETHOUR(Rates[i]);
  
  #ifdef __MQL5__
    if (!MQL4Method) // Битые баровые спреды - проблема.
      Hours[HourNow] += (((HourNow != GETHOUR(Rates[i - 1])) ? GETMINUTE(Rates[i]) : 0) +
                         ((HourNow != GETHOUR(Rates[i + 1])) ? MINUTE : GETMINUTE(Rates[i + 1])) -
                         GETMINUTE(Rates[i])) * Rates[i].spread;
    else
  #endif // #ifdef __MQL5__
    Hours[HourNow] += (Rates[i].high - Rates[i].low) / Rates[i].tick_volume;            
  }
  
  return(ArrayMaximum(Hours));
  
}

// Возвращает время ролловера FOREX-символа на указанной неделе (кроме текущей).
datetime RolloverTime( const datetime time, const string Symb = NULL, const bool MQL4Method = false )
{  
  int Hours[HOURS];
  ArrayInitialize(Hours, 0);  
  
  MqlRates Rates[];    

  datetime From = GetTimeDayOfWeek(time);
  datetime To = GetTimeDayOfWeek(time) + WEEK * DAY - 1;

  if (CopyRates(Symb, PERIOD_M1, From, To, Rates) > 0)
  {
  #define  OFFSET 3
    From = (Rates[0].time / HOUR - OFFSET) * HOUR;
    To = From + ((OFFSET << 1) - 1) * HOUR;
  #undef  OFFSET
    
    for (int Count = 0; Count < 4; Count++)
      Hours[GetRolloverInterval(Rates, From += DAY, To += DAY, MQL4Method)]++;
  }
                                    
  return(ArrayMaximum(Hours) * HOUR);
}

#undef  GETMINUTE
#undef  GETHOUR


Application.

// Через Тестер выводит по неделям данные по времени ролловера.
const bool Init = EventSetTimer(WEEK * DAY);

void OnTimer()
{
  const datetime time = TimeTradeServer() - WEEK * DAY;
  const datetime From = GetTimeDayOfWeek(time, MONDAY);
  
  Print((string)TimeToString(From, TIME_DATE) + " - " + (string)TimeToString(From + WEEK * DAY - 1, TIME_DATE) +
        ": RolloverTime = " + TimeToString(RolloverTime(time), TIME_MINUTES));
}


Result.

2021.03.01 - 2021.03.07: RolloverTime = 00:00
2021.03.08 - 2021.03.14: RolloverTime = 00:00
2021.03.15 - 2021.03.21: RolloverTime = 23:00
2021.03.22 - 2021.03.28: RolloverTime = 23:00
2021.03.29 - 2021.04.04: RolloverTime = 00:00
2021.04.05 - 2021.04.11: RolloverTime = 00:00
 

Peculiarities of min. lot calculation.

double NormalizeDouble( const double Value, const double Step )
{
  return(NormalizeDouble(Step ? (int)(Value / Step + 0.1) * Step : Value, 8));
}

// Минимальный лот с учетом требования мин. объема.
double GetMinLot( const string Symb, const double MinValue = 0 )
{
  const double MinLot = SymbolInfoDouble(Symb, SYMBOL_VOLUME_MIN)       ;
  double Res = MinLot;
  
  if (MinValue)
  {
    const double Diff = SymbolInfoDouble(Symb, SYMBOL_ASK) * SymbolInfoDouble(Symb, SYMBOL_TRADE_TICK_VALUE);
    
    Res = Diff ? MinValue * SymbolInfoDouble(Symb, SYMBOL_TRADE_TICK_SIZE) / Diff : 0;
    
    if (Res <= MinLot)
      Res = MinLot;
    else
    {
      double StepLot = SymbolInfoDouble(Symb, SYMBOL_VOLUME_STEP);      
      
      if (!StepLot)
        StepLot = MinLot;
      
      const double NormRes = NormalizeDouble(Res, StepLot);
      
      Res = (NormRes < Res) ? NormalizeDouble(NormRes + StepLot, 8) : NormRes;                                                                  
    }
  }             

  return(Res);
}


Example (RannForex-Binance_futures).

void OnStart()
{
  for ( int i = SymbolsTotal(true) - 1; i >= 0; i--)
  {
    const string Symb = SymbolName(i, true);
    
    Print(Symb + ", MinLot =  " + (string)GetMinLot(Symb, 5));
  }
}


XMRUSDT.fut, MinLot =  0.019
XRPUSDT.fut, MinLot =  4.7
TRXUSDT.fut, MinLot =  51.0
LTCUSDT.fut, MinLot =  0.027
FTMUSDT.fut, MinLot =  2.0
ETHUSDT.fut, MinLot =  0.002
EOSUSDT.fut, MinLot =  1.1
BNBUSDT.fut, MinLot =  0.02
BCHUSDT.fut, MinLot =  0.008
BTCUSDT.fut, MinLot =  0.001
Спецификации фьючерсных контрактов USDⓈ-Margined | Binance
Спецификации фьючерсных контрактов USDⓈ-Margined | Binance
  • www.binance.com
Фьючерсные контракты USDT-margined не являются инверсными. Это линейные фьючерсные продукты, которые котируются и рассчитываются в BUSD или USDT – стейблкоинах, привязанных к доллару США. Одним из ...
 

Is this a feature of MQL5 or a bug?

void OnStart()
{     
  uchar ArrayDst1[];
  uchar ArraySrc1[];
  
  ArrayCopy(ArrayDst1, ArraySrc1, 10);
  Print(ArraySize(ArrayDst1)); // MQL4 - 10, MQL5 - 0

  uchar ArrayDst2[];
  uchar ArraySrc2[1];

  ArrayCopy(ArrayDst2, ArraySrc2, 10);
  Print(ArraySize(ArrayDst2)); // 11
      
  return;
}
 

Forum on trading, automated trading systems and trading strategies testing

Peculiarities of mql5, tips and tricks

A100, 2021.05.20 13:43

You can see the difference between inline (indefinite order) and standard (from right to left) functions.

Inline functions are not functions at all, i.e. they cannot have an address. From this point of view, there is no difference between regular and custom functions, so for example, it's unclear why the arguments of the simplest custom function (which is in essence inline) are always calculated from right to left. I do not exclude that in the future for inline functions the order may change, so

I suggested at one time to introduce the keyword inline for safe use of the order of calculations:


In the current MQL5 is it possible to prohibit inlining for certain functions?

 
hi why so

 
MqlTick Ticks[4] = {}; // Обнуление статического массива.
 
fxsaber #:

There is no point because:

struct X {
    int i;
};
void OnStart()
{
    X x[200000] = {};
}

F5 hangs up. Also, it is a contradictory workaround for the constructor

 
A100 #:

There is no point because:

F5 hangs up.

I don't get it. Zeroing is a useful thing, so there is a point.

Reason: