Indicador de sazonalidade por horas, dias da semana e meses
Os preços tocam uma melodia que se repete em determinados dias do mês, dias da semana ou até mesmo horas do dia. Esses ritmos repetitivos, ou padrões sazonais, podem se tornar para o trader uma pista de quando o mercado tende a subir e quando tende a cair. A sazonalidade nos mercados financeiros não é apenas um fenômeno curioso, mas uma ferramenta que ajuda a encontrar momentos previsíveis no caos dos preços. Por exemplo, você já percebeu que alguns pares de moedas frequentemente sobem às segundas-feiras ou caem no final do mês? Isso é sazonalidade, e estudá-la pode dar aos traders uma vantagem.
Neste guia criaremos um indicador de sazonalidade na linguagem MQL5 para a plataforma MetaTrader 5. Nosso indicador analisará dados históricos de preços para identificar a rentabilidade média dos dias do mês (de 1 a 31), dos dias da semana (de segunda-feira a domingo) ou das horas do dia (de 0 a 23). Os resultados serão exibidos na forma de um histograma em uma janela separada do gráfico, com uma linha de previsão conectando os valores de sazonalidade e pontos destacando os valores esperados nas próximas barras. Além disso, o indicador exibirá estatísticas textuais com previsões, melhores e piores períodos. Vamos destrinchar o processo de desenvolvimento passo a passo, explicando cada parte do código para que você não apenas possa usar o indicador, mas também adaptá-lo às suas próprias ideias. Será uma jornada pelo mundo da programação e da análise financeira, onde o código se torna uma ponte entre dados e decisões de trading.
Para que estudar a sazonalidade
A sazonalidade é como um pulso oculto do mercado. Ela surge devido a diversos fatores, comportamento dos traders, eventos econômicos e até psicologia humana. Por exemplo, no final do mês grandes fundos podem fechar posições, provocando movimentos previsíveis de preços. Ou em determinadas horas do dia a atividade do mercado aumenta devido à abertura das sessões de negociação em Londres ou Nova York. Nosso indicador ajudará a identificar esses padrões, transformando dados caóticos em gráficos e números compreensíveis. Isso não é magia, mas ciência de dados trabalhando a favor do trader.
O indicador que criaremos será universal. Ele permitirá escolher o tipo de sazonalidade, configurar o número de barras analisadas, exibir a rentabilidade em porcentagens ou valores absolutos, além de ativar ou desativar a previsão no gráfico. A flexibilidade é a chave para que o indicador se torne uma ferramenta útil para diferentes mercados e timeframes, seja um gráfico diário de EUR/USD ou um gráfico horário do ouro.
Definimos a estrutura do indicador
A criação do indicador começa com o entendimento de como ele será exibido e como funcionará. Queremos que ele seja mostrado em uma janela separada abaixo do gráfico de preços, para não sobrecarregar o espaço principal. Para a visualização utilizamos três elementos: um histograma que mostrará a rentabilidade média para cada período, uma linha de previsão que conectará os valores de sazonalidade e os dados previstos, e pontos de previsão que destacam os valores esperados nas próximas duas barras. Cada elemento estará associado a um buffer de dados, um array que armazena valores para renderização. Também precisaremos de variáveis globais para armazenar os dados de sazonalidade e os rótulos dos períodos, além de parâmetros de entrada para que o usuário possa configurar o indicador.
//+------------------------------------------------------------------+ //| SeasonalityIndicator.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 3 //--- plot Seasonality #property indicator_label1 "Seasonality" #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 2 //--- plot Forecast Line #property indicator_label2 "Forecast" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_DASH #property indicator_width2 2 //--- plot Forecast Points #property indicator_label3 "Forecast Points" #property indicator_type3 DRAW_ARROW #property indicator_color3 clrOrange #property indicator_width3 3
Neste código definimos as informações principais do indicador: direitos autorais, o link para o site da MetaQuotes e a versão. A diretiva #property indicator_separate_window indica que o indicador será exibido em uma janela separada. Definimos três buffers e três gráficos. O histograma (DRAW_HISTOGRAM) é colorido em azul claro; a linha de previsão (DRAW_LINE), em vermelho pontilhado; e os pontos de previsão (DRAW_ARROW), em laranja com largura de três pixels. Essas configurações definem o estilo visual que tornará o indicador claro e visualmente atraente.
Configuramos os parâmetros de entrada
Para que o indicador seja flexível, adicionamos parâmetros de entrada que o usuário pode alterar na janela de configurações do MetaTrader 5. O parâmetro para escolher o tipo de sazonalidade permite analisar dias do mês, dias da semana ou horas do dia. A quantidade de barras para análise determina quão profundamente examinaremos o histórico. Existe a possibilidade de exibir a rentabilidade em porcentagens ou valores absolutos, além de mostrar apenas valores positivos de sazonalidade. O parâmetro para ativar a previsão no gráfico e configurar as cores da linha e dos pontos de previsão torna o indicador ainda mais configurável.
//--- Входные параметры enum ENUM_SEASONALITY_TYPE { SEASONALITY_DAYS_OF_MONTH = 0, // Дни месяца (1-31) SEASONALITY_DAYS_OF_WEEK = 1, // Дни недели (Пн-Вс) SEASONALITY_HOURS = 2 // Часы (0-23) }; input ENUM_SEASONALITY_TYPE SeasonalityType = SEASONALITY_DAYS_OF_MONTH; // Тип сезонности input int BarsToAnalyze = 1000; // Количество баров для анализа input bool ShowPercentage = true; // Показывать в процентах input bool ShowPositiveOnly = false; // Показывать только положительные значения input bool ShowForecastOnChart = true; // Показывать прогноз на графике input color ForecastColor = clrRed; // Цвет линии прогноза input color ForecastPointsColor = clrOrange; // Цвет точек прогноза
A enumeração ENUM_SEASONALITY_TYPE define três opções de sazonalidade. Por padrão é selecionada a análise por dias do mês. O parâmetro BarsToAnalyze está definido como 1000 barras, o que corresponde aproximadamente a quatro anos de dados em um gráfico diário. O parâmetro ShowPercentage está ativado por padrão para que a rentabilidade seja exibida em porcentagens, pois isso é mais intuitivo. Os parâmetros ShowPositiveOnly e ShowForecastOnChart oferecem flexibilidade adicional, enquanto as cores podem ser alteradas pela interface do MetaTrader.
Definimos os buffers e as variáveis
Para armazenar os dados o indicador utiliza três buffers: um para o histograma, outro para a linha de previsão e o terceiro para os pontos de previsão. Também são necessárias variáveis globais: um array para armazenar a rentabilidade média por período, um array para os rótulos dos períodos (por exemplo, "Seg" ou "1") e uma variável que define a quantidade de períodos, que depende do tipo de sazonalidade (31 para dias do mês, 7 para dias da semana, 24 para horas).
//--- Буферы индикатора double SeasonalityBuffer[]; double ForecastLineBuffer[]; double ForecastPointsBuffer[]; //--- Глобальные переменные double seasonality_data[]; string period_labels[]; int periods_count;
Os buffers conterão os dados para renderização, enquanto as variáveis seasonality_data e period_labels ajudarão a armazenar e exibir os resultados da análise. A variável periods_count define quantos períodos serão analisados e é configurada de acordo com o tipo de sazonalidade.
Inicialização do indicador
A função OnInit é executada quando o indicador é iniciado e é responsável pela configuração inicial. Ela conecta os buffers aos gráficos, define o estilo das setas para os pontos de previsão e aplica as cores definidas nos parâmetros do usuário. Dependendo do tipo de sazonalidade são criados os rótulos dos períodos, e o array para armazenamento dos dados de sazonalidade é inicializado com zeros. A precisão da exibição é ajustada conforme a escolha entre porcentagens ou valores absolutos.
int OnInit() { SetIndexBuffer(0, SeasonalityBuffer, INDICATOR_DATA); SetIndexBuffer(1, ForecastLineBuffer, INDICATOR_DATA); SetIndexBuffer(2, ForecastPointsBuffer, INDICATOR_DATA); PlotIndexSetInteger(2, PLOT_ARROW, 159); PlotIndexSetInteger(1, PLOT_LINE_COLOR, ForecastColor); PlotIndexSetInteger(2, PLOT_LINE_COLOR, ForecastPointsColor); switch(SeasonalityType) { case SEASONALITY_DAYS_OF_MONTH: periods_count = 31; ArrayResize(period_labels, periods_count); for(int i = 0; i < periods_count; i++) period_labels[i] = IntegerToString(i + 1); IndicatorSetString(INDICATOR_SHORTNAME, "Сезонность по дням месяца"); break; case SEASONALITY_DAYS_OF_WEEK: periods_count = 7; ArrayResize(period_labels, periods_count); period_labels[0] = "Пн"; period_labels[1] = "Вт"; period_labels[2] = "Ср"; period_labels[3] = "Чт"; period_labels[4] = "Пт"; period_labels[5] = "Сб"; period_labels[6] = "Вс"; IndicatorSetString(INDICATOR_SHORTNAME, "Сезонность по дням недели"); break; case SEASONALITY_HOURS: periods_count = 24; ArrayResize(period_labels, periods_count); for(int i = 0; i < periods_count; i++) period_labels[i] = IntegerToString(i) + ":00"; IndicatorSetString(INDICATOR_SHORTNAME, "Сезонность по часам"); break; } ArrayResize(seasonality_data, periods_count); ArrayInitialize(seasonality_data, 0.0); IndicatorSetInteger(INDICATOR_DIGITS, ShowPercentage ? 2 : _Digits); return(INIT_SUCCEEDED); }
Essa função estabelece a base do funcionamento do indicador. Por exemplo, para os dias da semana é criado um array de rótulos de "Seg" até "Dom", enquanto para as horas é criado de "0:00" até "23:00". O nome do indicador também é alterado para que o usuário entenda imediatamente qual tipo de sazonalidade foi selecionado. Isso torna o indicador intuitivo.
Cálculo da sazonalidade
O trabalho principal do indicador ocorre na função OnCalculate. Ela analisa os dados históricos de preços, calcula a rentabilidade média para cada período e preenche os buffers para renderização. Primeiro é verificado se há barras suficientes no gráfico. Em seguida são criados arrays auxiliares para somar a rentabilidade e contar o número de barras em cada período.
Para cada barra é calculada a rentabilidade como a razão entre a diferença dos preços de fechamento e o preço de fechamento atual. A função GetPeriodIndex determina a qual período a barra pertence, e os dados são registrados nos arrays. Depois disso é calculada a rentabilidade média, que pode ser convertida em porcentagem ou zerada no caso de valores negativos. Os buffers são então preenchidos com os dados, e para a previsão é chamada uma função separada.
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total < BarsToAnalyze + 1) return(0); ArrayInitialize(seasonality_data, 0.0); double period_returns[]; int period_counts[]; ArrayResize(period_returns, periods_count); ArrayResize(period_counts, periods_count); ArrayInitialize(period_returns, 0.0); ArrayInitialize(period_counts, 0); int start_pos = MathMax(0, rates_total - BarsToAnalyze - 1); for(int i = start_pos; i < rates_total - 1; i++) { double return_value = 0.0; if(close[i] != 0) return_value = (close[i+1] - close[i]) / close[i]; int period_index = GetPeriodIndex(time[i]); if(period_index >= 0 && period_index < periods_count) { period_returns[period_index] += return_value; period_counts[period_index]++; } } for(int i = 0; i < periods_count; i++) { if(period_counts[i] > 0) { seasonality_data[i] = period_returns[i] / period_counts[i]; if(ShowPercentage) seasonality_data[i] *= 100.0; if(ShowPositiveOnly && seasonality_data[i] < 0) seasonality_data[i] = 0.0; } } for(int i = 0; i < rates_total; i++) { int period_index = GetPeriodIndex(time[i]); if(period_index >= 0 && period_index < periods_count) { SeasonalityBuffer[i] = seasonality_data[period_index]; ForecastLineBuffer[i] = seasonality_data[period_index]; } else { SeasonalityBuffer[i] = 0.0; ForecastLineBuffer[i] = 0.0; } ForecastPointsBuffer[i] = EMPTY_VALUE; } if(ShowForecastOnChart) DrawForecastOnChart(rates_total, time); return(rates_total); }
Esse código é o coração do indicador. Ele transforma dados brutos de preços em padrões compreensíveis. Imagine que você esteja analisando o gráfico diário de um par de moedas. Para cada dia da semana o indicador calcula quanto o preço mudou e encontra o valor médio. Se você observar que às sextas-feiras o mercado cai em média 0.05%, isso pode servir como sinal para uma estratégia de trading.
Determinação do período
Para entender a qual período uma barra pertence, criamos a função GetPeriodIndex. Ela converte o tempo da barra em um índice de período dependendo do tipo de sazonalidade. Para os dias do mês ela obtém o número do dia e subtrai uma unidade para gerar um índice de 0 a 30. Para os dias da semana ela converte o valor do dia da semana, onde domingo é 0 e segunda-feira é 1, em uma ordem onde segunda-feira é 0 e domingo é 6. Para as horas simplesmente retorna o valor da hora de 0 a 23.
int GetPeriodIndex(datetime bar_time) { MqlDateTime dt; TimeToStruct(bar_time, dt); switch(SeasonalityType) { case SEASONALITY_DAYS_OF_MONTH: return(dt.day - 1); case SEASONALITY_DAYS_OF_WEEK: return(dt.day_of_week == 0 ? 6 : dt.day_of_week - 1); case SEASONALITY_HOURS: return(dt.hour); } return(-1); }
Essa função funciona como uma bússola que ajuda o indicador a entender em qual "compartimento" os dados da barra devem ser colocados. Sem ela não seria possível associar o preço a um dia ou hora específicos.
Renderização da previsão
A previsão é o que torna o indicador não apenas analítico, mas também útil na prática. A função DrawForecastOnChart desenha os valores esperados de sazonalidade nas duas últimas barras do gráfico. Ela identifica o período atual e os dois seguintes utilizando a função GetNextPeriod. Os valores de sazonalidade desses períodos são registrados nos buffers da linha e dos pontos de previsão. Para que a linha de previsão pareça suave, o valor do período atual é registrado no buffer correspondente à penúltima barra.
void DrawForecastOnChart(int rates_total, const datetime &time[]) { if(rates_total < 3) return; datetime current_time = time[rates_total - 1]; int current_period = GetPeriodIndex(current_time); int next_period1 = GetNextPeriod(current_period); int next_period2 = GetNextPeriod(next_period1); int forecast_pos1 = rates_total - 2; int forecast_pos2 = rates_total - 1; if(next_period1 >= 0 && next_period1 < periods_count) { ForecastLineBuffer[forecast_pos1] = seasonality_data[next_period1]; ForecastPointsBuffer[forecast_pos1] = seasonality_data[next_period1]; } if(next_period2 >= 0 && next_period2 < periods_count) { ForecastLineBuffer[forecast_pos2] = seasonality_data[next_period2]; ForecastPointsBuffer[forecast_pos2] = seasonality_data[next_period2]; } if(rates_total >= 3) { int current_pos = rates_total - 3; int current_period_idx = GetPeriodIndex(time[current_pos]); if(current_period_idx >= 0 && current_period_idx < periods_count) { double current_value = seasonality_data[current_period_idx]; double next_value = (next_period1 >= 0) ? seasonality_data[next_period1] : current_value; ForecastLineBuffer[current_pos] = current_value; if(forecast_pos1 < rates_total) ForecastLineBuffer[forecast_pos1] = next_value; } } }
A previsão se assemelha a um olhar para o futuro: o indicador informa o que esperar com base em dados históricos. Se, por exemplo, as terças-feiras geralmente apresentam uma rentabilidade de +0.07%, o indicador mostrará isso no gráfico, ajudando o trader a se preparar.
Cálculo do próximo período
A função GetNextPeriod determina qual período vem após o atual. Ela utiliza aritmética modular para garantir uma transição cíclica: após o dia 31 do mês vem o dia 1, após domingo vem segunda-feira e após 23:00 vem 0:00.
int GetNextPeriod(int current_period) { if(current_period < 0) return(-1); switch(SeasonalityType) { case SEASONALITY_DAYS_OF_MONTH: return((current_period + 1) % 31); case SEASONALITY_DAYS_OF_WEEK: return((current_period + 1) % 7); case SEASONALITY_HOURS: return((current_period + 1)rate_total % 24); } return(-1); }
Essa função garante que a previsão sempre observe os períodos futuros corretos, preservando a lógica do tempo cíclico. Ela atua como um calendário preciso do mercado, assegurando que o indicador faça a transição correta de um período para o seguinte, seja na mudança dos dias do mês, dos dias da semana ou das horas. Imagine que o mercado seja um enorme relógio em que cada tique marca não apenas o tempo, mas também possíveis movimentos de preço. Após o dia 31 do mês a função retorna suavemente ao dia 1, após domingo passa para segunda-feira e após 23:00 retorna para 0:00. Essa abordagem cíclica reflete a estrutura real do tempo nos mercados financeiros, permitindo que o indicador antecipe quais períodos podem ser relevantes para o trader.
Exibição das estatísticas

Para que o trader compreenda rapidamente os resultados da análise, o indicador exibe estatísticas detalhadas diretamente no gráfico. A função ShowStatistics cria uma mensagem de texto que, como um narrador, transforma números secos em uma história interessante sobre os padrões do mercado.
Ela começa com um título que muda conforme o tipo de sazonalidade selecionado, seja análise por dias do mês, dias da semana ou horas do dia. Em seguida é indicado o número de barras analisadas, o que dá ao trader uma noção da profundidade dos dados históricos utilizados nos cálculos. Depois é adicionada a previsão obtida pela função GetForecast, que estima como o mercado pode se comportar nos próximos dois períodos com base nas tendências históricas. Em seguida a função examina cuidadosamente o array seasonality_data, encontrando os períodos com a maior e a menor rentabilidade. Esses períodos recebem a classificação de melhores e piores, e seus valores são exibidos com precisão de três casas decimais para que o trader possa avaliar sua relevância.
A mensagem termina com estatísticas completas, nas quais para cada período é indicado seu rótulo, por exemplo "Seg" ou "15", e a rentabilidade média. Esse texto aparece no canto superior direito do gráfico, como um relatório de um pesquisador que revela os ritmos do mercado e os torna claros e úteis para a tomada de decisões de trading.
Considerações finais
A sazonalidade nos mercados financeiros não é misticismo, mas uma regularidade fundamentada matematicamente que pode se tornar uma ferramenta poderosa no arsenal de um trader. O indicador que criamos transforma movimentos caóticos de preços em padrões compreensíveis, revelando ritmos ocultos do mercado por dias do mês, dias da semana ou horas da sessão de negociação.
Graças à configuração flexível de parâmetros, à exibição visual dos resultados na forma de um histograma com previsão e às estatísticas detalhadas, esta ferramenta permite não apenas analisar dados históricos, mas também construir suposições fundamentadas sobre movimentos futuros do preço. A integração de elementos de previsão torna o indicador aplicável na prática para desenvolver estratégias de trading.
O código do indicador é fácil de adaptar para diferentes ativos e timeframes, e a explicação passo a passo de cada função dá a possibilidade de modificar o algoritmo de acordo com as próprias ideias de trading. Em última instância, este indicador é uma ponte entre cálculos estatísticos complexos e a tomada de decisões de trading concretas, transformando dados em conhecimento e conhecimento em lucro potencial.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/18672
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.
Análise de lacunas tempo<rais de preço em MQL5 (Parte II): Criamos um mapa de calor da distribuição de liquidez no tempo
Operando com o Calendário Econômico do MQL5 (Parte 6): Automatizando a Entrada de Trades com Análise de Eventos de Notícias e Temporizadores de Contagem Regressiva
Está chegando o novo MetaTrader 5 e MQL5
Redes neurais em trading: Segmentação periódica adaptativa (Criação de tokens)
- 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