
Создание торговой панели администратора на MQL5 (Часть VIII): Панель аналитики
Введение
В статье мы займемся разработкой третьей вспомогательной панели для советника Admin Panel, сосредоточившись на устранении текущих ограничений и улучшении функциональности. Хотя существующий дизайн уже поддерживает взаимодействие и управление торговлей, сегодняшнее расширение представляет статистические инструменты для оптимизации анализа важнейших рыночных показателей. Благодаря автоматизации исследований и расчетов эти инструменты устраняют необходимость в ручных методах, упрощая процесс для торговых администраторов. Вдохновленные простотой и ясностью данных, визуализируемых с помощью круговых диаграмм, мы сосредоточимся на двух ключевых аспектах распределения эффективности торговли: соотношении выигрышей и убытков и категоризации типов торговли. Эти показатели дают мгновенное представление об успешности торговли и распределении сделок по различным классам активов, таким как Форекс, акции или опционы.
Аналитическая панель использует визуализацию данных в реальном времени для преодоления неэффективности ручного анализа. Благодаря использованию круговых диаграмм панель позволяет пользователям быстро оценивать соотношение выигрышей и проигрышей и распределение типов торговли без задержек в принятии решений. Эта функция представляет собой значительный скачок эффективности, позволяя администраторам принимать обоснованные решения точно и быстро.
Мы будем использовать возможности классов MQL5 PieChart и ChartCanvas для автоматизации этих процессов и продемонстрируем потенциал современных статистических инструментов. Благодаря этому усовершенствованию Admin Panel превращается в еще более надежную систему, предлагающую ценную информацию с первого взгляда, а также подчеркивающую образовательные и практические преимущества этой серии разработок.
Я выделил следующие подтемы в качестве основного содержания:
- Обзор аналитической панели
- Подготовка панели аналитики с использованием класса CDialog
- Получение истории торговли для отображения
- Реализация классов PieChart и ChartCanvas для представления данных
- Тестирование новых функций
- Заключение
Обзор аналитической панели
Аналитическая панель (Analytics Panel) будет представлять собой динамичный и интерактивный интерфейс, предназначенный для предоставления визуальной информации об эффективности торговли и распределении активности. В рамках текущей статьи панель содержит две основные круговые диаграммы: выигрышных и проигрышных сделок (Win vs. Loss Pie Chart) и диаграмму распределения типов сделок (Trade Type Distribution Chart), которая классифицирует сделки на валюты, акции и фьючерсы. Эти диаграммы органично интегрируются в панель, обеспечивая интуитивно понятную структуру для простоты интерпретации. Используя данные из истории торговли в реальном времени, панель аналитики предоставляет комплексную картину результатов торговли, позволяя пользователям оценивать эффективность торговли.
Аналитическая панель может быть дополнительно расширена за счет дополнительных визуализаций и параметров для более комплексного анализа эффективности и активности торговли. Вот некоторые функции, которые можно включить:
- Линейный график производительности
- Столбчатая диаграмма объема торговли
- Таблица показателей прибыльности
- Наиболее эффективные активы
- Тепловая карта торговых часов
- Трекер серии выигрышей/убытков
- Диаграмма подверженности риску
- Настраиваемые оповещения и пороговые значения
- Интеграция анализа настроений
- Интерактивные фильтры и т. д.
Другими словами, аналитическая панель обеспечивает комплексный обзор эффективности торговли, позволяя пользователям выявлять закономерности, оценивать прибыльность и отслеживать прогресс с течением времени. Это помогает трейдерам оставаться в курсе своих сильных и слабых сторон, гарантируя им возможность вносить коррективы в свои стратегии на основе имеющихся данных. Теперь подготовим нашу старую версию Admin Panel к обновлению. Я также потратил время на доработку каждой строки предыдущего кода, чтобы сделать его простым для понимания.
Подготовка панели аналитики с использованием класса CDialog
Обновление большой программы часто может показаться невыполнимой задачей, особенно если это предполагает повторение ранее выполненных задач. Вот почему так важно иметь четко определенный шаблон, определяющий макет и структуру программы. При наличии надежного шаблона и его многократном использовании он прочно укоренится в вашем рабочем процессе, позволяя вам выполнять все задачи по разработке, не обращаясь к нему постоянно. Наша программа действительно значительно выросла, и чтобы справиться с этой сложностью, я сосредотачиваюсь на том, чего и как я хочу достичь, сопоставляя эти цели с модульными разделами программы.
Например, рассмотрим нашу домашнюю панель администратора (Admin Home Panel), которая служит центральным интерфейсом после запуска программы. Из нее мы можем получить доступ к другим панелям. Для включения панели аналитики я хочу добавить кнопку на главной панели администратора. Панель аналитики также будет содержать необходимые кнопки управления и функции. С учетом этого видения процесс разработки приобретает ясность и направление, обеспечивая обоснованную отправную точку. Рассмотрим примененный подход.
Сначала рассмотрим включение необходимых классов:
#include <Controls\Dialog.mqh> #include <Controls\Button.mqh>
Объявление Dialog и кнопки для панели аналитики:
// Global variables for the Analytics Panel CDialog analyticsPanel; // The main panel for analytics CButton adminHomeAnalyticsButton; // Button for accessing analytics from the Home panel CButton minimizeAnalyticsButton; // Minimize button for the Analytics panel CButton closeAnalyticsButton; // Close button for the Analytics panel CButton analyticsPanelAccessButton; // The first Button that will take us a next step
Создание панели аналитики и обработчики кнопок:
Чтобы создать панель аналитики при нажатии на analyticsPanelAccessButton, мы реализовали эту функциональность с помощью функции-обработчика кнопок. Аналогичный подход был применен и к другим панелям. Ранее эти панели создавались и скрывались на этапе инициализации, что добавляло ненужную нагрузку на функцию инициализации. Теперь панели динамически создаются по запросу путем нажатия соответствующих кнопок, что оптимизирует производительность и использование ресурсов. Ниже представлен фрагмент кода, демонстрирующий это улучшение:
//+------------------------------------------------------------------+ //| Analytics Panel Event Handling | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "AnalyticsPanelAccessButton") { analyticsPanel.Show(); adminHomePanel.Hide(); if (!analyticsPanel.Create(ChartID(), "Analytics Panel", 0, 500, 450, 1280, 650) || !CreateAnalyticsPanelControls()) {} CreateAnalyticsPanel(); } else if (sparam == "MinimizeAnalyticsButton") { analyticsPanel.Hide(); adminHomePanel.Show(); } else if (sparam == "CloseAnalyticsButton") { analyticsPanel.Destroy(); adminHomePanel.Show(); } } }
Этот фрагмент кода обрабатывает события, связанные с панелью аналитики в функции OnChartEvent, в частности, при обнаружении щелчков пользователя по объектам диаграммы (CHARTEVENT_OBJECT_CLICK). При нажатии на кнопку доступа к панели аналитики отобразится панель, главная панель администратора будет скрыта. Аналитическая панель создается динамически вместе с элементами управления с использованием функции CreateAnalyticsPanel. Если нажать кнопку Minimize Analytics (свернуть аналитику), панель аналитики будет скрыта и снова отобразится главная панель администратора. Наконец, если нажать кнопку Close Analytics (закрыть аналитику), панель аналитики будет полностью удалена, и на экране снова появится главная панель администратора. Такая динамическая обработка обеспечивает отображение или скрытие соответствующих панелей в зависимости от действий пользователя, что улучшает как функциональность, так и удобство использования.
Создание элементов управления панели аналитики:
Этот фрагмент кода определяет функцию CreateAnalyticsPanelControls, которая инициализирует и добавляет элементы управления на панель аналитики в приложении MQL5. Фрагмент начинается с получения идентификатора текущего графика с помощью ChartID() и попытки создать кнопку минимизации (minimizeAnalyticsButton) в определенных координатах. Если создание не удалось, регистрируется сообщение об ошибке и возвращается false. В случае успеха кнопка помечается подчеркиванием ("_") и добавляется в контейнер analyticsPanel. Аналогично, следуя той же процедуре проверки ошибок, создается кнопка закрытия (closeAnalyticsButton), помеченная "X" в другом наборе координат. Функция заканчивается комментарием-заполнителем, указывающим, где можно добавить дополнительные элементы управления, связанные с аналитикой, такие как диаграммы или элементы ввода. Если все элементы управления созданы успешно, функция возвращает true.
bool CreateAnalyticsPanelControls() { long chart_id = ChartID(); // Create Minimize Button if (!minimizeAnalyticsButton.Create(chart_id, "MinimizeAnalyticsButton", 0, 210, -22, 240, 0)) { Print("Failed to create minimize button for Analytics Panel"); return false; } minimizeAnalyticsButton.Text("_"); analyticsPanel.Add(minimizeAnalyticsButton); // Create Close Button if (!closeAnalyticsButton.Create(chart_id, "CloseAnalyticsButton", 0, 240, -22, 270, 0)) { Print("Failed to create close button for Analytics Panel"); return false; } closeAnalyticsButton.Text("X"); analyticsPanel.Add(closeAnalyticsButton); // Add additional controls specific to analytics as needed // For example, charts, labels, or input elements for data representation return true; }
Мы также перенесли создание многих панелей из функций инициализации в функции, запускаемые через обработчики кнопок. После внесения этого изменения я заметил значительное улучшение производительности советника, особенно с точки зрения скорости навигации между различными панелями.
Главная объединенная функция обработчика OnChartEvent:
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } else if (sparam == "AdminHomeAnalyticsButton") { adminHomePanel.Show(); analyticsPanel.Hide(); } else if (sparam == "MinimizeAnalyticsButton") { analyticsPanel.Hide(); adminHomePanel.Show(); } else if (sparam == "CloseAnalyticsButton") { analyticsPanel.Destroy(); adminHomePanel.Show(); } else if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 500, 30, 1280, 170) || !CreateTradeManagementControls()) {} } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); if (!communicationsPanel.Create(ChartID(), "Communications Panel", 0, 20, 150, 490, 650) || !CreateCommunicationsPanelControls()) {} } else if (sparam == "CloseHomeButton") { adminHomePanel.Destroy(); } else if (sparam == "MinimizeHomeButton") { adminHomePanel.Hide(); maximizeHomeButton.Show(); } else if (sparam == "MaximizeHomeButton") { adminHomePanel.Show(); maximizeHomeButton.Show(); } else if (sparam == "AnalyticsPanelAccessButton") { analyticsPanel.Show(); adminHomePanel.Hide(); if (!analyticsPanel.Create(ChartID(), "Analytics Panel", 0, 500, 450, 1280, 650) || !CreateAnalyticsPanelControls()) {}; CreateAnalyticsPanel(); } else if (sparam == "ShowAllButton") { analyticsPanel.Show(); communicationsPanel.Show(); tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "MinimizeComsButton") { OnMinimizeComsButtonClick(); } else if (sparam == "CloseComsButton") { communicationsPanel.Destroy(); } else if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeComsButton") OnMinimizeComsButtonClick(); else if (sparam == "CloseComsButton") OnCloseComsButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } }
Наконец, я также рассмотрел возможность настройки главной панели администратора, как показано по ее координатам и ширине во фрагменте кода ниже:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminHomePanel.Create(ChartID(), "Admin Home Panel", 0, 30, 80,330, 550)) { Print("Failed to create Admin Home Panel"); return INIT_FAILED; } if (!CreateAdminHomeControls()) { Print("Home panel control creation failed"); return INIT_FAILED; } adminHomePanel.Hide(); // Hide home panel by default on initialization return INIT_SUCCEEDED; }
Получение истории торговли для отображения
Теперь нам нужно получить данные из истории терминала, которые мы можем представить через круговую диаграмму в нашей новой панели. Функция GetTradeData предназначена для анализа исторических торговых данных и их классификации по определенным категориям, обеспечивая основу для детального анализа эффективности торговли. Сначала он инициализирует счетчики выигрышей, проигрышей и трех типов сделок: валюты, акции и фьючерсы. Функция использует HistorySelect для извлечения торговых данных с начала истории торгового счета до текущего времени. Если выбор завершается неудачей, функция регистрирует ошибку и завершает работу, обеспечивая устойчивость к недоступным историческим данным. Затем он перебирает все доступные сделки, используя HistoryDealGetTicket для получения уникального идентификатора каждой сделки. Для каждой действительной сделки функция оценивает ее прибыльность, анализируя величину прибыли, увеличивая счетчик выигрышей или проигрышей в зависимости от того, была ли прибыль положительной или отрицательной.
Категоризация сделок определяется их символами. Сделки на рынке Форекс идентифицируются по отсутствию точки в названии их символов, тогда как сделки с акциями и фьючерсами классифицируются путем проверки свойства символа SYMBOL_PATH. Групповое название символа определяет, относится ли он к категории Stocks или Futures. Этот шаг обеспечивает точную группировку сделок по финансовым инструментам. Объединяя эту информацию, функция обеспечивает комплексную разбивку эффективности торговли, которую можно использовать для дальнейшего анализа или визуализации.
В текущем сценарии эту функцию можно интегрировать в аналитическую панель для создания круговой диаграммы, показывающей распределение категорий сделок и соотношение выигрышей и проигрышей. Например, трейдер может использовать функцию для визуализации того, что 60% его сделок приходится на валюты, 30% — на акции и 10% — на фьючерсы, тогда как их общий показатель успешности составляет 70%. Такие знания бесценны для оценки эффективности торговли и выявления областей, требующих улучшения. Кроме того, возможности функции анализа данных в реальном времени делают ее пригодной для создания адаптивных панелей управления, которые помогают трейдерам адаптировать стратегии на основе исторических трендов.
Помимо текущей реализации, функция GetTradeData имеет потенциал для более широкого применения. Его можно расширить для анализа определенных временных диапазонов или включить дополнительные показатели, такие как средняя прибыль или просадка. Затем эти данные можно интегрировать во внешние инструменты, такие как модели машинного обучения для предиктивной аналитики или интерактивные отчеты для презентаций для инвесторов. Благодаря таким расширениям функция становится универсальным инструментом как для индивидуальных трейдеров, так и для крупных торговых систем, стремящихся к максимальной эффективности и прибыльности.
Код:
//+------------------------------------------------------------------+ //| Data for Pie Chart | //+------------------------------------------------------------------+ void GetTradeData(int &wins, int &losses, int &forexTrades, int &stockTrades, int &futuresTrades) { wins = 0; losses = 0; forexTrades = 0; stockTrades = 0; futuresTrades = 0; if (!HistorySelect(0, TimeCurrent())) { Print("Failed to select trade history."); return; } int totalDeals = HistoryDealsTotal(); for (int i = 0; i < totalDeals; i++) { ulong dealTicket = HistoryDealGetTicket(i); if (dealTicket > 0) { double profit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT); if (profit > 0) wins++; else if (profit < 0) losses++; string symbol = HistoryDealGetString(dealTicket, DEAL_SYMBOL); if (SymbolInfoInteger(symbol, SYMBOL_SELECT)) { if (StringFind(symbol, ".") == -1) forexTrades++; else { string groupName; if (SymbolInfoString(symbol, SYMBOL_PATH, groupName)) { if (StringFind(groupName, "Stocks") != -1) stockTrades++; else if (StringFind(groupName, "Futures") != -1) futuresTrades++; } } } } } }
Реализация классов PieChart и ChartCanvas для представления данных
Начнем с включения классов:
#include <Canvas\Charts\PieChart.mqh> #include <Canvas\Charts\ChartCanvas.mqh>
Пользовательский класс круговой диаграммы:
Начнем с вывода класса CCustomPieChart для базового класса CPieChart. Цель состояла в том, чтобы раскрыть защищенный метод DrawPie, который обычно недоступен за пределами родительского класса. Создав публичный метод DrawPieSegment, которая является оболочкой DrawPie, мы получили возможность динамически рисовать отдельные сегменты круговой диаграммы. Это было особенно полезно при реализации пользовательской логики отрисовки в методе DrawPieChart класса CAnalyticsChart. Этот шаг гарантировал нам точный контроль над визуальным представлением каждого сектора круговой диаграммы, что позволило нам создавать более динамичные и визуально адаптированные круговые диаграммы для нашей аналитической панели.
//+------------------------------------------------------------------+ //| Custom Pie Chart Class | //+------------------------------------------------------------------+ class CCustomPieChart : public CPieChart { public: void DrawPieSegment(double fi3, double fi4, int idx, CPoint &p[], const uint clr) { DrawPie(fi3, fi4, idx, p, clr); // Expose protected method } };
Класс аналитической диаграммы:
Далее мы расширили класс CWnd для создания CAnalyticsChart, специализированного контейнера графика. В этом классе мы интегрировали CCustomPieChart в качестве члена, что позволяет ему служить основой для построения круговых диаграмм. Мы внедрили такие методы, как CreatePieChart для инициализации виджета круговой диаграммы в определенной области и SetPieChartData для привязки значений данных, меток и цветов к диаграмме. Кроме того, метод DrawPieChart был тщательно закодирован для расчета углового размаха каждого сегмента на основе набора данных и вызова DrawPieSegment для отрисовки. Используя эту логику, мы добились того, что круговую диаграмму можно было рисовать динамически, отражая базовые данные в визуально привлекательной форме.
//+------------------------------------------------------------------+ //| Analytics Chart Class | //+------------------------------------------------------------------+ class CAnalyticsChart : public CWnd { private: CCustomPieChart pieChart; // Declare pieChart as a member of this class public: bool CreatePieChart(string label, int x, int y, int width, int height) { if (!pieChart.CreateBitmapLabel(label, x, y, width, height)) { Print("Error creating Pie Chart: ", label); return false; } return true; } void SetPieChartData(const double &values[], const string &labels[], const uint &colors[]) { pieChart.SeriesSet(values, labels, colors); pieChart.ShowPercent(); } void DrawPieChart(const double &values[], const uint &colors[], int x0, int y0, int radius) { double total = 0; int seriesCount = ArraySize(values); if (seriesCount == 0) { Print("No data for pie chart."); return; } for (int i = 0; i < seriesCount; i++) total += values[i]; double currentAngle = 0.0; // Resize the points array CPoint points[]; ArrayResize(points, seriesCount + 1); for (int i = 0; i < seriesCount; i++) { double segmentValue = values[i] / total * 360.0; double nextAngle = currentAngle + segmentValue; // Define points for the pie slice points[i].x = x0 + (int)(radius * cos(currentAngle * M_PI / 180.0)); points[i].y = y0 - (int)(radius * sin(currentAngle * M_PI / 180.0)); pieChart.DrawPieSegment(currentAngle, nextAngle, i, points, colors[i]); currentAngle = nextAngle; } // Define the last point to close the pie points[seriesCount].x = x0 + (int)(radius * cos(0)); // Back to starting point points[seriesCount].y = y0 - (int)(radius * sin(0)); } };
Функция создания панели аналитики:
Чтобы связать все воедино, мы написали функцию CreateAnalyticsPanel для обработки фактической реализации аналитической панели. Сначала мы извлекли данные о сделках, такие как количество выигрышей, проигрышей и количество типов сделок, используя нашу функцию GetTradeData. Затем мы создали два экземпляра объектов CAnalyticsChart для различных визуализаций. Для первой диаграммы мы использовали полученные данные о выигрышах/проигрышах, чтобы построить круговую диаграмму Win vs. Loss Pie Chart (выигрышные и проигрышные сделки). Аналогично, для второй диаграммы мы использовали данные о типах сделок, чтобы создать круговую диаграмму Trade Type Distribution (распределение типов сделок). Вызвав SetPieChartData и DrawPieChart для каждой диаграммы мы визуализировали их динамически и добавили их в analyticsPanel. Такой подход позволил нам разбить код на модульные и повторно используемые компоненты, обеспечив ясность и удобство поддержки.
//+------------------------------------------------------------------+ //| Create Analytics Panel | //+------------------------------------------------------------------+ void CreateAnalyticsPanel() { int wins, losses, forexTrades, stockTrades, futuresTrades; GetTradeData(wins, losses, forexTrades, stockTrades, futuresTrades); // Declare pieChart1 and pieChart2 as local variables CAnalyticsChart pieChart1; CAnalyticsChart pieChart2; // Win vs Loss Pie Chart if (!pieChart1.CreatePieChart("Win vs. Loss Pie Chart", 20, 20, 300, 300)) { Print("Error creating Win/Loss Pie Chart"); return; } double winLossValues[] = {wins, losses}; string winLossLabels[] = {"Wins", "Losses"}; uint winLossColors[] = {clrGreen, clrRed}; pieChart1.SetPieChartData(winLossValues, winLossLabels, winLossColors); pieChart1.DrawPieChart(winLossValues, winLossColors, 150, 150, 140); // Add pieChart1 to the analyticsPanel analyticsPanel.Add(pieChart1); // Trade Type Pie Chart if (!pieChart2.CreatePieChart("Trade Type Distribution", 350, 20, 300, 300)) { Print("Error creating Trade Type Pie Chart"); return; } double tradeTypeValues[] = {forexTrades, stockTrades, futuresTrades}; string tradeTypeLabels[] = {"Forex", "Stocks", "Futures"}; uint tradeTypeColors[] = {clrBlue, clrOrange, clrYellow}; pieChart2.SetPieChartData(tradeTypeValues, tradeTypeLabels, tradeTypeColors); pieChart2.DrawPieChart(tradeTypeValues, tradeTypeColors, 500, 150, 140); // Add pieChart2 to the analyticsPanel analyticsPanel.Add(pieChart2); // Show the analyticsPanel analyticsPanel.Show(); }
Почему мы сделали это именно так?
Кодируя систему таким образом, мы гарантировали, что создание диаграмм будет динамичным и гибким. Выведение CCustomPieChart дало нам контроль над отображением круговой диаграммы, в то время как CAnalyticsChart позволила нам инкапсулировать функциональность круговой диаграммы в автономный класс. Это позволило легко добавлять новые диаграммы или корректировать их поведение, не затрагивая другие части программы. Например, в сегодняшнем проекте, если бы мы хотели добавить еще одну диаграмму для анализа кривой эквити, мы могли бы повторно использовать ту же структуру CAnalyticsChart с минимальными усилиями. Такой модульный подход не только оптимизирует разработку, но и делает панель аналитики легко расширяемой для будущих улучшений.
Предотвращение ошибки выхода массива за пределы диапазона (array out of range):
Чтобы предотвратить ошибку "array out of range" в методе CPieChart::DrawPie из PieChart.mqh, мы добавили проверку диапазона, чтобы гарантировать, что index (idx + 1) находится в пределах CPoint array (p[]) перед доступом к нему. Эта мера предосторожности обеспечивает правильный размер массива перед использованием и предотвращает недопустимые операции. Если индекс выходит за пределы допустимого диапазона, функция завершает работу досрочно и выводит сообщение об ошибке для отладки. Кроме того, во время отображения круговой диаграммы размер массива CPoint изменяется соответствующим образом, чтобы вместить все сегменты круговой диаграммы, гарантируя, что структура данных всегда будет достаточно большой для вычислений. Добавленное условие if (idx + 1 >= ArraySize(p)) проверяет, является ли следующий индекс допустимым, и если нет, выводит сообщение об ошибке и возвращается раньше времени, чтобы предотвратить дальнейшую обработку. Эта проверка предотвращает попытки функции обратиться к элементу массива, находящемуся за пределами допустимого диапазона, тем самым избегая ошибки.
if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; }
Обратите внимание, что нам пришлось изменить встроенный класс круговой диаграммы, чтобы предотвратить ошибку, упомянутую ранее во время тестирования советника.
//+------------------------------------------------------------------+ //| Draw pie | //+------------------------------------------------------------------+ void CPieChart::DrawPie(double fi3, double fi4, int idx, CPoint &p[], const uint clr) { // Ensure array index is within bounds if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; } //--- draw arc Arc(m_x0, m_y0, m_r, m_r, fi3, fi4, p[idx].x, p[idx].y, p[idx + 1].x, p[idx + 1].y, clr); //--- variables int x3 = p[idx].x; int y3 = p[idx].y; int x4 = p[idx + 1].x; int y4 = p[idx + 1].y; //--- draw radii if (idx == 0) Line(m_x0, m_y0, x3, y3, clr); if (idx != m_data_total - 1) Line(m_x0, m_y0, x4, y4, clr); //--- fill double fi = (fi3 + fi4) / 2; int xf = m_x0 + (int)(0.99 * m_r * cos(fi)); int yf = m_y0 - (int)(0.99 * m_r * sin(fi)); Fill(xf, yf, clr); //--- for small pie if (fi4 - fi3 <= M_PI_4) Line(m_x0, m_y0, xf, yf, clr); }
Тестирование новых функций
В этом разделе мы представляем результаты наших улучшений, демонстрируя обновленную версию нашей программы и ее функции. Ниже представлена серия изображений, иллюстрирующих улучшения. Во-первых, это переработанная главная панель администратора и недавно добавленная кнопка. Далее панель аналитики с визуализацией распределения торговых данных. Далее полный вид панели администратора со всеми видимыми дополнительными панелями. Наконец, анимированный скриншот, демонстрирующий развертывание приложения на графике терминала для бесшовной интеграции.
Новая панель администратора
Панель аналитики
Admin Panel V1.23 Полный вид
Индекс Boom 300, H4: запуск Admin Panel V1.24
Заключение
Мы рассмотрели разработку расширенных функций в MQL5, сосредоточившись на интеграции новых классов и методов для улучшения панели администратора и ее функциональности. Используя возможности MQL5, мы успешно реализовали динамические панели и визуальные элементы на основе данных, такие как круговые диаграммы, для эффективного представления эффективности торговли. Проект демонстрирует огромный потенциал MQL5 для создания сложных и удобных инструментов, рассчитанных как на трейдеров, так и на разработчиков.
Внедренная аналитическая панель предоставляет трейдерам полезную информацию об эффективности их торговли, а разработчикам — надежную основу для дальнейшей работы. Решив такие проблемы, как нагромождение панелей, наложение объектов друг на друга и создание динамических элементов управления, мы заложили основу для более эффективного и интуитивно понятного интерфейса. Эти усовершенствования являются основополагающими и служат трамплином для будущих инноваций. Разработчики могут расширить эту структуру, включив в нее дополнительную аналитику, интерактивные функции или даже совершенно новые функции. Прикрепленные исходные файлы и изображения демонстрируют результаты наших усилий, вдохновляя других на исследование безграничных возможностей MQL5. Удачной торговли! Пусть это руководство пробудит в вас творческий потенциал для реализации ваших проектов!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16356




- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Привет, хотел бы посмотреть, как это работает, но получил несколько ошибок при компиляции. Что я пропустил?
Привет, хотел бы посмотреть, как это работает, но получил несколько ошибок при компиляции. Что я пропустил?
Привет, мой хороший друг!
В третьей части цикла мы расширили класс Dialog, добавив в него функции управления темами. Чтобы устранить ошибки, с которыми вы столкнулись, просто загрузите расширенные файлы и скопируйте их в соответствующее место:
После этого попробуйте скомпилировать еще раз. Ошибки должны быть устранены. Если вы столкнетесь с какими-либо другими ошибками, пожалуйста, свяжитесь с нами.