Criando um Painel de Administração de Trading em MQL5 (Parte IX): Organização do Código (V): Classe AnalyticsPanel
Conteúdo
Introdução
Nas seções anteriores, apresentei o conceito de um Painel de Análises que, naquela etapa, consistia principalmente em elementos estáticos da interface, como um gráfico de setores exibindo a proporção entre ganhos e perdas. No entanto, esses componentes não possuíam atualizações de dados em tempo real, limitando sua utilidade em ambientes de negociação dinâmicos. Nesta discussão, damos um passo significativo à frente ao aprimorar tanto o design quanto a funcionalidade da interface, com foco em como recuperar e exibir dados de negociação em tempo real.
Nossa abordagem de desenvolvimento aproveita a Biblioteca Padrão do MQL5, particularmente as classes encontradas no diretório \Include\Controls. Estenderemos e personalizaremos classes existentes, como CLabel, CEdit e CDialog, para criar componentes de interface responsivos e orientados por dados. Esses componentes formam a base do nosso Painel de Administração de Trading em constante evolução, projetado como uma ferramenta modular composta por várias interfaces, oferecendo gerenciamento abrangente de conta e estratégia, bem como uma interface de comunicação via Telegram para controle remoto e notificações em tempo real.
Embora o objetivo principal continue sendo o desenvolvimento desse painel avançado, as técnicas compartilhadas aqui, especialmente aquelas relacionadas à aquisição de dados em tempo real e às atualizações dinâmicas da interface, podem ser aplicadas a diversos projetos em MQL5 além de interfaces administrativas, incluindo Expert Advisors, indicadores personalizados e ferramentas interativas de aprendizado.
Visão geral da classe AnalyticsPanel
Como parte de uma abordagem de desenvolvimento modular adequada para programas MQL5 de grande escala e para promover a reutilização e a manutenção do código, estamos criando um arquivo de cabeçalho dedicado para a classe AnalyticsPanel. Essa classe foi projetada para encapsular tanto o layout visual do painel de análises quanto a recuperação e a exibição, em tempo real, de dados de mercado.
Além de fornecer métricas padrão da conta, o painel exibirá diversos valores de indicadores técnicos que alimentam uma estratégia personalizada que denominei Estratégia de Confluência. Essa estratégia baseia-se no princípio da confluência, no qual os sinais de vários indicadores são comparados para gerar um sinal de negociação unificado. Se não houver concordância entre os indicadores, o painel simplesmente exibirá uma mensagem de "Sem Consenso", evitando assim sinais falsos ou fracos.
A classe AnalyticsPanel incluirá métodos para inicializar e atualizar o layout do painel, atualizar os valores dos rótulos em tempo real e gerenciar o feedback visual dos sinais com base na lógica da estratégia. Abaixo, incluí um layout visual do design do painel e, na discussão seguinte, examinaremos os detalhes da implementaçãoque deram vida a ele.

Recursos do AnalyticsPanel
Como parte da nossa jornada contínua de desenvolvimento, após concluirmos o desenvolvimento da nossa classe, nós a integraremos ao programa principal do Expert Advisor, o New_Admin_Panel. Essa integração reforça a arquitetura modular do nosso sistema e destaca as vantagens de construir componentes reutilizáveis e independentes que podem interagir perfeitamente dentro de uma estrutura de aplicação maior. Abaixo está uma imagem destacando o resultado final do nosso produto, no qual os sinais de negociação são gerados apenas quando todos os valores dos indicadores se alinham para formar um forte consenso de compra ou de venda.

AnalyticsPanel em Tempo Real
Ao integrar o AnalyticsPanel ao New_Admin_Panel, passamos a contar com diversos benefícios práticos.
- Monitoramento Centralizado: análises em tempo real, como proporções de ganhos/perdas, alterações no patrimônio líquido e resumos das negociações, agora podem ser acessadas pela interface principal, sem a necessidade de ferramentas separadas.
- Experiência do Usuário Aprimorada: combinar análises com funcionalidades principais, como execução de estratégias e mensagens via Telegram, proporciona um fluxo de trabalho mais unificado e intuitivo para o usuário
- Escalabilidade e Manutenção do Código: separar os componentes da interface em classes, como AnalyticsPanel, melhora a legibilidade do código, facilita os testes e oferece suporte a futuras atualizações com o mínimo de interrupções.
- Reutilização entre Projetos: o design modular permite que o AnalyticsPanel (e outros painéis) seja reutilizado ou adaptado em outros Expert Advisors ou utilitários de negociação.
- Sinal de Negociação: a versão que temos aqui fornece sinais de confluência úteis.
Implementação em MQL5
Ao projetar nosso Painel de Análises, seguimos os princípios da programação orientada a objetos, que separam os componentes essenciais em diferentes níveis de acesso para melhorar a clareza, a segurança e a facilidade de manutenção. A classe é estruturada de forma que determinados recursos estejam disponíveis para outras partes do programa. São os elementos públicos ("public"), que servem como interface para interação com o painel. Outros detalhes internos, que tratam do funcionamento interno e do gerenciamento de dados, permanecem ocultos dos componentes externos. São os elementos privados ("private"). Esse método de encapsulamento nos permite apresentar uma estrutura clara e organizada para o nosso painel, facilitando para futuros desenvolvedores compreenderem o papel e a finalidade de cada seção.
Antes de definir a classe CAnalyticsPanel, dois arquivos de cabeçalho essenciais são incluídos:
Dialog.mqh – Este arquivo de cabeçalho fornece acesso às classes relacionadas a diálogos, incluindo CAppDialog, que serve como classe base para a criação do painel personalizado.
Label.mqh – Este arquivo inclui a definição da classe CLabel, utilizada para criar e gerenciar todos os rótulos de texto exibidos no painel.
Essas inclusões são necessárias para dar ao painel personalizado acesso aos controles padrão de interface do MQL5. Sem elas, a classe do painel não seria capaz de herdar de CAppDialog nem de criar controles de rótulo.
Também precisamos definir macros para espaçamento e layout (AP_GAP, AP_DEFAULT_LABEL_HEIGHT) para manter a estrutura visual limpa, consistente e bem espaçada ou bem organizada.#include <Controls\Dialog.mqh> #include <Controls\Label.mqh> // Use unique macro names for layout in this class: #define AP_DEFAULT_LABEL_HEIGHT 20 #define AP_GAP 10
A estrutura a seguir divide os principais componentes da nossa classe em cinco áreas principais:
1. Estrutura e Finalidade da Classe
A classe CAnalyticsPanel atua como um painel altamente visual e informativo, projetado para atualizações em tempo real sobre negociações e condições de mercado diretamente em um gráfico do MetaTrader 5. Derivada da classe CAppDialog da Biblioteca Padrão do MQL5, ela utiliza programação orientada a objetos para exibir dados estruturados em seções organizadas. O painel inclui rótulos para detalhes da conta, negociações abertas, cotações de mercado, indicadores e um resumo consolidado dos sinais, permitindo que os traders monitorem tudo em uma única janela compacta.
//+------------------------------------------------------------------+ //| Analytics Panel Class | //+------------------------------------------------------------------+ class CAnalyticsPanel : public CAppDialog { protected: // Helper: Create a text label. // The label's text color is set as provided and its background is forced to black. bool CreateLabelEx(CLabel &label, int x, int y, int width, int height, string label_name, string text, color clr) { // Construct a unique control name by combining the dialog name and label_name. string unique_name = m_name + "_" + label_name; if(!label.Create(m_chart_id, unique_name, m_subwin, x, y, x+width, y+height)) { Print("Failed to create label: ", unique_name, " Err=", GetLastError()); return false; } if(!Add(label)) { Print("Failed to add label: ", unique_name, " Err=", GetLastError()); return false; } if(!label.Text(text)) { Print("Failed to set text for label: ", unique_name); return false; } label.Color(clr); // Set text color label.Color(clrBlack); // Force background to black return true; } // Account and Trade Data Labels: CLabel m_lblBalance; CLabel m_lblEquity; CLabel m_lblMargin; CLabel m_lblOpenTrades; // PnL is split into two labels: CLabel m_lblPnLName; CLabel m_lblPnLValue; // Market Data Labels (split Bid/Ask): CLabel m_lblBidName; CLabel m_lblBidValue; CLabel m_lblAskName; CLabel m_lblAskValue; CLabel m_lblSpread; // Indicator Section Separator: CLabel m_lblIndicatorSeparator; // New header for indicator section: CLabel m_lblIndicatorHeader; // Indicator Labels (static name and dynamic value labels): CLabel m_lblRSIName; CLabel m_lblRSIValue; CLabel m_lblStochName; CLabel m_lblStochK; // %K value CLabel m_lblStochD; // %D value CLabel m_lblCCIName; CLabel m_lblCCIValue; CLabel m_lblWilliamsName; CLabel m_lblWilliamsValue; // New Summary Labels (for consensus across indicators): CLabel m_lblSignalHeader; // Header label for summary column ("SIGNAL") CLabel m_lblExpectation; // Text summary (e.g., "Buy" or "Sell") CLabel m_lblConfirmation; // Confirmation symbol (e.g., up or down arrow) // Previous values for dynamic color changes (market data): double m_prevBid; double m_prevAsk; public: CAnalyticsPanel(); virtual ~CAnalyticsPanel(); // Create the panel and initialize UI controls. virtual bool CreatePanel(const long chart, const string name, const int subwin, int x1, int y1, int x2, int y2); // Update the panel with the latest account, trade, market and indicator data. void UpdatePanel(); void Toggle(); private: void CreateControls(); void UpdateAccountInfo(); void UpdateTradeStats(); void UpdateMarketData(); void UpdateIndicators(); };
Forneci abaixo uma descrição detalhada e uma explicação para as variáveis.
Variáveis-Membro
Rótulos da Interface para Dados da Conta e das Negociações:
Rótulos da Conta:
- m_lblBalance, m_lblEquity e m_lblMargin exibem, respectivamente, o saldo da conta, o patrimônio líquido e a margem.
- m_lblOpenTrades exibe o número de negociações atualmente abertas.
- m_lblPnLName: Um rótulo estático que simplesmente exibe o texto "PnL:" (permanece na cor preta).
- m_lblPnLValue: Um rótulo dinâmico que exibe o valor numérico do PnL e altera sua cor (verde para lucro e vermelho para prejuízo).
Rótulos de Dados de Mercado:
Esses rótulos exibem os valores de bid/ask e as informações sobre o spread:
- m_lblBidName e m_lblBidValue para o preço de compra (bid).
- m_lblAskName e m_lblAskValue para o preço de venda (ask).
- m_lblSpread exibe o spread atual em pips.
- As cores dos valores de bid e ask são atualizadas dinamicamente para refletir as mudanças do mercado (por exemplo, azul quando o valor aumenta e vermelho quando diminui).
Seção de Indicadores:
- Um separador (m_lblIndicatorSeparator) distingue visualmente a seção de indicadores do restante do painel.
- Um rótulo de cabeçalho (m_lblIndicatorHeader) exibe "INDICATORS", identificando claramente a seção.
A seção inclui diversos indicadores:
- RSI: Dois rótulos, m_lblRSIName e m_lblRSIValue, exibem o nome ("RSI:") e seu valor atual.
- Oscilador Estocástico: Este indicador é dividido em duas partes:
- m_lblStochName: A parte estática ("Stoch:").
- m_lblStochK e m_lblStochD: Exibem os valores dinâmicos de %K e %D.
- CCI: m_lblCCIName e m_lblCCIValue exibem o Índice de Canal de Commodities (Commodity Channel Index).
- Williams %R: m_lblWilliamsName e m_lblWilliamsValue exibem os valores do Williams %R.
Seção de Resumo (Consenso):
- Um rótulo de cabeçalho (m_lblSignalHeader) exibe a palavra "SIGNAL" acima da coluna de resumo.
- Dois rótulos, m_lblExpectation e m_lblConfirmation, são utilizados para exibir o sinal de consenso de todos os indicadores:
- m_lblExpectation fornece um resumo em texto, como "Compra", "Venda" ou "Sem Consenso".
- m_lblConfirmation exibe uma confirmação simbólica (uma seta para cima "↑" para compra, uma seta para baixo "↓" para VENDA ou um hífen "-" caso nenhum consenso seja alcançado).
Estado Interno para Dados de Mercado:
Duas variáveis, m_prevBid e m_prevAsk, armazenam os valores anteriores de bid e ask para ajudar a determinar se esses valores estão aumentando ou diminuindo, orientando assim a codificação por cores utilizada nesses rótulos.
2. Método Auxiliar para Criação de Rótulos
Uma função utilitária central dentro da classe é CreateLabelEx, um método reutilizável para criar e personalizar rótulos de texto no painel. Esse método encapsula todas as etapas necessárias para instanciar um rótulo, atribuir-lhe um nome exclusivo, configurar seu tamanho e posição, aplicar o texto e as cores desejados e adicioná-lo à lista de controles do painel. Se qualquer etapa desse processo falhar, mensagens de erro apropriadas serão registradas para fins de depuração.
bool CAnalyticsPanel::CreateLabelEx(CLabel &label, int x, int y, int width, int height, string label_name, string text, color clr) { string unique_name = m_name + "_" + label_name; if(!label.Create(m_chart_id, unique_name, m_subwin, x, y, x+width, y+height)) { Print("Failed to create label: ", unique_name, " Err=", GetLastError()); return false; } if(!Add(label)) { Print("Failed to add label: ", unique_name, " Err=", GetLastError()); return false; } if(!label.Text(text)) { Print("Failed to set text for label: ", unique_name); return false; } label.Color(clr); // Set text color label.BackColor(clrBlack); // Force background to black return true; }
3. Organizando o Layout da Interface do Usuário
O método CreateControls organiza todos os elementos da interface do usuário no painel. Aqui organizamos diferentes seções: informações da conta (saldo, patrimônio líquido e margem), estatísticas das negociações (negociações abertas e lucro e prejuízo), dados de mercado (bid, ask e spread) e a seção de indicadores. Na seção de indicadores, criamos cabeçalhos como "INDICATORS" e "SIGNAL" para identificar claramente os grupos de informações. O código utiliza constantes predefinidas para a altura dos rótulos e os espaçamentos, garantindo que todos os elementos fiquem uniformemente distribuídos e visualmente organizados.
//+------------------------------------------------------------------+ //| CreateControls: Instantiate and add UI controls | //+------------------------------------------------------------------+ void CAnalyticsPanel::CreateControls() { int curX = AP_GAP; int curY = AP_GAP; int labelWidth = 150; // Account Information Labels: CreateLabelEx(m_lblBalance, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Balance", "Balance: $0.00", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; CreateLabelEx(m_lblEquity, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Equity", "Equity: $0.00", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; CreateLabelEx(m_lblMargin, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Margin", "Margin: 0", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Trade Statistics Labels: CreateLabelEx(m_lblOpenTrades, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "OpenTrades", "Open Trades: 0", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // PnL labels: CreateLabelEx(m_lblPnLName, curX, curY, 50, AP_DEFAULT_LABEL_HEIGHT, "PnLName", "PnL:", clrBlack); CreateLabelEx(m_lblPnLValue, curX+50, curY, labelWidth-50, AP_DEFAULT_LABEL_HEIGHT, "PnLValue", "$0.00", clrLime); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Market Data Labels: CreateLabelEx(m_lblBidName, curX, curY, 40, AP_DEFAULT_LABEL_HEIGHT, "BidName", "Bid:", clrDodgerBlue); CreateLabelEx(m_lblBidValue, curX+40, curY, 100, AP_DEFAULT_LABEL_HEIGHT, "BidValue", "0.00000", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; CreateLabelEx(m_lblAskName, curX, curY, 40, AP_DEFAULT_LABEL_HEIGHT, "AskName", "Ask:", clrDodgerBlue); CreateLabelEx(m_lblAskValue, curX+40, curY, 100, AP_DEFAULT_LABEL_HEIGHT, "AskValue", "0.00000", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; CreateLabelEx(m_lblSpread, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Spread", "Spread: 0.0 pips", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Indicator Section Separator: CreateLabelEx(m_lblIndicatorSeparator, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Separator", "------------------------------------------", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Indicator Section Header: CreateLabelEx(m_lblIndicatorHeader, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "IndicatorHeader", "INDICATORS", clrDodgerBlue); // Summary Column Header for Signal: CreateLabelEx(m_lblSignalHeader, curX+250, curY , 100, AP_DEFAULT_LABEL_HEIGHT, "SignalHeader", "SIGNAL", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Indicator Labels: // RSI: CreateLabelEx(m_lblRSIName, curX, curY, 50, AP_DEFAULT_LABEL_HEIGHT, "RSIName", "RSI:", clrDodgerBlue); CreateLabelEx(m_lblRSIValue, curX+50, curY, 90, AP_DEFAULT_LABEL_HEIGHT, "RSIValue", "N/A", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Stochastic: CreateLabelEx(m_lblStochName, curX, curY, 60, AP_DEFAULT_LABEL_HEIGHT, "StochName", "Stoch:", clrDodgerBlue); CreateLabelEx(m_lblStochK, curX+60, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "StochK", "K: N/A", clrDodgerBlue); CreateLabelEx(m_lblStochD, curX+150, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "StochD", "D: N/A", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // CCI: CreateLabelEx(m_lblCCIName, curX, curY, 50, AP_DEFAULT_LABEL_HEIGHT, "CCIName", "CCI:", clrDodgerBlue); CreateLabelEx(m_lblCCIValue, curX+50, curY, 90, AP_DEFAULT_LABEL_HEIGHT, "CCIValue", "N/A", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Williams %R: CreateLabelEx(m_lblWilliamsName, curX, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "WilliamsName", "Williams:", clrDodgerBlue); CreateLabelEx(m_lblWilliamsValue, curX+70, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "WilliamsValue", "N/A", clrDodgerBlue); curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP; // Summary Column: Expectation text and Confirmation symbol. CreateLabelEx(m_lblExpectation, curX+250, curY - (AP_DEFAULT_LABEL_HEIGHT+AP_GAP)*4, 100, AP_DEFAULT_LABEL_HEIGHT, "Expectation", "Expect: N/A", clrDodgerBlue); CreateLabelEx(m_lblConfirmation, curX+300, curY - (AP_DEFAULT_LABEL_HEIGHT+AP_GAP)*4, 50, AP_DEFAULT_LABEL_HEIGHT, "Confirmation", "N/A", clrDodgerBlue); ChartRedraw(m_chart_id); }
4. Atualizações de Dados em Tempo Real para Informações da Conta e do Mercado
Utilizando as funções integradas do MQL5, o painel recupera informações da conta, como saldo, patrimônio líquido e valor bruto da margem, bem como dados de mercado, como os preços de bid e ask e o spread. Os métodos UpdateAccountInfo e UpdateTradeStats consultam diretamente a conta utilizando funções como AccountInfoDouble(). Enquanto isso, UpdateMarketData obtém dados de ticks em tempo real usando SymbolInfoTick(), compara os valores atuais com os anteriores e atualiza a codificação por cores dos rótulos de bid e ask com base nas alterações. Isso permite que os traders visualizem o estado mais recente da conta e do mercado à medida que as mudanças ocorrem.
//+------------------------------------------------------------------+ //| UpdateAccountInfo: Refresh account-related data | //+------------------------------------------------------------------+ void CAnalyticsPanel::UpdateAccountInfo() { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double equity = AccountInfoDouble(ACCOUNT_EQUITY); double margin = AccountInfoDouble(ACCOUNT_MARGIN); m_lblBalance.Text("Balance: $" + DoubleToString(balance, 2)); m_lblEquity.Text("Equity: $" + DoubleToString(equity, 2)); // Directly display the raw margin value. m_lblMargin.Text("Margin: " + DoubleToString(margin, 2)); } //+------------------------------------------------------------------+ //| UpdateTradeStats: Refresh trade statistics | //+------------------------------------------------------------------+ void CAnalyticsPanel::UpdateTradeStats() { int total = PositionsTotal(); double pnl = 0; for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(ticket != 0) pnl += PositionGetDouble(POSITION_PROFIT); } // Update PnL labels: m_lblPnLName.Text("PnL:"); // static remains black m_lblPnLValue.Text("$" + DoubleToString(pnl, 2)); if(pnl < 0) m_lblPnLValue.Color(clrRed); else m_lblPnLValue.Color(clrLime); m_lblOpenTrades.Text("Open Trades: " + IntegerToString(total)); } //+------------------------------------------------------------------+ //| UpdateMarketData: Refresh market data display | //+------------------------------------------------------------------+ void CAnalyticsPanel::UpdateMarketData() { MqlTick last_tick; if(SymbolInfoTick(Symbol(), last_tick)) { // Update Bid value and color based on change: color bidColor = clrBlue; if(m_prevBid != 0) bidColor = (last_tick.bid >= m_prevBid) ? clrBlue : clrRed; m_lblBidValue.Color(bidColor); m_lblBidValue.Text(DoubleToString(last_tick.bid, 5)); // Update Ask value and color based on change: color askColor = clrBlue; if(m_prevAsk != 0) askColor = (last_tick.ask >= m_prevAsk) ? clrBlue : clrRed; m_lblAskValue.Color(askColor); m_lblAskValue.Text(DoubleToString(last_tick.ask, 5)); m_prevBid = last_tick.bid; m_prevAsk = last_tick.ask; // Update Spread: double spread_pips = (last_tick.ask - last_tick.bid) * 1e4; m_lblSpread.Text("Spread: " + DoubleToString(spread_pips, 1) + " pips"); } }
5. Calculando Indicadores Técnicos e Gerando um Sinal de Consenso
O método UpdateIndicators recupera os valores de diversos indicadores técnicos, como RSI, Estocástico, CCI e Williams %R, chamando as funções dos indicadores e lendo seus dados mais recentes. O valor de cada indicador é comparado com limites predefinidos para determinar se ele sugere uma condição de compra ou de venda. Por exemplo, um RSI abaixo de 30 é interpretado como um sinal de compra, enquanto um valor acima de 70 sugere venda. Em seguida, o painel consolida esses sinais individuais em um consenso geral. Se todos os indicadores concordarem, um sinal claro de "Compra" ou "Venda" será exibido na seção de resumo juntamente com um símbolo de seta. Isso fornece aos traders uma indicação visual rápida das condições do mercado.
//+------------------------------------------------------------------+ //| UpdateIndicators: Calculate and display various indicators | //+------------------------------------------------------------------+ void CAnalyticsPanel::UpdateIndicators() { // Local suggestion variables (1 = Buy, -1 = Sell, 0 = Neutral) int suggestionRSI = 0, suggestionStoch = 0, suggestionCCI = 0, suggestionWilliams = 0; // --- RSI --- int handleRSI = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE); double rsi[1]; color rsiValueColor = clrGreen; // default if(CopyBuffer(handleRSI, 0, 0, 1, rsi) > 0) { if(rsi[0] < 30) { rsiValueColor = clrBlue; // buy condition suggestionRSI = 1; } else if(rsi[0] > 70) { rsiValueColor = clrRed; // sell condition suggestionRSI = -1; } m_lblRSIValue.Color(rsiValueColor); m_lblRSIValue.Text(DoubleToString(rsi[0], 2)); } IndicatorRelease(handleRSI); // --- Stochastic --- int handleStoch = iStochastic(Symbol(), PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH); double stochK[1], stochD[1]; if(CopyBuffer(handleStoch, 0, 0, 1, stochK) > 0 && CopyBuffer(handleStoch, 1, 0, 1, stochD) > 0) { // Initialize color variables. color colorK = clrGreen; color colorD = clrGreen; if(stochK[0] > stochD[0]) { colorK = clrBlue; colorD = clrRed; suggestionStoch = 1; } else if(stochK[0] < stochD[0]) { colorK = clrRed; colorD = clrBlue; suggestionStoch = -1; } else suggestionStoch = 0; m_lblStochK.Color(colorK); m_lblStochD.Color(colorD); m_lblStochK.Text("K: " + DoubleToString(stochK[0], 4)); m_lblStochD.Text("D: " + DoubleToString(stochD[0], 4)); } IndicatorRelease(handleStoch); // --- CCI --- int handleCCI = iCCI(Symbol(), PERIOD_CURRENT, 14, PRICE_TYPICAL); double cci[1]; color cciValueColor = clrGreen; if(CopyBuffer(handleCCI, 0, 0, 1, cci) > 0) { if(cci[0] < -100) { cciValueColor = clrBlue; // buy condition suggestionCCI = 1; } else if(cci[0] > 100) { cciValueColor = clrRed; // sell condition suggestionCCI = -1; } m_lblCCIValue.Color(cciValueColor); m_lblCCIValue.Text(DoubleToString(cci[0], 2)); } IndicatorRelease(handleCCI); // --- Williams %R --- int handleWPR = iWPR(Symbol(), PERIOD_CURRENT, 14); double williams[1]; color williamsValueColor = clrGreen; if(CopyBuffer(handleWPR, 0, 0, 1, williams) > 0) { if(williams[0] > -80) { williamsValueColor = clrBlue; // buy condition suggestionWilliams = 1; } else if(williams[0] < -20) { williamsValueColor = clrRed; // sell condition suggestionWilliams = -1; } m_lblWilliamsValue.Color(williamsValueColor); m_lblWilliamsValue.Text(DoubleToString(williams[0], 2)); } IndicatorRelease(handleWPR); // --- Consensus Summary --- int consensus = 0; if(suggestionRSI != 0 && suggestionRSI == suggestionStoch && suggestionRSI == suggestionCCI && suggestionRSI == suggestionWilliams) consensus = suggestionRSI; if(consensus == 1) { m_lblExpectation.Text("Buy"); m_lblExpectation.Color(clrBlue); m_lblConfirmation.Text("↑"); // Up arrow for Buy m_lblConfirmation.Color(clrBlue); } else if(consensus == -1) { m_lblExpectation.Text("Sell"); m_lblExpectation.Color(clrRed); m_lblConfirmation.Text("↓"); // Down arrow for Sell m_lblConfirmation.Color(clrRed); } else { m_lblExpectation.Text("No Consensus"); m_lblExpectation.Color(clrOrangeRed); m_lblConfirmation.Text("-"); m_lblConfirmation.Color(clrOrangeRed); } }
Integrando a CAnalyticsPanel ao Painel Principal de Administração
1. Na parte superior do arquivo do EA, o arquivo de cabeçalho AnalyticsPanel.mqh é incluído para FORNECER acesso à classe CAnalyticsPanel:
#include <AnalyticsPanel.mqh> Isso garante que o compilador reconheça a classe e seus membros durante a compilação.
2. Declarando um Ponteiro Global
É declarado um ponteiro global do tipo CAnalyticsPanel, que será utilizado para gerenciar dinamicamente a instância do painel:
CAnalyticsPanel *g_analyticsPanel = NULL; Esse ponteiro ajuda a controlar se o painel existe e permite sua criação, destruição e alternância de visibilidade de forma dinâmica.
3. Criando um Botão para Abrir o Painel
Na função CreateAdminPanel(), é criado um botão com o rótulo "Analytics Panel", que é adicionado ao painel principal de administração. Esse botão serve como acionador para que o usuário abra o painel.
bool CreateAdminPanel() { // Analytics Panel Button if(!CreateButton(g_analyticsButton, ANALYTICS_BTN_NAME, INDENT_LEFT, y, INDENT_LEFT+btnWidth, y+BUTTON_HEIGHT, "Analytics Panel")) return false; return true; }
4. Tratando os Eventos de Clique do Botão
A função HandleAnalytics() é responsável por gerenciar o ciclo de vida do painel. Ela verifica se o painel já foi criado. Caso contrário, instancia a CAnalyticsPanel, chama seu método CreatePanel() com as coordenadas de posicionamento e alterna sua visibilidade. Caso contrário, apenas alterna o painel entre visível e oculto.
//------------------------------------------------------------------ // Handle Analytics Panel button click void HandleAnalytics() { if(g_analyticsPanel == NULL) { g_analyticsPanel = new CAnalyticsPanel(); // Coordinates for Analytics panel (adjust as needed) if(!g_analyticsPanel.CreatePanel(g_chart_id, "AnalyticsPanel", g_subwin, 900, 20, 900+500, 20+460)) { delete g_analyticsPanel; g_analyticsPanel = NULL; Print("Failed to create Analytics Panel"); return; } } g_analyticsPanel.Toggle(); ChartRedraw(); }
5. Encaminhamento de Eventos
Na função AdminPanelOnEvent(), eventos como cliques ou interações do usuário são encaminhados para o g_analyticsPanel, caso ele esteja visível. Isso garante que o painel possa responder de forma independente às ações do usuário, sem entrar em conflito com o painel principal ou com outros subpainéis.
if(g_analyticsPanel != NULL && g_analyticsPanel.IsVisible()) return g_analyticsPanel.OnEvent(id, lparam, dparam, sparam);
6. Atualizando o Painel Dinamicamente
Dentro da função OnTick(), se o painel de análises existir, seu método UpdatePanel() será chamado regularmente. Isso permite que o painel atualize dinamicamente as análises exibidas ou o conteúdo da interface durante a execução do EA.
void OnTick() { if(g_analyticsPanel != NULL) { g_analyticsPanel.UpdatePanel(); } }
7. Limpeza
Na função OnDeinit(), o painel é corretamente destruído e a memória é liberada chamando Destroy() e excluindo o ponteiro. Isso é essencial para evitar vazamentos de memória quando o EA for removido ou recompilado.
Testes
Tive uma experiência de testes incrível. Parecia quase ao vivo, observando os valores sendo atualizados no painel a cada tick. Consegui realizar uma negociação utilizando a estratégia de confluência, mas, infelizmente, quando comecei a gravar, o sinal já havia mudado para "Sem Consenso". Mesmo assim, estou muito feliz em compartilhar os resultados. Veja a imagem abaixo!

Demonstração do funcionamento do AnalyticsPanel
Na imagem acima, o valor de Open Trades foi atualizado a cada encerramento de posição. Começamos com 21 posições e concluímos com 18.

Todos os painéis são acessíveis a partir do painel principal
Conclusão
Expandimos com sucesso o nosso programa integrando o Analytics Panel. Essa adição demonstra que muitos outros subpainéis podem ser incorporados utilizando a mesma abordagem modular aplicada aos demais painéis. Esta discussão marca a conclusão da Parte (IX) da série. No entanto, isso não significa que o trabalho esteja concluído. Ainda existem diversas áreas que podem ser aprimoradas. Dito isso, o conceito principal agora está bem estabelecido e claramente apresentado.
Tanto iniciantes quanto desenvolvedores experientes podem se beneficiar desta série em diferentes níveis. Há muitas observações valiosas que podem ser aproveitadas. Essas ideias estabelecem uma base sólida para desenvolvimentos ainda mais avançados no futuro.
Nos resultados apresentados, eu havia desenhado linhas de canal no gráfico e, coincidentemente, um sinal de compra foi gerado pelo Analytics Panel. Esse sinal foi resultado da confluência de todos os indicadores listados, alinhando-se perfeitamente à zona de suporte do canal. Realizei a negociação com confiança com base nessa estratégia de confluência. O teste foi realizado em uma conta demo. Como sempre, recomendo fortemente que todos os traders testem exaustivamente em uma conta demo antes de arriscar dinheiro real.
O ponto forte dessa configuração é que os traders podem obter acesso imediato a informações essenciais do mercado e da conta por meio do painel de análises, ao mesmo tempo em que se beneficiam do poder analítico do sinal baseado em confluência. Uma área que ainda pode ser aprimorada é a ausência de alertas para a estratégia. A adição de notificações tornaria o sistema ainda mais amigável ao usuário e garantiria que nenhuma oportunidade fosse perdida.
Tanto o arquivo de cabeçalho quanto o programa principal estão anexados abaixo. Não deixe de compartilhar sua opinião na seção de comentários. Até a próxima publicação. Bom desenvolvimento e ótimas negociações!
| Nome do Arquivo | Especificação |
|---|---|
| AnalyticsPanel.mqh | Um arquivo de cabeçalho que define a estrutura e o comportamento do Painel de Análises, que agrega múltiplos indicadores para gerar sinais de negociação baseados em confluência. |
| New_Admin_Panel.mqh | O programa principal do EA em MQL5 que inicializa e gerencia toda a interface do painel de administração, incluindo navegação, autenticação e integração de diversos subpainéis, como Comunicações, Análises e Gerenciamento de Negociações. |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/17397
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.
Caminhe em novos trilhos: Personalize indicadores no MQL5
Redes neurais no trading: uma visão unificada sobre espaço e tempo (Global-Local Attention)
Está chegando o novo MetaTrader 5 e MQL5
Algoritmo de otimização do dingo - Dingo Optimization Algorithm (DOA)
- 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