Разработчикам и кому интересно - WHILE неравильно работает в тестере (вообще не работает с переменной на основе времени)

 

    Доброго времени суток! Давече я писАл о глюках While, но похоже, что глюки не у While, а скорее у RefreshRates и Sleep. Они не работают в тестере вообще (или в тестере, когда они внутри While). Следующий код это наглядно демонстрирует.


int start()
    {
     int i=0; //Счетчик циклов WHILE
     int delay=(1000*60*60); // 1секунда * 60секунд * 60минут (Время ожидания между        проходами цикла 1 час)
     Print ("Local ДО ",TimeHour(TimeLocal()),"H",TimeMinute(TimeLocal()),"M",TimeSeconds(TimeLocal()),"S");
     Print ("Тик до цикла ", GetTickCount());
     while(true)
        { //Управление находится внутри WHILE и START НЕ должен запускаться по тику
         i++; //Пока WHILE не завершит работу
         Print("Проход №",i," Local В ЦИКЛЕ ДО задержки          ",TimeHour(TimeLocal()),"H",TimeMinute(TimeLocal()),"M",TimeSeconds(TimeLocal()),"S");
         Print ("Проход №",i," Тик до ожидания ", GetTickCount());
         Sleep(delay); //************* Подождем 1 час *******************
         RefreshRates(); //Обновим данные (через час после входа в цикл)
         Print("Local В ЦИКЛЕ ПОСЛЕ задержки ",          TimeHour(TimeLocal()),"H",TimeMinute(TimeLocal()),"M",TimeSeconds(TimeLocal()),"S");
         Print ("Тик после ожидания ", GetTickCount());
         if (i==10) break; //Прерываем после 10 циклов ожидания по 1 часу каждый
        }
     RefreshRates(); //Обновим данные после выхода из WHILE
     Print ("Local ПОСЛЕ ",TimeHour(TimeLocal()),"H",TimeMinute(TimeLocal()),"M",TimeSeconds(TimeLocal()),"S");
     Print ("Тик после цикла ", GetTickCount());
     return(0);
    }


В журнале после запуска на тестере получам примерно следуюшее.


09:02:28 WhileTest started for testing
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local ДО 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик до цикла 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №1 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №1 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S (А где же тут разница в 1 час?!)
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №2 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №2 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №3 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №3 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №4 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №4 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №5 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №5 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №6 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №6 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №7 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №7 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №8 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №8 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №9 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №9 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №10 Local В ЦИКЛЕ ДО задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Проход №10 Тик до ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local В ЦИКЛЕ ПОСЛЕ задержки 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после ожидания 8277937
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Local ПОСЛЕ 17H49M0S
09:02:28 2008.05.30 17:49 WhileTest USDCAD,M1: Тик после цикла 8277937

Из чего можно сделать вывод: While перезапускался 10 раз без Refresh'а и без Sleep'а. Если погонять эту прогу на DEMO она перезапускает WHILE раз в час и через 10 часов заканчивает его исполнять. Таким образом получается, что проги с While'ом на основе временных факторов работать не могут и Refresh, а также Sleep на тестере не реализованы как надо.

    Если у кого есть мнения или объяснения - милости прошу ;)

А что касается DEMO. то у меня уже пару дней там вертится Советник с зацикленным на чисто While'ом внутри старта. который в отличие от глюков тестера не залипает глухо при обрыве связи или Отжатой кнопке [Советники], а терпеливо ожидает прокручивая while с интервалом в 10 секунд. в любой не очень аварийной ситуации Советник сам готов перезапуститься и откоректировать свои ошибки типа (нет цены., сервер занят, связь потеряна, поток занят, ненормализованная цена, торги закрыты из-за выходных и др.) При обрыве он ждет. А при коннекте пересчитывает позиции и начинает работать, как ни в чем ни бывало. Страно то. что мане почти не попадалось советников. которые себя корректируют, большинство только выкидывает код ошибки.

P.S. Чтоб у Вас Все было и Вам за это Ничего не было

Файлы:
whiletest.mq4  2 kb
 

Особенности и ограничения тестирования торговых стратегий в MetaTrader 4:


Особенности работы тестера стратегий на истории

  • Некоторые функции отрабатываются/пропускаются без вывода

    Это Sleep(), Alert(), SendMail(), SpeechText(), PlaySound(), MessageBox(), WindowFind(), WindowHandle(), WindowIsVisible()

 

то что sleep пропускается вполне объяснимо..

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

при чем тут реальное время ?

 
AlexTrader0618 писал(а) >>

Попробую объяснить.

Не суть принципиально какое использовать время Current или Local или еще какое - факт в том, что стратегия на основе временной последовательности с задержкой (т.е имеем событие А. Когда оно наступило подождем N секунд если B не наступило - подождем еще и т.д. пока не наступит B при N циклов, которое может не иметь ограничения. Если N > limit т.е. ждем уже слишком долго - тогда отменяется условие А [если имеем А - то ждем появления B. Общее количество циклов ожидания ограничено limit по t секунд или maxdelay по сумме секунд на всех уже проиденных циклах] т.е. нет привязки ко времени суток, дня или года.1. Просто жалко, что из-за тиковой природы тестера стратегий, то что работает на задержках между запросами на DEMO, и работает абсолютно нормально, при этом не перегружая сервер данных слишком частыми запросами, начисто виснет при запуске на тестере. Т.е. система с зацикленным внутри "старт" циклом "WHILE" (т.е. поле первого тика start не перезапускается никогда и дальнейший процесс идет внутри While с запросами новых данных через RefrashRates) на демо работает нормально. 2. При разрыве связи вместе с крохотной строчкой "нет связи" в углу окна терминала система периодически выдает на экран предупреждение, что связь потеряна и надо принять меры. 3. При появлении ошибок. которые система не может откорректировать сама - сразу выдаются сообщения и не нужно ждать свежего тика от сервера. Т.е. нет такого долго-занудного процесса, когда у нас позиция открыта уже 15 часов (с утра пятницы), порвалась связь с сервером или инетом, стопов нету, а терминал молчит как раба. и мы узнаем об этом утром понедельника т.к. торговля была закрыта в выходные и сервера данных молчали. Опачки мы в минусе на 500 бакинских рублей или вылетели по StopOut и кто виноват? 4. Зацикленная while'ом система не пропускает ничего мимо ушей, но тестировать на тестере стратегий ее в таком варианте невозможно. т.к. тестер работает на тиковых данных и игнорирует некоторые команды. А перезапуск "Старт" внутри цикла не происходит никода.

1. 4. Есть такая функция IsTesting(), при помощи нее можно разделить алгоримы работающие в тестере и на счете.

2. Для этих целей можно написать отдельного советника, который бы постоянно работал в терминаеле независимо от всего остального.

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

 
Integer >>:

1. 4. Есть такая функция IsTesting(), при помощи нее можно разделить алгоримы работающие в тестере и на счете.

2. Для этих целей можно написать отдельного советника, который бы постоянно работал в терминаеле независимо от всего остального.

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

 В ообще-то я про нее знаю и сейчас переписываю советника по принципу: если мы на тестере - тогда вырубаем все зацикливания на основе времени т.к. тестер их пролетает. А также не будут вызываться функции IstradeAllowed(), MarketInfo(Symbol(),MODE_TRADEALLOWED), sleep(), Alert(), MessageBox() некоторые другие функции, которые игнорируются тестером или завешивают его и WHILE циклы с уходом в старт без выхода (т.е. Start-->While {IsStopped != true} while бесконечен пока не остановлен вручную через {IsStopped==true} ) т.е. программа будет в слегка урезанной версии запускаться на тестере и в полной на DEMO или REAL, а опознание режима работы будет происходить в Init(). Т.е. если мы не на тестере {IsTesting !=true или IsOptimization != true}  тогда некий флаг для каждой отключаемой функции будет переводиться в иное состояние и каждый компонент будет знать запускаться ему или пропускаться. Всего одним флаго из Init() должно получиться несложно - правда повозиться придется.

P.S. Чтоб у вас все было и вам за это ничего не было. :)

 

А вот что делать, если советник обязательно должен крутиться в бесконечном цикле while? Как его тестировать в таком случае?

Суть проблемы в следующем: основная работа советника производится во внешней программе - MATLAB Engine, связь через вызовы функций DLL. Для запуска и остановки матлабовской машины используются две функции в DLL, и исполняются они, само собой, достаточно долго . По этому логично запускать их только один раз - в начале работы и при завершении соответственно, а не на каждом тике. То есть логично использовать бесконечный цикл - тогда ф-я start вызывается только один раз. Процесс работы советника тогда такой: 1)start() 2)Запускаем MATLAB 3)Бесконечный цикл while, в котором происходит основная работа и торговля 4)Выгружаем MATLAB 5)Завершение start().

При этом запустить MATLAB в init() и выгрузить его в deinit() нельзя по ряду причин. По крайней мере, мне это не удалось, может быть я что-то не понимаю.

Если убрать цикл, старт и стоп матлабовской машины будет происходить на каждом тике и занимать кучу времени - до нескольких секунд. Я правильно понимаю, что тестирование в этом случае будет невозможно? Просто до стадии тестирования пока не еще не дошел. Кто что может посоветовать?

 
mysty >>:

А вот что делать, если советник обязательно должен крутиться в бесконечном цикле while? Как его тестировать в таком случае?

Суть проблемы в следующем: основная работа советника производится во внешней программе - MATLAB Engine, связь через вызовы функций DLL. Для запуска и остановки матлабовской машины используются две функции в DLL, и исполняются они, само собой, достаточно долго . По этому логично запускать их только один раз - в начале работы и при завершении соответственно, а не на каждом тике. То есть логично использовать бесконечный цикл - тогда ф-я start вызывается только один раз. Процесс работы советника тогда такой: 1)start() 2)Запускаем MATLAB 3)Бесконечный цикл while, в котором происходит основная работа и торговля 4)Выгружаем MATLAB 5)Завершение start().

При этом запустить MATLAB в init() и выгрузить его в deinit() нельзя по ряду причин. По крайней мере, мне это не удалось, может быть я что-то не понимаю.

Если убрать цикл, старт и стоп матлабовской машины будет происходить на каждом тике и занимать кучу времени - до нескольких секунд. Я правильно понимаю, что тестирование в этом случае будет невозможно? Просто до стадии тестирования пока не еще не дошел. Кто что может посоветовать?


Я этот момент обошел на редкость лениво и просто - через INIT.

bool GoToWhile;

int init()

    {

    //Для тестового режима запускаем простой старт.

    //А для реального - зацикленный в WHILE.

    if (IsTesting()==false && IsOptimization()==false) {GoToWhile=true; return(0);}
    else {GoToWhile=false; return(0);}
    }


int start();

    {

    if (GoToWhile==true) //Для работы на REAL И DEMO.

       {

       while (true)

             {

             //Все тело программы находится здесь

             Sleep(500);

             RefreshRates();

             //Данные принудительно обновляются через строгие

             //интервалы - если мы находимся в реальной торговле.

             if (IsExpertEnabled()==false || IsStopped==true) {break;}

             //WHILE прерывается кнопкой "Советники" в окне терминала.

             }

       }

 

    if (GoToWhile==false) // Для тестирования и оптимизации.

       {

       //Все тело программы находится здесь.

       //Данные идут потиково и перезапускается Старт. 

       }

     return(0);

     }


Может я чего-то не доглядел, но пока эта конструкция работает на DEMO и на тестере без проблем.

P.S. Чтоб у вас все было и вам за это ничего не было.

 
Спасибо за ответ. Но Ваша конструкция очевидна и проблема моя не в том, что бы запускать while в реале и не запускать его при тестировании. Проблема в том, что при вызове и завершении start() у меня вызывается некая внешняя программа, которая запускается долго - до нескольких сек. И поместить вызов этой программы в init() я не могу в принципе. Как протестировать такую систему - пока не понимаю :(
 
AlexTrader0618 >>:


Я этот момент обошел на редкость лениво и просто - через INIT.


Доброе время суток. Лениво и просто - перед закрывающей while скобкой прописать if(IsTesting()) break; проверял. работает. У меня проблема: while не работает без строки Comment(). При запуске на демо приведённого ниже кода открываю терминал и слежу насколько код успевает за реальным показанием профита.

extern string   Symbols         = "-1";        
extern int      Magic           = -1;          
extern string   Comments        = "-1";        
extern int      Set_Y           = 20;          // Смещение по вертикали
extern int      Set_X           = 50;           // Смещение по горизонтали
extern double   updatesecond    = 0.3;         //время обновления в секундах

double CurrentProfitAll;
//------- Поключение внешних модулей -------------------------------------------
#include <stdlib.mqh>
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   Comment("");
   ObjectDelete("1");
   ObjectDelete("2");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {while (IsExpertEnabled())
    {Sleep (1000*updatesecond);
     RefreshRates(); 
     
     //Comment("без Comment не работает ?!");
     
     CurrentProfitAll  = GetProfitOpenPosInCurrency("", -1, Magic, Comments);
     SetLabel("1", DoubleToStr(CurrentProfitAll,2), "Arial Black",Red, Set_X, Set_Y, 1, 10);
     SetLabel("2", "CurrentProfit", "Arial Black",Red, Set_X+80, Set_Y, 1, 10);
    }
   return(0);
  }
//+----------------------------------------------------------------------------+
// текущий профит.
//+----------------------------------------------------------------------------+
double GetProfitOpenPosInCurrency(string sy, int op, int mn ,string comm) {
  double p, pr=0;
  int    i, k=OrdersTotal();

  if (sy=="0") sy=Symbol();
  for (i=0; i<k; i++) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if ((OrderSymbol()==sy || sy=="") && (op<0 || OrderType()==op)) {
        if ((mn<0 || OrderMagicNumber()==mn)&&(comm=="-1" || OrderComment()==comm)) {
          p=MarketInfo(OrderSymbol(), MODE_POINT);
          if (p==0) if (StringFind(OrderSymbol(), "JPY")<0) p=0.0001; else p=0.01;
          if (OrderType()==OP_BUY) {
            pr+=OrderProfit()+OrderCommission()+OrderSwap();//
          }
          if (OrderType()==OP_SELL) {
            pr+=OrderProfit()+OrderCommission()+OrderSwap();//
          }
        }
      }
    }
  }
  return(pr);
}
//+----------------------------------------------------------------------------+
void SetLabel(string nm, string tx, string font_name,color cl, int xd, int yd, int cr=0,  int fs=9) {
  if (ObjectFind(nm)<0) ObjectCreate(nm, OBJ_LABEL, 0, 0,0);
  ObjectSetText(nm, tx, fs, font_name);
  ObjectSet(nm, OBJPROP_COLOR    , cl);
  ObjectSet(nm, OBJPROP_XDISTANCE, xd);
  ObjectSet(nm, OBJPROP_YDISTANCE, yd);
  ObjectSet(nm, OBJPROP_CORNER   , cr);
  ObjectSet(nm, OBJPROP_FONTSIZE , fs);
}
//+----------------------------------------------------------------------------+

так вот если убрать из кода строчку 
Comment("без Comment не работает ?!");

(она закомментирована) то цикл явно не работает. Тоесть в таком виде как выложен данные обрабатываются некорректно. Так должно быть или чтото не то пытаюсь сделать?

Файлы:
 
Yugo2 >>:

Доброе время суток. Лениво и просто - перед закрывающей while скобкой прописать if(IsTesting()) break; проверял. работает. У меня проблема: while не работает без строки Comment(). При запуске на демо приведённого ниже кода открываю терминал и слежу насколько код успевает за реальным показанием профита.


так вот если убрать из кода строчку 

(она закомментирована) то цикл явно не работает. Тоесть в таком виде как выложен данные обрабатываются некорректно. Так должно быть или чтото не то пытаюсь сделать?


     Доброго времени суток! А вот мне кажется, что тут все нормально. Может у вас терминал кривой - не 221 случайно, или выключены бибиотеки и импорт из DLL. У меня ваша функция отработала на демо как положено. С проверкой через Print() и ВЫКЛюченном Comment'е.


Дело по моему не в функции, поищите проблемму где-то в другом месте. Может быть вы на демо как-то некорректно работаете с объектами - у меня-то ведь с первого раза запустилась как надо. Или именно в том и лажа, что библиотеки не все подключены, поэтому некоторые команды игнорируются. Да еще одно замечание - может стоит поменять местами вызов функции и RefreshRates().

Я обычно подключаю <WinUser32.mqh> <stdlib.mqh> <stderror.mqh> и все путем :)

P.S. Чтоб у вас все бало и вам за это ничего не было.

 
AlexTrader0618 >>:


     Доброго времени суток! А вот мне кажется, что тут все нормально. Может у вас терминал кривой - не 221 случайно, или выключены бибиотеки и импорт из DLL. У меня ваша функция отработала на демо как положено. С проверкой через Print() и ВЫКЛюченном Comment'е.

Терминал 224. бибиотеки и импорт из DLL включены. уточню ситуацию. С проверкой через Print() и ВЫКЛюченном Comment'е  это выглядит так:

видно что циклы проходят, но показания кода и терминала явно расходятся. А вот если Comment включить, то графика кода вполне успевает за терминалом. Вариации с расположением RefreshRates(), Comment() и Print() ничего не меняют. Вот и ломаю голову - почему эта строчка Comment так влияет на цикл. Или на графику. Или плюнуть на всё.

Причина обращения: