Як швидко додати панель управління до індикатора та радника - Статті по MQL5

Навіщо потрібна графічна панель

Ваша MQL4/MQL5-програма – індикатор чи радник – може бути однією з найкращих і повністю виконувати покладені на неї завдання. Але ви завжди можете трохи покращити її. Як правило, у 99% випадків для будь-якої зміни вхідних параметрів програми користувачеві потрібно заходити до її налаштувань. Бажаєте обійтися без цього?

Зробити це можна, створивши власну панель управління з урахуванням класів Стандартної бібліотеки. Це дозволить змінювати налаштування без перезапуску програми. До того ж такий підхід пожвавлює програму і вигідно виділяє її серед інших. Подивитися приклади графічних панелей ви можете у Маркеті.

1. З'єднуємо індикатор та панель

Індикатор "NewBar.mq5" виконує одну дію: при появі нового бару друкує повідомлення до журналу експертів терміналу. Код індикатора наведено нижче:

Розповім трохи докладніше про те, як працює індикатор "NewBar.mq5".

У функції OnCalculate() оголошується статична змінна "prev_time" - у цій змінній зберігається час відкриття "time[0]". У наступному заході порівнюється час відкриття "time[0]" із змінною "prev_time" - тобто відбувається порівняння часу відкриття "time[0]" на поточному тиці та час відкриття "time[0]" на попередньому тику. У разі виконання умови

вважаємо, що виявлено новий бар.

На наступному прикладі детально розберемо, як індикатор "NewBar.mq5" виявляє новий бар:

управління

Мал. 1. Процес виявлення нового бару в індикаторі

Розглянемо 10 тиків на дуже спокійному ринку.

Тики з 1 по 3 включно: час відкриття бару з індексом "0" (time[0])дорівнює часу, яке збережено в статичній зміннійprev_time, а отже, нового бару немає.

Тік №4: цей тик прийшов на новому барі. При вході в функцію OnCalculate() уtime[0]буде час відкриття бару (2015.12.01 00:02:00), а зміннаprev_timeще зберігає час із попереднього тику (2015.12.01 00:01:00). Тому під час перевірки умовиtime[0]>prev_timeми виявимо новий бар. Перед виходом з OnCalculate() у зміннійprev_timeбуде записано час ізtime[0](2015.12.01 00:02:00).

Тики з 5 по 8 включно: час відкриття бару з індексом "0" (time[0]) дорівнює часу, який збережено в статичній зміннійprev_time, отже, нового бару немає.

Тік №9: цей тик прийшов на новому барі. При вході в функцію OnCalculate() уtime[0]буде час відкриття бару (2015.12.01 00:03:00), а зміннаprev_timeще зберігає час з попереднього тику (2015.12.01 00:02:00). Тому під час перевірки умовиtime[0]>prev_timeми виявимо новий бар. Перед виходом з OnCalculate() у зміннійprev_timeбуде записано час ізtime[0](2015.12.01 00:03:00).

Тик 10: час відкриття бару з індексом "0" (time[0]) дорівнює часу, який збережено в статичній зміннійprev_time, Отже, нового бару немає.

Всі параметри побудови панелі: кількість, розміри та координати елементів керування зосереджені в одному файлі "PanelDialog.mqh". Файл "PanelDialog.mqh" - це клас реалізації панелі.

Панель має такий вигляд:

Код файлу "PanelDialog.mqh" представлений нижче:

Як бачите, у класі нашої панелі немає методів встановлення та читання властивостей стану перемикачів із незалежною фіксацією.

Наше завдання: зробити індикатор "NewBar.mq5" основним файлом і додати вхідні параметри - наприклад, за допомогою яких методів ("Mail", "Push" або "Alert") повідомляти користувачеві про те, що знайдено новий бар. Крім того, ми повинні додати у файл "PanelDialog.mqh" методи установки і читання властивостей стану перемикачів з незалежною фіксацією "Mail", "Push" і "Alert".

1.3. Змінюємо індикатор

Примітка: всі зміни, що вносяться, відзначатимуться кольором .

Спочатку потрібно підключити файл "PanelDialog.mqh":

Потім додамо вхідні параметри:

Скомпілюємо індикатор (F7 в MetaEditor) і перевіримо відображення вхідних параметрів у терміналі:

панель

Мал. 3. Вхідні параметри індикатора

1.4. Змінюємо панель

У панель потрібно додати методи встановлення та читання властивостей стану перемикачів з незалежною фіксацією "Mail", "Push" та "Alert".

Додамо до класу панелі нові методи:

Реалізація цих методів:

1.5. Заключний етап з'єднання індикатора та панелі

і додамо в кінець індикатора функцію OnChartEvent():

У функції OnInit() індикатора "NewBar.mq5", створимо панель і програмно натиснемо чекбокси відповідно до вхідних параметрів:

На цьому з'єднання індикатора та панелі закінчено. У класі панелі нами реалізовано метод встановлення стану чекбоксу натиснутий/віджатий (SetCheck) та метод отримання стану чекбоксу (GetCheck).

2. З'єднуємо радник та панель

За основу взято радникаіз стандартної поставки. \MQL5\Experts\Examples\MACD\MACD Sample.mq5.

Вигляд панелі "PanelDialog2.mqh" після внесення остаточних змін:

швидко

Мал. 4. Панель номер два

Що ми отримаємо після об'єднання радника "MACD Sample.mq5" та панелі "PanelDialog2.mqh"? На поточному таймфреймі, на якому працюватиме радник, можна буде оперативно змінювати параметри радника ("Lots", "Trailing Stop Level (in pips)" та інші), а також параметри оповіщення про торгові події радника ("Mail", "Push", "Alert").

Змінені параметри радника ("Lots", "Trailing Stop Level (in pips)" та інші) застосовуються після клацання на кнопці "Застосувати зміни". Зміна параметрів оповіщення про торгові події радника ("Mail", "Push", "Alert") застосовуються автоматично - клацнути на кнопці "Застосувати зміни" не потрібно.

2.3. Раднику та панелі потрібно спілкуватися

індикатора

Мал. 5. Спілкування радника та панелі

При запуску радник повинен передавати параметри в панель. Панель, після натискання кнопки "Застосувати зміни" і якщо дані були змінені, теж повинна повертати змінені параметри до радника для його ініціалізації з новими параметрами.

2.4. Крок перший. Внесення змін до радника

План дій: візьміть радник зі стандартного постачання. \MQL5\Experts\Examples\MACD\MACD Sample.mq5і скопіюйте його в свою папку. Наприклад, можна створити папку "Notification" і в неї скопіювати радник:

швидко

Мал. 6. Створення нової папки

У сфері глобальних змінних радника (не плутайте їх із глобальними змінними терміналу) оголосимо нові змінні, які будутьвідповідати за спосіб відправлення повідомлення про торгові дії радника. Зверніть увагу, що ці змінні, як і інші зовнішні змінні, мають приставку "Inp":

Трохи нижче додамо дублікати всіх зовнішніх змінних радників. Дублікати матимуть приставку "Ext":

На даному етапі у функціях радникаCSampleExpert::InitIndicators,CSampleExpert::InitCheckParametersтаCSampleExpert::Initвикористовуються зовнішні змінні радника з приставкою "Inp". Нам потрібно в цих функціях замінити зовнішні змінні на їх дублікати (дублікати у нас із приставкою "Ext"). Я пропоную зробити це досить оригінальним методом:

Після заміни потрібно обов'язково перевірити правильність дій - компіляцію файлу. Помилок не повинно бути.

2.5. Крок другий. Внесення змін до панелі

Панель, зображена на рис. 4, - це заготівля. У ній ще немає ні функцій для "спілкування" з радником, ні функцій обробки даних, що вводяться. Файл заготівлі панелі "PanelDialog2Original.mqh" також скопіюйте в папку "Notification".

Додамо до класу панелі внутрішні змінні, в яких потім зберігатимемо стан всіх введених даних. Зверніть увагу на змінну "mModification" - про неї буде сказано у пункті 2.7.

Відразу за цим у конструкторі класу панелі ініціалізуємо внутрішні змінні:

У функцію CControlsDialog::Create додамо встановлення групи елементів перемикачів відповідно до внутрішніх змінних:

2.6.Крок третій.Внесення змін дорадник

Досі радник та панель були двома окремими, незалежними один від одного файлами. Зв'яжемо їх і оголосимо змінну класу нашої панелі "ExtDialog":

Щобпанель запрацювала і стала видна, її потрібно створити та запустити на виконання. Також необхідно додати функцію OnChartEvent(), яка є обробником події ChartEvent, та функцію OnDeinit(). OnInit() у раднику набуде такого вигляду:

В OnDeinit() знищуємо нашу панель, а саму функцію OnDeinit() пропишемо відразу після OnInit():

Функцію OnChartEvent() додамо до кінця радника (після функції OnTick):

Тепер радник можна компілювати і перевірити на графіку. Радник запускатиметься разом із панеллю:

панель

Мал. 7. Радник разом із панеллю

2.7.Крок четвертий.Внесення змін до панелі. Велика інтеграція

Спочатку запускається радник, потім користувач встановлює вхідні параметри, і тільки після цього запускається панель. Саме з цієї причини в панелі потрібно передбачити функції обміну даними між нею та радником.

Додамо методInitialization()— цей метод приймає параметри та ініціалізує цими параметрами внутрішні змінні панелі. Оголошення:

Саме тіло методу (вставимо його перед CControlsDialog::GetCheck):

Оскільки внутрішні змінні панелі проініціалізовані даними, тепер потрібно правильно заповнити елементи управління панелі — поля вводу. Оскільки полів уведення у нас шість, то я наведу приклад на базіm_edit1. Рядок, в якому присвоювався текст, був такий:

Таким чином, кожному полю введення відповідає своя внутрішня змінна.

Наступний метод- GetValues ​​()- відповідає за повернення значень внутрішніх змінних:

Його тіло вставимо після CControlsDialog::Initialization()):

Так як саме панель відповідає за відправлення повідомлень у відповідь на будь-які торгові дії радника,отже, у ній потрібний спеціальний метод, який відповідає за це. Оголосимо його:

Його тіло вставимо після CControlsDialog::GetValues()):

Щоб запам'ятати, чи змінювалися параметри в панелі, введено внутрішню змінну — прапор "mModification" (про неї згадувалося раніше, у пункті 2.5.).

Контроль за змінами будемо проводити в "CControlsDialog::OnClickButtonOK" - обробнику натискання на кнопку "Застосувати зміни":

Також панель перевіряє введені дані в обробниках:

Їхній опис я пропущу.

2.8.Крок п'ятий.Внесення змін до радника. Останнє редагування

На даний момент панель не працює в тестері стратегій, тому потрібно захиститись - ввести внутрішню змінну, а саме - прапор "bool_tester".

Вносимо зміни до OnInit() — захищаємось від запуску в тестері стратегій, а також перед візуалізацією панелі ініціалізуємо її параметри:

В OnChartEvent() перевіряємо, чи змінили параметри в панелі. Якщо вони змінені, то необхідно запустити ініціалізацію радника з новими параметрами:

Висновок

З'єднати панель та індикатор виявилося нескладно. Для цього потрібно в класі панелі реалізувати весь функціонал (розміри та розміщення елементів керування, реакцію на події), а в індикаторі оголосити змінну класу нашої панелі та додати функцію OnChartEvent().

Поєднати радник з більш складною панеллю виявилося серйознішим завданням, головним чином через необхідність "спілкування" радника та панелі. Трудомісткість завдання великою мірою залежить від того, наскільки сама панель готова до з'єднання. Іншими словами, чим більше в панелі спочатку реалізовано функцій та можливостей щодо інтеграції з іншими програмами, тим легше буде з'єднати її зіншою програмою (індикатором чи радником).

До статті додані файли:

  • NewBarOriginal.mq5 - початковий файл індикатора.
  • PanelDialogOriginal.mqh - початковий файл панелі.
  • NewBar.mq5 — змінений файл індикатора.
  • PanelDialog.mqh — змінений файл панелі.
  • PanelDialog2Original.mqh — початковий файл другої панелі.
  • PanelDialog2.mqh — змінений файл другої панелі.
  • MACD Sample.mq5 — змінений файл радника.