Особенности языка mql5, тонкости и приёмы работы - страница 142

fxsaber
15008
fxsaber  
ResourceSave не работает в Тестере. Альтернатива ниже.
// Сохраняет ресурс в BMP-формате.
bool ResourceSaveBMP( const string ResourceName, const string FileName )
{
  struct BMPFILEHEADER
  {
    short Type;
    uint   Size;
    short Reserved1;
    short Reserved2;
    uint   OffBits;
  };
  
  struct BMPINFOHEADER
  {    
    uint   Size;
    uint   Width;
    uint   Height;
    short Planes;
    short BitCount;
    int   Compression;
    uint   SizeImage;
    int   XPelsPerMeter;
    int   YPelsPerMeter;
    int   ClrUsed;
    int   ClrImportant;
    
    void Set( void )
    {
      this.Size = sizeof(this);
      this.Planes = 1;
      this.BitCount = 32;
      this.SizeImage = this.Width * this.Height * (this.BitCount >> 3);
      
      return;      
    }
  };
  
  struct BMPHEADER
  {
    BMPFILEHEADER File;
    BMPINFOHEADER Info;
    
    void Set( void )
    {
      this.Info.Set();

      this.File.Type = 19778;
      this.File.OffBits = sizeof(this);
      this.File.Size = this.Info.SizeImage + this.File.OffBits;
      
      return;
    }
  } BMPHeader = {0};
  
  uint Data[];  
  bool Res = ResourceReadImage(ResourceName, Data, BMPHeader.Info.Width, BMPHeader.Info.Height);
  
  if (Res)
  {
    const int handle = FileOpen(FileName, FILE_WRITE | FILE_BIN);
    
    if (Res = (handle != INVALID_HANDLE))
    {      
      BMPHeader.Set();

      uint Picture[];
      
      const uint Size = ArrayResize(Picture, ArraySize(Data));
      
      for (uint i = 0; i < Size; i += BMPHeader.Info.Width)
        ArrayCopy(Picture, Data, i, Size - i - BMPHeader.Info.Width, BMPHeader.Info.Width);
              
      FileWriteStruct(handle, BMPHeader);
      FileWriteArray(handle, Picture);
      
      FileClose(handle);
    }
  }
  
  return(Res);
}


Применение

  ResourceSave(ResourceName, "test.bmp");  
  ResourceSaveBMP(ResourceName, "test2.bmp");
Edgar Akhmadeev
1408
Edgar Akhmadeev  

Для уменьшения количества переборов параметров оптимизации применяю два приёма создания нелинейной шкалы.

Для перебора длительности в часах с достаточной точностью:

enum eHours { _0, _4, _6, _8, _12, _16, _24, _32, _48, _64, _96, _128 };

input eHours TrendHours = _8;

int
eHours2Hours(eHours e) {
	switch (e) {
	case _0:	return 0;
	case _4:	return 4;
	case _6:	return 6;
	case _8:	return 8;
	case _12:	return 12;
	case _16:	return 16;
	case _24:	return 24;
	case _32:	return 32;
	case _48:	return 48;
	case _64:	return 64;
	case _96:	return 96;
	case _128:	return 128;
	default:	return -1;
	}
}

Для перебора, например, шага SAR с точностью 2 цифры (~1%):

// Приводит параметр оптимизации к нелинейному виду
// 001-099 >> 0.0001-0.0099
// 101-199 >> 0.001-0.099
// 201-299 >> 0.10-0.99
// Внимание: коды 000, 100, 200 возвращают 0.0
double
NonlinPar(int code) {
        int order = code / 100;
        int mod = code - order * 100;
        return mod * MathPow(10, order) / 10000;
}

При оптимизации от 0.0001 до 0.99 требовалось бы почти 10К шагов. При использовании в оптимизации кодов 001-299 требуется меньше 300 шагов.

fxsaber
15008
fxsaber  
Способ нарваться на деление на ноль даже с проверкой.
void OnStart()
{  
  const double Profit = 100;
  const double Lots = 1;

  double TickValue[];  
  ArrayResize(TickValue, 1);
  
  const double Points = TickValue[0] ? Profit / (Lots * TickValue[0] * _Point) : 0; // zero divide    
}


Ошибка понятна по факту. Но во время написания подобного кода не всегда очевидно, что такой проверки не достаточно, чтобы избежать деления на ноль.

TheXpert
17972
TheXpert  
Повод не пользоваться тернарным оператором.
fxsaber
15008
fxsaber  
TheXpert:
Повод не пользоваться тернарным оператором.

Для if аналогично, конечно.

Alexey Viktorov
22220
Alexey Viktorov  

Просто не надо надеяться, что если отсутствует значение, то это обязательно 0 и соответственно false если это переменная не типа bool. Даже явное приведение к типу bool не спасёт.

void OnStart()
{  
  const double Profit = 100;
  const double Lots = 1;

  double TickValue[];  
  ArrayResize(TickValue, 1);
  
  const double Points = TickValue[0] == 0? Profit / (Lots * TickValue[0] * _Point) : 0;   
}

Так работает без ошибок.

fxsaber
15008
fxsaber  

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

Alexey Viktorov, 2019.10.28 10:22

Просто не надо надеяться, что если отсутствует значение, то это обязательно 0 и соответственно false если это переменная не типа bool. Даже явное приведение к типу bool не спасёт.

void OnStart()
{  
  const double Profit = 100;
  const double Lots = 1;

  double TickValue[];  
  ArrayResize(TickValue, 1);
  
  const double Points = TickValue[0] == 0? Profit / (Lots * TickValue[0] * _Point) : 0;   
}

Так работает без ошибок.

В выделенном месте ошибка.
Alexey Viktorov
22220
Alexey Viktorov  
fxsaber:
В выделенном месте ошибка.

Не вижу выделенного места. В чём ошибка?

Artyom Trishkin
Модератор
43750
Artyom Trishkin  
fxsaber:
В выделенном месте ошибка.

Ты написал "==", а должно быть "!="

Там выделено "очень-бледно-жёлтым" :)

Alexey Viktorov
22220
Alexey Viktorov  
Artyom Trishkin:

Ты написал "==", а должно быть "!="

Там выделено "очень-бледно-жёлтым" :)

Ну ведь не все знают что я как та мартышка "К старости слаба глазами стала".

Наверное да, но почему-то такой вариант прокатил без деления на 0. А в общем, мой посыл был о том, что не надо проверять на 0 любую переменную как булеву на false.