
Filtragem de Sazonalidade e Período de Tempo para Modelos de Deep Learning ONNX com Python para EA
Introdução
Depois de ler o artigo: Benefícios da Sazonalidade no Mercado Forex, decidi criar outro artigo para comparar um EA com e sem sazonalidade para ver se ele pode se beneficiar.
Eu já sabia que os mercados eram influenciados por fatores sazonais. Isso ficou claro quando descobri que Mark Zuckerberg financiou o Facebook com dinheiro de um investidor. Esse investidor havia investido anteriormente o dinheiro do seu Bar Mitzvah em ações de petróleo, prevendo um aumento devido aos furacões esperados no Caribe. Ele havia analisado previsões meteorológicas que indicavam mau tempo durante aquele período.
Estou muito orgulhoso e interessado em escrever este artigo, que tem como objetivo explorar a ideia de que mercado e sazonalidade são bons companheiros. Uma boa abordagem para concretizar isso seria fundir ambos os EAs em um só, mas já temos um artigo sobre isso, aqui está o link: Um exemplo de como fazer ensemble de modelos ONNX no mql5.
Primeiro, vamos comparar modelos com e sem filtragem utilizando um EA, para ver como a filtragem de dados afeta ou não, e, depois disso, discutiremos a sazonalidade com um gráfico, para terminar com um estudo de caso real, para fevereiro de 2024, com e sem sazonalidade. Na última parte do artigo (que considero muito interessante), discutiremos outras abordagens para o EA que já temos no artigo: Como usar modelos ONNX no MQL5, e veremos se podemos nos beneficiar do ajuste fino desses EAs e modelos ONNX. Vou te adiantar que a resposta é sim, podemos.
Para que isso aconteça, primeiro vamos baixar os dados (todos os ticks) com este script: Baixar todos os dados de um símbolo. Basta adicionar o script ao gráfico do símbolo que precisamos estudar e, em algum tempo (menos de uma hora), teremos baixado todos os ticks históricos desse símbolo na nossa pasta Files.
Basta adicionar o script ao gráfico do símbolo que precisamos estudar e, em algum tempo (menos de uma hora), teremos baixado todos os ticks históricos desse símbolo na nossa pasta Files.
Sazonalidade
A sazonalidade no trading é sobre identificar os fluxos regulares nos preços dos ativos que ocorrem de forma previsível ao longo do ano. É como reconhecer que certas ações tendem a ter um desempenho melhor em determinados períodos do que em outros. Vamos explorar essa ideia um pouco mais.
Entendendo a Sazonalidade no Trading:
- Definição: Sazonalidade significa notar como os preços tendem a flutuar em um padrão recorrente com base na época do ano. Isso pode estar relacionado às estações do ano (como verão ou inverno), estações comerciais (como a correria das compras de fim de ano), ou até meses específicos.
- Exemplos: Investidores inteligentes ficam de olho nesses padrões porque eles geralmente são confiáveis e lucrativos. Aqui estão alguns exemplos:
- Sazonalidade Relacionada ao Clima: Assim como o clima afeta as estações agrícolas, também impacta coisas como os preços das commodities e as ações relacionadas. Por exemplo, uma empresa que vende equipamentos de praia pode ver um aumento nas vendas durante o verão, mas uma queda nos meses mais frios, afetando suas ações.
- Sazonalidade de Feriados: Ações de varejo geralmente veem um aumento durante as frenéticas compras de feriados. Empresas que prosperam nas vendas de fim de ano, como lojas de presentes, tendem a brilhar nesses períodos.
- Sazonalidade de Resultados Trimestrais: Empresas de capital aberto relatam seus ganhos a cada trimestre, e os preços de suas ações podem reagir de maneira previsível durante essas temporadas.
- Sazonalidade Fiscal: Eventos relacionados a impostos podem abalar o mercado, especialmente para setores ligados a finanças.
- Ciclos Naturais: Indústrias como turismo ou energia têm seus próprios padrões sazonais de demanda, como férias de verão ou necessidades de aquecimento no inverno.
Estratégias de Trading Baseadas na Sazonalidade:
- Os traders podem alavancar a sazonalidade de algumas maneiras:
- Identificação de Padrões Sazonais: Explorar dados passados para identificar tendências que se repetem em determinados períodos do ano.
- Sincronização de Trades: Fazer movimentos de entrada e saída de posições com base nessas tendências sazonais.
- Gerenciamento de Risco: Ajustar o quanto de risco você está assumindo durante períodos voláteis.
- Rotação de Setores: Alternar investimentos entre setores que tendem a ter um desempenho melhor em diferentes épocas do ano.
Filtragem de Dados
Usaremos o filtro passa-baixa. De acordo com a Wikipedia:
Um filtro passa-baixa é um filtro que permite a passagem de sinais com uma frequência inferior a uma frequência de corte selecionada e atenua sinais com frequências superiores à frequência de corte. A resposta exata em frequência do filtro depende do design do filtro. O filtro às vezes é chamado de filtro corta-altas ou filtro corta-agudos em aplicações de áudio. Um filtro passa-baixa é o complemento de um filtro passa-alta.
Por que escolhemos filtros passa-baixa em vez de filtros passa-alta no trading algorítmico? No trading algorítmico, a preferência por filtros passa-baixa decorre de várias vantagens-chave:- Suavização de Sinais: Filtros passa-baixa suavizam efetivamente os movimentos de preço ruidosos, enfatizando as tendências de longo prazo sobre as flutuações de curto prazo.
- Redução de Ruído de Alta Frequência: Eles ajudam a atenuar o ruído de alta frequência, que pode não fornecer informações significativas para as estratégias de trading.
- Custos de Transação Mais Baixos: Ao focar em tendências de longo prazo, os filtros passa-baixa podem levar a menos negociações, mais estratégicas, potencialmente reduzindo as despesas de transação.
- Melhor Gestão de Riscos: Os filtros passa-baixa contribuem para uma estratégia de negociação mais estável e previsível, reduzindo o impacto das flutuações de mercado de curto prazo.
- Alinhamento com o Horizonte de Investimento: Eles são bem adequados para estratégias com horizontes de investimento de longo prazo, capturando tendências ao longo de períodos estendidos de forma eficaz.
Eu pessoalmente uso filtro passa-baixa para filtrar altas frequências. Não faz muito sentido usar um filtro passa-alta aqui.
Isso é o que vamos usar (nota: acabei mudando os parâmetros de order e cutoff_frequency na última parte do artigo para 0,1 de cutoff e order igual a 1, porque acabaram dando melhores resultados). Além disso, o .py correto para filtragem é o da última parte do artigo (lá, usei não apenas melhores parâmetros, mas também usei minmaxscaler para ajustar e reverter).
# Low-pass filter parameters cutoff_frequency = 0.01 # Cutoff frequency as a proportion of the Nyquist frequency order = 4 # Apply the low-pass filter def butter_lowpass_filter(data, cutoff, fs, order): nyquist = 0.5 * fs normal_cutoff = cutoff / nyquist b, a = butter(order, normal_cutoff, btype='low', analog=False) print("Filter coefficients - b:", b) print("Filter coefficients - a:", a) y = lfilter(b, a, data) return y filtered_data_low = butter_lowpass_filter(df2['close'], cutoff_frequency, fs=1, order=order)
Usaremos "onnx_LSTM_simple_filtered.py" e "onnx_LSTM_simple_not_filtered.py" para criar os modelos ONNX e compará-los.
Nota: Usei o modelo v1 e o modelo v2, que têm diferentes parâmetros de filtro passa-baixa.
Aqui estão os resultados:
Vamos usar os mesmos inputs para os EAs
O período de tempo a ser estudado será de primeiro de fevereiro a primeiro de março.
Para o modelo não filtrado:
RMSE : 0.0010798043714784716 MSE : 1.165977480664017e-06 R2 score : 0.8799146678247277
Filtered v1
# Parámetros del filtro pasa bajo cutoff_frequency = 0.01 # Frecuencia de corte en proporción a la frecuencia de Nyquist order = 4
RMSE : 0.0010228999869332884 MSE : 1.0463243832681218e-06 R2 score : 0.8922378749062259
Filtered v2
cutoff_frequency = 0.1 # Frecuencia de corte en proporción a la frecuencia de Nyquist order = 2
RMSE : 0.0010899163515744447 MSE : 1.1879176534293484e-06 R2 score : 0.8775550550819025
Conclusão sobre filtragem
Então, sim. É conveniente usar filtragem.
Código usado e modelos:
- ONNX.eurusd.H1.120.Prediction_FILTERED.mq5
- ONNX.eurusd.H1.120.Prediction_FILTERED_v2.mq5 ONNX.eurusd.H1.120.Prediction_NOT_FILTERED.mq5
- onnx_LSTM_simple_EURUSD_filtered.py onnx_LSTM_simple_EURUSD_not_filtered.py
- Baixar todos os dados de um símbolo EURUSD_LSTM_120_1h_not_filtered.onnx EURUSD_LSTM_120_1h_filtered_v1.onnx EURUSD_LSTM_120_1h_filtered_v2.onnx
Os símbolos são sazonais?
Para esta parte, vamos primeiro ver isso em um gráfico, vamos obter os dados de fevereiro desde 2015 até 2023 e vamos adicionar os dados para ver como eles se comportam ao longo dessas semanas.
Isso é o que podemos ver desse período:
Conclusão
Podemos ver que há algumas tendências, ou pelo menos não vemos uma linha horizontal preta (linha da soma). Há lacunas entre cada linha, porque o símbolo é negociado ao longo do ano e seus preços flutuam. É por isso que, na próxima parte do artigo, vamos concatenar todos os símbolos por anos em fevereiro e é por isso que precisamos usar um filtro, para que não passe a alta frequência de, por exemplo, a última data de 2022 para o primeiro de fevereiro de 2023 e quando a IA for treinada, por exemplo, no fechamento de uma sexta-feira e na abertura de uma segunda-feira, para que não estude essas mudanças e busque dados mais suavizados.
Scripts e dados utilizados:
Esses dados do símbolo são correlacionados?
A autocorrelação é uma característica dos dados que mostra o grau de similaridade entre valores em intervalos de tempo sucessivos.
Um valor próximo a 1 indica que há uma grande correlação positiva.
Abaixo estão os resultados que obtivemos com autocorrelation.py
[1. 0.99736147 0.99472432 0.99206626 0.98937664 0.98671649 0.98405706 0.98144222 0.9787753 0.97615525 0.97356318 0.97099777 0.96848029 0.96602671 0.96360361 0.96113539 0.95865344 0.95615626 0.95362417 0.95108177 0.94854957 0.94599045 0.94346076 0.94091564 0.93837742 0.93583734 0.9332909 0.93074655 0.92826504 0.92579028 0.92330505 0.92084645 0.91834403 0.91581296 0.91328091 0.91076099 0.90826447]
Criando um modelo ONNX para as estações de fevereiro
Para esta tarefa, só precisamos concatenar todos os dados em um único arquivo CSV e criar um modelo com ele.
Vamos usar o script criado concat_seasonal.py para fazer um único arquivo CSV, que será adicionado ao zip seasonal_feb_concat. Com o script onnx_LSTM_..._seasonals.py, vamos treinar e criar o modelo.
Scripts e dados utilizados:
Resultados dos testes para o modelo sazonal e comparação com o modelo filtrado de 120 dias (1h)
Modelo Sazonal
RMSE : 0.013137568368684325 MSE : 0.00017259570264185493 R2 score : 0.7166764010650979
Embora não sejam surpreendentes, os resultados parecem bons no geral (não apresenta muitos resultados negativos de Sharpe).
Se compararmos com o modelo filtrado,
O que achei curioso é que o número de valores de Sharpe negativos ocupa metade da tabela de otimização para o modelo filtrado, enquanto os negativos para o modelo sazonal ocupam cerca de um quinto da tabela. Isso é notável, porque, mesmo tendo um r2 mais baixo, parece ser um modelo robusto que proporciona retornos lucrativos.
Eu também poderia ter testado o EA sem SL e TP, mas acho uma prática melhor sempre usá-los em EAs.
Código e modelo ONNX utilizados:
ONNX.eurusd.H1.120.Prediction_seasonal.mq5 EURUSD_LSTM_270_1h_filtered_seasonal0.72.onnx onnx_LSTM_simple_EURUSD_concat_seasonals.py
Qual período de tempo usar?
Para esta parte do artigo, ajustei o filtro para obter melhores resultados para o EURUSD.
cutoff_frequency = 0.1 # Frecuencia de corte en proporción a la frecuencia de Nyquist order = 1
Também modifiquei o filtro:
from sklearn.preprocessing import MinMaxScaler from scipy.signal import butter, lfilter # Parámetros del filtro pasa bajo cutoff_frequency = 0.1 # Frecuencia de corte en proporción a la frecuencia de Nyquist order = 1 # Aplicar filtro pasa bajo def butter_lowpass_filter(data, cutoff, fs, order): nyquist = 0.5 * fs normal_cutoff = cutoff / nyquist b, a = butter(order, normal_cutoff, btype='low', analog=False) print("Coeficientes del filtro - b:", b) print("Coeficientes del filtro - a:", a) y = lfilter(b, a, data) return y scaled = MinMaxScaler(feature_range=(0,1)) valores_df1 = df.filter(['close']).values valores_df1 = pd.DataFrame(valores_df1) x_features1 = valores_df1[[0]] valores_df2 = x_features1.values data_escalada = scaled.fit_transform(valores_df2) print(data_escalada) filtered_data_low = butter_lowpass_filter(data_escalada, cutoff_frequency, fs=1, order=order) print("filtered_data_low",filtered_data_low) filtered_data_low_unscaled = scaled.inverse_transform(filtered_data_low)
A ordem deve ser arredondada para um preço inteiro.
Essa estratégia é testada ao longo de um mês para o intervalo de 1 hora, especificamente em fevereiro de 2024. Para o intervalo de 30 minutos, o teste é realizado de 1 a 15 de fevereiro, e assim por diante.
Para o intervalo de 15 minutos, realizei testes com e sem filtros. Os resultados indicam que o uso de um filtro com ajuste fino proporciona melhores resultados (pelo menos no geral).
15 minutos com filtro (Sharpe)
15 min sem filtro
30 min com filtro (agora sempre usarei filtro)
LSTM.30m.EURUSD.120.0.94.onnx LTSM_simple_30m_filtrado.py ONNX.eurusd.H1.120.30m_eurusd.mq5
1 hora
1 hour files.zip (815.64 KB)
2 horas
Como não posso usar um período de dois dias, utilizei um período de um dia (para o valor do próximo dia no EA).
Como não posso carregar mais de 32 arquivos, os próximos arquivos serão todos carregados em uma pasta.
Conclusão
Parece que, com essa estratégia, à medida que o período aumenta, os resultados parecem mais robustos para todos os TPs e SLs.
Var NextDay
Usei a estratégia deste artigo: Como usar modelos ONNX no mql5, mas como tive bons resultados com a estratégia de 2 horas, e nesse usei o período de 1 dia. Estudaremos outros valores para a variável NextDays.
if(TimeCurrent()>=ExtNextDay) { GetMinMax(); //--- set next day time ExtNextDay=TimeCurrent(); ExtNextDay-=ExtNextDay%PeriodSeconds(PERIOD_D1); ExtNextDay+=PeriodSeconds(PERIOD_D1); }
void GetMinMax(void) { vectorf close; close.CopyRates(_Symbol,PERIOD_D1,COPY_RATES_CLOSE,0,SAMPLE_SIZE); ExtMin=close.Min(); ExtMax=close.Max(); }
Agora procederemos ao estudo do EURUSD com período de 30 minutos com dados filtrados, e diferentes períodos de NextDay (Usaremos 1D, 12h e 6h) e discutiremos os resultados.
1D com período de 30 min
12 H com período de 30 min
6h com período de 30 min
Os resultados parecem melhores ao ajustar a variável NextDay. Vamos ver como isso evolui em períodos de NextDay mais curtos.
30 min com períodos de NextDay de 4h
30 min com períodos de NextDay de 2h
30 min com períodos de NextDay de 1h
Parece que, para períodos de pelo menos 30 minutos, cerca de 8 a 12 barras de 30 minutos dão melhores resultados.
Como este "jogo" é para ganhar mais dinheiro, e uma maneira de fazer isso é ter mais operações vencedoras e uma estratégia sólida. Vamos ver se podemos usar esse início para vencer com períodos de 5 minutos, então tentaremos essa estratégia para 5 minutos e 1 hora e 30 minutos para a variável NextDay.
5 minutos com variável NextDay de 1h.
5 minutos com variável NextDay de 30 min.
Arquivos usados: Last files.zip
Outros períodos de tempo parecem ser mais confiáveis, mas, se você quiser outro EA, tem mais para usar.
Por fim, podemos fazer ajustes na estratégia, o que poderia resultar em melhores ou mais sólidos resultados, como estabelecer um limite de tempo ou barras, por exemplo, em períodos de 1 hora, e usar um período de 12 horas para o próximo dia. Poderíamos estabelecer que, uma vez que a ordem seja feita, ela deve permanecer aberta por no máximo 12 horas.
if(ExtPredictedClass>=0) { if(PositionSelect(_Symbol)) CheckForClose(); else { CheckForOpen(); started_time1 = rates[0].time; string started_time1_str = TimeToString(started_time1);
int total = PositionsTotal(); if(total>0) { datetime started_time2 = rates[0].time; string started_time2_str = TimeToString(started_time2); int segundos = started_time2 - started_time1; Print("Tiempo 1: ", started_time1_str); Print("Tiempo 2: ", started_time2_str); Print("Diferencia en segundos: ", segundos); if((segundos >= days*PeriodSeconds(PERIOD_H12)) && segundos != 0) { Print("closing position----------------"); ExtTrade.PositionClose(_Symbol,3); } }
ONNX.eurusd.120.1h_H12_eurusd.v3.mq5 (9.23 KB)
Conclusão
Vimos temperar, filtrar e comparar modelos, EAs e parâmetros, tentando alcançar melhores resultados com ajustes finos. Espero que você tenha gostado de ler este artigo tanto quanto eu gostei de escrevê-lo.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14424
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.







- 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