Новая версия платформы MetaTrader 5 build 4620: исправления ошибок в MQL5 и новые методы OpenBLAS - страница 23

 

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

Вот казалось бы простая функция:

bool DumpTextToFile(const string name, const string buffer)
{
   uchar bytes[];
   StringToCharArray(buffer, bytes, 0, -1, CP_UTF8);
   return FileSave(name, bytes);
}

Но не верьте своим глазам. Текстовый файл, созданный таким образом, не сможет открыть MetaEditor - точнее он открывает для него вкладку, но содержимое не показывает. Все дело в том, что в массив (и в файл) попадает терминальный 0. Все другие текстовые редакторы открывают такой файл спокойно.

Если предположить тривиальное решение:

bool DumpTextToFile(const string name, const string buffer)
{
   uchar bytes[];
   StringToCharArray(buffer, bytes, 0, StringLen(buffer), CP_UTF8);
   return FileSave(name, bytes);
}

получим новый баг - если в тексте есть нелатинские буквы, то в файл запишется не весь текст, потому что аргументы функции StringToCharArray относятся к буферу (!), а не строке и при кодировке в utf-8 буфер увеличивается по сравнению со строкой.

Окончательное решение (с багами, которые я еще не нашел):

bool DumpTextToFile(const string name, const string buffer)
{
   uchar bytes[];
   StringToCharArray(buffer, bytes, 0, -1, CP_UTF8);
   ArrayResize(bytes, bytes.Size() - 1);
   return FileSave(name, bytes);
}
 
Stanislav Korotky #:

...

Вот казалось бы простая функция:

Но не верьте своим глазам. Текстовый файл, созданный таким образом, не сможет открыть MetaEditor...

...Окончательное решение (с багами, которые я еще не нашел):

Спасибо за поднятый вопрос. Эта проблема должна была возникнуть в будущем, а теперь может и не возникнет.
 
Stanislav Korotky #:

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

Вот казалось бы простая функция:

Но не верьте своим глазам. Текстовый файл, созданный таким образом, не сможет открыть MetaEditor - точнее он открывает для него вкладку, но содержимое не показывает. Все дело в том, что в массив (и в файл) попадает терминальный 0. Все другие текстовые редакторы открывают такой файл спокойно.

Если предположить тривиальное решение:

получим новый баг - если в тексте есть нелатинские буквы, то в файл запишется не весь текст, потому что аргументы функции StringToCharArray относятся к буферу (!), а не строке и при кодировке в utf-8 буфер увеличивается по сравнению со строкой.

Окончательное решение (с багами, которые я еще не нашел):

bool DumpTextToFile(const string name, const string buffer)
{
   uchar bytes[];
   StringToCharArray(buffer, bytes, 0, StringLen(buffer));
   return FileSave(name, bytes);
}


//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{

   DumpTextToFile("TEST_FILE.txt", "Привет мир!\nДругие символы: @/>{}\nЛатиница: HELLO WORLD");

}

Если не указывать параметр кодовой страницы, по умолчанию будет использована codepage=CP_ACP
Тогда всё работает.

tst

 
Roman #:

Если не указывать параметр кодовой страницы, по умолчанию будет использована codepage=CP_ACP
Тогда всё работает.

Этот файл непереносим в общемировом масштабе - текст будет виден нормально только у тех, у кого CP_ACP совпадает с вашей операционкой (в данном случае 1251). Например, если грек по гречески что-то сохранит с вашим кодом, то мы уже не прочитаем.

 

Я в недоумении. Ниже код, который в двух вариантах макроса должен, ИМХО, давать один и тот же результат, но дает разные. Почему-то портится последовательность инициализации.

Пример с макросами - упрощенный. В реальности желаемый результат нужно получить не через макрос, а через вызов более сложной функции, поэтому нужны круглые скобки.

//#define prepend(A, B) A+B                 // expected output: /struct Main/struct Derived
#define prepend(A, B) (A+B)             // wrong output:    /struct Derived

// Task: 'prepend' must be a function with the expected output above

struct Base
{
   string type;
   string path;
   
   Base(Base &p, string t): 
      type(t),
      path(p.path + prepend("/", t)) { }
};

struct Derived: public Base
{
   Derived(Base &p): Base(p, typename(this)) {  }
};

struct Main: public Base
{
   Derived derived;
   Main(): Base(this, typename(this)), derived(this) {  }
};

void OnStart()
{
   Main main;
   Print(main.derived.path);
}
 
Stanislav Korotky #:
Ниже код, который в двух вариантах макроса должен, ИМХО, давать один и тот же результат, но дает разные.

Да, воспроизводится.

В МТ4, к стати, оба варианта макроса дают одинаковый результат.

 
Vladislav Boyko #:

Да, воспроизводится.

В МТ4, к стати, оба варианта макроса дают одинаковый результат.

Даже в C++ работает как надо для обоих вариантов:

#define prepend(A, B) (A+B)             // expected output
//#define prepend(A, B) A+B             // expected output

// Task: 'prepend' must be a function with the expected output above

struct Base
{
public:
   std::string type;
   std::string path;
   
   Base(Base &p, std::string t): 
      type(t),
      path(p.path + prepend("/", t)) { }
};

struct Derived: public Base
{
public:
   Derived(Base &p): Base(p, typeid(this).name()) {  }
};

struct Main: public Base
{
public:
   Derived derived;
   Main(): Base(*this, typeid(this).name()), derived(*this) {  }
};

int main()
{
  Main main;
  std::cout << "Hello, " << main.derived.path << "!\n";
}

Выводит:

Hello, /P4Main/P7Derived!
 
Stanislav Korotky #:

Даже в C++ работает как надо:

Надеюсь, исправление данной ошибки в MQL5 не сломает сложно-уловимые места написанного кода.

 
fxsaber #:

Надеюсь, исправление данной ошибки в MQL5 не сломает сложно-уловимые места написанного кода.

Да, что-то нет особой надежды, что это поправят. Обошел, сделав функцию на все 3 аргумента в инициализаторе (prepend(p.path, "/", t), надо будет переобозвать). Жалко, что день потратил на выявление бага. Обычно в таких элементарных вещах не ждешь подвоха.

 
igor_spb #:

Ренат, добрый день!, а что нужно убрать/почистить/исправить в барах и тиках, чтобы работало.
1_ выгрузить историю по инструменту тики + бары
2_ убрать ошибочные
3_ закинуть в свой инструмент.

Может у Вас скрипт есть какой или хотя бы на скрине / пеинт покажите, что надо исправлять в данных.
Заранее спасибо!

Проблема массовая, я еще тикеров могу накидать, где это происходит)
По хорошему, надо эту проверку внутрь mql5 тестера впихнуть, чтобы "качество истории" мерил, а то он 100% пишет. ага)) охотно верим

ссылка на исходник вопроса  https://www.mql5.com/ru/forum/474452/page18#comment_55076381

Проблема, судя по всему, в том, что Финамовцы проставили Тиковый объем = 1 в минутках. Кроме этого они еще чего-то намихинировали в Тиковых данных на склейках, да так, что в тестере склейки использовать стало невозможно ни в режиме баров, ни в режиме тиков. 

Ну и про качество истории конечно смешно:

Тест на ALLFUTSi  с 01.01.2024 по 31.08.2024 в логе:

 

При этом в отчете:

 

38 272 511 тиков было, 281 567 стало. Качество истории 100% :)