Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 209

 

Un altro ai modi precedentemente pubblicati (uno,due) per determinare l'offset GMT di un server di trading.

#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 simbiosi di tutti e tre i metodi dà una probabilità molto alta di ottenere il risultato corretto.

 

Una continuazione del tema dei rollover. Cercando di identificare il momento del ribaltamento sulla storia della 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


Applicazione.

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


Risultato.

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
 

Peculiarità del calcolo del lotto minimo.

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


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

È una caratteristica di MQL5 o 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 sul trading, sistemi di trading automatico e test di strategie di trading

Peculiarità di mql5, consigli e trucchi

A100, 2021.05.20 13:43

Potete vedere la differenza tra le funzioni in linea (ordine indefinito) e quelle standard (da destra a sinistra).

Le funzioni in linea non sono affatto funzioni, cioè non possono avere un indirizzo. Da questo punto di vista, non c'è differenza tra le funzioni regolari e quelle personalizzate, quindi, per esempio, non è chiaro perché gli argomenti della funzione personalizzata più semplice (che è in sostanza inline) sono sempre calcolati da destra a sinistra. Non escludo che in futuro per le funzioni in linea l'ordine possa cambiare, quindi

Ho suggerito una volta di introdurre la parola chiave inline per un uso sicuro dell'ordine di calcolo:


Nell'attuale MQL5 è possibile proibire l'inlining per certe funzioni?

 
ciao perché così

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

Non ha senso perché:

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

F5 riaggancia. Inoltre, è un workaround contraddittorio per il costruttore

 
A100 #:

Non ha senso perché:

F5 riaggancia.

Non capisco. L'azzeramento è una cosa utile, quindi c'è un punto.