| / | Статьи |
Cтатьи
Примеры
Синхронизация работы экспертов, скриптов и индикаторов
Авторизуйтесь или зарегистрируйтесь , чтобы добавить новую статью
|
|
Синхронизация работы экспертов, скриптов и индикаторов [ en ]ВведениеРазличают три вида программ, написанных на языке MQL 4 и исполняемых в клиентском терминале MetaTrader 4: 1. Краткая характеристика пользовательских MQL4-программ1.1. Эксперты Эксперты и скрипты прикрепляются к основному окну финансового инструмента и не могут иметь специальное, поставленное им в соответствие, подокно. 1.3. Индикаторы Мы перечислили здесь лишь основные характеристики пользовательских программ, а именно - те, которые понадобятся нам в ходе дальнейшего изложения. Как видно из представленного описания, ни одна из пользовательских программ не обладает свойствами их всех: эксперт и скрипт не умеют рисовать, индикатор не имеет права торговать, и так далее. В случае если наша торговая стратегия предполагает использование в динамике торговли всей совокупности свойств пользовательских программ, единственным решением является одновременное использование эксперта, скрипта и индикатора. 2. Постановка задачиРассмотрим критерии, диктующие необходимость одновременного использования всех видов пользовательских программ. 2.1. Своевременность Эту же идею можно успешно реализовать с помощью скрипта, то есть организовать бесконечный цикл в нём. Но скрипт не имеет настраиваемых переменных. Обеспечить настраиваемость торговой системы и своевременность исполнения всех распоряжений пользователя путём поддержания непрерывной работы можно лишь используя одновременно эксперт для настроек и скрипт для немедленного исполнения. 2.2. Информированность 2.3. Элементы управления 2.4. Требования к системе скрипт - основной код, содержащий аналитику и торговые функции; эксперт - предоставление панели для настроек; индикатор - предоставление поля подокна для отображения управляющих элементов и информации. 3. Программные решенияСразу оговоримся, что здесь рассматривается структура приложения, основанного на трёх составляющих в минимально необходимых пределах. Если вы решите использовать приложение на практике, то вам придётся самостоятельно доработать его в части аналитики и торговых операций. Но для создания структуры рассматриваемого материала этого вполне достаточно. 3.1. Эксперт // Expert.mq4
// Metsenat_exp.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Metsenat_exp() { //============================================ Предопределения ==== Symb = "_"+Symbol(); GV = "MyGrafic_GV_"; //============================================= GlobalVariable ==== GV_Ind_Yes = GV+"Ind_Yes" +Symb; // 0/1 удостоверяет факт загруженности индикатора GV_Scr_Yes = GV+"Scr_Yes" +Symb; // 0/1 удостоверяет факт загруженности скрипта //---------------------------------------------- Обнародование ---- GV_Exp_Yes = GV+"Exp_Yes" +Symb; GlobalVariableSet(GV_Exp_Yes, 1 ); GV_Extern = GV+"Extern" +Symb; GlobalVariableSet(GV_Extern, 1 ); // AAA используется в качестве примера: GV_AAA = GV+"AAA" +Symb; GlobalVariableSet(GV_AAA, AAA ); //================================================================= return; } //жжжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж Одной из задач для поддержания работоспособности всего приложения является задача отслеживания наличия всех составляющих. Поэтому все компоненты (скрипт, эксперт и индикатор) должны следить друг за другом, в случае отсутствия любого из компонентов - прекратить работу и сообщить об этом пользователю. Для этой цели на начальном этапе работы каждая программа заявляет о своём присутствии посредством публикования глобальной переменной. В данном случае, в функции Metsenat_exp() эксперта, это делается в строке: GV_Exp_Yes = GV+"Exp_Yes" +Symb; GlobalVariableSet(GV_Exp_Yes, 1 ); Функция Metsenat_exp() подчинена специальной функции init() эксперта, то есть используется всего один раз в период загрузки или изменения значений extern-переменных. Факт изменения настроек должен быть известен скрипту, поэтому эксперт сообщает скрипту об этом посредством изменения значения глобальной переменной GV_Extern: GV_Extern = GV+"Extern" +Symb; GlobalVariableSet(GV_Extern, 1 ); Component_exp() - функция, предназначенная для слежения за комплектностью. В зависимости от того, в какой специальной функции эксперта используется Component_exp(), ситуация получает то или иное развитие. // Component_exp.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Component_exp() { //================================================================= while( Fishka < 3 && // Находимся в init() или start() и .. (GlobalVariableGet(GV_Ind_Yes)!=1 || GlobalVariableGet(GV_Scr_Yes)!=1)) { // ..до тех пор, пока кого-то нет. Complect=0; // Раз кого-то нет, то некомплект GlobalVariableSet(GV_Exp_Yes, 1); // Заявим о присутствии эксперта //----------------------------------------------------------------- if(GlobalVariableGet(GV_Ind_Yes)==1 && GlobalVariableGet(GV_Scr_Yes)!=1) {//Если есть индикатор,но нет срипта,то.. Graf_Text = "Не установлен скрипт Script."; // Текст сообщения Component_uni(); // Пропишем текст. сообщ. в окно инд. } //----------------------------------------------------------------- Sleep(300); } //================================================================= if(Complect==0) { ObjectDelete("Necomplect_1"); // Удаление уже не нужных сообщений об отсутствии компонентов ObjectDelete("Necomplect_2"); ObjectsRedraw(); // Для быстрого удаления Complect=1; // Если мы вышли из цикла, то все есть } //================================================================= if(Fishka == 3 && GlobalVariableGet(GV_Ind_Yes)==1) // Находимся в deinit() и есть куда прописать (индикатор) { //----------------------------------------------------------------- if(GlobalVariableGet(GV_Scr_Yes)!=1) // Если нет срипта { Graf_Text = "Не установлены компоненты Expert и Script"; // Сообщение (выгружаемся же) Component_uni(); // Пропишем текст. сообщ. в окно инд. } //---------------------------------------------------------------- } //================================================================ return; } //жжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж Факт наличия скрипта и индикатора отслеживается на основе считывания значений соответствующих глобальных переменных - GV_Scr_Yes и GV_Ind_Yes. Если нет одного из компонентов, то управление передаётся в бесконечный цикл до тех пор, пока не будет достигнут полный комплект, то есть пока не будут установлены и скрипт, и индикатор. О текущей ситуации приложение сообщает пользователю посредством функции Component_uni(). Это универсальная функция, входящая в состав всех компонентов. // Component_uni.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Component_uni() { //================================================================ //---------------------------------------------------------------- Win_ind = WindowFind("Indicator"); // Какой номер окна у нашего индикатора? // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ObjectCreate ( "Necomplect_1", OBJ_LABEL, Win_ind, 0, 0 ); // Создаём объект в окне индикат ObjectSet ( "Necomplect_1", OBJPROP_CORNER, 3 ); // с коорд. от прав. нижн. угла ObjectSet ( "Necomplect_1", OBJPROP_XDISTANCE, 450 ); // с координатами по Х.. ObjectSet ( "Necomplect_1", OBJPROP_YDISTANCE, 16 ); // с координатами по Y.. ObjectSetText("Necomplect_1", Graf_Text,10,"Courier New",Tomato); // текст, шрифт и цвет // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Graf_Text = "Приложение не работает."; // Текст сообщения ObjectCreate ( "Necomplect_2", OBJ_LABEL, Win_ind, 0, 0); // Создаём объект в окне индикат ObjectSet ( "Necomplect_2", OBJPROP_CORNER, 3); // с коорд. от прав. нижн. угла ObjectSet ( "Necomplect_2", OBJPROP_XDISTANCE, 450); // с координатами по Х.. ObjectSet ( "Necomplect_2", OBJPROP_YDISTANCE, 2); // с координатами по Y.. ObjectSetText("Necomplect_2", Graf_Text,10,"Courier New",Tomato); // текст, шрифт и цвет // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ObjectsRedraw(); // Перерисуемся. return; //================================================================ } //жжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж По достижении комплектности управление в эксперте передаётся из цикла к последующему коду, где стираются теперь уже ненужные сообщения о неукомплектованности. При выгрузке эксперта специальная функция deinit() тоже вызывает Component_exp(), но уже для другой цели - сообщить о выгрузке в текущий момент. В deinit() эксперта также вызывается функция Del_GV_exp(). Она используется для удаления всех глобальных переменных GlobalVariable, открытых экспертом. В соответствии с неписаным правилом каждая программа при выгрузке должна "почистить за собой", то есть удалить созданные ею глобальные переменные и графические объекты.// Del_GV_exp.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Del_GV_exp() { //================================================================= GlobalVariableDel(GV_Exp_Yes ); GlobalVariableDel(GV_Extern ); GlobalVariableDel(GV_AAA ); //================================================================= return; } //жжжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж
Чтобы понять, каким образом это происходит, рассмотрим как устроен скрипт. 3.2. Скрипт // Script.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж include жжжж #include <stdlib.mqh> #include <stderror.mqh> #include <WinUser32.mqh> //================================================================= #include <Peremen_scr.mq4> // Файл описания переменных скрипта. #include <Metsenat_scr.mq4> // Предопределение переменных скрипта. #include <Mess_graf_scr.mq4> // Список графических сообщений. #include <Novator_scr.mq4> // Опрос окружения, получение новых значений некот переменных #include <Del_GV_scr.mq4> // Удаление всех GlobalVariable, созданных скриптом. #include <Component_scr.mq4> // Проверка наличия компонентов. #include <Component_uni.mq4> // Сообщение в индикаторе об отсутствии компонентов. #include <Del_Obj_scr.mq4> // Удаление всех объектов, созданных программным комплексом. #include <Work_scr.mq4> // Главная рабочая функция скрипта. //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж // // //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int init() { Fishka = 1; // Находимся в init() Metsenat_scr(); // Предопределение переменных скрипта. return; } //================================================================ int start() { Fishka = 2; // Находимся в start() while(true) { Component_scr(); // Проверка наличия компонентов Work_scr(); // Главная рабочая функция скрипта. } return; } //================================================================= int deinit() { Fishka = 3; // Находимся в deinit() Component_scr(); // Проверка наличия компонентов Del_Obj_scr(); // Удаление созданных графич. объектов Del_GV_scr(); // Удаление GlobalVariable скрипта. return; } //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж Основой представленного кода является наличие бесконечного цикла в специальной функции start(). В коде скрипта применяются функции с похожими названиями и содержанием. Остановимся подробнее на их особенностях. В начале каждого цикла вызывается функция Component_scr(). // Component_scr.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Component_scr() { //================================================================= Iter=0; // Обнулим счётчик итераций while (Fishka <3 && // Находимся в init() или start() (GlobalVariableGet(GV_Ind_Yes)!=1 || GlobalVariableGet(GV_Exp_Yes)!=1)) { // До тех пор, пока кого-то нет GlobalVariableSet(GV_Scr_Yes, 1); // Заявим о присутствии скрипта //----------------------------------------------------------------- Iter++; // Счётчик итераций if(Iter==1) // Первую итерацию пропускаем { Sleep(500); continue; } //----------------------------------------------------------------- if(Iter==2) // На второй итерации принимаем меры { Complect=0; // Раз кого-то нет, то некомплект for (i=0;i<=31;i++)ObjectDelete(Name_Graf_Text[i]); // Удаление всех строк // Сюда можно вставить функцию, обнуляющую очередь торговых операций. } //----------------------------------------------------------------- if(GlobalVariableGet(GV_Ind_Yes)==1 && GlobalVariableGet(GV_Exp_Yes)!=1) { // Если есть индикатор ,но нет эксперта Graf_Text = "Не установлен эксперт Expert."; // Текст сообщения Component_uni(); // Пропишем текст. сообщ. в окно инд. } //----------------------------------------------------------------- Sleep(300); } //----------------------------------------------------------------- if(Complect==0) // Это отрабатываем 1 раз при укомплект. { ObjectDelete("Necomplect_1"); // Удаление уже не нужных сообщений.. ObjectDelete("Necomplect_2"); // ..об отсутствии компонентов Mess_graf_scr(1); // Сообщим юзеру о комплектности if( IsExpertEnabled()) // Кнопка включена { Mess_graf_scr(3000); Knopka_Old = 1; } if(!IsExpertEnabled()) // Кнопка выключена { Mess_graf_scr(4000); Knopka_Old = 0; } Complect=1; // Достигнут миним.установочний копмлект Redraw = 1; // Для быстрого удаления } //================================================================= if(Fishka == 3 && GlobalVariableGet(GV_Ind_Yes)==1) // Находимся в deinit() { for(i=0;i<=31;i++)ObjectDelete(Name_Graf_Text[i]); // Удаление всех строк //----------------------------------------------------------------- if(GlobalVariableGet(GV_Exp_Yes)!=1) // Есть индикатор, но нет эксперта Graf_Text="Не установлены компоненты Expert и Script."; // Сообщение (выгружаемся же) if(GlobalVariableGet(GV_Exp_Yes)==1) // Есть индикатор и эксперт, то.. Graf_Text="Не установлен скрипт Script."; // Сообщение (выгружаемся же) Component_uni(); // Пропишем сообщ. в окно индик. //---------------------------------------------------------------- ObjectsRedraw(); // Для быстрого удаления } //================================================================= return; } //жжжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж Чтобы в скрипте не было принято ошибочное решение о том, что эксперт не загружен вовсе, в функции Component_scr() имеется небольшой блок, запрещающий принимать это решение на первой итерации: Iter++; // Счётчик итераций if(Iter==1) // Первую итерацию пропускаем { Sleep(500); continue; }
Complect = 0; // Раз кого-то нет, то некомплект
// Сюда можно вставить функцию, обнуляющую очередь торговых операций.Предполагается, что в функции Work_scr() в реально работающей программе, кроме тех функций, используемых в данном примере, будут и другие, отвечающие за некоторый порядок событий. Например, если ваша программа будет приспособлена для модификации нескольких ордеров, то наверняка в ней будет использован массив, в котором будет храниться очередь на исполнение торговых операций, если на текущем тике таковых возникло несколько. В случае если некомплект возник (например, по неаккуратности выгружен эксперт или индикатор) именно в тот момент, когда существует такая очередь, необходимо запретить любые торговые операции, а для этого - обнулить упомянутый массив очереди торговых операций и, возможно, некоторые другие переменные, соответствующие ситуации. В бесконечном цикле скрипта имеется также функция Work_scr(). Это - основная функция скрипта, в которой должен быть собран собственно весь его основной код. // Work_scr.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Work_scr() { Novator_scr(); //----------------------------------------------------------------- // Основной код всего приложения. //------------------------------------------------ Для примера ---- if(New_Tick==1) // На каждом новом тике { Alert ("Текущее значение ААА = ", AAA); } //----------------------------------------------------------------- if(Redraw==1) { ObjectsRedraw(); // Для моментального отображения Redraw=0; // Снимаем флажок перерисовки объектов } //----------------------------------------------------------------- Mess_graf_scr(0); Sleep(1); // На всякий случай от перегрузки return; } //жжжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// Novator_scr.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Novator_scr() { //================================================================= //---------------------------------------- Обновление настроек ---- if(GlobalVariableGet(GV_Extern)==1) // Произошло обновление в эксперте { Metsenat_scr(); // Обновление переменных скрипта. Mess_graf_scr(5000); // Сообщение о новой настройке. Redraw=1; // Вконце цикла перерисуемся. } //--------------------------------- Состояние кнопки советника ---- Knopka = 0; // Предустановка if( IsExpertEnabled()) Knopka = 1; // Выясним истинное состояние кнопки if(Knopka==1 && Knopka_Old==0) // Если состояние изменилось на ВКЛ { Knopka_Old = 1; // Старое теперь будет такое Mess_graf_scr(3); // Сообщим юзеру об изменениях } if(Knopka==0 && Knopka_Old==1) // Если состояние изменилось на ВЫКЛ { Knopka_Old = 0; // Старое теперь будет такое Mess_graf_scr(4); // Сообщим юзеру об изменениях } //-------------------------------------------------- Новый тик ---- New_Tick=0; // Для начала обнулимся if (RefreshRates()==true) New_Tick=1; // Поймать новый тик легко, если знать как //----------------------------------------------------------------- //================================================================= return; } //жжжжжжжжжжжжжжжжжжжжж; Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//---------------------------------------- Обновление настроек ---- if (GlobalVariableGet(GV_Extern)==1) // Произошло обновление в эксперте { Metsenat_scr(); // Обновление переменных скрипта. Mess_graf_scr(5000); // Сообщение о новой настройке. Redraw=1; // Вконце цикла перерисуемся. } Здесь анализируется значение упомянутой переменной, и, в случае если надо обновиться, вызывается функция Metsenat_scr(), которая и производит обновление (считывание новых значений глобальных переменных). // Metsenat_scr.mq4
Обратите внимание, немотря на то, что в связи с изменением настроек эксперт проходит все стадии выгрузки и загрузки, скрипт не прекращает работу ни в период, пока пользователь меняет настройки, ни после того. Таким образом, совместное использование скрипта и эксперта позволяет удовлетворить требование непрерывности работы всего приложения и оставляет пользователю возможность менять настройки, то есть управлять процессом. В последующих блоках функции Novator_scr() отслеживается состояние кнопки советника, разрешающей вести торговлю, и выявляется новый тик. Если ваша торговая система предполагает использовать эти и подобные им параметры, то функция Novator_scr() как раз и предназначена для подобных вычислений.Например, вы можете дополнить эту функцию блоками выявления факта появления нового бара, наступления времени критических событий, изменения условий торговли (наприммер, величины спреда, минимальной дистанции установки стоп-приказов и прочее), а также другими вычислениями, необходимыми перед началом работы основных аналитических функций. В составе функции Work_scr() не показаны функции, составляющие основное содержание программы. В статье Учёт ордеров в большой программе мы рассматривали функцию учёта ордеров Terminal(). Если в вашей торговой системе будет использован такой принцип учёта, то функцию Terminal() необходимо включить в состав функции Work_scr() непосредственно после функции Novator_scr(). В распоряжении скрипта имеется ещё одна вспомогательная функция - Mess_graf_scr(), назначением которой является отображение сообщений в окне индикатора. // Mess_graf_scr.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Mess_graf_scr(int Mess_Number) { //================================================================= if(Mess_Number== 0) // Это происходит в каждом цикле Work { if(Time_Mess>0 && GetTickCount()-Time_Mess>15000) // За последние 15 сек цветная печать { // ..устарела, покрасим строки серым ObjectSet(Name_Graf_Text[1],OBJPROP_COLOR,Gray); // Последние 2 строки ObjectSet(Name_Graf_Text[2],OBJPROP_COLOR,Gray); // Последние 2 строки Time_Mess=0; // Дополн.флажок, чтоб зря не красить Redraw=1; // Потом перерисуемся } return; // Это был такой маленький заход } //----------------------------------------------------------------- Time_Mess=GetTickCount(); // Запоминаем время публикации сообщения Por_Nom_Mess_Graf++; // Считаем строки. Это будет часть имени. Stroka_2=0; // Исходим из того, что сообщ в одну строку if(Mess_Number>1000) // Но если встретился огромный номер, то номер приводим в чувство, // понимаем, что предыдущая строка из этого же сообщения, т.е её не // красить серым { Mess_Number=Mess_Number/1000; Stroka_2=1; } //================================================================= switch(Mess_Number) { //----------------------------------------------------------------- case 1: Graf_Text = "Необходимые компоненты установлены."; Color_GT = LawnGreen; break; //----------------------------------------------------------------- case 2: Graf_Text = " "; break; //----------------------------------------------------------------- case 3: Graf_Text = "Кнопка советников включена."; Color_GT = LawnGreen; break; //----------------------------------------------------------------- case 4: Graf_Text = "Кнопка советников выключена."; Color_GT = Tomato; break; //----------------------------------------------------------------- case 5: Graf_Text = "Произошло обновление настроек эксперта."; Color_GT = White; break; //---------------------------------------------------- default ---- default: Graf_Text = "Строка default "+ DoubleToStr( Mess_Number, 0); Color_GT = Tomato; break; } //================================================================= ObjectDelete(Name_Graf_Text[30]); // 30й объект вытесняется, удаляем его int Kol_strok=Por_Nom_Mess_Graf; if(Kol_strok>30) Kol_strok=30; //----------------------------------------------------------------- for(int lok=Kol_strok;lok>=2;lok--) // Пройдёмся по именам граф текстов { Name_Graf_Text[lok]=Name_Graf_Text[lok-1]; // Переприсваиваем их (поднимаем) ObjectSet(Name_Graf_Text[lok],OBJPROP_YDISTANCE,2+14*(lok-1)); //Меняем коор Y(поднимаем) if(lok==3 || lok==4 || (lok==2 && Stroka_2==0)) ObjectSet(Name_Graf_Text[lok],OBJPROP_COLOR,Gray); //Старые строки красим в серое.. фэ } //------------------------------------------------------------------- Graf_Text_Number=DoubleToStr( Por_Nom_Mess_Graf, 0); //Уник. часть имени объ = номер сообщ. Name_Graf_Text[1] = MyGrafic + Mess_Graf + Graf_Text_Number; // Формируем имя сообщения. Win_ind= WindowFind("Indicator"); //Какой номер окна у нашего индикат.? ObjectCreate ( Name_Graf_Text[1],OBJ_LABEL, Win_ind,0,0); // Созд. объект в окне индикатора ObjectSet ( Name_Graf_Text[1],OBJPROP_CORNER, 3 ); // ..с коорд от прв. нижн. угла.. ObjectSet ( Name_Graf_Text[1],OBJPROP_XDISTANCE,450); // ..с координатами по Х.. ObjectSet ( Name_Graf_Text[1],OBJPROP_YDISTANCE, 2); // ..с координатами по Y.. ObjectSetText(Name_Graf_Text[1],Graf_Text,10,"Courier New", Color_GT); //текст, шрифт, цвет Redraw=1; // Потом перерисуемся //================================================================= return; } //жжжжжжжжжжжжжжжжжжжжжж Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж Рассматривать подробно эту функцию нет необходимости. Можно упомянуть лишь о некоторых её особенностях. 1. Все сообщения отображаются графическими средствами. Mess_graf_scr(0);
Для полноты изложения следует рассмотреть и индикатор, хотя его код довольно простой. // Indicator.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж; include жжжж #include <stdlib.mqh> #include <stderror.mqh> #include <WinUser32.mqh> //================================================================= #include <Peremen_ind.mq4> // Описание переменных индикатора. #include <Metsenat_ind.mq4> // Предопределение переменных индикатора. #include <Del_GV_ind.mq4> // Удаление всех GlobalVariable, созданных индикатором. #include <Component_ind.mq4> // Проверка наличия компонентов. #include <Component_uni.mq4> // Сообщение в индикаторе об отсутствии компонентов. //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж // // //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж #property indicator_separate_window //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж // // //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int init() { Metsenat_ind(); return; } //================================================================= int start() { if(Component_ind()==0) return; // Проверка наличия компонентов //... return; } //================================================================= int deinit() { Del_GV_ind(); // Удаление GlobalVariable индикатора. return; } //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
#property indicator_separate_window Содержание функций Metsenat_ind() и Del_GV_ind() аналогично содержанию рассмотренных ранее функций, используемых в эксперте и скрипте. Простое содержание и у функции Component_ind(): // Component_ind.mq4 //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж int Component_ind() { //================================================================ if(GlobalVariableGet(GV_Exp_Yes)==1 && GlobalVariableGet(GV_Scr_Yes)==1) //Если все на месте { // Заявляем о присутствии индикатора if(GlobalVariableGet(GV_Ind_Yes)!=1) GlobalVariableSet(GV_Ind_Yes,1); return(1); } //----------------------------------------------------------------- if(GlobalVariableGet(GV_Scr_Yes)!=1 && GlobalVariableGet(GV_Exp_Yes)!=1) { // Если нет ни скрипта ни эксперта Graf_Text = "Не установлены компоненты Expert и Script."; // Текст сообщения Component_uni(); // Пропишем текст. сообщ. в окно инд } //================================================================= return(0); } //жжжжжжжжжжжжжжжжжжжжж; Конец модуля жжжжжжжжжжжжжжжжжжжжжжжжжжжжж Как видно из кода, функция Component_ind() делает сообщение только в том случае, если не загружены оба других компонента - и скрипт, и эксперт. В случае отсутствия всего одной из программ никаких действий не производится. Этим полагается, что в случае присутствия в окне финансового инструмента эти программы сами будут отслеживать состав программного комплекса и сами сообщат об этом пользователю. При необходимости можно также использовать и основное свойство индикатора - рисование. С точки зрения построения программного комплекса в этом свойстве нет необходимости, однако в реально используемой программе оно может применяться, например, для разделения подокна на зоны. 4. Практическое использованиеПорядок прикрепления компонентов приложения в окно финансового инструмента значения не имеет. Вместе с тем, есть основание первым прикрепить индикатор, так как он с момента своего появления предоставляет нам возможность считывать комментарии. Итак, для демонстрации работы приложения необходимо проделать следующее. 1. Закрепить на окне финансового инструмента индикатор. Это явление сразу отзовётся сообщением в окне индикатора:
2. Закрепить на окне финансового инструмента эксперт. В результате срабатывания функции Component_exp() эксперта в окне индикатора появится сообщение:
3. Закрепить на окно финансового инструмента скрипт. Это событие будет обработано в функции Component_scr() скрипта и отражено в окне индикатора:
Если же при этом кнопка советников была в режиме запрета торговли, то сообщение будет таким:
4. Вы можете несколько раз нажать на кнопку советников и убедиться, что эта последовательность событий будет моментально обработана приложением и отражена в строках сообщений:
Обратите внимание, что, благодаря использованию в программном комплексе скрипта с зацикленным основным кодом, реакция программы на управляющие воздействия пользователя осуществляется не кратно тикам, а именно сразу после такого воздействия. В качестве примера в функцию Work_scr() вставлено потиковое отображение с помощью функции Alert() некоторой переменной из состава настроек эксперта. Обратим внимание на эту особенность. Функция Work_scr() является составной частью скрипта. В период между тиками основной цикл скрипта успевает обернуться сотни раз, в то время как сообщение с помощью функции Alert() выдаётся кратно тикам. 5. Откройте панель настроек эксперта и измените значение ААА на 3. Скрипт отследит это событие и выдаст в окно индикатора сообщение:
А в окне функции Alert() потиково будет отображаться новое значение переменной ААА: 6. Теперь вы можете в произвольной последовательности выгрузить или загрузить тот или иной компонент, поиграть кнопкой советников, поменять значение настраиваемой переменной и составить собственное представление о качестве работы описанного программного комплекса. ЗаключениеГлавное, чего нам удалось достичь в результате применения предлагаемой технологии, заключается в том. что скрипт ни на миг не прерывает свою работу независимо от наличия или отсутствия событий в его окружении. Разумеется, скрипт прекратит работу в том случае, если отследит неукомплектованность приложения, то есть отсутствие индикатора или эксперта. Рассмотренный принцип построения программного комплекса в несколько ином программном исполнении применён в реально работающем приложении AutoGraf, описание которого вы можете найти в статье Графический эксперт AutoGraf . SK. Днепропетровск. 2006. Предупреждение:
все права на данные материалы
принадлежат MetaQuotes Software Corp. Полная или частичная перепечатка запрещена.
|