Статьи по MQL4
Функции init() и deinit()

Функции init() и deinit()


например, forex

Для того, чтобы приблизиться к написанию первого индикатора, мы немного доработаем скрипт CrossMASignals. Добавим в наш скрипт возможность записи в файл сигналов покупок и продаж, для этого разместим в начале скрипта блок открытия файла, в цикле добавим операцию записей сигналов, в конце пропишем закрытие файла. Назовем этот скрипт CrossMASignals-2. Можно заметить, что бары на графике делятся на два вида – бары, на которых стоят стреки вверх или вниз, и бары, на которых стрелок нет. Будем записывать в файл время открытия бара, номер бара, цена, по которой рисуется стрелка вверх, и цена , по которой рисуется стрелка вниз. То есть, у нас будет csv-файл, содержащий 4 столбца: Time[Индекс_Бара], Индекс_Бара, Цена_Синей_Стрелки, Цена_Красной_Стрелки. Бары, на которых стрелок нет, будут содержать в двух последних столбцах нулевые значения. Я добавил несколько строк в начале скрипта:






и в конце


и в самом конце скрипта:



Получившийся файл можно скачать здесь .

int start()
  {
   double maLongCur, maLongPrev, maShortCur, maShortPrev;
string arrowName; // здесь будут назначаться уникальное имя объекта-стрелки int arrowCounter=0; int deletedArrows;
string FileName; int FileHandle;
// сформируем имя файла FileName="CrossMA.csv"; //откроем файл с именем FileName (создадим указатель/handle на него)
FileHandle=FileOpen(FileName,FILE_WRITE | FILE_CSV,";"); if (FileHandle<1)
{ Print("Не удалось открыть файл, ошибка ",GetLastError()); return; } // запишем названия столбцов (создание шапки) FileWrite(FileHandle,"Дата","Номер бара","Стрелка вверх","Стрелка вниз"); // удалим все стрелки, если они есть
deletedArrows=ObjectsDeleteAll(0,OBJ_ARROW); Comment("Удалено ",deletedArrows," обектов OBJ_ARROW");

// объявим служебные переменные, в которых будем хранить ценовые координаты стрелок double value1,value2;
//---- for(int i=Bars-1;i>=0;i--)
{ // обнулим службные переменные value1=0.0; value2=0.0; maLongCur=iMA(NULL,0,21,0,MODE_SMA,PRICE_CLOSE,i+1);// медленная средняя на предыдущем баре
maLongPrev=iMA(NULL,0,21,0,MODE_SMA,PRICE_CLOSE,i+2);// медленная средняя на предпредыдущем баре
maShortCur=iMA(NULL,0,13,0,MODE_SMA,PRICE_CLOSE,i+1);// быстрая средняя на предпредыдущем баре
maShortPrev=iMA(NULL,0,13,0,MODE_SMA,PRICE_CLOSE,i+2);// быстрая средняя на предыдущем баре


//Если есть сигнал к покупке на предыдущем баре - поставим синюю стрелку вверх // по цене открытия бара if((maShortCur>maLongCur)&&(maShortPrev<maLongPrev)) { // Поставим стрелку
// имя объекта - arrowName // тип объекта - OBJ_ARROW // координата по горизонтали - Time[i] время открытия бара // координата по вертикали - Open[i] цена открытия бара arrowName="arrow"+arrowCounter; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 241 , стрелка вверх ObjectSet(arrowName,OBJPROP_ARROWCODE,241); // зададим цвет стрелке - голубой ObjectSet(arrowName,OBJPROP_COLOR,Blue);
// увеличить счетчик стрелок arrowCounter++; value1=Open[i];//запомним цену голубой стрелки } //Если есть сигнал к продаже на предыдущем баре - поставим красную стрелку вниз
// по цене открытия бара if((maShortCur<maLongCur)&&(maShortPrev>maLongPrev)) { // Поставим стрелку // имя объекта - arrowName
// тип объекта - OBJ_ARROW // координата по горизонтали - Time[i] время открытия бара // координата по вертикали - Open[i] цена открытия бара arrowName="arrow"+arrowCounter; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 242 , стрелка вниз ObjectSet(arrowName,OBJPROP_ARROWCODE,242);
// зададим цвет стрелке - красный ObjectSet(arrowName,OBJPROP_COLOR,Red);
// увеличить счетчик стрелок arrowCounter++; value2=Open[i];//запомним цену красной стрелки }
//запишем данные для текущего бара в файл
FileWrite(FileHandle,TimeToStr(Time[i]),i,value1,value2);
} //закроем файл (освободим указатель/handle, чтобы файл можно было //открыть для редактирования другими программами) if(FileHandle>0) FileClose(FileHandle);

return(0); }


Если внимательно рассмотреть получившийся код, то можно заметить, что функционально он состоит из трех частей:
  1. Блок подготовки, в котором удаляются старые значки(стрелки) и открывается файл для записи.
  2. Блок нанесения стрелок на график и записи значений стрелок в файл.
  3. Завершающий блок, в нем мы закрываем файл.
В языке MQL-4 существуют три предопределенные процедуры, которые выполняется в определенном порядке – при запуске кода (скрипт, советник или индикатор) сначала выполняется функция init() (если она определена), в которой удобно провести подготовительные работы – инициализацию. В ней задаются значения необходимых переменных, заполняются глобальные массивы, открываются файлы и так далее. В блоке init() нельзя делать больших вычислительных работ, которые тормозят работу кода. Далее выполняется функция start(), в ней производится вся основная работа, пока код работает в памяти терминала, это основная рабочая функция. В ней производятся торговые операции (советники и скрипты), рассчитываются значения индикаторов, производится обработка любых доступных значений. Последней выполняется функция deinit() (если она определена), в которой производится завершение кода. Именно эта функция выполняется, когда мы снимаем с графика индикатор или советник. Эта функция также не может быть перегружена вычислительными действиями, на ее выполнение терминал отводит не более 2,5 секунд, после чего она будет принудительно завершена.Более подробную информацию можно получить во встроенной справке по теме «Выполнение программ» .
Изменим наш скрипт в соответствие с этими стандартами и назовем CrossMASignals-3. Я добавил в начало каждой функции оператор Print(), чтобы можно было видеть последовательность выполнения этих функций. Кроме того, переменную
int FileHandle;  // указатель на на файл - глобальная переменная
я вынес в самое начало скрипта, за пределы функций start, init и deinit. Такие переменные называются глобальными, обратиться к таким переменным можно из любого места программы, говорят, что эти переменные видимы на глобальном уровне. Мы к ней обращаемся в init() при создании указателя на файл, в блоке start() для записей в файл и в блоке deinit() при закрытии файла. В то же время переменную
string FileName; // имя файла - локальная переменная
  
оставил в блоке init(), так как больше она нигде не используется. Эта переменная уничтожается в памяти терминала сразу после выполнения блока init() и попытка обратиться к ней в других функциях скрипта (start или deinit) приведет к выдаче сообщения об ошибке. Такие переменные, которые живут только в пределах той функции, в которой они объявлены, называют локальными переменными. Мы даже можем объявить такую же переменную в остальных функциях, и каждая из них не будет знать о существовании другого близнеца, но делать так не рекомендуется, так как будет очень легко самому запутаться в коде.

int FileHandle;  // указатель на на файл - глобальная переменная
int init() { string FileName; // имя файла - локальная переменная
int deletedArrows;
// сформируем имя файла Print("Выполняется init()"); FileName="CrossMA.csv"; //откроем файл с именем FileName (создадим указатель/handle на него)
FileHandle=FileOpen(FileName,FILE_WRITE | FILE_CSV,";"); if (FileHandle<1)
{ Print("Не удалось открыть файл, ошибка ",GetLastError()); return; } // запишем названия столбцов (создание шапки) FileWrite(FileHandle,"Дата","Номер бара","Стрелка вверх","Стрелка вниз"); // удалим все стрелки, если они есть
deletedArrows=ObjectsDeleteAll(0,OBJ_ARROW); Comment("Удалено ",deletedArrows," обектов OBJ_ARROW");

} //---- int deinit() { Print("Выполняется deinit()"); //закроем файл (освободим указатель/handle, чтобы файл можно было
//открыть для редактирования другими программами) if(FileHandle>0) FileClose(FileHandle);
return(0);
} //---- int start() { double maLongCur, maLongPrev, maShortCur, maShortPrev;
string arrowName; // здесь будут назначаться уникальное имя объекта-стрелки int arrowCounter=0;// счетчик стрелок // объявим служебные переменные, в которых будем хранить ценовые координаты стрелок
double value1,value2;
Print("Выполняется start()"); for(int i=Bars-1;i>=0;i--)
{ // обнулим службные переменные value1=0.0; value2=0.0; maLongCur=iMA(NULL,0,21,0,MODE_SMA,PRICE_CLOSE,i+1);// медленная средняя на предыдущем баре
maLongPrev=iMA(NULL,0,21,0,MODE_SMA,PRICE_CLOSE,i+2);// медленная средняя на предпредыдущем баре
maShortCur=iMA(NULL,0,13,0,MODE_SMA,PRICE_CLOSE,i+1);// быстрая средняя на предпредыдущем баре
maShortPrev=iMA(NULL,0,13,0,MODE_SMA,PRICE_CLOSE,i+2);// быстрая средняя на предыдущем баре


//Если есть сигнал к покупке на предыдущем баре - поставим синюю стрелку вверх // по цене открытия бара if((maShortCur>maLongCur)&&(maShortPrev<maLongPrev)) { // Поставим стрелку
// имя объекта - arrowName // тип объекта - OBJ_ARROW // координата по горизонтали - Time[i] время открытия бара // координата по вертикали - Open[i] цена открытия бара arrowName="arrow"+arrowCounter; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 241 , стрелка вверх ObjectSet(arrowName,OBJPROP_ARROWCODE,241); // зададим цвет стрелке - голубой ObjectSet(arrowName,OBJPROP_COLOR,Blue);
// увеличить счетчик стрелок arrowCounter++; value1=Open[i];//запомним цену голубой стрелки } //Если есть сигнал к продаже на предыдущем баре - поставим красную стрелку вниз
// по цене открытия бара if((maShortCur<maLongCur)&&(maShortPrev>maLongPrev)) { // Поставим стрелку // имя объекта - arrowName
// тип объекта - OBJ_ARROW // координата по горизонтали - Time[i] время открытия бара // координата по вертикали - Open[i] цена открытия бара arrowName="arrow"+arrowCounter; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 242 , стрелка вниз ObjectSet(arrowName,OBJPROP_ARROWCODE,242);
// зададим цвет стрелке - красный ObjectSet(arrowName,OBJPROP_COLOR,Red);
// увеличить счетчик стрелок arrowCounter++; value2=Open[i];//запомним цену красной стрелки }
//запишем данные для текущего бара в файл
FileWrite(FileHandle,TimeToStr(Time[i]),i,value1,value2);
} return(0); }

Теперь у нас все готово, но код скрипта на самом деле не очень удобен. У нас жестко задано, что период медленной средней равен 21, а период быстрой средней равен 13. Нет необходимой гибкости, в следующий раз, когда мы захотим проверить другую пару периодов, нам придется менять эти значения в коде и заново компилировать, что не очень удобно. Для таких случаев существуют внешние переменные – параметры индикаторов, советников и скриптов. Введем новые переменные LongPeriod и ShortPeriod, зададим им начальные значения, а сами переменные объявим с ключевым словом extern (внешний).



Вычисление значений средних теперь будет выглядеть так:


Мы уже имеем 4-ый вариант такого простого скрипта.


extern int LongPeriod=21; // период медленной средней
extern int ShortPeriod=13; // период быстрой средней

int FileHandle; // указатель на на файл - глобальная переменная int init() { string FileName; // имя файла - локальная переменная
int deletedArrows;
// сформируем имя файла Print("Выполняется init()"); FileName="CrossMA.csv"; //откроем файл с именем FileName (создадим указатель/handle на него)
FileHandle=FileOpen(FileName,FILE_WRITE | FILE_CSV,";"); if (FileHandle<1)
{ Print("Не удалось открыть файл, ошибка ",GetLastError()); return; } // запишем названия столбцов (создание шапки) FileWrite(FileHandle,"Дата","Номер бара","Стрелка вверх","Стрелка вниз"); // удалим все стрелки, если они есть
deletedArrows=ObjectsDeleteAll(0,OBJ_ARROW); Comment("Удалено ",deletedArrows," обектов OBJ_ARROW");

} //---- int deinit() { Print("Выполняется deinit()"); //закроем файл (освободим указатель/handle, чтобы файл можно было
//открыть для редактирования другими программами) if(FileHandle>0) FileClose(FileHandle);
return(0);
} //---- int start() { double maLongCur, maLongPrev, maShortCur, maShortPrev;
string arrowName; // здесь будут назначаться уникальное имя объекта-стрелки int arrowCounter=0;// счетчик стрелок // объявим служебные переменные, в которых будем хранить ценовые координаты стрелок
double value1,value2;
Print("Выполняется start()"); for(int i=Bars-1;i>=0;i--)
{ // обнулим службные переменные value1=0.0; value2=0.0; maLongCur=iMA(NULL,0,LongPeriod,0,MODE_SMA,PRICE_CLOSE,i+1);// медленная средняя на предыдущем баре
maLongPrev=iMA(NULL,0,LongPeriod,0,MODE_SMA,PRICE_CLOSE,i+2);// медленная средняя на предпредыдущем баре
maShortCur=iMA(NULL,0,ShortPeriod,0,MODE_SMA,PRICE_CLOSE,i+1);// быстрая средняя на предпредыдущем баре
maShortPrev=iMA(NULL,0,ShortPeriod,0,MODE_SMA,PRICE_CLOSE,i+2);// быстрая средняя на предыдущем баре


//Если есть сигнал к покупке на предыдущем баре - поставим синюю стрелку вверх // по цене открытия бара if((maShortCur>maLongCur)&&(maShortPrev<maLongPrev)) { // Поставим стрелку
// имя объекта - arrowName // тип объекта - OBJ_ARROW // координата по горизонтали - Time[i] время открытия бара // координата по вертикали - Open[i] цена открытия бара arrowName="arrow"+arrowCounter; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 241 , стрелка вверх ObjectSet(arrowName,OBJPROP_ARROWCODE,241); // зададим цвет стрелке - голубой ObjectSet(arrowName,OBJPROP_COLOR,Blue);
// увеличить счетчик стрелок arrowCounter++; value1=Open[i];//запомним цену голубой стрелки } //Если есть сигнал к продаже на предыдущем баре - поставим красную стрелку вниз
// по цене открытия бара if((maShortCur<maLongCur)&&(maShortPrev>maLongPrev)) { // Поставим стрелку // имя объекта - arrowName
// тип объекта - OBJ_ARROW // координата по горизонтали - Time[i] время открытия бара // координата по вертикали - Open[i] цена открытия бара arrowName="arrow"+arrowCounter; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 242 , стрелка вниз ObjectSet(arrowName,OBJPROP_ARROWCODE,242);
// зададим цвет стрелке - красный ObjectSet(arrowName,OBJPROP_COLOR,Red);
// увеличить счетчик стрелок arrowCounter++; value2=Open[i];//запомним цену красной стрелки }
//запишем данные для текущего бара в файл
FileWrite(FileHandle,TimeToStr(Time[i]),i,value1,value2);
} return(0); }

Но тут появляется новый ньюанс. При запуске советника или индикатора на графике появляется диалоговое окно, в котором можно задать входные параметры, но при запуске скрипта (как в нашем случае) такого нет. В этом случае, если требуется , чтобы скрипт получил входные параметры (предложил их ввести пользователю) используется директива
#property show_inputs

Добавим эту строчку и получим пятый окончательный вариант. При использовании его на графике увидим:



Если просто закрыть диалоговое окно, то увидим по закладке «Эксперты», что ни одна из функций не вызывалась, скрипт был удален сразу без исполнения. Откроем файл CrossMA.csv , в нем 4 столбца. Два последних столбца нам понадобятся для написания индикатора.



Сами скрипты можно скачать здесь
Перейти к статье «Создание индикатора».
 
+7 (495) 710-76-76
8 (800) 200-01-31
по России бесплатно

закрыть

Вход в личный кабинет

Для счета alpari.classic введите номер счета (буква и 4 цифры) и пароль в ЛК.

Для счетов alpari.micro и alpari.partner введите логин и пароль в МТ.

Зарегистрироваться!Забыли пароль?

 
Rambler's Top100