Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 209

 

Eine weitere zu den bisher veröffentlichten (ein,zwei) Möglichkeiten, den GMT-Offset eines Handelsservers zu bestimmen.

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

Eine Symbiose aller drei Methoden bietet eine sehr hohe Wahrscheinlichkeit, das richtige Ergebnis zu erhalten.

 

Eine Fortsetzung des Themas "Rollover". Ich versuche, den Zeitpunkt des Überschlags auf der M1-Historie zu ermitteln.

#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


Anwendung.

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


Ergebnis.

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
 

Besonderheiten bei der Berechnung der Mindestmenge.

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


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

Ist dies eine Funktion von MQL5 oder ein Fehler?

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 zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Eigenheiten von mql5, Tipps und Tricks

A100, 2021.05.20 13:43

Sie können den Unterschied zwischen Inline- (unbestimmte Reihenfolge) und Standardfunktionen (von rechts nach links) erkennen.

Inline-Funktionen sind gar keine Funktionen, d.h. sie können keine Adresse haben. Aus dieser Sicht gibt es keinen Unterschied zwischen regulären und benutzerdefinierten Funktionen. So ist es beispielsweise unklar, warum die Argumente der einfachsten benutzerdefinierten Funktion (die im Grunde genommen inline ist) immer von rechts nach links berechnet werden. Ich schließe nicht aus, dass sich in Zukunft bei Inline-Funktionen die Reihenfolge ändern kann, also

Ich habe einmal vorgeschlagen, das Schlüsselwort inline für die sichere Verwendung der Berechnungsreihenfolge einzuführen:


Ist es im aktuellen MQL5 möglich, das Inlining für bestimmte Funktionen zu verbieten?

 
Hallo, warum so

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

Das hat nämlich keinen Sinn:

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

F5 legt auf. Außerdem ist es eine widersprüchliche Abhilfe für den Konstruktor

 
A100 #:

Das hat nämlich keinen Sinn:

F5 legt auf.

Das verstehe ich nicht. Der Nullabgleich ist eine nützliche Sache, also gibt es einen Grund dafür.