Советники: Grid MA ATR - страница 2

 

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

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

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

 
Vitaly Murlenko #:

Автор, плохая практика на каждой итерации цикла объявлять одну и ту же переменную. Посмотрите, это Ваш код

Если в коде Вы дважды объявляете переменную, то компилятор выдаёт ошибку, мол, переменная уже объявлена. Здесь же он не может выдать эту ошибку. Но логика не верна - исправьте. Эта ошибка повторяется у Вас и далее по коду. В том числе и конструкция for (int i....) не верна именно в этом случае. Ваш цикл for находится внутри цикла while. for будет повторяться и повторяться пока ни произойдёт принудительное прерывание цикла while. И точно также переменная int i будет каждый раз объявляться заново - не каждый тик, а внутри одного тика на каждой итерации цикла while. Я не процитировал этот участок кода - смотрите сами ниже по коду.

А что с логикой не так? Я согласен, что объявлять переменную нужно заранее, но как это повлияет на логику? Или в новых билдах есть какие то нововведения в этом плане?
 
Yuriy Bykov #:

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

Скачал код ещё раз. Думал, проморгал где-то объявление статической переменной. Ан нет - ни где в коде не встречается static. Отсюда вопрос, чего это Вы вдруг решили заговорить о статических переменных? И про однократное выделение памяти понятно уже из справки и без всяких пояснений. Раз в справке написано " Статические переменные существуют с момента выполнения программы и инициализируются однократно перед вызовом специализированной функции OnInit() ", значит выделение памяти происходит один, и только один раз. Дык дело то всё в том, что ни где в коде нет конструкции, например, 

 static int i=0;

Ни чего подобного в коде нет.

Документация по MQL5: Обработка событий / OnInit
Документация по MQL5: Обработка событий / OnInit
  • www.mql5.com
OnInit - Обработка событий - Справочник MQL5 - Справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
 
Vladimir Khlystov #:
А что с логикой не так? Я согласен, что объявлять переменную нужно заранее, но как это повлияет на логику? Или в новых билдах есть какие то нововведения в этом плане?

Проведите эксперимент. Создайте пустого советника. В старте напишите:

int i;

int g,i;

Попробуйте откомпилировать. В результате ошибка "i - variable already defined". Эту ошибку компилятор видит, ибо вторая конструкция int g,i; предполагает следующий алгоритм действий: 1) проверить, ни объявлена ли ранее переменная g, если нет, то объявить; 2) проверить, ни объявлена ли переменная i. Ага, объявлена ранее. Выдать сообщение об ошибке.

Когда Вы объявляете  переменную внутри цикла, вы заставляете программу выполнять команду,  int i;  int i;  int i;... столько раз, сколько у цикла итераций. Такая логика ошибочна.

 

Внутри цикла while у Вас цикл for. В заголовке этого цикла объявляется переменная i, которая затем инициализируется значением. В принципе, по большому счёту ошибки как бы нет. Итерация цикла while отработала, перменная i уничтожается. На новой итерации цикла while она опять создаётся и снова инициализируется. Ну, подумайте сами, зачем кучу раз применять инициализацию, если её можно применить всего 1 раз? Тем более, что у вас ко всему ещё и цикл while, который будет выполнен неизвестно сколько раз, вплоть до чуть ли ни бесконечности.

Просто, если не заострять внимание на подобных вопросах, привыкаешь к подобным формам записи кода - делаешь их впоследствии на автопилоте. А вот это уже черевато. Вы ведь знаете, за что уволили дида Панаса?

 
Vitaly Murlenko #:

Скачал код ещё раз. Думал, проморгал где-то объявление статической переменной. Ан нет - ни где в коде не встречается static. Отсюда вопрос, чего это Вы вдруг решили заговорить о статических переменных? 

Я немного неточно выразился. Действительно, статической переменной называют ту, которая объявлена со словом static. Я же имел ввиду переменную, размещаемую в области памяти, которая выделяется однократно при запуске программы. Такую область памяти тоже, кажется, называют статической. К таким переменным относятся все переменные, которые не являются указателями. В указатели записываются адреса объектов, создаваемых оператором new в динамической области памяти.


Когда Вы объявляете  переменную внутри цикла, вы заставляете программу выполнять команду,  int i;  int i;  int i;... столько раз, сколько у цикла итераций. Такая логика ошибочна.

Как раз пытался сказать, что "int i;" это не команда, которая выполняется столько раз, сколько выполняется это место после запуска скомпилированной программы. Это указание компилятору, что в этом блоке кода понадобится место памяти, под хранение одного целого числа. Это место будет выделено однократно при старте программы.


Проведите эксперимент. Создайте пустого советника. В старте напишите:

int i;

int g,i;

Попробуйте откомпилировать. В результате ошибка "i - variable already defined". Эту ошибку компилятор видит, ибо вторая конструкция int g,i; предполагает следующий алгоритм действий: 1) проверить, ни объявлена ли ранее переменная g, если нет, то объявить; 2) проверить, ни объявлена ли переменная i. Ага, объявлена ранее. Выдать сообщение об ошибке.

Компилятор не такой уж и глупый. Неужели вы думаете, что разработчики компилятора позаботились об обнаружении ошибки объявления переменных с одинаковым именем в одной области видимости, и на протяжении десятка лет игнорируют ошибку многократного объявления переменной внутри цикла? Раз нет - значит, может и нет того, что вы считаете ошибкой? 

Ваш эксперимент можно немного модифицировать и, например, такой код не вызовет ошибку:

int i; // Первая переменная - в будет выделено 4 байта в статической области памяти при старте программы
i = 10;
{
   // Это уже новая область видимости
   int g, i;  // Вторая и третья переменная - будет выделено еще 8 байт в статической области памяти при старте программы
   i = 20;
   Print(i);  // Печатает 20

   // Здесь эта область видимости заканчивается, поэтому 
}
Print(i);  // Печатает 10

Компилятор, однако, предупреждает, что

declaration of 'i' hides local variable

то есть побуждает программиста лишний раз проверить, понимает ли он, что внутри блока переменная i это не та (первая) переменная i, а уже новая. И внутри блока под именем i будет подразумеваться уже не первая переменная.


Просто, если не заострять внимание на подобных вопросах, привыкаешь к подобным формам записи кода - делаешь их впоследствии на автопилоте. А вот это уже черевато.

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

 
Vitaly Murlenko #:

Вы ведь знаете, за что уволили дида Панаса?


А кто это?
 
Sergey Gridnev #:

А кто это?

В личку гляньте, такое нельзя опубликовывать :))

 
Подскажите пожалуйста как теперь можно посмотреть код советника и скачать его.
 

Хотел бы вставить свои четыре копейки одной монетой.

Сети на отложках строятся не оптимально. МА поменяла направление, взяли текущий ATR, рассчитали общий шаг для всех отложек и вперёд. Схема простая и рабочая. Не оптимальная, правда.  Чем дальше отложка, тем более вероятность, что цена до неё не дойдёт. Логично поиграться с щагом и размером лота. Либо ATR брать при открытии очередного рыночного ордера, и на его основании определять шаг следующей отложки.


Ну как-то так. Пардон.