Características del lenguaje mql5, sutilezas y técnicas - página 209

 

Otra de las formas publicadas anteriormente (una,dos) para determinar el offset GMT de un servidor de comercio.

#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);
}

Una simbiosis de los tres métodos proporciona una probabilidad muy alta de obtener el resultado correcto.

 

Una continuación del tema de los vuelcos. Intentando identificar la hora del vuelco en la historia de la M1.

#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


Aplicación.

// Через Тестер выводит по неделям данные по времени ролловера.
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));
}


Resultado.

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
 

Peculiaridades del cálculo del lote mínimo.

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);
}


Ejemplo (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 – стейблкоинах, привязанных к доллару США. Одним из ...
 

¿Es una característica de MQL5 o un error?

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;
}
 

Foro sobre trading, sistemas de trading automatizados y pruebas de estrategias de trading

Peculiaridades de mql5, consejos y trucos

A100, 2021.05.20 13:43

Puede ver la diferencia entre las funciones inline (orden indefinido) y las estándar (de derecha a izquierda).

Las funciones en línea no son funciones en absoluto, es decir, no pueden tener una dirección. Desde este punto de vista, no hay diferencia entre las funciones regulares y las personalizadas, así que, por ejemplo, no está claro por qué los argumentos de la función personalizada más sencilla (que en esencia es inline) se calculan siempre de derecha a izquierda. No excluyo que en el futuro para las funciones en línea el orden pueda cambiar, así que

En su día sugerí introducir la palabra clave inline para el uso seguro del orden de los cálculos:


¿En el actual MQL5 es posible prohibir el inlining para ciertas funciones?

 
Hola, ¿por qué?

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

No tiene sentido porque:

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

F5 cuelga. Además, es una solución contradictoria para el constructor

 
A100 #:

No tiene sentido porque:

F5 cuelga.

No lo entiendo. La puesta a cero es algo útil, así que tiene sentido.

Razón de la queja: