Инициализация переменных советника при смене периода, компиляции и т.п.

 

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

Инициализация переменных и массивов в советнике (MT4 Build 409)

Под термином «инициализация» в данном случае понимается выделение памяти и однократное присвоение начальных значений (явное или по умолчанию) глобальным, внешним и статическим переменным и массивам (переменные), которое происходит перед запуском на исполнение специальной функции init().

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

События и его последствия для программы (советника)

Специальная функция deinit() запускается всегда при завершении программы ( при переинициализации - перед запуском init()).

Успешная компиляция при включенном терминале изменяет Код на REASON_RECOMPILE (2), запускается init(), происходит инициализация всех внешних переменных со значениями, заданными по умолчанию в программе.
Глобальные и статические переменные не инициализируются.
Успешная компиляция при выключенном и последующем включении терминала запускает советник, который был прикреплен к графику с параметрами, сохраненными в терминале (свойства советника).

При смене счета (Код изменяется на REASON_ACCOUNT (6)) инициализация не происходит, init(0 не запускается, отжимается кнопка «советники» - эксперт может быть запущен только вручную.

При переключении таймфрейма (Код = REASON_CHARTCHANGE (3)), запускается init(), внешние переменные инициализируются начальными значениями, статические и глобальные сохраняют свои текущие значения.

При удалении советника (Код = REASON_REMOVE (1)), прорамма завершается функцией deinit(), в окне графика сохраняется поледний код деинициализации. Код может быть прочитан на следующем запуске в этом окне любым экспертом.

Если удалить график вместе с советником или перегрузить терминал (Код = REASON_CHARTCLOSE (4)), программа завершается функцией deinit(), а при востановлении окна из удаленных (загрузки терминала), советник также восстанавливается, и происходит полная инициализация всех переменных, при этом Код = 0.

При смене параметров в свойствах советника (только по нажатию кнопки ОК) (Код = REASON_PARAMETERS (5)), запускается init(), инициализицруются все внешние переменные, при этом статические и глобальные сохраняют свои текущие значения.

 

События, значения Кода и факт инициализации сведены в таблицы:

Для deinit()

События

Реак-ция

Код деинициализации

Инициализация переменных
и массивов

Манипуляции в терминале

вызов

UninitializeReason()

значение

Extern

Global

Static

Удаление советника с графика

deinit()

REASON_REMOVE

1

-

-

-

Перекомпиляция (успешная)

deinit()

REASON_RECOMPILE

2

-

-

-

Смена Таймфрейма

deinit()

REASON_CHARTCHANGE

3

-

-

-

Перезагрузка терминала
Удаление графика

deinit()

REASON_CHARTCLOSE

4

-

-

-

Открытие свойств

deinit()

REASON_PARAMETERS

5

-

-

-

 

для init()

События

Реак-ция

Код деинициализации

Инициализация переменных
и массивов

Востановление графика
Перезагрузка терминала
Первый запуск на графике

init()

NO_CODE

0

Да

Да

Да

Повторный запуск на графике

init()

REASON_REMOVE

1

Да

Да

Да

Перекомпиляция (успешная)

init()

REASON_RECOMPILE

2

Да

Да

Да

Смена Таймфрейма

init()

REASON_CHARTCHANGE

3

Да

-

-

Открытие свойств

init()

REASON_PARAMETERS

5

Да

-

-

Смена счета->"Expert" turned off

-

REASON_ACCOUNT

6

-

-

-

 

Предлагаю сформулировать правила:

1. Если вы хотите перекомпилировать используемый советник или индикатор, то рекомендуется перед компиляцией завершить исполнение терминала и проследить факт завершения с помощью Диспетчера задач.

2. При программировании прикладного ПО никогда не рассчитывайте на то, что вы не теряли связи с ДЦ.

 

Все глобальные переменные программы должны инициализироваться в ините.

Можно даже возвести инициализацию вообще всех переменных до параноидальной степени. Лишним не будет.

 

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

Вот какие общие правила я для себя сформулировал в итоге:

  1. Полная и явная инициализация всех переменных.
    Присваивать значения глобальным переменным (и массивам) в init()
    a. Инициализация константой
    b. Присвоение расчетного значения, переменным которые в дальнейшем остаются неизменными до конца работы программы.
    c. Присвоение значений из предварительно сохраненного файла для переменных, которые изменяются во время работы программы (находятся слева от «=»), а появляются впервые в тексте программы справа от «=», а вернее в параметрах, в условиях или в расчетах.
    d. Учитывать вероятность сброса статических локальных переменных внутри функций и продумывать для них возможность восстановления при нежелательной инициализации.
  2. Внешние переменные не изменять в программе, используя их только для хранения входных параметров советника.
  3. Учитывать, что при наличии в откомпилированных библиотеках или импортируемых функциях (без исходного кода) статических переменных, возможна ситуация сброса накопленных значений, если не предусмотрено их восстановление/сохранение.
  4. Сохранять каждый раз после важных изменений текущие значения переменных в файл для последующего восстановления в init() (см п.1.с)
  5. Использовать UninitializeReason() для анализа кода, если есть необходимость использования features инициализации советника.
 
TheXpert:

Все глобальные переменные программы должны инициализироваться в ините.

Можно даже возвести инициализацию вообще всех переменных до параноидальной степени. Лишним не будет.

Please ask developers to create new new function for setting global variables to start numbers.

Like "ResetGlobalVariables()" (not variables of terminal) 

It will be very usefull. 

 
eevviill:

Please ask developers to create new new function for setting global variables to start numbers.

Like "ResetGlobalVariables()" (not variables of terminal) 

It will be very usefull. 

?