Caractéristiques du langage mql5, subtilités et techniques - page 209

 

Un autre moyen de déterminer le décalage GMT d'un serveur de négociation est déjà publié (un,deux).

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

Une symbiose de ces trois méthodes donne une très forte probabilité d'obtenir le bon résultat.

 

Une continuation du thème des renversements. J'essaie d'identifier l'heure du renversement sur la M1-historique.

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


Résultat.

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
 

Particularités du calcul du lot minimal.

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


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

Est-ce une fonctionnalité de MQL5 ou un 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 sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Particularités de mql5, trucs et astuces

A100, 2021.05.20 13:43

Vous pouvez voir la différence entre les fonctions en ligne (ordre indéfini) et les fonctions standard (de droite à gauche).

Les fonctions en ligne ne sont pas des fonctions du tout, c'est-à-dire qu'elles ne peuvent pas avoir d'adresse. De ce point de vue, il n'y a pas de différence entre les fonctions ordinaires et les fonctions personnalisées. Par exemple, on ne comprend pas pourquoi les arguments de la fonction personnalisée la plus simple (qui est par essence inline) sont toujours calculés de droite à gauche. Je n'exclus pas qu'à l'avenir pour les fonctions en ligne l'ordre puisse changer, donc

J'ai suggéré à un moment donné d'introduire le mot-clé inline pour une utilisation sûre de l'ordre de calcul :


Dans la version actuelle de MQL5, est-il possible d'interdire l'inlining pour certaines fonctions ?

 
Bonjour, pourquoi ?

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

Il n'y a pas de raison parce que :

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

F5 raccroche. En outre, il s'agit d'une solution de rechange contradictoire pour le constructeur.

 
A100 #:

Il n'y a pas de raison parce que :

F5 raccroche.

Je ne comprends pas. La remise à zéro est une chose utile, donc il y a un intérêt.