Ferramentas de Trading em MQL5 (Parte 3): Construindo um Painel de Scanner Multitemporal para Negociação Estratégica
Introdução
Em nosso artigo anterior, Parte 2, aprimoramos uma ferramenta de assistência à negociação desenvolvida em MetaQuotes Language 5 (MQL5), adicionando feedback visual dinâmico para melhorar a interatividade. Agora, nosso foco será desenvolver um painel de scanner multitemporal capaz de fornecer sinais de negociação em tempo real para fornecer sinais para a tomada de decisão estratégicas. Apresentaremos uma interface baseada em grade, com sinais gerados por indicadores e um botão de fechamento, abordando esses avanços nos seguintes tópicos:
Essas seções nos orientarão no desenvolvimento de um painel de scanner multitemporal intuitivo e robusto.
Plano do Painel de Scanner
Nosso objetivo é criar um painel de scanner multitemporal que forneça sinais de negociação claros e em tempo real, aprimorando a tomada de decisões estratégicas. O painel terá uma estrutura em grade, exibindo sinais de compra e venda em diferentes tempos gráficos, permitindo avaliar rapidamente as condições do mercado sem precisar alternar entre gráficos. Também incluiremos um botão de fechamento para permitir que o painel seja ocultado facilmente, garantindo uma experiência de uso organizada e flexível, adaptada às nossas necessidades de negociação.
Incorporaremos sinais de indicadores importantes, incluindo o Índice de Força Relativa (RSI), o Oscilador Estocástico (STOCH), o Índice de Canal de Commodities (CCI), o Índice Direcional Médio (ADX) e o Awesome Oscillator (AO), concebidos para identificar possíveis oportunidades de negociação com limites de intensidade personalizáveis. No entanto, a escolha dos indicadores ou da leitura da ação do preço fica a seu critério. Essa configuração nos ajudará a identificar tendências e reversões em diferentes tempos gráficos, oferecendo suporte tanto para estratégias de curto quanto de longo prazo. Nosso objetivo é desenvolver uma ferramenta otimizada e intuitiva, que forneça informações práticas para orientar decisões e seja fácil de utilizar, abrindo caminho para futuras melhorias, como alertas automatizados ou indicadores adicionais. Abaixo, apresentamos uma visualização do que pretendemos construir.

Implementação em MQL5
Para desenvolver o programa em MQL5, precisaremos definir os metadados do programa e, em seguida, algumas constantes para os nomes dos objetos, que nos ajudarão a referenciar e gerenciar facilmente os elementos do painel.
//+------------------------------------------------------------------+ //| TimeframeScanner Dashboard EA.mq5 | //| Copyright 2025, Allan Munene Mutiiria. | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Allan Munene Mutiiria." #property link "https://t.me/Forex_Algo_Trader" #property version "1.00" // Define identifiers and properties for UI elements #define MAIN_PANEL "PANEL_MAIN" //--- Main panel rectangle identifier #define HEADER_PANEL "PANEL_HEADER" //--- Header panel rectangle identifier #define HEADER_PANEL_ICON "PANEL_HEADER_ICON" //--- Header icon label identifier #define HEADER_PANEL_TEXT "PANEL_HEADER_TEXT" //--- Header title label identifier #define CLOSE_BUTTON "BUTTON_CLOSE" //--- Close button identifier #define SYMBOL_RECTANGLE "SYMBOL_HEADER" //--- Symbol rectangle identifier #define SYMBOL_TEXT "SYMBOL_TEXT" //--- Symbol text label identifier #define TIMEFRAME_RECTANGLE "TIMEFRAME_" //--- Timeframe rectangle prefix #define TIMEFRAME_TEXT "TIMEFRAME_TEXT_" //--- Timeframe text label prefix #define HEADER_RECTANGLE "HEADER_" //--- Header rectangle prefix #define HEADER_TEXT "HEADER_TEXT_" //--- Header text label prefix #define RSI_RECTANGLE "RSI_" //--- RSI rectangle prefix #define RSI_TEXT "RSI_TEXT_" //--- RSI text label prefix #define STOCH_RECTANGLE "STOCH_" //--- Stochastic rectangle prefix #define STOCH_TEXT "STOCH_TEXT_" //--- Stochastic text label prefix #define CCI_RECTANGLE "CCI_" //--- CCI rectangle prefix #define CCI_TEXT "CCI_TEXT_" //--- CCI text label prefix #define ADX_RECTANGLE "ADX_" //--- ADX rectangle prefix #define ADX_TEXT "ADX_TEXT_" //--- ADX text label prefix #define AO_RECTANGLE "AO_" //--- AO rectangle prefix #define AO_TEXT "AO_TEXT_" //--- AO text label prefix #define BUY_RECTANGLE "BUY_" //--- Buy rectangle prefix #define BUY_TEXT "BUY_TEXT_" //--- Buy text label prefix #define SELL_RECTANGLE "SELL_" //--- Sell rectangle prefix #define SELL_TEXT "SELL_TEXT_" //--- Sell text label prefix #define WIDTH_TIMEFRAME 90 //--- Width of timeframe and symbol rectangles #define WIDTH_INDICATOR 70 //--- Width of indicator rectangles #define WIDTH_SIGNAL 90 //--- Width of BUY/SELL signal rectangles #define HEIGHT_RECTANGLE 25 //--- Height of all rectangles #define COLOR_WHITE clrWhite //--- White color for text and backgrounds #define COLOR_BLACK clrBlack //--- Black color for borders and text #define COLOR_LIGHT_GRAY C'230,230,230' //--- Light gray color for signal backgrounds #define COLOR_DARK_GRAY C'105,105,105' //--- Dark gray color for indicator backgrounds
Começaremos estabelecendo a estrutura da interface do usuário para nosso painel de scanner multitemporal, utilizando a diretiva #define para criar constantes como "MAIN_PANEL" e "HEADER_PANEL", que representam os retângulos do painel principal e do cabeçalho, além de "HEADER_PANEL_ICON", "HEADER_PANEL_TEXT" e "CLOSE_BUTTON", correspondentes ao ícone, ao título e ao botão de fechamento do cabeçalho.
Definiremos identificadores para a estrutura em grade do painel. Para o símbolo, utilizaremos "SYMBOL_RECTANGLE" e "SYMBOL_TEXT", enquanto os prefixos "TIMEFRAME_RECTANGLE" e "TIMEFRAME_TEXT" serão responsáveis pelas linhas dos tempos gráficos. Utilizaremos os prefixos "HEADER_RECTANGLE" e "HEADER_TEXT" para os cabeçalhos das colunas, além de prefixos como "RSI_RECTANGLE", "STOCH_RECTANGLE" e "BUY_RECTANGLE", com seus correspondentes "RSI_TEXT", "STOCH_TEXT" e "BUY_TEXT", para as células dos indicadores e dos sinais.
Configuraremos as dimensões utilizando "WIDTH_TIMEFRAME" (90 pixels), "WIDTH_INDICATOR" (70 pixels), "WIDTH_SIGNAL" (90 pixels) e "HEIGHT_RECTANGLE" (25 pixels). Definiremos as cores utilizando "COLOR_WHITE" e "COLOR_BLACK" para textos e bordas, "COLOR_LIGHT_GRAY" ("C'230,230,230'") para os fundos dos sinais e "COLOR_DARK_GRAY" ("C'105,105,105'") para os indicadores, garantindo uma disposição uniforme e clara dos elementos. Em seguida, precisaremos definir algumas variáveis globais adicionais que utilizaremos ao longo do programa.
bool panel_is_visible = true; //--- Flag to control panel visibility // Define the timeframes to be used ENUM_TIMEFRAMES timeframes_array[] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M20, PERIOD_M30, PERIOD_H1, PERIOD_H2, PERIOD_H3, PERIOD_H4, PERIOD_H8, PERIOD_H12, PERIOD_D1, PERIOD_W1}; //--- Array of timeframes for scanning // Global variables for indicator values double rsi_values[]; //--- Array to store RSI values double stochastic_values[]; //--- Array to store Stochastic signal line values double cci_values[]; //--- Array to store CCI values double adx_values[]; //--- Array to store ADX values double ao_values[]; //--- Array to store AO values
Aqui, declaramos a variável booleana "panel_is_visible" e atribuímos a ela o valor true, que determina se o painel será exibido no gráfico. Essa variável de controle permite alternar a visibilidade do painel conforme necessário, especialmente quando não precisamos atualizar os dados. Em seguida, definimos o array "timeframes_array" utilizando o tipo ENUM_TIMEFRAMES, listando os tempos gráficos de "PERIOD_M1" (1 minuto) até "PERIOD_W1" (semanal). Esse array especifica os tempos gráficos que serão analisados pelo painel, permitindo monitorar os sinais do mercado em diferentes horizontes temporais de maneira estruturada. Se você não precisar de alguns desses períodos ou quiser ajustá-los, basta modificar os valores da enumeração.
Para armazenar os dados dos indicadores, criamos os arrays do tipo double "rsi_values", "stochastic_values", "cci_values", "adx_values" e "ao_values". Esses arrays armazenam, respectivamente, os valores calculados do Índice de Força Relativa, do Oscilador Estocástico, do Índice de Canal de Commodities (CCI), do Índice Direcional Médio e do Awesome Oscillator, permitindo processar e exibir com eficiência os sinais de negociação de cada período gráfico. Agora, para definir funções auxiliares para formatar os nomes dos timeframes e tratar o símbolo obtido do gráfico, conforme apresentado a seguir.
//+------------------------------------------------------------------+ //| Truncate timeframe enum to display string | //+------------------------------------------------------------------+ string truncate_timeframe_name(int timeframe_index) //--- Function to format timeframe name { string timeframe_string = StringSubstr(EnumToString(timeframes_array[timeframe_index]), 7); //--- Extract timeframe name return timeframe_string; //--- Return formatted name } //+------------------------------------------------------------------+ //| Calculate signal strength for buy/sell | //+------------------------------------------------------------------+ string calculate_signal_strength(double rsi, double stochastic, double cci, double adx, double ao, bool is_buy) //--- Function to compute signal strength { int signal_strength = 0; //--- Initialize signal strength counter if(is_buy && rsi < 40) signal_strength++; //--- Increment for buy if RSI is oversold else if(!is_buy && rsi > 60) signal_strength++; //--- Increment for sell if RSI is overbought if(is_buy && stochastic < 40) signal_strength++; //--- Increment for buy if Stochastic is oversold else if(!is_buy && stochastic > 60) signal_strength++; //--- Increment for sell if Stochastic is overbought if(is_buy && cci < -70) signal_strength++; //--- Increment for buy if CCI is oversold else if(!is_buy && cci > 70) signal_strength++; //--- Increment for sell if CCI is overbought if(adx > 40) signal_strength++; //--- Increment if ADX indicates strong trend if(is_buy && ao > 0) signal_strength++; //--- Increment for buy if AO is positive else if(!is_buy && ao < 0) signal_strength++; //--- Increment for sell if AO is negative if(signal_strength >= 3) return is_buy ? "Strong Buy" : "Strong Sell"; //--- Return strong signal if 3+ conditions met if(signal_strength >= 2) return is_buy ? "Buy" : "Sell"; //--- Return regular signal if 2 conditions met return "Neutral"; //--- Return neutral if insufficient conditions }
Aqui, definimos a função "truncate_timeframe_name", que recebe um parâmetro inteiro chamado "timeframe_index" para formatar os nomes dos tempos gráficos que serão exibidos. Dentro dela, utilizamos a função StringSubstr para extrair uma substring do resultado retornado pela função EnumToString, aplicada a "timeframes_array[timeframe_index]", começando na posição 7, e armazenamos o resultado em "timeframe_string". Em seguida, retornamos "timeframe_string", fornecendo um nome de período gráfico limpo e facilmente compreensível pelo usuário.
Criamos a função "calculate_signal_strength" para determinar os sinais de compra ou venda com base nos valores dos indicadores. Inicializamos a variável inteira "signal_strength" com zero para contar quantas condições são atendidas. Para o Índice de Força Relativa, incrementamos "signal_strength" se "is_buy" for true e "rsi" estiver abaixo de 40 (sobrevenda), ou se "is_buy" for false e "rsi" estiver acima de 60 (sobrecompra). Da mesma forma, verificamos "stochastic" (abaixo de 40 ou acima de 60), "CCI" (abaixo de -70 ou acima de 70) e "ao" (positivo para compra e negativo para venda), incrementando "signal_strength" para cada condição atendida.
Também avaliamos o Índice Direcional Médio, incrementando "signal_strength" se "adx" ultrapassar 40, indicando uma tendência forte tanto nos cenários de compra quanto nos de venda. Se "signal_strength" atingir 3 ou mais, retornaremos “Strong Buy” quando "is_buy" for true, ou “Strong Sell” caso contrário. Se o valor for 2, retornaremos “Buy” ou “Sell”; para valores inferiores, retornaremos “Neutral”, permitindo uma classificação clara dos sinais no painel. Por fim, podemos definir as funções que permitirão criar os objetos.
//+------------------------------------------------------------------+ //| Create a rectangle for the UI | //+------------------------------------------------------------------+ bool create_rectangle(string object_name, int x_distance, int y_distance, int x_size, int y_size, color background_color, color border_color = COLOR_BLACK) //--- Function to create a rectangle { ResetLastError(); //--- Reset error code if(!ObjectCreate(0, object_name, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { //--- Create rectangle object Print(__FUNCTION__, ": failed to create Rectangle: ERR Code: ", GetLastError()); //--- Log creation failure return(false); //--- Return failure } ObjectSetInteger(0, object_name, OBJPROP_XDISTANCE, x_distance); //--- Set x position ObjectSetInteger(0, object_name, OBJPROP_YDISTANCE, y_distance); //--- Set y position ObjectSetInteger(0, object_name, OBJPROP_XSIZE, x_size); //--- Set width ObjectSetInteger(0, object_name, OBJPROP_YSIZE, y_size); //--- Set height ObjectSetInteger(0, object_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER); //--- Set corner to top-right ObjectSetInteger(0, object_name, OBJPROP_BGCOLOR, background_color); //--- Set background color ObjectSetInteger(0, object_name, OBJPROP_BORDER_COLOR, border_color); //--- Set border color ObjectSetInteger(0, object_name, OBJPROP_BORDER_TYPE, BORDER_FLAT); //--- Set flat border style ObjectSetInteger(0, object_name, OBJPROP_BACK, false); //--- Set to foreground ChartRedraw(0); //--- Redraw chart return(true); //--- Return success } //+------------------------------------------------------------------+ //| Create a text label for the UI | //+------------------------------------------------------------------+ bool create_label(string object_name, string text, int x_distance, int y_distance, int font_size = 12, color text_color = COLOR_BLACK, string font = "Arial Rounded MT Bold") //--- Function to create a label { ResetLastError(); //--- Reset error code if(!ObjectCreate(0, object_name, OBJ_LABEL, 0, 0, 0)) { //--- Create label object Print(__FUNCTION__, ": failed to create Label: ERR Code: ", GetLastError()); //--- Log creation failure return(false); //--- Return failure } ObjectSetInteger(0, object_name, OBJPROP_XDISTANCE, x_distance); //--- Set x position ObjectSetInteger(0, object_name, OBJPROP_YDISTANCE, y_distance); //--- Set y position ObjectSetInteger(0, object_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER); //--- Set corner to top-right ObjectSetString(0, object_name, OBJPROP_TEXT, text); //--- Set label text ObjectSetString(0, object_name, OBJPROP_FONT, font); //--- Set font ObjectSetInteger(0, object_name, OBJPROP_FONTSIZE, font_size); //--- Set font size ObjectSetInteger(0, object_name, OBJPROP_COLOR, text_color); //--- Set text color ObjectSetInteger(0, object_name, OBJPROP_ANCHOR, ANCHOR_CENTER); //--- Center text ChartRedraw(0); //--- Redraw chart return(true); //--- Return success }
Para permitir a criação dos objetos, definimos a função "create_rectangle" com os parâmetros "object_name", "x_distance", "y_distance", "x_size", "y_size", "background_color" e "border_color". Utilizamos a função ResetLastError, criamos um objeto do tipo OBJ_RECTANGLE_LABEL por meio da função ObjectCreate e, caso a criação falhe, registramos o erro utilizando a função "Print" e retornamos false.
Definimos as propriedades do retângulo utilizando a função ObjectSetInteger para configurar a posição, as dimensões, "CORNER_RIGHT_UPPER", "background_color", "border_color" e "BORDER_FLAT", garantindo que o objeto seja exibido em primeiro plano. Em seguida, utilizamos a função ChartRedraw e retornamos true. Para os textos, definimos a função "create_label" com os parâmetros "object_name", "text", "x_distance", "y_distance", "font_size", "text_color" e "font".
Utilizamos a função "ResetLastError", criamos um objeto do tipo "OBJ_LABEL" por meio da função "ObjectCreate" e registramos os erros caso a criação falhe. Utilizamos a função "ObjectSetInteger" para configurar a posição, o tamanho, a cor e "ANCHOR_CENTER", e a função ObjectSetString para definir "text" e "font". Em seguida, utilizamos a função "ChartRedraw" e retornamos true. Com essas funções disponíveis, podemos criar os objetos iniciais do painel, estabelecendo um ponto de partida no manipulador de eventos "OnInit".
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() //--- Initialize EA { create_rectangle(MAIN_PANEL, 632, 40, 617, 374, C'30,30,30', BORDER_FLAT); //--- Create main panel background create_rectangle(HEADER_PANEL, 632, 40, 617, 27, C'60,60,60', BORDER_FLAT); //--- Create header panel background create_label(HEADER_PANEL_ICON, CharToString(91), 620, 54, 18, clrAqua, "Wingdings"); //--- Create header icon create_label(HEADER_PANEL_TEXT, "TimeframeScanner", 527, 52, 13, COLOR_WHITE); //--- Create header title create_label(CLOSE_BUTTON, CharToString('r'), 32, 54, 18, clrYellow, "Webdings"); //--- Create close button // Create header rectangle and label create_rectangle(SYMBOL_RECTANGLE, 630, 75, WIDTH_TIMEFRAME, HEIGHT_RECTANGLE, clrGray); //--- Create symbol rectangle create_label(SYMBOL_TEXT, _Symbol, 585, 85, 11, COLOR_WHITE); //--- Create symbol label // Create summary and indicator headers (rectangles and labels) string header_names[] = {"BUY", "SELL", "RSI", "STOCH", "CCI", "ADX", "AO"}; //--- Define header titles for(int header_index = 0; header_index < ArraySize(header_names); header_index++) { //--- Loop through headers int x_offset = (630 - WIDTH_TIMEFRAME) - (header_index < 2 ? header_index * WIDTH_SIGNAL : 2 * WIDTH_SIGNAL + (header_index - 2) * WIDTH_INDICATOR) + (1 + header_index); //--- Calculate x position int width = (header_index < 2 ? WIDTH_SIGNAL : WIDTH_INDICATOR); //--- Set width based on header type create_rectangle(HEADER_RECTANGLE + IntegerToString(header_index), x_offset, 75, width, HEIGHT_RECTANGLE, clrGray); //--- Create header rectangle create_label(HEADER_TEXT + IntegerToString(header_index), header_names[header_index], x_offset - width/2, 85, 11, COLOR_WHITE); //--- Create header label } // Create timeframe rectangles and labels, and summary/indicator cells for(int timeframe_index = 0; timeframe_index < ArraySize(timeframes_array); timeframe_index++) { //--- Loop through timeframes // Highlight current timeframe color timeframe_background = (timeframes_array[timeframe_index] == _Period) ? clrLimeGreen : clrGray; //--- Set background color for current timeframe color timeframe_text_color = (timeframes_array[timeframe_index] == _Period) ? COLOR_BLACK : COLOR_WHITE; //--- Set text color for current timeframe create_rectangle(TIMEFRAME_RECTANGLE + IntegerToString(timeframe_index), 630, (75 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), WIDTH_TIMEFRAME, HEIGHT_RECTANGLE, timeframe_background); //--- Create timeframe rectangle create_label(TIMEFRAME_TEXT + IntegerToString(timeframe_index), truncate_timeframe_name(timeframe_index), 585, (85 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), 11, timeframe_text_color); //--- Create timeframe label // Create summary and indicator cells for(int header_index = 0; header_index < ArraySize(header_names); header_index++) { //--- Loop through headers for cells string cell_rectangle_name, cell_text_name; //--- Declare cell name and label variables color cell_background = (header_index < 2) ? COLOR_LIGHT_GRAY : COLOR_BLACK; //--- Set cell background color switch(header_index) { //--- Select cell type case 0: cell_rectangle_name = BUY_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = BUY_TEXT + IntegerToString(timeframe_index); break; //--- Buy cell case 1: cell_rectangle_name = SELL_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = SELL_TEXT + IntegerToString(timeframe_index); break; //--- Sell cell case 2: cell_rectangle_name = RSI_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = RSI_TEXT + IntegerToString(timeframe_index); break; //--- RSI cell case 3: cell_rectangle_name = STOCH_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = STOCH_TEXT + IntegerToString(timeframe_index); break; //--- Stochastic cell case 4: cell_rectangle_name = CCI_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = CCI_TEXT + IntegerToString(timeframe_index); break; //--- CCI cell case 5: cell_rectangle_name = ADX_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = ADX_TEXT + IntegerToString(timeframe_index); break; //--- ADX cell case 6: cell_rectangle_name = AO_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = AO_TEXT + IntegerToString(timeframe_index); break; //--- AO cell } int x_offset = (630 - WIDTH_TIMEFRAME) - (header_index < 2 ? header_index * WIDTH_SIGNAL : 2 * WIDTH_SIGNAL + (header_index - 2) * WIDTH_INDICATOR) + (1 + header_index); //--- Calculate x position int width = (header_index < 2 ? WIDTH_SIGNAL : WIDTH_INDICATOR); //--- Set width based on cell type create_rectangle(cell_rectangle_name, x_offset, (75 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), width, HEIGHT_RECTANGLE, cell_background); //--- Create cell rectangle create_label(cell_text_name, "-/-", x_offset - width/2, (85 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), 10, COLOR_WHITE); //--- Create cell label } } // Initialize indicator arrays ArraySetAsSeries(rsi_values, true); //--- Set RSI array as timeseries ArraySetAsSeries(stochastic_values, true); //--- Set Stochastic array as timeseries ArraySetAsSeries(cci_values, true); //--- Set CCI array as timeseries ArraySetAsSeries(adx_values, true); //--- Set ADX array as timeseries ArraySetAsSeries(ao_values, true); //--- Set AO array as timeseries return(INIT_SUCCEEDED); //--- Return initialization success }
No manipulador de eventos OnInit, inicializamos a interface do usuário do painel de scanner multitemporal. Utilizamos a função "create_rectangle" para desenhar o "MAIN_PANEL" na posição (632, 40), com dimensões de 617x374 pixels e cor “C’30,30,30’”, e o "HEADER_PANEL" na mesma posição, com altura de 27 pixels e cor “C’60,60,60’”. Utilizamos a função "create_label" para adicionar o "HEADER_PANEL_ICON" com um caractere da fonte Wingdings na posição (620, 54). Utilizamos os caracteres padrão do MQL5 e a função CharToString para converter o código do caractere em uma string. O código do caractere que utilizamos é 91, mas você pode escolher qualquer outro de sua preferência.

Em seguida, criamos o "HEADER_PANEL_TEXT" com o texto “TimeframeScanner” na posição (527, 52) e o "CLOSE_BUTTON" na posição (32, 54). Desta vez, porém, utilizamos uma fonte diferente e convertemos a letra "r" em string. Abaixo, apresentamos uma visualização dos diferentes símbolos de fonte que você pode utilizar.

Configuramos a exibição do símbolo utilizando a função "create_rectangle" para criar o "SYMBOL_RECTANGLE" na posição (630, 75), com dimensões definidas por "WIDTH_TIMEFRAME" e "HEIGHT_RECTANGLE", na cor cinza. Utilizamos a função "create_label" para posicionar o "SYMBOL_TEXT" em (585, 85), exibindo o símbolo atual. Para os cabeçalhos, definimos o array "header_names" com títulos como “BUY” e “RSI” e percorremos seus elementos em um laço para criar os objetos "HEADER_RECTANGLE" na coordenada y=75, com deslocamentos horizontais baseados em "WIDTH_SIGNAL" e "WIDTH_INDICATOR", além dos rótulos "HEADER_TEXT" na coordenada y=85, utilizando a função "create_label".
Construímos a grade dos tempos gráficos percorrendo o array "timeframes_array" em um laço. Utilizamos a função "create_rectangle" para criar os objetos "TIMEFRAME_RECTANGLE" na coordenada x=630, com deslocamentos verticais a partir de (75 + "HEIGHT_RECTANGLE"), ajustados por -(1 + "timeframe_index"), e com a cor definida por "timeframe_background". Utilizamos a função "create_label" para criar os objetos "TIMEFRAME_TEXT", com os nomes obtidos pela função "truncate_timeframe_name". Para as células, percorremos um laço para criar "BUY_RECTANGLE", "RSI_RECTANGLE" e outros objetos semelhantes utilizando a função "create_rectangle", com "cell_background", e adicionamos rótulos “-/-” por meio da função "create_label". Inicializamos os arrays dos indicadores, como "rsi_values", utilizando a função ArraySetAsSeries, configurando-os como séries temporais para o processamento dos dados. Retornamos INIT_SUCCEEDED para confirmar que a inicialização foi concluída com sucesso, estabelecendo a estrutura visual e a organização dos dados do painel. Após a compilação, obtemos o seguinte resultado.

Pela imagem, podemos observar que o painel está pronto. Agora, precisamos apenas adicionar os valores dos indicadores e utilizá-los na análise. Já temos uma função responsável pela análise; precisamos apenas obter os dados. Para facilitar esse processo, criaremos uma função responsável por toda a lógica de atualização dinâmica.
//+------------------------------------------------------------------+ //| Update indicator values | //+------------------------------------------------------------------+ void updateIndicators() //--- Update dashboard indicators { for(int timeframe_index = 0; timeframe_index < ArraySize(timeframes_array); timeframe_index++) { //--- Loop through timeframes // Initialize indicator handles int rsi_indicator_handle = iRSI(_Symbol, timeframes_array[timeframe_index], 14, PRICE_CLOSE); //--- Create RSI handle int stochastic_indicator_handle = iStochastic(_Symbol, timeframes_array[timeframe_index], 14, 3, 3, MODE_SMA, STO_LOWHIGH); //--- Create Stochastic handle int cci_indicator_handle = iCCI(_Symbol, timeframes_array[timeframe_index], 20, PRICE_TYPICAL); //--- Create CCI handle int adx_indicator_handle = iADX(_Symbol, timeframes_array[timeframe_index], 14); //--- Create ADX handle int ao_indicator_handle = iAO(_Symbol, timeframes_array[timeframe_index]); //--- Create AO handle // Check for valid handles if(rsi_indicator_handle == INVALID_HANDLE || stochastic_indicator_handle == INVALID_HANDLE || cci_indicator_handle == INVALID_HANDLE || adx_indicator_handle == INVALID_HANDLE || ao_indicator_handle == INVALID_HANDLE) { //--- Check if any handle is invalid Print("Failed to create indicator handle for timeframe ", truncate_timeframe_name(timeframe_index)); //--- Log failure continue; //--- Skip to next timeframe } // Copy indicator values if(CopyBuffer(rsi_indicator_handle, 0, 0, 1, rsi_values) <= 0 || //--- Copy RSI value CopyBuffer(stochastic_indicator_handle, 1, 0, 1, stochastic_values) <= 0 || //--- Copy Stochastic signal line value CopyBuffer(cci_indicator_handle, 0, 0, 1, cci_values) <= 0 || //--- Copy CCI value CopyBuffer(adx_indicator_handle, 0, 0, 1, adx_values) <= 0 || //--- Copy ADX value CopyBuffer(ao_indicator_handle, 0, 0, 1, ao_values) <= 0) { //--- Copy AO value Print("Failed to copy buffer for timeframe ", truncate_timeframe_name(timeframe_index)); //--- Log copy failure continue; //--- Skip to next timeframe } // Update RSI color rsi_text_color = (rsi_values[0] < 30) ? clrBlue : (rsi_values[0] > 70) ? clrRed : COLOR_WHITE; //--- Set RSI text color update_label(RSI_TEXT + IntegerToString(timeframe_index), DoubleToString(rsi_values[0], 2), rsi_text_color); //--- Update RSI label // Update Stochastic (Signal Line only) color stochastic_text_color = (stochastic_values[0] < 20) ? clrBlue : (stochastic_values[0] > 80) ? clrRed : COLOR_WHITE; //--- Set Stochastic text color update_label(STOCH_TEXT + IntegerToString(timeframe_index), DoubleToString(stochastic_values[0], 2), stochastic_text_color); //--- Update Stochastic label // Update CCI color cci_text_color = (cci_values[0] < -100) ? clrBlue : (cci_values[0] > 100) ? clrRed : COLOR_WHITE; //--- Set CCI text color update_label(CCI_TEXT + IntegerToString(timeframe_index), DoubleToString(cci_values[0], 2), cci_text_color); //--- Update CCI label // Update ADX color adx_text_color = (adx_values[0] > 25) ? clrBlue : COLOR_WHITE; //--- Set ADX text color update_label(ADX_TEXT + IntegerToString(timeframe_index), DoubleToString(adx_values[0], 2), adx_text_color); //--- Update ADX label // Update AO color ao_text_color = (ao_values[0] > 0) ? clrGreen : (ao_values[0] < 0) ? clrRed : COLOR_WHITE; //--- Set AO text color update_label(AO_TEXT + IntegerToString(timeframe_index), DoubleToString(ao_values[0], 2), ao_text_color); //--- Update AO label // Update Buy/Sell signals string buy_signal = calculate_signal_strength(rsi_values[0], stochastic_values[0], cci_values[0], adx_values[0], ao_values[0], true); //--- Calculate buy signal string sell_signal = calculate_signal_strength(rsi_values[0], stochastic_values[0], cci_values[0], adx_values[0], ao_values[0], false); //--- Calculate sell signal color buy_text_color = (buy_signal == "Strong Buy") ? COLOR_WHITE : COLOR_WHITE; //--- Set buy text color color buy_background = (buy_signal == "Strong Buy") ? clrGreen : (buy_signal == "Buy") ? clrSeaGreen : COLOR_DARK_GRAY; //--- Set buy background color update_rectangle(BUY_RECTANGLE + IntegerToString(timeframe_index), buy_background); //--- Update buy rectangle update_label(BUY_TEXT + IntegerToString(timeframe_index), buy_signal, buy_text_color); //--- Update buy label color sell_text_color = (sell_signal == "Strong Sell") ? COLOR_WHITE : COLOR_WHITE; //--- Set sell text color color sell_background = (sell_signal == "Strong Sell") ? clrRed : (sell_signal == "Sell") ? clrSalmon : COLOR_DARK_GRAY; //--- Set sell background color update_rectangle(SELL_RECTANGLE + IntegerToString(timeframe_index), sell_background); //--- Update sell rectangle update_label(SELL_TEXT + IntegerToString(timeframe_index), sell_signal, sell_text_color); //--- Update sell label // Release indicator handles IndicatorRelease(rsi_indicator_handle); //--- Release RSI handle IndicatorRelease(stochastic_indicator_handle); //--- Release Stochastic handle IndicatorRelease(cci_indicator_handle); //--- Release CCI handle IndicatorRelease(adx_indicator_handle); //--- Release ADX handle IndicatorRelease(ao_indicator_handle); //--- Release AO handle } }
Para facilitar o gerenciamento da atualização dos valores do painel, implementamos a função "updateIndicators", responsável por atualizar os valores dos indicadores e os sinais. Percorremos o array "timeframes_array" utilizando "timeframe_index", processando cada período gráfico. Utilizamos as funções iRSI, "iStochastic", "iCCI", iADX e "iAO" para criar os handles dos indicadores, como "rsi_indicator_handle", para o símbolo e o período gráfico atuais, configurando parâmetros como um RSI de 14 períodos e um CCI de 20 períodos. Todas as configurações dos indicadores podem ser personalizadas de acordo com suas necessidades. Portanto, não é necessário se limitar aos valores padrão.
Em seguida, verificamos se algum handle, como "rsi_indicator_handle", é igual a INVALID_HANDLE, indicando uma falha na criação. Se isso ocorrer, utilizamos a função "Print" para registrar o erro, incluindo o resultado retornado pela função "truncate_timeframe_name", e passamos para o próximo período gráfico. Utilizamos a função CopyBuffer para recuperar os valores mais recentes e armazená-los em arrays como "rsi_values". Se alguma operação falhar, registramos o erro e continuamos o processamento. Atualizamos a exibição dos indicadores utilizando a função "update_label". Por exemplo, definimos "rsi_text_color" com base em "rsi_values[0]" (azul se for inferior a 30, vermelho se for superior a 70 e "COLOR_WHITE" nos demais casos) e atualizamos "RSI_TEXT" com o valor formatado pela função "DoubleToString". Repetimos esse procedimento para "stochastic_values", "cci_values", "adx_values" e "ao_values", aplicando as regras de cores correspondentes (por exemplo, verde para valores positivos de "ao_values").
Calculamos os sinais utilizando a função "calculate_signal_strength", passando "rsi_values[0]" e os demais valores dos indicadores para obter "buy_signal" e "sell_signal". Definimos "buy_background" (por exemplo, verde para “Strong Buy”) e utilizamos a função "update_rectangle" para atualizar "BUY_RECTANGLE", além de atualizar "BUY_TEXT" por meio de "update_label". Fazemos o mesmo para "sell_background" e "SELL_TEXT". Por fim, utilizamos a função IndicatorRelease para liberar os handles, como "rsi_indicator_handle", garantindo um gerenciamento eficiente dos recursos. As funções auxiliares que utilizamos estão definidas a seguir.
//+------------------------------------------------------------------+ //| Update rectangle background color | //+------------------------------------------------------------------+ bool update_rectangle(string object_name, color background_color)//--- Function to update rectangle color { int found = ObjectFind(0, object_name); //--- Find rectangle object if(found < 0) { //--- Check if object not found ResetLastError(); //--- Reset error code Print("UNABLE TO FIND THE RECTANGLE: ", object_name, ". ERR Code: ", GetLastError()); //--- Log error return(false); //--- Return failure } ObjectSetInteger(0, object_name, OBJPROP_BGCOLOR, background_color); //--- Set background color ChartRedraw(0); //--- Redraw chart return(true); //--- Return success } //+------------------------------------------------------------------+ //| Update label text and color | //+------------------------------------------------------------------+ bool update_label(string object_name, string text, color text_color) //--- Function to update label { int found = ObjectFind(0, object_name); //--- Find label object if(found < 0) { //--- Check if object not found ResetLastError(); //--- Reset error code Print("UNABLE TO FIND THE LABEL: ", object_name, ". ERR Code: ", GetLastError()); //--- Log error return(false); //--- Return failure } ObjectSetString(0, object_name, OBJPROP_TEXT, text); //--- Set label text ObjectSetInteger(0, object_name, OBJPROP_COLOR, text_color); //--- Set text color ChartRedraw(0); //--- Redraw chart return(true); //--- Return success }
Definimos a função "update_rectangle", que recebe os parâmetros "object_name" e "background_color" para modificar a aparência de um retângulo. Utilizamos a função ObjectFind para localizar o retângulo, armazenando o resultado em "found". Se "found" for menor que 0, indicando que o objeto não foi encontrado, utilizamos a função ResetLastError, registramos o erro por meio das funções "Print" e "GetLastError" e retornamos false. Atualizamos o fundo do retângulo utilizando a função "ObjectSetInteger" para definir a propriedade "OBJPROP_BGCOLOR" com o valor de "background_color". Utilizamos a função ChartRedraw para atualizar o gráfico e retornamos true para indicar que a operação foi concluída com sucesso. Para atualizar os textos, definimos a função "update_label" com os parâmetros "object_name", "text" e "text_color".
Utilizamos a função "ObjectFind" para verificar se o rótulo existe. Se "found" for negativo, utilizamos a função "ResetLastError", registramos o erro por meio da função "Print" e retornamos false. Utilizamos a função ObjectSetString para definir "OBJPROP_TEXT" com o valor de "text" e a função ObjectSetInteger para definir "OBJPROP_COLOR" com o valor de "text_color". Utilizamos a função "ChartRedraw" para atualizar o gráfico e retornamos true, permitindo a atualização dinâmica dos rótulos. Agora, podemos chamar a função de atualização a cada tick para manter os dados do painel atualizados.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() //--- Handle tick events { if (panel_is_visible) { //--- Check if panel is visible updateIndicators(); //--- Update indicators } }
Aqui, no manipulador de eventos OnTick, simplesmente chamamos a função "updateIndicators" quando o painel estiver visível, para aplicar as atualizações. Por fim, precisamos excluir os objetos que criamos, garantindo que sejam removidos do gráfico quando não forem mais necessários.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) //--- Deinitialize EA { ObjectDelete(0, MAIN_PANEL); //--- Delete main panel ObjectDelete(0, HEADER_PANEL); //--- Delete header panel ObjectDelete(0, HEADER_PANEL_ICON); //--- Delete header icon ObjectDelete(0, HEADER_PANEL_TEXT); //--- Delete header title ObjectDelete(0, CLOSE_BUTTON); //--- Delete close button ObjectsDeleteAll(0, SYMBOL_RECTANGLE); //--- Delete all symbol rectangles ObjectsDeleteAll(0, SYMBOL_TEXT); //--- Delete all symbol labels ObjectsDeleteAll(0, TIMEFRAME_RECTANGLE); //--- Delete all timeframe rectangles ObjectsDeleteAll(0, TIMEFRAME_TEXT); //--- Delete all timeframe labels ObjectsDeleteAll(0, HEADER_RECTANGLE); //--- Delete all header rectangles ObjectsDeleteAll(0, HEADER_TEXT); //--- Delete all header labels ObjectsDeleteAll(0, RSI_RECTANGLE); //--- Delete all RSI rectangles ObjectsDeleteAll(0, RSI_TEXT); //--- Delete all RSI labels ObjectsDeleteAll(0, STOCH_RECTANGLE); //--- Delete all Stochastic rectangles ObjectsDeleteAll(0, STOCH_TEXT); //--- Delete all Stochastic labels ObjectsDeleteAll(0, CCI_RECTANGLE); //--- Delete all CCI rectangles ObjectsDeleteAll(0, CCI_TEXT); //--- Delete all CCI labels ObjectsDeleteAll(0, ADX_RECTANGLE); //--- Delete all ADX rectangles ObjectsDeleteAll(0, ADX_TEXT); //--- Delete all ADX labels ObjectsDeleteAll(0, AO_RECTANGLE); //--- Delete all AO rectangles ObjectsDeleteAll(0, AO_TEXT); //--- Delete all AO labels ObjectsDeleteAll(0, BUY_RECTANGLE); //--- Delete all buy rectangles ObjectsDeleteAll(0, BUY_TEXT); //--- Delete all buy labels ObjectsDeleteAll(0, SELL_RECTANGLE); //--- Delete all sell rectangles ObjectsDeleteAll(0, SELL_TEXT); //--- Delete all sell labels ChartRedraw(0); //--- Redraw chart }
Para finalizar, implementamos o processo de limpeza utilizando a função OnDeinit, executada quando o Expert Advisor é removido. Utilizamos a função ObjectDelete para remover individualmente os elementos da interface, começando pelo retângulo "MAIN_PANEL", seguido de "HEADER_PANEL", "HEADER_PANEL_ICON", "HEADER_PANEL_TEXT" e "CLOSE_BUTTON", garantindo que o painel principal e os componentes do cabeçalho sejam removidos do gráfico.
Removemos sistematicamente todos os objetos do painel utilizando a função ObjectsDeleteAll para cada tipo de elemento. Excluímos todos os retângulos e rótulos associados a "SYMBOL_RECTANGLE" e "SYMBOL_TEXT", "TIMEFRAME_RECTANGLE" e "TIMEFRAME_TEXT", além de "HEADER_RECTANGLE" e "HEADER_TEXT", removendo as informações exibidas sobre o símbolo, os tempos gráficos e os cabeçalhos. Também removemos os objetos relacionados aos indicadores, incluindo "RSI_RECTANGLE", "STOCH_RECTANGLE", "CCI_RECTANGLE", "ADX_RECTANGLE" e "AO_RECTANGLE", juntamente com seus respectivos rótulos de texto, como "RSI_TEXT".
Concluímos a limpeza utilizando a função "ObjectsDeleteAll" para excluir todos os objetos "BUY_RECTANGLE" e "SELL_RECTANGLE", juntamente com seus rótulos "BUY_TEXT" e "SELL_TEXT", removendo todos os elementos relacionados aos sinais. Por fim, utilizamos a função ChartRedraw para atualizar o gráfico, garantindo que ele fique visualmente limpo após a desinicialização. Também precisamos configurar o botão de fechamento para que, ao ser clicado, o painel seja fechado e as atualizações posteriores sejam desativadas.
//+------------------------------------------------------------------+ //| Expert chart event handler | //+------------------------------------------------------------------+ void OnChartEvent(const int event_id, //--- Event ID const long& long_param, //--- Long parameter const double& double_param, //--- Double parameter const string& string_param) //--- String parameter { if (event_id == CHARTEVENT_OBJECT_CLICK) { //--- Check for object click event if (string_param == CLOSE_BUTTON) { //--- Check if close button clicked Print("Closing the panel now"); //--- Log panel closure PlaySound("alert.wav"); //--- Play alert sound panel_is_visible = false; //--- Hide panel ObjectDelete(0, MAIN_PANEL); //--- Delete main panel ObjectDelete(0, HEADER_PANEL); //--- Delete header panel ObjectDelete(0, HEADER_PANEL_ICON); //--- Delete header icon ObjectDelete(0, HEADER_PANEL_TEXT); //--- Delete header title ObjectDelete(0, CLOSE_BUTTON); //--- Delete close button ObjectsDeleteAll(0, SYMBOL_RECTANGLE); //--- Delete all symbol rectangles ObjectsDeleteAll(0, SYMBOL_TEXT); //--- Delete all symbol labels ObjectsDeleteAll(0, TIMEFRAME_RECTANGLE); //--- Delete all timeframe rectangles ObjectsDeleteAll(0, TIMEFRAME_TEXT); //--- Delete all timeframe labels ObjectsDeleteAll(0, HEADER_RECTANGLE); //--- Delete all header rectangles ObjectsDeleteAll(0, HEADER_TEXT); //--- Delete all header labels ObjectsDeleteAll(0, RSI_RECTANGLE); //--- Delete all RSI rectangles ObjectsDeleteAll(0, RSI_TEXT); //--- Delete all RSI labels ObjectsDeleteAll(0, STOCH_RECTANGLE); //--- Delete all Stochastic rectangles ObjectsDeleteAll(0, STOCH_TEXT); //--- Delete all Stochastic labels ObjectsDeleteAll(0, CCI_RECTANGLE); //--- Delete all CCI rectangles ObjectsDeleteAll(0, CCI_TEXT); //--- Delete all CCI labels ObjectsDeleteAll(0, ADX_RECTANGLE); //--- Delete all ADX rectangles ObjectsDeleteAll(0, ADX_TEXT); //--- Delete all ADX labels ObjectsDeleteAll(0, AO_RECTANGLE); //--- Delete all AO rectangles ObjectsDeleteAll(0, AO_TEXT); //--- Delete all AO labels ObjectsDeleteAll(0, BUY_RECTANGLE); //--- Delete all buy rectangles ObjectsDeleteAll(0, BUY_TEXT); //--- Delete all buy labels ObjectsDeleteAll(0, SELL_RECTANGLE); //--- Delete all sell rectangles ObjectsDeleteAll(0, SELL_TEXT); //--- Delete all sell labels ChartRedraw(0); //--- Redraw chart } } }
No manipulador de eventos OnChartEvent, monitoramos os cliques nos objetos quando o identificador do evento corresponde a CHARTEVENT_OBJECT_CLICK. Quando o objeto clicado é o botão de fechamento, reproduzimos um som de alerta utilizando a função PlaySound para informar ao usuário que o painel está sendo desativado. Em seguida, desativamos a visibilidade do painel e utilizamos a mesma lógica de limpeza empregada em OnDeinit para remover todos os elementos do painel. Após a compilação, obtemos o seguinte resultado.

Pela imagem, podemos observar que o painel foi atualizado com os dados dos indicadores e a indicação das direções de negociação. Agora, resta testar o funcionamento do projeto, o que será abordado na próxima seção.
Backtesting
Realizamos os testes e, a seguir, apresentamos uma visualização consolidada em um único arquivo GIF animado.

Conclusão
Concluindo, desenvolvemos um painel de scanner multitemporal em MQL5, integrando uma estrutura organizada em grade, sinais de indicadores em tempo real e um botão de fechamento interativo para aprimorar as decisões estratégicas de negociação. Demonstramos o planejamento e a implementação desses recursos, garantindo sua eficácia por meio de uma inicialização consistente ou assegurando seu funcionamento com uma inicialização adequada. Você pode personalizar esse painel de acordo com suas preferências, melhorando significativamente sua capacidade de monitorar os sinais do mercado e agir com base neles em diferentes tempos gráficos.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/18319
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
Ciência de Dados e ML (Parte 42): Previsão de Séries Temporais no Mercado Forex com ARIMA em Python
Está chegando o novo MetaTrader 5 e MQL5
Machine Learning e Data Science (Parte 45): Previsão de séries temporais no Forex com o modelo PROPHET do Facebook
- 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