Ошибки, баги, вопросы - страница 2575

 

Предложение о небольшом расширении возможности события OnTimer()

В данный момент, событие OnTimer() начинает возникать с момента установки периодичности вызова ф-цией EventSetTimer().

Получается, что вот такой советник:

bool timer_set = false;
int OnInit()
{
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick()
{
   if (!timer_set)
      {
         // -- имитация включения советника в какое-то
         // -- случайное время
         string time = TimeToString(TimeTradeServer(), TIME_DATE | TIME_MINUTES | TIME_SECONDS);
         if (TimeCurrent() >= D'2019.09.24 3:47:40')
            {
               EventSetTimer(600);
               timer_set = true;
            }
      }
}
//+------------------------------------------------------------------+
void OnTimer()
{
//---
   string time = TimeToString(TimeTradeServer(), TIME_DATE | TIME_MINUTES | TIME_SECONDS);
   printf("Current time: %s", time);
}
//+------------------------------------------------------------------+

Выдает примерно следующее:

QJ      0       07:53:10.369    test_timer (GBPUSD_i,D1)        2019.09.24 03:57:41   Current time: 2019.09.24 03:57:41
NF      0       07:53:11.246    test_timer (GBPUSD_i,D1)        2019.09.24 04:07:41   Current time: 2019.09.24 04:07:41

Однако, часто, для проверки возникновения сигнала, достаточно делать проверку после появления очередного бара.

И получается, что, например, для PERIOD_M15 бар возникнет в 00:15:00, а проверка советником может произойти только в 00:29:59.

Т.е. для более менее стабильных и одинаковых результатов, независимо от времени запуска советника,

придется ставить таймер на более короткие промежутки времени, либо дополнительно использовать OnTick().

Как показали эксперименты, это очень сильно замедляет скорость тестирования в тестере стратегий.

Предложение:

Добавить функцию, которая бы позволила установить начальное время, от которого ведется отсчет для возникновения события OnTimer.

Например, какую-нибудь функцию EventSetTimerFrom(const datetime SinceDT), которая бы позволила подстроить вызов таймера через несколько секунд после нового бара.

 
Roman:

В dll всё просто, лишнее убрано для наглядности, показана сама идея

Вывожу результат data  в консоль, все строки в консоли идут чётко без пропусков и без глюков.
Передаю в mql через wcscpy(out, data) начинаются траблы
А если передаю проверочную строку написанную руками

То почему то проблем нет.

Хм, а тип string в mql учитывает терминальный ноль wchar_t*  ???

А вот эта функция заработала

wcsncpy(out, data, wcslen(data));

Но кривовато, кажется один символ бажит в конце строки, лишняя скобка } то появляется то пропадает.
wcslen(data)+1
wcslen(data)+2
не помогло,
и парсится стало без ошибок, без якобы каких то утечек

вообще не понятно, какая длина или размер, одного символа в mql-овскоком string
в типе string точно присутствует какая то ошибка

И в давнейшей статье в пункте 3.3 Передача и модификация строк, в примере скорее всего допущена ошибка.

_DLLAPI void fnReplaceString(wchar_t *text, wchar_t *from, wchar_t *to)
  {
   wchar_t *cp;
    
   //проверка параметров
   if(text==NULL || from==NULL || to==NULL) return;
   if(wcslen(from)!=wcslen(to))             return;
   
   //поищем подстроку
   if((cp=wcsstr(text,from))==NULL)         return;
   
   //заменим
   memcpy(cp,to,wcslen(to)*sizeof(wchar_t));  //в этой строке должен быть указатель sizeof(wchar_t *)
  }

Возможно, где то в коде терминала, преобразование mql-овского string работает таким же образом, без указателя.

 
Maksim Emeliashin:

установить начальное время, от которого ведется отсчет для возникновения события OnTimer.

Вы можете сами это сделать через повторный вызов EventSetTimer. Учитывайте, что на счете (не в Тестере) таймер плавает и требует постоянной корректировки.

 
fxsaber:

Вы можете сами это сделать через повторный вызов EventSetTimer. Учитывайте, что на счете (не в Тестере) таймер плавает и требует постоянной корректировки.

Спасибо, полезная вещь!

Очень странно, конечно, что такой несложный момент не учтен в терминале "из коробки".

 
Roman:

А вот эта функция заработала

Но кривовато, кажется один символ бажит в конце строки, лишняя скобка } то появляется то пропадает.
wcslen(data)+1
wcslen(data)+2
не помогло,
и парсится стало без ошибок, без якобы каких то утечек

вообще не понятно, какая длина или размер, одного символа в mql-овскоком string
в типе string точно присутствует какая то ошибка

И в давнейшей статье в пункте 3.3 Передача и модификация строк, в примере скорее всего допущена ошибка.

Возможно, где то в коде терминала, преобразование mql-овского string работает таким же образом, без указателя.

getData() копай. Сдается мне, что где-то там засада.
[Удален]  
Roman:

В dll всё просто, лишнее убрано для наглядности, показана сама идея

Прикольные такие примеры у вас, всё убрали, оставили UB (модификация строковых литералов), а все телепатить должны. Если рассчитывайте на какой-то толковый совет, то приведите минимальный рабочий код (на двух сторонах), иначе просто трёп.

 
Vict:

Прикольные такие примеры у вас, всё убрали, оставили UB (модификация строковых литералов), а все телепатить должны. Если рассчитывайте на какой-то толковый совет, то приведите минимальный рабочий код (на двух сторонах), иначе просто трёп.

В примере показано то место которое вызывает проблему, то есть проблема в копировании указателя wchar_t* в mql-овкий string.
Остальной код не относящийся к проблеме, не несёт полезной нагрузки, так как всего лишь выполняет проверку if данные есть, тогда читаем, и т.д.
Зачем его писать в пример и засорять саму суть проблемы, когда даже с упрощённым кодом многие не поймут в чём суть проблемы.
Поймите getData() сетевая функция, которая читает  FrameOpcode, и возвращает полученные данные в виде указателя на строку типа const wchar_t*.

Всем известно что простая функция wcscpy(out, data) копирует  const wchar_t* строку,  в  строку wchar_t*, и автоматически считает длину символов до терминального нуля  const wchar_t* 
Вот тут то и проявляется ошибка, mql-овский string не корректно принимает скопированную строку wchar_t*, вопрос почему такое может быть? Если функция автоматически определяет терминальный ноль.
В статье Рената строки копируются через memcpy с допущенной ошибкой по размеру байтов. Возможно такой же подход используется в самом коде терминала, для формирования mql-овского типа string.
Понимаете, 
memcpy  не только не подходит для копирования строк, так ещё и с ошибкой в размере переданных байт, приводит к неровным данным.
Для копирования строк ведь есть другие специальные для этого Сишные функции, такие как wcscpy,  wcsncpy и т.д.
Да и сам Ренат в одной из веток писал, что вскоре будут полностью перерабатывать работу со строками, видимо проблема известна, но почему то тишина в ответ на обозначенную мной проблему.

Вот для сравнения размер байт указателя wchar_t*, и простого типа wchar_t

Файлы:
1.PNG  83 kb
[Удален]  
Roman:

Кончено, проще написать целую портянку в ответ, чем нормальный воспроизводимый тест заменив getData() на что-то. Чего ожидаете, если UB на UB, и выводы неверны:

memcpy(cp,to,wcslen(to)*sizeof(wchar_t));  //в этой строке должен быть указатель sizeof(wchar_t *)

всё там правильно. Что-то не так с вашими представлениями о строках, отсюда и обшибки.

 
Vict:

Кончено, проще написать целую портянку в ответ, чем нормальный воспроизводимый тест заменив getData() на что-то. Чего ожидаете, если UB на UB, и выводы неверны:

всё там правильно. Что-то не так с вашими представлениями о строках, отсюда и ошибки.

Воспроизводимый код предоставить нет возможности, так как сами понимаете что это dll, использующая сторонние библиотеки.
По поводу почему я решил что в примере ошибка.
memcpy(cp,to,wcslen(to)*sizeof(wchar_t));  //в этой строке должен быть указатель sizeof(wchar_t *)

Используя функцию без указателя,

memcpy(out, data, wcslen(data) * sizeof(wchar_t));

то конец строки начинает плыть лишними символами. Посмотрите на конец строки на снимке.
Да и логично же, что если мы копируем строку wchar_t* как указатель, то и нужно передавать размер указателя, а не размер типа.

А если использую указатель,

memcpy(out, data, wcslen(data) * sizeof(wchar_t*));

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

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

wcsncpy(out, data, wcslen(data));

Вот и перебираю кучу вариантов где может быть причина, но используя memcpy без указателя в sizeof, результат виден на скрине.

Хочу ещё проверить полученную wchar_t* строку на терминальный ноль, есть он или нет.
Как это можно сделать?

Файлы:
[Удален]  
Используя функцию без указателя,

тут out останется без \0 в конце

А если использую указатель,

тут вы выходите за границы out

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

опять out останется без \0. Смотрите доки

wcsncpy, wcsncpy_s

...

If countis reached before the entire string srcwas copied, the resulting wide character array is not null-terminated.

...

ЗЫ: может не связываться со строками вообще? сохраняйте в wchar_t массивы и гоняйте их, а внутри мкл конвертировать в строку если надо https://www.mql5.com/ru/docs/convert/shortarraytostring