Criando um Painel de Administração de Trading em MQL5 (Parte VIII): Painel de Análises
Introdução
Este artigo marca o desenvolvimento do terceiro subpainel dentro do Admin Panel EA, com foco em romper limitações atuais e aprimorar sua funcionalidade. Embora o design existente já ofereça suporte à comunicação e ao gerenciamento de operações, a expansão de hoje introduz ferramentas estatísticas para otimizar a análise de métricas vitais do mercado. Ao automatizar pesquisas e cálculos, essas ferramentas eliminam a dependência de métodos manuais, simplificando o processo para administradores de trading. Inspirados pela simplicidade e clareza dos dados visualizados por meio de gráficos de pizza, focaremos em dois aspectos principais da distribuição de desempenho de operações: a proporção de vitórias versus perdas e a categorização dos tipos de operações. Essas métricas fornecem insights imediatos sobre o sucesso das operações e a alocação das negociações entre diferentes classes de ativos, como Forex, Ações ou Opções.
O Painel de Análises utiliza visualização de dados em tempo real para resolver as ineficiências da análise manual. Ao incorporar gráficos de pizza, o painel permite que os usuários avaliem rapidamente suas proporções de vitória versus perda e distribuições de tipos de operações sem atrasos na tomada de decisão. Este recurso representa um avanço significativo em eficiência, capacitando administradores a tomarem decisões informadas com precisão e rapidez.
Por meio deste desenvolvimento, utilizaremos as classes PieChart e ChartCanvas do MQL5 para automatizar esses processos, demonstrando o potencial de ferramentas estatísticas avançadas. Com essa melhoria, o EA do Painel de Administração evolui para um sistema ainda mais robusto, oferecendo informações valiosas de forma imediata enquanto reforça os benefícios educacionais e práticos desta série de desenvolvimento.
Para o sucesso do projeto, tenho estes subtópicos como nosso conteúdo principal:
- Visão geral do Painel de Análises
- Preparando o Painel de Análises usando a Classe CDialog
- Obtendo dados do histórico de operações para exibição
- Implementando as classes PieChart e ChartCanvas para apresentar dados
- Testando os novos recursos
- Conclusão
Visão geral do Painel de Análises
O Painel de Análises será uma interface dinâmica e interativa projetada para fornecer insights visuais sobre desempenho de operações e distribuição de atividades. Para a discussão de hoje, este painel apresenta dois gráficos de pizza principais: o Gráfico de Vitórias vs. Perdas, que ilustra a proporção de operações vencedoras e perdedoras, e o Gráfico de Distribuição por Tipo de Operação, que categoriza operações em Forex, Ações e Futuros. Esses gráficos são integrados perfeitamente ao painel, oferecendo um layout limpo e intuitivo para fácil interpretação. Ao aproveitar dados em tempo real do histórico de operações, o Painel de Análises fornece um panorama completo dos resultados das negociações, permitindo que os usuários avaliem o desempenho operacional.
O Painel de Análises pode ser ainda mais aprimorado com visualizações e métricas adicionais para fornecer uma análise mais completa do desempenho e da atividade de trading. Aqui estão alguns recursos que poderiam ser incorporados:
- Gráfico de Linha de Desempenho
- Gráfico de Barras de Volume de Operações
- Tabela de Métricas de Lucratividade
- Seção de Ativos com Melhor Desempenho
- Mapa de Calor dos Horários de Trading
- Rastreador de Sequência de Vitórias/Derrotas
- Gráfico de Exposição ao Risco
- Alertas e Limites Personalizáveis
- Integração de Análise de Sentimento
- Filtros Interativos etc.
Em outras palavras, o Painel de Análises fornece uma visão abrangente do desempenho de trading, permitindo aos usuários identificar padrões, avaliar lucratividade e monitorar progresso ao longo do tempo. Isso ajuda os traders a permanecerem informados sobre seus pontos fortes e fracos, garantindo que façam ajustes baseados em dados em suas estratégias. Agora, avançamos para a etapa de preparar nossa versão antiga do Painel de Administração para uma atualização. Também refinei cada linha do código anterior para garantir que ele seja fácil de acompanhar.
Preparando o Painel de Análises usando a Classe CDialog
Atualizar um programa grande pode frequentemente parecer sobrecarregador, especialmente quando envolve repetir tarefas já realizadas. Por isso, ter um template bem definido para organizar o layout e a estrutura do programa é essencial. Com um template sólido em mãos e seu uso repetido, ele se torna incorporado ao seu fluxo de trabalho, permitindo executar tarefas completas de desenvolvimento sem precisar consultá-lo constantemente. Nosso programa realmente cresceu significativamente, e para gerenciar essa complexidade, foco no que desejo alcançar e como isso flui, alinhando esses objetivos com as seções modulares do programa.
Por exemplo, considere nosso Painel Inicial de Administração, que serve como a interface central após o programa ser iniciado. A partir dele, podemos acessar outros painéis. Para incluir um Painel de Análises, imagino um botão dentro do Painel Inicial de Administração que cria e abre o Painel de Análises ao ser clicado. Dentro do Painel de Análises, imagino botões de controle e recursos específicos ao seu propósito. Com essa visão em mente, o processo de desenvolvimento ganha clareza e direção, fornecendo um ponto de partida justificado. Permita-me guiá-lo pela abordagem que aplicamos.
Para resumir, a história começa aqui;
Primeiro, consideramos a inclusão das classes necessárias que vamos usar:
#include <Controls\Dialog.mqh> #include <Controls\Button.mqh>
Declaração do Dialog e do botão para o Painel de Análises:
// 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
Criação do Painel de Análises e manipuladores do botão:
Para criar o Painel de Análises ao clicar no analyticsPanelAccessButton, implementamos essa funcionalidade usando uma função manipuladora de botão. Uma abordagem similar foi aplicada a outros painéis também. Anteriormente, esses painéis eram criados e ocultados durante a fase de inicialização, o que adicionava carga desnecessária à função de inicialização. Agora, os painéis são criados dinamicamente sob demanda através de seus respectivos cliques nos botões, otimizando o desempenho e o uso de recursos. Abaixo está o trecho de código demonstrando essa melhoria:
//+------------------------------------------------------------------+ //| 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(); } } }
Este trecho de código trata eventos relacionados ao Painel de Análises dentro da função OnChartEvent, especificamente quando cliques do usuário são detectados em objetos do gráfico (CHARTEVENT_OBJECT_CLICK). Se o botão de acesso ao Painel de Análises for clicado, o painel é exibido, o Painel Inicial de Administração é ocultado e o Painel de Análises é criado dinamicamente junto com seus controles usando a função CreateAnalyticsPanel. Se o Botão de Minimizar Análises for clicado, o Painel de Análises é ocultado e o Painel Inicial de Administração é exibido novamente. Por fim, se o Botão de Fechar Análises for clicado, o Painel de Análises é destruído completamente, e o Painel Inicial de Administração é restaurado na tela. Esse tratamento dinâmico garante que os painéis apropriados sejam exibidos ou ocultados com base nas ações do usuário, melhorando tanto a funcionalidade quanto a experiência do usuário.
Criando os Controles do Painel de Análises:
Este trecho de código define uma função, CreateAnalyticsPanelControls, que inicializa e adiciona controles a um painel de análises em uma aplicação MQL5. Ele começa obtendo o ID do gráfico atual com ChartID() e tenta criar um botão de minimizar (minimizeAnalyticsButton) em coordenadas específicas. Se a criação falhar, ele registra uma mensagem de erro e retorna false. Se for bem-sucedido, o botão recebe o rótulo de sublinhado ("_") e é adicionado ao container analyticsPanel. Da mesma forma, ele cria um botão de fechar (closeAnalyticsButton) rotulado com "X" em outro conjunto de coordenadas, seguindo o mesmo processo de verificação de erro. A função termina com um comentário indicativo sugerindo onde controles adicionais relacionados a análises, como gráficos ou elementos de entrada, poderiam ser adicionados. Se todos os controles forem criados com sucesso, a função retorna 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; }
Também movemos a criação de muitos painéis das funções de inicialização para serem acionados através de manipuladores de botões. Desde que fizemos essa mudança, notei uma melhoria significativa no desempenho do Expert Advisor (EA), especialmente em termos de velocidade ao navegar entre vários painéis.
Aqui está a função principal OnChartEvent combinada:
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; } }
Por fim, também considerei ajustar o Painel Inicial de Administração, conforme mostrado por suas coordenadas e largura no trecho de código abaixo:
//+------------------------------------------------------------------+ //| 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; }
Obtendo dados do histórico de operações para exibição
Agora precisamos obter dados do histórico do terminal que possamos apresentar por meio do Piechart em nosso novo Painel. A função GetTradeData foi projetada para analisar dados históricos de negociações e classificá-los em categorias específicas, fornecendo uma base para uma análise detalhada do desempenho das operações. Ela começa inicializando contadores para vitórias, perdas e três tipos de operações: Forex, Ações e Futuros. A função depende da função HistorySelect para recuperar dados de operações desde o início do histórico da conta de trading até o momento atual. Se esse processo de seleção falhar, a função registra um erro e sai, garantindo robustez contra dados históricos indisponíveis. Em seguida, ela itera por todas as negociações disponíveis, usando HistoryDealGetTicket para recuperar o identificador único de cada negociação. Para cada negociação válida, a função avalia sua lucratividade analisando o valor do lucro, incrementando o contador de vitórias ou perdas com base em o lucro ter sido positivo ou negativo.
A categorização das operações é determinada por seus símbolos. Operações Forex são identificadas pela ausência de um ponto no nome do símbolo, enquanto operações de Ações e Futuros são classificadas verificando a propriedade SYMBOL_PATH do símbolo. O nome do grupo do símbolo determina se ele se enquadra nas categorias "Ações" ou "Futuros". Essa etapa garante que as operações sejam agrupadas com precisão de acordo com seus instrumentos financeiros. Ao agregar essas informações, a função fornece uma divisão abrangente do desempenho das negociações, que pode ser usada para análise adicional ou visualização.
No cenário de hoje, essa função pode ser integrada em um Painel de Análises para gerar um gráfico de pizza mostrando a distribuição das categorias de operações e a proporção de vitórias para perdas. Por exemplo, um trader pode usar a função para visualizar que 60% de suas operações estão em Forex, 30% em ações e 10% em Futuros, enquanto sua taxa total de sucesso é de 70%. Esses insights são inestimáveis para avaliar o desempenho das operações e identificar áreas de melhoria. Além disso, a capacidade de análise de dados em tempo real da função a torna adequada para a criação de dashboards responsivos que ajudam traders a adaptar estratégias com base em tendências históricas.
Além de sua implementação atual, a função GetTradeData tem potencial para aplicações mais amplas. Ela pode ser estendida para analisar intervalos de tempo específicos ou incorporar métricas adicionais, como lucro médio ou drawdown. Esses dados podem então ser integrados a ferramentas externas, como modelos de machine learning para análises preditivas ou relatórios interativos para apresentações a investidores. Com tais extensões, a função se torna uma ferramenta versátil tanto para traders individuais quanto para sistemas maiores de negociação que buscam maximizar eficiência e lucratividade
Aqui está o código como implementado:
//+------------------------------------------------------------------+ //| 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++; } } } } } }
Implementando as classes PieChart e ChartCanvas para apresentar dados
Começamos incluindo as classes:
#include <Canvas\Charts\PieChart.mqh> #include <Canvas\Charts\ChartCanvas.mqh>
Classe Custom Pie Chart:
Começamos derivando a classe CCustomPieChart da classe base CPieChart. O objetivo era expor o método protegido DrawPie, que normalmente é inacessível fora da classe pai. Criando um método público DrawPieSegment que encapsula o DrawPie, ganhamos a flexibilidade de desenhar segmentos individuais do gráfico de pizza dinamicamente. Isso foi particularmente útil ao implementar lógica de renderização personalizada no método DrawPieChart da classe CAnalyticsChart. Essa etapa garantiu que tivéssemos controle refinado sobre a representação visual de cada fatia do gráfico de pizza, permitindo construir gráficos mais dinâmicos e visualmente ajustados para nosso painel de análises.
//+------------------------------------------------------------------+ //| 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 } };
Classe de gráfico analítico:
Em seguida, estendemos a classe CWnd para criar CAnalyticsChart, um container de gráfico especializado. Esta classe é onde integramos o CCustomPieChart como um membro, permitindo que ele sirva como base para desenhar gráficos de pizza. Implementamos métodos como CreatePieChart para inicializar o widget de gráfico de pizza dentro de uma área definida e SetPieChartData para vincular valores de dados, rótulos e cores ao gráfico. Além disso, o método DrawPieChart foi cuidadosamente codificado para calcular o ângulo de cada segmento com base no conjunto de dados e chamar DrawPieSegment para a renderização. Ao trabalhar com essa lógica, garantimos que o gráfico de pizza pudesse ser desenhado dinamicamente, refletindo os dados subjacentes de forma visualmente envolvente.
//+------------------------------------------------------------------+ //| 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)); } };
Criar função do painel de análise:
Para unir tudo, escrevemos a função CreateAnalyticsPanel para lidar com a implementação real do painel de análises. Primeiro, buscamos os dados de negociações — como vitórias, perdas e contagem de tipos de operações — usando nossa função GetTradeData. Em seguida, instanciamos dois objetos CAnalyticsChart para diferentes visualizações. Para o primeiro gráfico, usamos os dados de vitórias/derrotas recuperados para configurar um gráfico de pizza rotulado “Win vs. Loss Pie Chart”. Da mesma forma, para o segundo gráfico, usamos dados dos tipos de operações para criar um gráfico de pizza “Trade Type Distribution”. Chamando SetPieChartData e DrawPieChart para cada gráfico, renderizamos ambos dinamicamente e os adicionamos ao analyticsPanel. Essa abordagem permitiu dividir o código em componentes modulares e reutilizáveis, garantindo clareza e manutenção facilitada.
//+------------------------------------------------------------------+ //| 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(); }
Por que fizemos dessa forma:
Ao codificar o sistema dessa maneira, garantimos que a criação dos gráficos fosse dinâmica e flexível. Derivar CCustomPieChart nos deu controle sobre a renderização dos gráficos de pizza, enquanto CAnalyticsChart permitiu encapsular a funcionalidade do gráfico de pizza em uma classe independente. Isso tornou fácil adicionar novos gráficos ou ajustar seu comportamento sem afetar outras partes do programa. Por exemplo, no projeto de hoje, caso quiséssemos adicionar outro gráfico para análise da curva de patrimônio, poderíamos reutilizar a mesma estrutura CAnalyticsChart com mínimo esforço. Essa abordagem modular não apenas agiliza o desenvolvimento, como também torna o painel de análises altamente extensível para melhorias futuras.
Evitando erro de matriz fora do intervalo:
Para evitar um erro “array out of range” no método CPieChart::DrawPie de PieChart.mqh, adicionamos uma verificação de intervalo para garantir que o índice (idx + 1) esteja dentro dos limites do array CPoint (p[]) antes de acessá-lo. Essa proteção garante que o array esteja devidamente dimensionado antes do uso e impede operações inválidas. Se o índice estiver fora do intervalo, a função encerra imediatamente e imprime uma mensagem de erro para depuração. Além disso, durante a renderização do gráfico de pizza, o array CPoint é redimensionado de forma apropriada para acomodar todos os segmentos, garantindo que a estrutura de dados seja sempre suficientemente grande para os cálculos.A condição adicionada (idx + 1 >= ArraySize(p)) verifica se o próximo índice é válido e, caso não seja, imprime uma mensagem de erro e retorna cedo para evitar processamento adicional. Essa verificação impede que a função tente acessar um elemento fora do limite do array, evitando assim o erro.
if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; }
Observe que tivemos que modificar a classe embutida de Pie Chart para evitar o erro mencionado anteriormente durante os testes do Expert Advisor (EA).
//+------------------------------------------------------------------+ //| 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); }
Testando os novos recursos
Nesta seção, apresentamos o resultado das melhorias, mostrando a versão atualizada do nosso programa e seus recursos. Abaixo está uma série de imagens ilustrando as melhorias. Primeiro, destacamos o Painel Inicial de Administração redesenhado junto com o novo botão adicionado. Em seguida, exibimos o Painel de Análises, apresentando visualizações da distribuição dos dados de operações. Isso é seguido por uma visualização completa do Painel de Administração com todos os seus subpainéis visíveis. Por fim, incluímos uma captura de tela animada demonstrando a implantação do aplicativo no gráfico do terminal para integração perfeita.

Novo painel inicial do administrador

Painel de Análise

Painel de administração V1.23 Visão completa

Índice Boom 300, H4: Lançamento do Painel Administrativo V1.24 EA
Conclusão
Na discussão de hoje, exploramos o desenvolvimento de recursos avançados em MQL5, com foco na integração de novas classes e técnicas para aprimorar o Painel de Administração e sua funcionalidade. Ao utilizar as capacidades do MQL5, implementamos com sucesso painéis dinâmicos e visuais orientados por dados, como gráficos de pizza, para representar o desempenho de operações de forma eficaz. Este projeto demonstra o grande potencial do MQL5 para criar ferramentas sofisticadas e fáceis de usar, projetadas para traders e desenvolvedores.
O Painel de Análises recém-implementado oferece aos traders insights acionáveis sobre seu desempenho operacional, enquanto fornece aos desenvolvedores uma base sólida para expansão. Ao resolver desafios como excesso de painéis, camadas de objetos e criação dinâmica de controles, estabelecemos as bases para uma interface mais eficiente e intuitiva. Essas melhorias são fundamentais e um passo inicial para futuras inovações. Os desenvolvedores podem estender essa estrutura para incorporar análises adicionais, recursos interativos ou até novas funcionalidades. Os arquivos fonte e imagens anexados mostram o resultado de nossos esforços, oferecendo inspiração para outros explorarem as possibilidades ilimitadas do MQL5. Boas negociações, e que este guia inspire sua criatividade no avanço de seus projetos!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16356
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Do básico ao intermediário: Classes (III)
MQL5 Trading Toolkit (Parte 4): Desenvolvendo uma Biblioteca EX5 de Gerenciamento de Histórico
Simulação de mercado: Position View (XVI)
Simulação de mercado: Position View (XV)
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Olá, gostaria de ver esse trabalho, mas recebi alguns erros na compilação. O que eu perdi?
Olá, gostaria de ver esse trabalho, mas recebi alguns erros na compilação. O que eu perdi?
Olá, meu bom amigo!
Na Parte III da série, estendemos a classe Dialog para incluir recursos de gerenciamento de temas. Para resolver os erros que você está encontrando, basta fazer o download dos arquivos estendidos e copiá-los para o local apropriado:
Depois de fazer isso, tente compilar novamente. Os erros deverão ser resolvidos. Se encontrar mais algum erro, não hesite em entrar em contato.