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

 
Slava:
Да. Любой Print из OnInit

Спасибо. Интересно, если бы случайно не заметил, как узнать об этом возможно было бы...


ЗЫ Оставил бы эту фишку только для локальных Агентов. В Облаке запросто можно заспамить лог  таким образом.

 
fxsaber:

Спасибо. Интересно, если бы случайно не заметил, как узнать об этом возможно было бы...


ЗЫ Оставил бы эту фишку только для локальных Агентов. В Облаке запросто можно заспамить лог  таким образом.

В облаке не выводится. Ибо незачем
 
Slava:

Когда запускаете генетику, то оптимизируете по пользовательскому критерию?

Судя по представленным логам, OnTester во всех случаях вернул 0

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

OnTester возвращает 0, поэтому в результатах и нули - это понятно. Вопрос в том почему он возвращает "0" при общем прогоне (оптимизации), а при единичном прогоне из "нулевых результатов" (с теми же параметрами) выдаёт нормальный результат, график и пр? Т.е. что-то не работает в "Полном переборе" и при этом генетика работает нормально. Есть ещё мысли/идеи?

 
Kuzmich:

Есть ещё мысли/идеи?

Вытянуть всю инфу оптимизационного прохода подобным способом

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

MT5. ТЕСТЕР СТРАТЕГИЙ. Расхождение результатов тестирования и оптимизации.

fxsaber, 2017.08.22 11:06

Вставить в советник эти строки

#define REPORT_TESTER // В тестере будут автоматически записываться отчеты
#include <Report.mqh>

и запустить Оптимизацию. Затем запустить несовпадающий одиночный прогон.

Далее сравнить сохраненные два отчета соответствующих прохода из Оптимизации и одиночного прохода.

Результат сравнения этих двух отчетов быстро выявит причины.

 
В рамках знакомства с функционалом Socket* возник целый ряд вопросов к текущей реализации.
Цель - максимально улучшить то, что сделано, прошу разработчиков не обижаться на возможную критику.



1. Не понятны причины таких сильных отличий "интерфейсов" для socket Read функций:
а) Для шифрованного соединения имеется две функции для чтения, а для не шифрованного - одна.
б) В SocketRead необходимо явно указывать timeout_ms , а в SocketTlsRead и SocketTlsReadAvailable такого параметра вообще нет (устанавливается отдельной функцией SocketTimeouts).
int  SocketTlsRead(int socket, uchar& buffer[], int buffer_maxlen);
int  SocketTlsReadAvailable(int socket, uchar& buffer[], int buffer_maxlen);

int  SocketRead(int socket, uchar& buffer[], int buffer_maxlen, uint timeout_ms);


2. Название функции SocketIsReadable не имеет ни чего общего с тем, что выполняет на самом деле:

bool  SocketIsWritable(const int  socket); // Return true if writing is possible, otherwise false.
uint  SocketIsReadable(const int  socket); // Number of bytes that can be calculated. In case of an error, 0 is returned.
bool  SocketIsConnected(const int socket); // New function without description. May be, it returns true if connection is not closed.

В действительности, SocketIsReadable -это аналог ioctlsocket() функции с флагом FIONREAD в Ws2_32.dll


3. Как пользователю с помощью функционала Socket* по не шифрованному соединению получить ответ от сервера с минимальными задержками по времени, если сервер не рвет соединение после передачи данных?

- функция SocketIsReadable без явного использования задержки во времени (например без Sleep) возвращает 0.
- функция SocketRead не знает сколько ей читать, укажешь значение buffer_maxlen с запасом - придется ждать тайм-аута по timeout_ms

Ага, вот так это делается:

- ожидаем в SocketRead 1 байт данных;
- затем узнаем размер всего ответа с помощью SocketIsReadable;
- читаем отсавшиюся длину в SocketRead;
- объедением в единое целое полученные результаты через копированием массивов:

#define PRINT(x) Print(#x, ": ", string(x))
                
void OnStart() {
   string domain = "www.mql5.com";
   int port = 80;
 
   string request = "GET / HTTP/1.1\r\nHost: " + domain + "\r\n\r\n";
   char req[];
   
   int socket = SocketCreate();
   PRINT(SocketConnect(socket, domain, port, 5000));
   int len=StringToCharArray(request,req)-1;
   PRINT(SocketSend(socket,req,len));
   
   
   
   uchar resp[];
   uchar result[];
   
   int resp_result;
   uint resp_len;
   int start_write;
   
   
   resp_len = 1;
   resp_result = SocketRead(socket, resp, resp_len, 5000);
   if (resp_result <= 0){
      PRINT(GetLastError());
      return;
   }
   start_write = ArraySize(result);
   ArrayResize(result, start_write + resp_result);
   ArrayCopy(result, resp, start_write);
   
   
   resp_len = SocketIsReadable(socket);
   resp_result = SocketRead(socket, resp, resp_len, 5000);
   if (resp_result <= 0){
      PRINT(GetLastError());
      return;
   }
   start_write = ArraySize(result);
   ArrayResize(result, start_write + resp_result);
   ArrayCopy(result, resp, start_write);
   
   
   PRINT(CharArrayToString(result));
};

А не многовато ли кода?


4. SocketIsReadable возвращает ложную информацию.
Выключить интернет и выполнить вышеприведенный код.
В результате SocketIsReadable возвращает вменяемое значение 1. Чудеса.


Удалось описать где-то третью часть от общей массы вопросов и проблем связанных с Socket*.
К сожалению, необходимо достаточно много времени, что бы все проверить, описать, перепроверить... (так что не факт что будет продолжение)

Общее впечатление: или все делалось в большой спешке, или функционал Socket* попал на реализацию к junior разработчику.
В любом случае, текущее решение весьма сырое и покрывает достаточно узкий подход по использованию сокетов.

 
MQL5\Include\Math\AlgLib\dataanalysis.mqh — CLinReg::LRLine не работает для 1М и больше значений?
 
Kuzmich:

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

OnTester возвращает 0, поэтому в результатах и нули - это понятно. Вопрос в том почему он возвращает "0" при общем прогоне (оптимизации), а при единичном прогоне из "нулевых результатов" (с теми же параметрами) выдаёт нормальный результат, график и пр? Т.е. что-то не работает в "Полном переборе" и при этом генетика работает нормально. Есть ещё мысли/идеи?

Можете поделиться советником (ex5 в личку) и условиями оптимизации?

Мы хотим воспроизвести указанную Вами проблему.

После исследований эксперт будет безвозвратно стёрт

 
Slava:

Можете поделиться советником (ex5 в личку) и условиями оптимизации?

Мы хотим воспроизвести указанную Вами проблему.

После исследований эксперт будет безвозвратно стёрт

А моего советника посмотрите? У меня похожая проблема - не считается profit, соответственно, оптимизация не работает.
 
Slava:

Можете поделиться советником (ex5 в личку) и условиями оптимизации?

Мы хотим воспроизвести указанную Вами проблему.

После исследований эксперт будет безвозвратно стёрт

Ответил в личку.

 
Sergey Dzyublik:
В рамках знакомства с функционалом Socket* возник целый ряд вопросов к текущей реализации.
Цель - максимально улучшить то, что сделано, прошу разработчиков не обижаться на возможную критику.



1. Не понятны причины таких сильных отличий "интерфейсов" для socket Read функций:
а) Для шифрованного соединения имеется две функции для чтения, а для не шифрованного - одна.
б) В SocketRead необходимо явно указывать timeout_ms , а в SocketTlsRead и SocketTlsReadAvailable такого параметра вообще нет (устанавливается отдельной функцией SocketTimeouts).


2. Название функции SocketIsReadable не имеет ни чего общего с тем, что выполняет на самом деле:

В действительности, SocketIsReadable -это аналог ioctlsocket() функции с флагом FIONREAD в Ws2_32.dll


3. Как пользователю с помощью функционала Socket* по не шифрованному соединению получить ответ от сервера с минимальными задержками по времени, если сервер не рвет соединение после передачи данных?

- функция SocketIsReadable без явного использования задержки во времени (например без Sleep) возвращает 0.
- функция SocketRead не знает сколько ей читать, укажешь значение buffer_maxlen с запасом - придется ждать тайм-аута по timeout_ms

Ага, вот так это делается:

- ожидаем в SocketRead 1 байт данных;
- затем узнаем размер всего ответа с помощью SocketIsReadable;
- читаем отсавшиюся длину в SocketRead;
- объедением в единое целое полученные результаты через копированием массивов:

А не многовато ли кода?


4. SocketIsReadable возвращает ложную информацию.
Выключить интернет и выполнить вышеприведенный код.
В результате SocketIsReadable возвращает вменяемое значение 1. Чудеса.


Удалось описать где-то третью часть от общей массы вопросов и проблем связанных с Socket*.
К сожалению, необходимо достаточно много времени, что бы все проверить, описать, перепроверить... (так что не факт что будет продолжение)

Общее впечатление: или все делалось в большой спешке, или функционал Socket* попал на реализацию к junior разработчику.
В любом случае, текущее решение весьма сырое и покрывает достаточно узкий подход по использованию сокетов.

1. Таков интерфейс.

TLS функции являются вспомогательными для поддержки сложных случаев. Никаких проблем с выставлением SocketTimeouts - именно их лучше и использовать.


2. Она выполняет свою функцию правильно.

Видимо, вы не в курсе проблем детекции разрыва TCP соединений. Это достаточно сложно(ресурсоемко за счет дополнительных вызовов) обнаружить, что соединение гарантированно оборвано правильно. Все сетевые реализации страдают от этой проблемы.

Наша реализация SocketIsReadible достаточно умна и имеет детект разрыва связи. При обнаружении чистого 0 байт, она делает дополнительную работу по проверке завершенности сокета:

   //+------------------------------------------------------------------+
   //| Доступно для чтения?                                             |
   //+------------------------------------------------------------------+
   UINT32 IsReadible(void)
     {
      unsigned long size=1;    // специально, чтобы убиться при попытке чтения, если сокет мертв
      //--- проверка
      if(m_socket!=INVALID_SOCKET)
        {
         //--- считаем количество доступных для чтения байт
         if(ioctlsocket(m_socket,FIONREAD,&size)!=0)
           {
            Close();
            return(1);        // вернем 1, чтобы убиться при попытке чтения
           }
         //--- если нет данных, проверим сокет на завершенность
         if(size==0)
           {
            timeval wait_time;
            fd_set  fd;
            //--- ждём
            FD_ZERO(&fd);
            FD_SET(m_socket,&fd);

            wait_time.tv_sec =0;          // секунды
            wait_time.tv_usec=1000;       // микросекунды
            //--- ждём
            if(select(0,&fd,NULL,NULL,&wait_time)>0)
               return(1);                 // вернем 1, чтобы убиться при попытке чтения
           }
        }
      //--- размер
      return(size);
     }

Так как она возвращает количество байт без флага завершенности, то она выдает 1 байт, чтобы последующая/неминуемая попытка SocketRead чтения штатно выдала ошибку.

Почему это правильно? Потому что большинство кода программистами в лоб пишется так:

if(SocketIsReadible(...)>0)
  {
   if(SocketRead( )<1)
     return(false);
   ...
  }
... уходим на следующий круг ожидания

фактически результат операции проверяется на прямой попытке чтении.


3. Нужно перед фактическим чтением делать SocketIsReadible(), если вы не знаете точного размера читаемых данных.

Связка SocketisReadible/SocketRead дает вам возможность не терять контроль(минимизировать почти до нуля утерю контроля) над потоком выполнения своей программы. Это позволяет избегать влетания в сетевые таймауты.

Да, на несколько строк больше кода, но вы ни на миллисекунду(грубо) не потеряете контроль. Вы сами решаете, что делать в промежутках отсутствия сетевых данных.


4. Объяснено во втором пункте.

Выдача 1 ради стимуляции чтения и выхода как ошибка чтения.



Ваши выводы неверные.

Такова природа TCP/IP транспорта, где вообще гарантий нет. Там и в сетевые черные дыры можно влететь на фильтрах/файрволах, когда нет части TCP сигналлинга. Сырой контроль таймаутов и потока данных позволяет их детектить и самостоятельно рвать соединения.

Мы дали сырой/прямой интерфейс доступа к сетевым функциям, включая TLS реализации. Если вы ими пользуетесь, то именно вам нужно правильно оборачивать сырые функции в защитный/контролируемый обработчик SocketIsReadible/SocketRead.

Если же вы хотите делать высокоуровневые запросы без необходимости думать о мелочах, то есть WebRequest функции. Там все защиты встроены.