Принудительная остановка индикаторов и скриптов - страница 2

 
Sergey Eremin:
Спасибо за ответ и понимание! Если я не ошибаюсь, то в одной из статей я видел Ваше решение. Если так, то, надеюсь, Вы не будете сильно возражать, если я напишу статью целиком полностью про утверждения и сделаю ссылку на Вас, как на пример применения оных (и если не будете против, то очень прошу скинуть сюда или в личку ссылку на ту статью)?


Ну и как человеку, понимающему мою задачу, отдельная просьба - оцените сам мой макрос (третье сообщение ветки), как оно Вам? Может что-то режет глаз?

В общем-то я статей не публиковал, поэтому не очень понятно, о какой ссылке идет речь. Хотя хальт выдернут действительно из кода моей забракованной статьи.

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

 
Stanislav Korotky:

В общем-то я статей не публиковал, поэтому не очень понятно, о какой ссылке идет речь. Хотя хальт выдернут действительно из кода моей забракованной статьи.

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

Видимо, ошибся насчёт статьи. Просто сейчас и сам не могу найти ту статью, но точно помню, что там был не макрос, а функция.

Преимущества макроса в основном такие: можно вывести выражение (#condition), имя файла (__FILE__), сигнатуру функции (__FUNCSIG__) и номер строки (__LINE__), где утверждение оказалось ложным. Получается примерно как на картинке. При варианте с функцией этих всех вкусностей уже не будет, придётся как-то через параметр указывать место в программе так, чтобы оно оставалось понятным программисту.

А насчёт диалога - задумка такая: если нажать "No", т.е. ответ на вопрос "Continue?" будет "No", то программа завершается, и последующие диалоги не будут выданы (см. UPD).

Спасибо!



UPD: посмотрел вариант с циклом и, похоже, ExpertRemove тоже не годится, т.к. в случае с циклом он не моментально грохнет программу, а дождётся окончания цикла (выдаст все диалоговые окна). Только хардкор, только ошибки времени выполнения :(

Крайний вариант теперь такой:

#define DEBUG

#ifdef DEBUG  
   #define assert(condition, message) \
      if(!(condition)) \
        { \
         string fullMessage= \
                            #condition+", " \
                            +__FILE__+", " \
                            +__FUNCSIG__+", " \
                            +"line: "+(string)__LINE__ \
                            +(message=="" ? "" : ", "+message); \
         \
         if(MessageBox(fullMessage+"\r\n\r\n"+"Continue?","Assertion failed!",MB_ICONWARNING|MB_YESNO)==IDNO) \
           { \
            double x = 0.0; \
            x = 1 / x; \
           } \
        }
#else 
   #define assert(condition, message) ;
#endif 
 
Sergey Eremin:

Преимущества макроса в основном такие: можно вывести выражение (#condition), имя файла (__FILE__), сигнатуру функции (__FUNCSIG__) и номер строки (__LINE__), где утверждение оказалось ложным. Получается примерно как на картинке. При варианте с функцией этих всех вкусностей уже не будет, придётся как-то через параметр указывать место в программе так, чтобы оно оставалось понятным программисту.

А насчёт диалога - задумка такая: если нажать "No", т.е. ответ на вопрос "Continue?" будет "No", то программа завершается, и последующие диалоги не будут выданы (см. UPD).

UPD: посмотрел вариант с циклом и, похоже, ExpertRemove тоже не годится, т.к. в случае с циклом он не моментально грохнет программу, а дождётся окончания цикла (выдаст все диалоговые окна). Только хардкор, только ошибки времени выполнения :(

Про преимущества макроса понятно. У меня тоже был макрос, но короткий - в нем содавался специальный объект куда эти все __FUNCSIG__ и прочее передавалось, а потом использовалось. Не столь эффективно, конечно.

Задумка про диалог тоже понятна, только у меня по-прежнему и в новом варианте впечатление, что в цикле будут множиться боксы.

 
Stanislav Korotky:

Про преимущества макроса понятно. У меня тоже был макрос, но короткий - в нем содавался специальный объект куда эти все __FUNCSIG__ и прочее передавалось, а потом использовалось. Не столь эффективно, конечно.

Задумка про диалог тоже понятна, только у меня по-прежнему и в новом варианте впечатление, что в цикле будут множиться боксы.

Я проверил на таком коде:

#property version   "1.00"
#include <assert.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+  
int OnInit()
  {
//---
   for(int i = 0; i < 1000; i++)
   {
      assert(0 > 1, "test message 001");   
   }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }

Т.к. MessageBox приостанавливает поток программы (в отличие от алертов), то до следующего варианта не доходит. По крайней мере в MT5 1159 это верно.

Но и этот вариант уже не вариант: вспомнилось, что MessageBox не работают в индикаторах. Так что теперь крайний вариант:

#define DEBUG

#ifdef DEBUG  
   #define assert(condition, message) \
      if(!(condition)) \
        { \
         string fullMessage= \
                            #condition+", " \
                            +__FILE__+", " \
                            +__FUNCSIG__+", " \
                            +"line: "+(string)__LINE__ \
                            +(message=="" ? "" : ", "+message); \
         \
         Alert("Assertion failed! "+fullMessage); \
         double x = 0.0; \
         x = 1 / x; \
        }
#else 
   #define assert(condition, message) ;
#endif 

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

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

Пример на картинке:


 
Sergey Eremin:

Т.к. MessageBox приостанавливает поток программы (в отличие от алертов), то до следующего варианта не доходит. По крайней мере в MT5 1159 это верно.

Но и этот вариант уже не вариант: вспомнилось, что MessageBox не работают в индикаторах. Так что теперь крайний вариант:

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

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

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

С пятеркой сейчас не работаю, а вот в четверке у меня подокно после ошибки в индюке пропадает. Может быть это зависит от типа ошибки. Попробуйте вызвать out of bounds.

 
Stanislav Korotky:

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

С пятеркой сейчас не работаю, а вот в четверке у меня подокно после ошибки в индюке пропадает. Может быть это зависит от типа ошибки. Попробуйте вызвать out of bounds.

Раз в MT4 (или и в MT5) возможно такое поведение (всё же решение универсальным предполагается), то, я думаю, что теперь ни к чему усложнять с MessageBox'ами. Но я попроверяю ещё. Out of bounds привёл к тому же побочному эффекту, но думаю это не смертельно. Главное, это описать в статье (если с таким кошмаром вообще одобрят).

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

 
Посмотрите эту тему, может подойдет? (касаемо индикатора)
 
Igor Konyashin:
Посмотрите эту тему, может подойдет? (касаемо индикатора)

Спасибо!

В данном примере идёт отталкивание от допущения, что в первом подокне наш индикатор будет первым (насколько видно по ChartIndicatorName(0, 1, 0)).

Однако, боюсь, это не универсально: мы заранее не знаем ни в каком подокне окажется наш индикатор, ни каким он будет там по счёту. Так можно снова вернуться к задаче "узнать короткое имя индикатора". И частный способ решения есть в указанной Вами ветке - запомнить в глобальную переменную, а хотелось бы общий :)


Но по крайней мере предположение Михаила в последнем сообщении кажется вполне логичным касательно того, почему окно индикатора остаётся висеть.

 
Михаил:

Есть очень простой способ:

Объявляем глобальную переменную н-р: stop_trading;

При инициализации присваиваем ей значение false

А в OnTick() пишем:

 А в любом месте кода ( когда Вам нужно остановить работу советника),

присваиваете переменной значение true 

Михаил, а почему Ваш код приведет к остановке работы советника?? Тут же просто выход из OnTick, советник как работал, так и будет работать, только в холостую.

void OnTick()
{
  if ( stop_trading ) return;

  //You code here.....
}

Я так понял, автору вопроса надо ExpertRemove()? Пример из справки.

void OnTick()
  {
   static int tick_counter=0;
//---
   tick_counter++;
   Comment("\nДо выгрузки эксперта ",__FILE__," осталось ",
           (ticks_to_close-tick_counter)," тиков ");
//--- до
   if(tick_counter>=ticks_to_close)
     {
      ExpertRemove();
      Print(TimeCurrent(),": ",__FUNCTION__," эксперт будет выгружен");
     }
   Print("tick_counter = ",tick_counter);
//---
  }
 
Alexey Volchanskiy:

Михаил, а почему Ваш код приведет к остановке работы советника?? Тут же просто выход из OnTick, советник как работал, так и будет работать, только в холостую.

Я так понял, автору вопроса надо ExpertRemove()? Пример из справки.

Я думал, что мне было надо нечто подобное ExpertRemove(), но для индикаторов и скриптов.

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

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