- зміст Вступ
- Елементи графічного інтерфейсу
- Збірка графічного інтерфейсу
- Форма для елементів управління
- статусна рядок
- Група вкладок
- Полі введення
- кнопка
- Комбо-бокс з списком, що випадає
- Чек-бокс
- Таблиця
- Стандартний графік
- індикатор виконання
- Оновлення бібліотеки EasyAndFast
- Висновок
зміст Вступ
Незважаючи на активний розвиток алготрейдінга, багато трейдерів до сих пір вважають за краще ручну торгівлю. Але і тут обійтися абсолютно без автоматизації рутинних операцій навряд чи вийде.
У цій статті продемонстровано створення мультісімвольного сигнального експерта для ручної торгівлі. Як приклад розглянемо сигнали індикатора Stochastic зі стандартної поставки терміналу. Цей код можна використовувати для створення власних експертів з графічним інтерфейсом: в нього можна підключити будь-який інший індикатор або використовувати результати певних обчислень для прийняття рішень.
Для тих, хто виконує роботи на замовлення, ця стаття може бути корисна як приклад технічного завдання для демонстрації замовникам. Можливо, що цей приклад допоможе скоротити час по складанню зрозумілого для програміста технічного завдання на програму з графічним інтерфейсом.
Перерахуємо питання, які детально будуть розглянуті в цій роботі.
- Створення графічного інтерфейсу.
- Отримання списку символів з заданими властивостями.
- Елементи управління торговими операціями.
- Швидке перемикання символів і таймфреймів на графіках без переініціалізація експерта.
- Управління властивостями графіків через призначений для користувача інтерфейс.
- Отримання сигналів індикатора від безлічі символів з колірною індикацією.
- Робота з відкритими позиціями.
- оновлення бібліотеки EasyAndFast .
Стаття буде опублікована в двох частинах. У цій статті розглянуто створення панелі, в наступній частині буде описано її наповнення функціоналом.
Елементи графічного інтерфейсу
Розробку експерта почнемо з побудови графічного інтерфейсу, через який буде реалізовано взаємодію з користувачем і візуалізація даних. Можна створити графічний інтерфейс, скориставшись можливостями стандартної бібліотеки, але в моєму прикладі він буде реалізований на основі бібліотеки EasyAndFast . Її багаті можливості дозволяють зосередитися на функціоналі самої програми, не відволікаючись на доопрацювання її графічної частини.
Спочатку обрисуємо загальну схему графічного інтерфейсу. На схемі нижче показано, що у вікні графічного інтерфейсу є група з двох вкладок. У списках відображаються функції, які на них потрібно розмістити. Це спрощений приклад, і замовник з виконавцем можуть пропрацювати його більш детально в процесі обговорення.
Мал. 1. Загальна схема графічного інтерфейсу з поясненнями.
Елементів управління графічним інтерфейсом може бути дуже багато. Тому спочатку просто перерахуємо їх в ієрархічному вигляді:
- Форма для елементів управління
- Рядок стану для показу додаткової підсумкової інформації
- Група вкладок:
- Trade:
- Поле введення з чек-боксом для фільтрації списку символів
- Кнопка запиту для початку збору списку символів
- Кнопка для торгової операції SELL
- Кнопка для торгової операції BUY
- Поле введення для установки обсягу угоди
- Кнопка для закриття всіх відкритих позицій
- Поле введення установки рівня для сигналу на продаж
- Поле введення установки рівня для сигналу на покупку
- Таблиця символів для торгівлі
- Графік для візуалізації даних символів. Для зручності зробимо так, щоб деякі властивості графіка можна було керувати за допомогою наступної групи елементів:
- Комбо-бокс з списком, що випадає для вибору перемикання таймфрейма
- Чек-бокс для включення / вимикання на шкалі часу
- Чек-бокс для включення / вимикання цінової шкали
- Поле введення для управління масштабом
- Кнопка для включення відступу
- Чек-бокс для показу індикатора
- Positions:
- Таблиця позицій
- Індикатор виконання процесу повторного програвання фреймів
У головному класі програми (CProgram) оголошуємо методи і екземпляри класів перерахованих вище елементів. Код методів для створення елементів винесено в окремий файл і підключається до файлу з класом MQL-програми:
class CProgram: public CWndEvents {private: CWindow m_window1; CStatusBar m_status_bar; CTabs m_tabs1; CTextEdit m_symb_filter; CTextEdit m_lot; CTextEdit m_up_level; CTextEdit m_down_level; CTextEdit m_chart_scale; CButton m_request; CButton m_chart_shift; CButton m_buy; CButton m_sell; CButton m_close_all; CComboBox m_timeframes; CCheckBox m_date_scale; CCheckBox m_price_scale; CCheckBox m_show_indicator; CTable m_table_positions; CTable m_table_symb; CStandardChart m_sub_chart1; CProgressBar m_progress_bar; public: bool CreateGUI (void); private: bool CreateWindow (const string text); bool CreateStatusBar (const int x_gap, const int y_gap); bool CreateTabs1 (const int x_gap, const int y_gap); bool CreateSymbFilter (const int x_gap, const int y_gap, const string text); bool CreateLot (const int x_gap, const int y_gap, const string text); bool CreateUpLevel (const int x_gap, const int y_gap, const string text); bool CreateDownLevel (const int x_gap, const int y_gap, const string text); bool CreateChartScale (const int x_gap, const int y_gap, const string text); bool CreateRequest (const int x_gap, const int y_gap, const string text); bool CreateChartShift (const int x_gap, const int y_gap, const string text); bool CreateBuy (const int x_gap, const int y_gap, const string text); bool CreateSell (const int x_gap, const int y_gap, const string text); bool CreateCloseAll (const int x_gap, const int y_gap, const string text); bool CreateComboBoxTF (const int x_gap, const int y_gap, const string text); bool CreateDateScale (const int x_gap, const int y_gap, const string text); bool CreatePriceScale (const int x_gap, const int y_gap, const string text); bool CreateShowIndicator (const int x_gap, const int y_gap, const string text); bool CreatePositionsTable (const int x_gap, const int y_gap); bool CreateSymbolsTable (const int x_gap, const int y_gap); bool CreateSubChart1 (const int x_gap, const int y_gap); bool CreateProgressBar (const int x_gap, const int y_gap, const string text); }; #include "CreateGUI.mqh"
Далі докладніше розглянемо складання графічного інтерфейсу, методи для створення його елементів і їх властивості.
Збірка графічного інтерфейсу
Отже, в графічному інтерфейсі розробляється будуть використовуватися елементи десяти різних типів.
- Форма для елементів управління (CWindow)
- Статусна рядок (CStatusBar)
- Група вкладок (CTabs)
- Поле введення (CTextEdit)
- Кнопка (CButton)
- Комбо-бокс з списком, що випадає (CComboBox)
- Чек-бокс (CCheckBox)
- Таблиця (CTable)
- Стандартний графік (CStandardChart)
- Індикатор виконання (CProgressBar)
Деяких елементів з цього списку буде кілька, тому розглянемо тільки по одному з кожної групи. У тій же послідовності розглянемо методи для їх створення.
Форма для елементів управління
Нижче представлений код методу для створення форми, на якій будуть розташовуватися всі інші елементи. На початку потрібно додати форму в список елементів графічного інтерфейсу програми. Для цього потрібно викликати метод CWndContainer :: AddWindow (), передавши в нього об'єкт елемента типу CWindow. Потім, перед створенням форми, встановлюємо її властивості. Ми встановлюємо такі властивості (в тій же послідовності, що і в лістингу нижче):
- Розміри форми (ширина і висота)
- Розмір шрифту в заголовку
- Режим переміщення форми (в межах графіка)
- Режим зміни розмірів форми вручну (перетягуванням кордонів)
- Кнопки форми. Видимість кожної кнопки включається окремо. В даному випадку задіяні такі з них:
- Закриття форми. У головній формі програми при натисканні на цю кнопку, вийде діалогове вікно з питанням про закриття програми.
- Згортання і розгортання форми.
- Підказки елементів. Ця кнопка теж має два стани. Якщо вона натиснута, то в елементах управління будуть показуватися спливаючі підказки (за умови, що вони були задані).
- Розгортання форми на всю область графіка терміналу. Розгорнувши форму, її потім можна повернути в попередні розміри, натиснувши цю кнопку повторно.
- Для кожної кнопки форми можна встановити підказку.
Після того, як властивості задані, потрібно викликати метод створення форми - CWindow :: CreateWindow () і передати в нього:
- ідентифікатор графіка,
- номер подокна графіка,
- текст заголовка,
- початкові координати розташування для форми.
bool CProgram :: CreateWindow (const string caption_text) {CWndContainer :: AddWindow (m_window1); m_window1.XSize (750); m_window1.YSize (450); m_window1.FontSize (9); m_window1.IsMovable (true); m_window1.ResizeMode (true); m_window1.CloseButtonIsUsed (true); m_window1.CollapseButtonIsUsed (true); m_window1.TooltipsButtonIsUsed (true); m_window1.FullscreenButtonIsUsed (true); m_window1.GetCloseButtonPointer (). Tooltip ( "Close"); m_window1.GetTooltipButtonPointer (). Tooltip ( "Tooltips"); m_window1.GetFullscreenButtonPointer (). Tooltip ( "Fullscreen"); m_window1.GetCollapseButtonPointer (). Tooltip ( "Collapse / Expand"); if (! m_window1.CreateWindow (m_chart_id, m_subwin, caption_text, 1, 1)) return (false); return (true); }
Кожен раз, додаючи в код новий елемент графічного інтерфейсу, бажано скомпілювати програму і подивитися, який виходить результат:
Мал. 2. Форма для елементів управління.
Нижче будуть показані скріншоти всіх проміжних результатів.
статусна рядок
Код методу для створення статусного рядка починається з вказівки головного елемента. Від нього буде розраховуватися позиціонування і вирівнювання за розміром прив'язаних до нього елементів. Це економить час при розробці програми: цілу групу пов'язаних елементів можна буде перемістити, змінивши координати тільки у головного з них. Для прив'язки елемента його покажчик передається в метод CElement :: MainPointer (). В даному прикладі ми прив'язуємо статусну рядок до форми, тому в метод передаємо об'єкт форми.
Потім встановимо властивості статусного рядка. У ній зробимо три пункти, в яких буде показуватися інформація для користувача.
- Щоб не вказувати розміри щодо форми, вкажемо, що ширина повинна змінюватися автоматично при зміні ширини форми.
- Відступ правого краю елемента від правого краю форми буде 1 піксель.
- Прив'яжемо статусну рядок до нижньої частини форми, щоб при зміні висоти форми вона автоматично коректувалася по ніжему краю.
- Далі, при додаванні пунктів, вказуємо для кожного ширину.
Після того, як властивості задані, створюємо елемент. Тепер він готовий для роботи, і ми можемо змінювати текст в його пунктах під час виконання програми. У нашому прикладі встановимо в першому пункті текст «For Help, press F1».
В кінці методу потрібно обов'язково зберегти покажчик створеного елемента в загальному списку елементів графічного інтерфейсу. Для цього викличемо метод CWndContainer :: AddToElementsArray (), передамо в нього індекс форми і об'єкт елемента. Оскільки форма у нас тільки одна, то її індекс буде 0.
bool CProgram :: CreateStatusBar (const int x_gap, const int y_gap) {#define STATUS_LABELS_TOTAL 3 m_status_bar.MainPointer (m_window1); m_status_bar.AutoXResizeMode (true); m_status_bar.AutoXResizeRightOffset (1); m_status_bar.AnchorBottomWindowSide (true); int width [STATUS_LABELS_TOTAL] = {0, 200, 110}; for (int i = 0; i <STATUS_LABELS_TOTAL; i ++) m_status_bar.AddItem (width [i]); if (! m_status_bar.CreateStatusBar (x_gap, y_gap)) return (false); m_status_bar.SetValue (0, "For Help, press F1"); CWndContainer :: AddToElementsArray (0, m_status_bar); return (true); }
Інші елементи бібліотеки EasyAndFast створюються за тим же принципом. Тому далі будемо розглядати тільки задаються властивості, які будуть використовуватися в нашому експерта.
Мал. 3. Додавання статусного рядка.
Група вкладок
У методі для створення групи вкладок задамо наступні властивості елементу:
- Текст у вкладках зробимо по центру.
- Виберіть розташуємо в верхній частині робочої області.
- Розміри будуть автоматично підлаштовуватися під область головного елемента (форма). В такому випадку необов'язково вказувати розміри області групи вкладок.
- Зазначимо відступи від правого і нижнього краю головного елемента. При зміні розмірів форми ці відступи будуть зберігатися.
- При додаванні наступних вкладок в метод передаються також назву вкладки і її ширина.
Ось код методу:
bool CProgram :: CreateTabs1 (const int x_gap, const int y_gap) {#define TABS1_TOTAL 2 m_tabs1.MainPointer (m_window1); m_tabs1.IsCenterText (true); m_tabs1.PositionMode (TABS_TOP); m_tabs1.AutoXResizeMode (true); m_tabs1.AutoYResizeMode (true); m_tabs1.AutoXResizeRightOffset (3); m_tabs1.AutoYResizeBottomOffset (25); string tabs_names [TABS1_TOTAL] = { "Trade", "Positions"}; for (int i = 0; i <TABS1_TOTAL; i ++) m_tabs1.AddTab (tabs_names [i], 100); if (! m_tabs1.CreateTabs (x_gap, y_gap)) return (false); CWndContainer :: AddToElementsArray (0, m_tabs1); return (true); }
Мал. 4. Додавання групи вкладок.
Полі введення
Для прикладу розглянемо поле введення, в якому користувач може вказати валюти і / або валютні пари для формування списку символів в таблиці. Головним елементом для нього буде група вкладок. Тут же потрібно вказати, на який вкладці потрібно відображати це поле введення. Для цього викличемо метод CTabs :: AddToElementsArray (), передамо в нього індекс вкладки і об'єкт приєднується елемента.
Далі розглянемо властивості, що встановлюються для цього поля введення.
- За замовчуванням в полі введення буде введений текст «USD»: програма буде збирати в таблицю символи, в яких є USD. Вказувати валюти і / або символи в цьому полі введення потрібно через кому. Нижче я покажу метод, за допомогою якого формується список символів по перерахованим через кому рядках в цьому полі введення.
- Поле введення буде з чек-боксом. При відключенні чек-боксу текст в поле введення ігнорується, і в список символів потраплять всі знайдені валютні пари.
- Ширина поля введення буде на всю ширину головного елемента, та при зміні ширини області вкладок буде теж коригуватися.
- Праворуч від поля введення буде кнопка Request. Під час роботи програми в поле введення можна вказати інші валюти і / або символи, а для того, щоб список сформувався, потрібно буде натиснути на цю кнопку. Так як мається на увазі автоматичну зміну ширини поля введення, а кнопка Request повинна бути завжди праворуч від нього, то потрібно, щоб у правого боку поля введення завжди був відступ від правого краю головного елемента.
Елемент типу CTextEdit складається з декількох інших елементів. Тому, якщо знадобиться змінити їх властивості, є можливість отримувати покажчики на них. Нам треба було змінити деякі властивості текстового поля введення (CTextBox). Розглянемо їх у тій же послідовності, як це реалізовано в лістингу коду нижче.
- Відступ поля введення від лівого краю головного елемента (CTextEdit).
- Автоматична зміна ширини щодо головного елементу.
- При активації поля введення (клік лівої кнопки миші на полі введення) текст буде виділятися повністю автоматично для можливості швидкої заміни.
- Якщо в поле введення взагалі не буде тексту, то буде показуватися така підказка: «Example: EURUSD, GBP, NOK».
За замовчуванням чек-бокс поля введення включений. Для цього потрібно його активувати відразу після створення елемента.
bool CProgram :: CreateSymbolsFilter (const int x_gap, const int y_gap, const string text) {m_symb_filter.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_symb_filter); m_symb_filter.SetValue ( "USD"); m_symb_filter.CheckBoxMode (true); m_symb_filter.AutoXResizeMode (true); m_symb_filter.AutoXResizeRightOffset (90); m_symb_filter.GetTextBoxPointer (). XGap (100); m_symb_filter.GetTextBoxPointer (). AutoXResizeMode (true); m_symb_filter.GetTextBoxPointer (). AutoSelectionMode (true); m_symb_filter.GetTextBoxPointer (). DefaultText ( "Example: EURUSD, GBP, NOK"); if (! m_symb_filter.CreateTextEdit (text, x_gap, y_gap)) return (false); m_symb_filter.IsPressed (true); CWndContainer :: AddToElementsArray (0, m_symb_filter); return (true); }
Крім текстового поля введення, в графічному інтерфейсі будуть і числові. Наприклад, поле введення Lot (обсяг для відкриття позицій). Для полів введення такого типу потрібно вказувати інші властивості.
- Загальна ширина елемента.
- Максимальне значення для введення.
- Мінімальне значення для введення.
- Крок при перемиканні кнопками інкремента і декремента.
- Кількість знаків після коми.
- Для того, щоб поле введення стало числовим, потрібно це вказати за допомогою методу CTextEdit :: SpinEditMode ().
- Значення за замовчуванням після завантаження програми на графік в терміналі.
- Ширина поля введення.
- Автоматичне виділення тексту в поле введення при кліці на ньому.
- Прімагнічіваніе поля введення до правого краю елемента.
Ось код цього методу:
bool CProgram :: CreateLot (const int x_gap, const int y_gap, const string text) {m_lot.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_lot); m_lot.XSize (80); m_lot.MaxValue (1000); m_lot.MinValue (0.01); m_lot.StepValue (0.01); m_lot.SetDigits (2); m_lot.SpinEditMode (true); m_lot.SetValue ((string) 0.1); m_lot.GetTextBoxPointer (). XSize (50); m_lot.GetTextBoxPointer (). AutoSelectionMode (true); m_lot.GetTextBoxPointer (). AnchorRightWindowSide (true); if (! m_lot.CreateTextEdit (text, x_gap, y_gap)) return (false); CWndContainer :: AddToElementsArray (0, m_lot); return (true); }
Мал. 5. Додавання полів введення.
Картинка виглядає не дуже логічною, але при додаванні інших елементів все виявиться на своїх місцях.
кнопка
Додамо в графічний інтерфейс нашого експерта кілька кнопок. Розглянемо ту з них, в якій задіяно найбільше властивостей: кнопку для відкриття позицій SELL.
- Ширина кнопки.
- Текст кнопки буде точно по центру, як по вертикалі, так і по горизонталі.
- Колір фону кнопки.
- Колір фону при наведенні курсору.
- Колір фону при кліці лівою кнопкою.
- Колір тексту кнопки.
- Колір тексту при наведенні курсору.
- Колір тексту при кліці лівою кнопкою.
- Колір рамки кнопки.
- Колір рамки при наведенні курсору.
- Колір рамки при кліці лівою кнопкою.
Такі ж властивості змінюються і в кнопці BUY, з різницею лише в задаються відтінках фону.
bool CProgram :: CreateSell (const int x_gap, const int y_gap, const string text) {m_sell.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_sell); m_sell.XSize (80); m_sell.IsCenterText (true); m_sell.BackColor (C'255,51,51 '); m_sell.BackColorHover (C'255,100,100 '); m_sell.BackColorPressed (C'195,0,0 '); m_sell.LabelColor (clrWhite); m_sell.LabelColorHover (clrWhite); m_sell.LabelColorPressed (clrWhite); m_sell.BorderColor (clrBlack); m_sell.BorderColorHover (clrBlack); m_sell.BorderColorPressed (clrBlack); if (! m_sell.CreateButton (text, x_gap, y_gap)) return (false); CWndContainer :: AddToElementsArray (0, m_sell); return (true); }
Мал. 6. Додавання кнопок.
Комбо-бокс з списком, що випадає
Для зміни таймфрейма зробимо комбо-бокс з списком, що випадає. Перерахуємо властивості для його настройки.
- Загальна ширина елемента.
- Кількість пунктів у списку (в нашому випадку 21, за кількістю таймфреймів в терміналі).
- Елемент буде прив'язаний до правої частини області вкладок.
- Ширина кнопки комбо-боксу.
- Кнопка прив'язана до правої частини елемента.
Далі кожному пункту в списку присвоюються значення, а після цього через покажчик встановлюються деякі властивості списку.
- Підсвічування пунктів по наведенню курсора миші.
- Виділений пункт. В даному випадку це буде пункт за індексом 18 (таймфрейм D1).
Ось код методу для створення цього комбо-боксу:
bool CProgram :: CreateComboBoxTF (const int x_gap, const int y_gap, const string text) {#define ITEMS_TOTAL2 21 m_timeframes.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_timeframes); m_timeframes.XSize (115); m_timeframes.ItemsTotal (ITEMS_TOTAL2); m_timeframes.AnchorRightWindowSide (true); m_timeframes.GetButtonPointer (). XSize (50); m_timeframes.GetButtonPointer (). AnchorRightWindowSide (true); string items_text [ITEMS_TOTAL2] = { "M1", "M2", "M3", "M4", "M5", "M6", "M10", "M12", "M15", "M20", "M30" , "H1", "H2", "H3", "H4", "H6", "H8", "H12", "D1", "W1", "MN"}; for (int i = 0; i <ITEMS_TOTAL2; i ++) m_timeframes.SetValue (i, items_text [i]); CListView * lv = m_timeframes.GetListViewPointer (); lv.LightsHover (true); lv.SelectItem (18); if (! m_timeframes.CreateComboBox (text, x_gap, y_gap)) return (false); CWndContainer :: AddToElementsArray (0, m_timeframes); return (true); }
Мал. 7. Додавання комбо-боксу.
Чек-бокс
Чек-бокс - найпростіший елемент. Для нього досить вказати два властивості.
- Ширина.
- Розташування в правій частині головного елемента.
Після створення елемента можна програмно включити чек-бокс.
bool CProgram :: CreateDateScale (const int x_gap, const int y_gap, const string text) {m_date_scale.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_date_scale); m_date_scale.XSize (70); m_date_scale.AnchorRightWindowSide (true); if (! m_date_scale.CreateCheckBox (text, x_gap, y_gap)) return (false); m_date_scale.IsPressed (true); CWndContainer :: AddToElementsArray (0, m_date_scale); return (true); }
Мал. 8. Додавання чек-боксів.
Таблиця
У графічному інтерфейсі будуть дві таблиці. Розглянемо ту, яка візуалізує сформований список символів і сигналів для відкриття позицій. Вона розміщується на першій вкладці. Спочатку оголошуємо і инициализируем масиви для установки властивостей таблиці. Налаштуємо наступні властивості.
- Ширина елемента.
- Розмірність таблиці (кількість стовпців і рядків).
- Ширина стовпців (значення передаються в масиві).
- Вирівнювання тексту (значення передаються в масиві).
- Відступ для тексту від країв осередків.
- Показ заголовків.
- Можливість виділяти рядки.
- Можливість змінювати розміри стовпців вручну, захоплюючи кордон заголовка.
- Показано друзів з форматуванням в стилі «Зебра».
- Автоматична зміна розміру по вертикалі щодо головного елементу.
- Відступ від нижнього краю головного елемента.
Текст для заголовків можна вказати після створення таблиці:
bool CProgram :: CreateSymbolsTable (const int x_gap, const int y_gap) {#define COLUMNS1_TOTAL 2 #define ROWS1_TOTAL 1 m_table_symb.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_table_symb); int width [COLUMNS1_TOTAL] = {95, 58}; ENUM_ALIGN_MODE align [COLUMNS1_TOTAL] = {ALIGN_LEFT, ALIGN_RIGHT}; int text_x_offset [COLUMNS1_TOTAL] = {5, 5}; m_table_symb.XSize (168); m_table_symb.TableSize (COLUMNS1_TOTAL, ROWS1_TOTAL); m_table_symb.ColumnsWidth (width); m_table_symb.TextAlign (align); m_table_symb.TextXOffset (text_x_offset); m_table_symb.ShowHeaders (true); m_table_symb.SelectableRow (true); m_table_symb.ColumnResizeMode (true); m_table_symb.IsZebraFormatRows (clrWhiteSmoke); m_table_symb.AutoYResizeMode (true); m_table_symb.AutoYResizeBottomOffset (2); if (! m_table_symb.CreateTable (x_gap, y_gap)) return (false); m_table_symb.SetHeaderText (0, "Symbol"); m_table_symb.SetHeaderText (1, "Values"); CWndContainer :: AddToElementsArray (0, m_table_symb); return (true); }
Друга таблиця відображає деякі властивості відкритих позицій. Десять її стовпців будуть відображати такі дані.
- Символ позиції.
- Кількість позицій.
- Загальний обсяг всіх відкритих позицій.
- Обсяг позицій BUY.
- Обсяг позицій SELL.
- Поточний загальний результат по всіх відкритих позиціях.
- Поточний результат по всіх відкритих BUY-позиціях.
- Поточний результат по всіх відкритих SELL-позиціях.
- Завантаження депозиту по кожному символу окремо.
- Середня ціна.
У другій таблиці додатково потрібно встановити такі властивості.
- Відступи для картинок від правого і верхнього країв осередків.
- Можливість сортування значень.
- Автоматична зміна розміру по горизонталі щодо головного елементу.
- Відступ від правого краю головного елемента.
Картинки в осередках першого стовпця будуть символізувати кнопки, натискаючи на які, можна закрити позицію або всі позиції, якщо це хедж-рахунок, на зазначеному символі.
bool CProgram :: CreatePositionsTable (const int x_gap, const int y_gap) {... m_table_positions.TableSize (COLUMNS2_TOTAL, ROWS2_TOTAL); m_table_positions.ColumnsWidth (width); m_table_positions.TextAlign (align); m_table_positions.TextXOffset (text_x_offset); m_table_positions.ImageXOffset (image_x_offset); m_table_positions.ImageYOffset (image_y_offset); m_table_positions.ShowHeaders (true); m_table_positions.IsSortMode (true); m_table_positions.SelectableRow (true); m_table_positions.ColumnResizeMode (true); m_table_positions.IsZebraFormatRows (clrWhiteSmoke); m_table_positions.AutoXResizeMode (true); m_table_positions.AutoYResizeMode (true); m_table_positions.AutoXResizeRightOffset (2); m_table_positions.AutoYResizeBottomOffset (2); ... return (true); }
Мал. 9. Додавання таблиці на першій вкладці.
Мал. 10. Додавання таблиці на другій вкладці.
Про те, як працювати з таблицями в головному файлі програми (CProgram), я розповім в одному з наступних розділах статті.
Стандартний графік
Для візуалізації даних по символам призначений елемент типу CStandardChart. За замовчуванням буде показуватися графік EURUSD на денному таймфрейме. У ньому задіяні такі властивості.
- Горизонтальний скролінг.
- Автоматичне налаштування ширини.
- Автоматичне налаштування висоти.
- Відступ від правого краю головного елемента.
- Відступ від нижнього краю головного елемента.
При необхідності можна створити масив графіків, побудованих в горизонтальний ряд. Для цього скористайтеся методом CStandardChart :: AddSubChart () передавши в нього в якості аргументів символ і таймфрейм графіка. Але в даному випадку нам потрібен тільки один графік, а символи і таймфрейме будемо перемикати за допомогою інших елементів управління.
bool CProgram :: CreateSubChart1 (const int x_gap, const int y_gap) {m_sub_chart1.MainPointer (m_tabs1); m_tabs1.AddToElementsArray (0, m_sub_chart1); m_sub_chart1.XScrollMode (true); m_sub_chart1.AutoXResizeMode (true); m_sub_chart1.AutoYResizeMode (true); m_sub_chart1.AutoXResizeRightOffset (125); m_sub_chart1.AutoYResizeBottomOffset (2); m_sub_chart1.AddSubChart ( "EURUSD", PERIOD_D1); if (! m_sub_chart1.CreateStandardChart (x_gap, y_gap)) return (false); CWndContainer :: AddToElementsArray (0, m_sub_chart1); return (true); }
Мал. 11. Додавання графіка.
індикатор виконання
Для того, щоб користувач розумів, що зараз робить програма, додамо в графічний інтерфейс індикатор виконання. Ось властивості для нашого прикладу (в тому ж порядку, що і в коді).
- Загальна висота елемента.
- Висота індикатора (смуга прогресу виконання).
- Відступ індикатора по осі X.
- Відступ індикатора по осі Y.
- Відступ головною текстової мітки по осі X.
- Відступ головною текстової мітки по осі Y.
- Відступ процентної текстової мітки по осі X.
- Відступ процентної текстової мітки по осі Y.
- Ознака випадає елемента (для автоматичного приховування).
- Шрифт.
- Колір рамки індикатора.
- Колір фону індикатора.
- Колір смуги прогресу індикатора.
- Автоматичне налаштування ширини.
- Відступ від правого краю головного елемента.
Нижче я покажу приклади використання індикатора виконання.
bool CProgram :: CreateProgressBar (const int x_gap, const int y_gap, const string text) {m_progress_bar.MainPointer (m_status_bar); m_progress_bar.YSize (17); m_progress_bar.BarYSize (14); m_progress_bar.BarXGap (0); m_progress_bar.BarYGap (1); m_progress_bar.LabelXGap (5); m_progress_bar.LabelYGap (2); m_progress_bar.PercentXGap (5); m_progress_bar.PercentYGap (2); m_progress_bar.IsDropdown (true); m_progress_bar.Font ( "Consolas"); m_progress_bar.BorderColor (clrSilver); m_progress_bar.IndicatorBackColor (clrWhiteSmoke); m_progress_bar.IndicatorColor (clrLightGreen); m_progress_bar.AutoXResizeMode (true); m_progress_bar.AutoXResizeRightOffset (2); if (! m_progress_bar.CreateProgressBar (text, x_gap, y_gap)) return (false); CWndContainer :: AddToElementsArray (0, m_progress_bar); return (true); }
Ми розглянули всі елементи управління, які будуть використовуватися в графічному інтерфейсі нашого експерта. На поточний момент це просто графічна оболонка. Але далі ми напишемо всі необхідні методи для того, щоб все це запрацювало відповідно до початкової ідеєю.
Оновлення бібліотеки EasyAndFast
У бібліотеці EasyAndFast в класі CTable доопрацьований публічний метод CTable :: SortData (). Тепер в якості другого аргументу можна вказати напрямок сортування таблиці (необов'язковий параметр). Раніше повторний виклик методу CTable :: SortData () починав сортування в протилежному напрямку від поточного. Також додані методи для отримання поточного напряму сортування і індексу відсортованого стовпчика. Тепер, якщо таблиця була відсортована користувачем вручну (кліком по заголовку), а потім дані в таблиці були оновлені не в тій же послідовності, то, з'ясувавши поточний напрямок сортування, можна її відновити.
class CTable: public CElement {public: ... void SortData (const uint column_index = 0, const int direction = WRONG_VALUE); int IsSortDirection (void) const {return (m_last_sort_direction); } Int IsSortedColumnIndex (void) const {return (m_is_sorted_column_index); } ...}; void CTable :: SortData (const uint column_index = 0, const int direction = WRONG_VALUE) {if (column_index> = m_columns_total) return; uint first_index = 0; uint last_index = m_rows_total- 1; if (direction == WRONG_VALUE) {if (m_is_sorted_column_index == WRONG_VALUE || column_index! = m_is_sorted_column_index || m_last_sort_direction == SORT_DESCEND) m_last_sort_direction = SORT_ASCEND; else m_last_sort_direction = SORT_DESCEND; } Else {m_last_sort_direction = (ENUM_SORT_MODE) direction; } M_is_sorted_column_index = (int) column_index; QuickSort (first_index, last_index, column_index, m_last_sort_direction); }
Ще одне маленьке доповнення додано в клас CKeys в метод CKeys :: KeySymbol (). Раніше цифрова клавіатура (окремий блок клавіш у правій частині клавіатури) і не виконує жодних. Тепер можна вводити цифри, а також спеціальні символи і з цього розділу клавіатури.
string CKeys :: KeySymbol (const long key_code) {string key_symbol = ""; if (key_code == KEY_SPACE) {key_symbol = ""; } Else if ((key_code> = KEY_A && key_code <= KEY_Z) || (key_code> = KEY_0 && key_code <= KEY_9) || (key_code> = KEY_NUMLOCK_0 && key_code <= KEY_NUMLOCK_SLASH) || (key_code> = KEY_SEMICOLON && key_code <= KEY_SINGLE_QUOTE)) {key_symbol = :: ShortToString (:: TranslateKey ((int) key_code)); } Return (key_symbol); }
Нові версії класів CTable і CKeys можна скачати в кінці статті.
Висновок
Ви прочитали першу частину статті. У ній ми розібрали, як без особливих зусиль можна створювати графічні інтерфейси для своїх програм будь-якого рівня складності. Ви можете продовжити розвивати цю програму і використовувати її в своїх цілях. У другій частині статті я покажу, як працювати з графічним інтерфейсом, а найголовніше - як наповнити його функціоналом.
Нижче ви можете завантажити до себе на комп'ютер файли для тестів і більш докладного вивчення представленого в статті коду.
Найменування файлу Коментар MQL5 \ Experts \ TradePanel \ TradePanel.mq5 Торговий експерт для ручної торгівлі з графічним інтерфейсом MQL5 \ Experts \ TradePanel \ Program.mqh Файл з класом програми MQL5 \ Experts \ TradePanel \ CreateGUI.mqh Файл з реалізацією методів для створення графічного інтерфейсу з класу програми в файлі Program.mqh MQL5 \ Include \ EasyAndFastGUI \ Controls \ Table.mqh Оновлений клас CTable MQL5 \ Include \ EasyAndFastGUI \ Keys.mqh Оновлений клас CKeys