Machine Learning e Data Science (Parte 40): Uso dos níveis de Fibonacci em dados para machine learning
Sumário
- Origem dos números de Fibonacci
- Entendendo os níveis de retração de Fibonacci no trading
- Criação de uma variável-alvo usando os níveis de retração de Fibonacci
- Treinamento de um modelo classificador com base na variável-alvo dos níveis de Fibonacci
- Treinamento de um modelo de regressão com base na variável-alvo dos níveis de Fibonacci
- Teste dos modelos de machine learning com níveis de Fibonacci no testador de estratégias
- Considerações finais
Origem dos números de Fibonacci
Os números de Fibonacci remontam ao antigo matemático Leonardo de Pisa, também conhecido como Fibonacci.
Em seu livro "Liber Abaci", publicado em 1202, Fibonacci apresentou a sequência de números hoje conhecida como sequência de Fibonacci. Essa sequência começa com 0 e 1, e cada número seguinte corresponde à soma dos dois anteriores.
Essa sequência tem um significado especial, pois aparece em diversos fenômenos naturais, incluindo o crescimento de plantas e animais.
Na biologia, embora não de forma exata, a espiral logarítmica observada nas conchas de alguns animais e insetos apresenta uma correspondência aproximada com os números de Fibonacci.
Também é possível observar padrões de crescimento associados à sequência de Fibonacci em populações de coelhos e nas árvores genealógicas das abelhas.
Os números de Fibonacci também são encontrados na estrutura do DNA de alguns mamíferos e dos seres humanos.

Esses números são universais, pois aparecem em praticamente toda parte. A seguir, veremos alguns termos comuns relacionados aos números de Fibonacci.
Sequência de Fibonacci
Na matemática, a sequência de Fibonacci é uma sequência em que cada elemento corresponde à soma dos dois anteriores. Os números que fazem parte dessa sequência são chamados de números de Fibonacci.

A sequência de Fibonacci pode ser expressa pela seguinte fórmula:
![]()
Onde n é maior que um (n > 1).
Proporção áurea
Trata-se de um conceito matemático que descreve a relação entre duas grandezas na qual a razão entre a menor e a maior é igual à razão entre a maior e a soma das duas.
A proporção áurea é aproximadamente igual a 1,6180339887 e é representada pela letra grega fi (φ).
A proporção áurea não é idêntica a fi, mas é próxima! Ela representa a relação entre dois números consecutivos da sequência de Fibonacci.
Se dividirmos o número maior pelo menor, o resultado ficará próximo do valor de fi. Quanto mais avançamos na sequência de Fibonacci, mais o valor se aproxima de Phi. No entanto, ele nunca será exatamente igual a Phi, pois Phi não pode ser expresso como uma fração. Trata-se de um número irracional.

Esse número é observado em diversas estruturas naturais e criadas pelo ser humano e é considerado um princípio universal de beleza e harmonia.
Entendendo os níveis de retração de Fibonacci no trading
Os níveis de retração de Fibonacci são linhas horizontais que indicam possíveis níveis de suporte e resistência nos quais o preço pode sofrer uma reversão. Eles são traçados com base nos princípios dos números de Fibonacci descritos anteriormente.
Essa ferramenta é frequentemente utilizada por traders no MetaTrader 5 para diversos fins, como definir níveis de saída da operação (stop loss e take profit) e identificar níveis de suporte e resistência nos quais há maior probabilidade de reversão dos preços.
No MetaTrader 5, a ferramenta está disponível no menu Inserir > Objetos > Fibonacci.
A seguir, são mostrados os níveis de retração de Fibonacci no gráfico EURUSD com timeframe de 1 hora.

À primeira vista, esses níveis de retração parecem ser uma ferramenta confiável para identificar níveis de negociação e reversões do mercado. Vamos, porém, avançar um pouco mais e investigar a eficácia dos níveis de Fibonacci em machine learning e inteligência artificial (AI), com destaque para o nível de 61,8% (0,618), derivado da proporção áurea.
Veremos diferentes formas de calcular matematicamente os níveis de Fibonacci e também os utilizaremos para criar uma variável-alvo que os modelos de machine learning possam usar para aprender e prever a direção do mercado.
Criação de uma variável-alvo usando os níveis de Fibonacci
Para treinar um modelo capaz de compreender as relações presentes nos dados por meio de aprendizado supervisionado, precisamos de uma variável-alvo corretamente definida. Como um nível de Fibonacci é simplesmente um número que representa determinado nível de preço, podemos obter o preço de mercado correspondente ao nível de Fibonacci desejado e usá-lo como variável-alvo em uma tarefa de regressão.
Em uma tarefa de classificação, criamos classes com base no movimento do mercado em relação às linhas de Fibonacci. Por exemplo, se o mercado estiver subindo e ultrapassar o nível de Fibonacci calculado, isso pode ser considerado um sinal de alta (representado por 1). Se o mercado estiver caindo e romper determinado nível de Fibonacci para baixo, temos um sinal de baixa (representado por 0). Os demais casos podem ser marcados como None (representado por -1).
Para a tarefa de classificação
Importação.
import pandas as pd import numpy as np
Funções.
def create_fib_clftargetvar(price: pd.Series, lookback_window: int=10, lookahead_window: int=10, fib_level: float=0.618): """ Creates a target variable based on Fibonacci breakthroughs in price data. Parameters: - price: pd.Series of price data (close, open, high, or low) - lookback_window: int - number of past periods to calculate high/low - lookahead_window: int - number of future periods to assess breakout - fib_level: float - Fibonacci retracement level (e.g. 0.618) Returns: - pd.Series: with values 1 => Bullish fib level reached 0 => Bearish fib level reached -1 => False breakthrough or no fib hit """ high = price.rolling(lookback_window).max() low = price.rolling(lookback_window).min() fib_level_value = high - (high - low) * fib_level # calculate the Fibonacci level in market price price_ahead = price.shift(-lookahead_window) # future price values target_var = [] for i in range(len(price)): if np.isnan(price_ahead.iloc[i]) or np.isnan(fib_level_value.iloc[i]) or np.isnan(price.iloc[i]): target_var.append(np.nan) continue # let's detect bull and bearish movement afterwards if price_ahead.iloc[i] > price.iloc[i]: # The market went bullish if price_ahead.iloc[i] >= fib_level_value.iloc[i]: target_var.append(1) # bullish Fibonacci target reached else: target_var.append(-1) # false breakthrough else: # The market went bearish if price_ahead.iloc[i] <= fib_level_value.iloc[i]: target_var.append(0) # bearish Fibonacci target reached else: target_var.append(-1) # false breakthrough return target_var
O nível de Fibonacci aplicado aos dados de mercado é calculado pela seguinte fórmula:
fib_level_value = high - (high - low) * fib_level
Como se trata de uma tarefa de classificação cujo objetivo é prever a reação do mercado com base no nível de Fibonacci anterior, precisamos olhar para os dados futuros e determinar a tendência. Em seguida, verificamos se o preço futuro cruzou o nível de Fibonacci, a partir de cima em uma tendência de alta ou a partir de baixo em uma tendência de baixa e, quando necessário, geramos um sinal de compra ou venda. Um sinal de espera é definido quando o preço não atinge o nível de Fibonacci em nenhuma das duas direções.
Vamos criar a variável-alvo com essa função e adicionar o resultado ao DataFrame.
df["Fib signals"] = create_fib_clftargetvar(price=df["Close"], lookback_window=10, lookahead_window=5, fib_level=0.618) df.dropna(inplace=True) # drop nan(s) caused by the shifting operation df
Resultado.
| Open | High | Low | Close | Fib signals | |
|---|---|---|---|---|---|
| 9 | 1.3492 | 1.3495 | 1.3361 | 1.3362 | 0.0 |
| 10 | 1.3364 | 1.3405 | 1.3350 | 1.3371 | 0.0 |
| 11 | 1.3370 | 1.3376 | 1.3277 | 1.3300 | 0.0 |
| 12 | 1.3302 | 1.3313 | 1.3248 | 1.3279 | -1.0 |
| 13 | 1.3279 | 1.3293 | 1.3260 | 1.3266 | 0.0 |
Para a tarefa de regressão
def create_fib_regtargetvar(price: pd.Series, lookback_window: int=10, fib_level: float=0.618): """ This function helps us in calculating the target variable based on fibonacci breakthroughs given a price price: Can be close, open, high, low """ high = price.rolling(lookback_window).max() low = price.rolling(lookback_window).min() return high - (high - low) * fib_level
Na tarefa de regressão, não é necessário deslocar os valores para obter informações futuras, pois, na negociação manual, comparamos os preços futuros com o nível de Fibonacci calculado na janela anterior (lookback_window) e determinamos se houve um cruzamento para cima ou para baixo.
O objetivo é treinar um modelo de regressão para prever o próximo valor do nível de Fibonacci com base nos dados anteriores.
df["Fibonacci Level"] = create_fib_regtargetvar(price=df["Close"], lookback_window=10, fib_level=0.618) df.dropna(inplace=True) df.head(5)
A seguir está o DataFrame resultante, agora com uma coluna adicional contendo os níveis de Fibonacci.
| Open | High | Low | Close | Fibonacci Level | |
|---|---|---|---|---|---|
| 9 | 1.3492 | 1.3495 | 1.3361 | 1.3362 | 1.343840 |
| 10 | 1.3364 | 1.3405 | 1.3350 | 1.3371 | 1.342923 |
| 11 | 1.3370 | 1.3376 | 1.3277 | 1.3300 | 1.339015 |
| 12 | 1.3302 | 1.3313 | 1.3248 | 1.3279 | 1.337717 |
| 13 | 1.3279 | 1.3293 | 1.3260 | 1.3266 | 1.335195 |
Treinamento do classificador com a variável-alvo de Fibonacci
Vamos começar pela variável-alvo de classificação "Fib signals" e treinar um modelo simples do tipo RandomForestClassifier com esses dados.
Importação.
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from sklearn.utils.class_weight import compute_class_weight from sklearn.pipeline import Pipeline from sklearn.preprocessing import RobustScaler
Divisão em conjuntos de treinamento e teste.
X = df.drop(columns=[ "Fib signals" ]) y = df["Fib signals"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, shuffle=False)
Modelo.
class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) weight_dict = dict(zip(np.unique(y_train), class_weights)) model = RandomForestClassifier(n_estimators=100, min_samples_split=2, max_depth=10, class_weight=weight_dict, random_state=42 ) clf_pipeline = Pipeline(steps=[ ("scaler", RobustScaler()), ("rfc", model) ]) clf_pipeline.fit(X_train, y_train)
O modelo de floresta aleatória, baseado em árvores de decisão, não exige escalonamento. No entanto, como os valores Open, High, Low e Close (OHLC) são contínuos e podem conter valores atípicos, utilizamos o RobustScaler para reduzir a influência desses valores.
Após o treinamento, testamos o modelo tanto nos dados de treinamento quanto nos dados de teste.
y_train_pred = clf_pipeline.predict(X_train) print("Train Classification report\n",classification_report(y_train, y_train_pred)) y_test_pred = clf_pipeline.predict(X_test) print("Test Classification report\n",classification_report(y_test, y_test_pred))
Resultado.
Train Classification report precision recall f1-score support -1.0 0.53 0.55 0.54 4403 0.0 0.59 0.64 0.61 7122 1.0 0.67 0.60 0.64 8294 accuracy 0.61 19819 macro avg 0.60 0.60 0.60 19819 weighted avg 0.61 0.61 0.61 19819 Test Classification report precision recall f1-score support -1.0 0.22 0.22 0.22 1810 0.0 0.38 0.60 0.46 3181 1.0 0.42 0.20 0.27 3504 accuracy 0.35 8495 macro avg 0.34 0.34 0.32 8495 weighted avg 0.36 0.35 0.33 8495
O resultado nos dados de treinamento parece excelente, mas o desempenho nos dados de teste é inferior. Isso indica que o modelo não aprendeu a reconhecer padrões fora da amostra de treinamento.
Isso pode estar relacionado a diversos fatores, como a quantidade insuficiente de atributos para capturar padrões relevantes do mercado, já que apenas os preços OHLC podem não ser suficientes, ou ainda à forma simplificada de determinar a tendência durante a criação da variável-alvo, fazendo com que o modelo ignore barras intermediárias.
Como nosso objetivo era treinar o modelo para prever cruzamentos do nível de Fibonacci, esse resultado da classificação pode ser enganoso, pois é incompleto. Ainda assim, continuaremos usando o modelo e analisaremos seu comportamento com dados de teste em um ambiente real de negociação.
Vamos salvar o modelo treinado no formato ONNX para uso externo no MQL5.
import skl2onnx from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType
# Define the initial type of the model’s input initial_type = [('input', FloatTensorType([None, X_train.shape[1]]))] # Convert the pipeline to ONNX onnx_model = convert_sklearn(clf_pipeline, initial_types=initial_type, target_opset=13) # Save the ONNX model to a file with open(f"{symbol}.{timeframe}.Fibonnacitarg-RFC.onnx", "wb") as f: f.write(onnx_model.SerializeToString())
Treinamento do modelo de regressão com base na variável-alvo dos níveis de Fibonacci
Os princípios usados para treinar o modelo de regressão permanecem os mesmos. Neste caso, mudam apenas o tipo de modelo e a variável-alvo.
Importação.
from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import r2_score
Divisão em conjuntos de treinamento e teste.
X = df.drop(columns=[ "Fibonacci Level" ]) y = df["Fibonacci Level"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, shuffle=False)
Modelo de floresta aleatória.
model = RandomForestRegressor(n_estimators=100, min_samples_split=2, max_depth=10, random_state=42 ) reg_pipeline = Pipeline(steps=[ ("scaler", RobustScaler()), ("rfr", model) ]) reg_pipeline.fit(X_train, y_train)
Por fim, podemos testar o modelo de regressão tanto no conjunto de treinamento quanto no conjunto de teste.
y_train_pred = reg_pipeline.predict(X_train) print("Train accuracy score:",r2_score(y_train, y_train_pred)) y_test_pred = reg_pipeline.predict(X_test) print("Test accuracy score:",r2_score(y_test, y_test_pred))
Resultado.
Train accuracy score: 0.9990321734526452 Test accuracy score: 0.9565827587164671
Não há muito a concluir apenas com a métrica R² do modelo de regressão, mas um R² de 0,9565 no conjunto de teste é um bom resultado de desempenho em dados fora da amostra de treinamento.
Vamos salvar esse modelo treinado no formato ONNX para uso no MQL5.
# Define the initial type of the model’s input initial_type = [('input', FloatTensorType([None, X_train.shape[1]]))] # Convert the pipeline to ONNX onnx_model = convert_sklearn(reg_pipeline, initial_types=initial_type, target_opset=13) # Save the ONNX model to a file with open(f"{symbol}.{timeframe}.Fibonnacitarg-RFR.onnx", "wb") as f: f.write(onnx_model.SerializeToString())
Agora vamos testar a capacidade preditiva dos modelos em condições reais de negociação.
Teste dos modelos de machine learning com níveis de Fibonacci no testador de estratégias
Carregamos os modelos de floresta aleatória no formato ONNX como recursos do EA.
#resource "\\Files\\EURUSD.PERIOD_H4.Fibonnacitarg-RFC.onnx" as uchar rfc_onnx[] #resource "\\Files\\EURUSD.PERIOD_H4.Fibonnacitarg-RFR.onnx" as uchar rfr_onnx[]
Em seguida, importamos a biblioteca responsável por carregar o classificador Random Forest e o modelo de regressão no formato ONNX.
#include <Random Forest.mqh>
CRandomForestClassifier rfc;
CRandomForestRegressor rfr; Usamos os mesmos valores das janelas lookahead e lookback empregados durante o treinamento. Isso permite determinar corretamente por quanto tempo as posições devem permanecer abertas e quando devem ser encerradas.
input group "Models configs"; input target_var_type fib_target = CLASSIFIER; //Model type input int lookahead_window = 5; input int lookback_window = 10;
A variável fib_target permite selecionar o tipo de modelo a ser utilizado.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Setting the symbol and timeframe if (!MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_DEBUG)) if (!ChartSetSymbolPeriod(0, symbol_, timeframe_)) { printf("%s failed to set symbol %s and timeframe %s",__FUNCTION__,symbol_,EnumToString(timeframe_)); return INIT_FAILED; } //--- m_trade.SetExpertMagicNumber(magic_number); m_trade.SetDeviationInPoints(slippage); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(Symbol()); //--- switch(fib_target) { case REGRESSOR: if (!rfr.Init(rfr_onnx)) { printf("%s failed to initialize the random forest regressor",__FUNCTION__); return INIT_FAILED; } break; case CLASSIFIER: if (!rfc.Init(rfc_onnx)) { printf("%s failed to initialize the random forest classifier",__FUNCTION__); return INIT_FAILED; } break; } //--- return(INIT_SUCCEEDED); }
Na função OnTick, os sinais do modelo são gerados com base nos dados OHLC, da mesma forma que fizemos durante o treinamento.
Esses sinais são usados para abrir operações de compra e venda.
void OnTick() { //--- Getting signals from the model if (!isNewBar()) return; vector x = { iOpen(Symbol(), Period(), 1), iHigh(Symbol(), Period(), 1), iLow(Symbol(), Period(), 1), iClose(Symbol(), Period(), 1) }; long signal = 0; switch(fib_target) { case REGRESSOR: { double pred_fib = rfr.predict(x); signal = pred_fib>iClose(Symbol(), Period(), 0)?1:0; //If the predicted fibonacci is greater than the current close price, thats bullish otherwise thats bearish signal } break; case CLASSIFIER: signal = rfc.predict(x).cls; break; } //--- Trading based on the signals received from the model MqlTick ticks; if (!SymbolInfoTick(Symbol(), ticks)) { printf("Failed to obtain ticks information, Error = %d",GetLastError()); return; } double volume_ = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN); if (signal == 1) { if (!PosExists(POSITION_TYPE_BUY) && !PosExists(POSITION_TYPE_SELL)) m_trade.Buy(volume_, Symbol(), ticks.ask); } if (signal == 0) { if (!PosExists(POSITION_TYPE_SELL) && !PosExists(POSITION_TYPE_BUY)) m_trade.Sell(volume_, Symbol(), ticks.bid); } //--- Closing trades switch(fib_target) { case CLASSIFIER: CloseTradeAfterTime((Timeframe2Minutes(Period())*lookahead_window)*60); //Close the trade after a certain lookahead and according the the trained timeframe break; case REGRESSOR: CloseTradeAfterTime((Timeframe2Minutes(Period())*lookback_window)*60); //Close the trade after a certain lookahead and according the the trained timeframe break; } }
O encerramento das operações depende do tipo de modelo e dos parâmetros lookahead_window e lookback_window.
No caso do classificador, as operações são encerradas, no timeframe atual, após um número de barras igual a lookahead_window.
Para o modelo de regressão, as operações são encerradas após um número de barras igual ao valor de lookback_window, também no timeframe atual.
Essa lógica corresponde à forma como as variáveis-alvo foram criadas no script Python.
Por fim, podemos testar os dois modelos no testador de estratégias.
Treinamos os modelos com dados do período de 01.01.2005 a 01.01.2023. Portanto, realizaremos o teste com dados fora da amostra, de 01.01.2023 a 31.12.2023.

Tipo de modelo: Classificador


Tipo de modelo: Regressor

O modelo de regressão apresentou excelentes resultados considerando que foi testado com dados novos: 57,42% das operações foram vencedoras.
Para simplificar a implementação, no EA converti a saída contínua do Random Forest Regressor em um sinal binário.
signal = pred_fib>iClose(Symbol(), Period(), 0)?1:0; //If the predicted Fibonacci is greater than the current close price, that's bullish otherwise that's bearish signal
Isso muda completamente a forma de interpretar o nível de Fibonacci previsto. Diferentemente da negociação manual, em que normalmente abrimos uma operação no final de uma tendência após recebermos um sinal de confirmação, aqui adotamos outra abordagem. Na negociação manual, em geral definimos os alvos da operação em determinado nível de Fibonacci, normalmente em 61,8%.
Com essa abordagem, partimos do pressuposto de que nossos modelos de machine learning já identificaram esse padrão dentro das janelas lookback e lookahead definidas durante o treinamento. Assim, basta abrir as operações e mantê-las durante um número previamente determinado de barras.
O principal fator nesse caso são os valores das janelas lookahead e lookback. Isso ocorre principalmente porque, ao utilizar manualmente a ferramenta de Fibonacci, normalmente não levamos em consideração a quantidade de barras usada para calcular os níveis a partir dos valores mínimos e máximos. Em geral, simplesmente posicionamos a ferramenta onde julgamos mais adequado.
Embora a ferramenta funcione na negociação manual, ela pode criar a falsa impressão de que foi posicionada corretamente, quando, na prática, muitas vezes apenas a colocamos em um ponto que nos parece conveniente, sem seguir regras claramente definidas.
São justamente esses dois parâmetros, as janelas lookahead e lookback, que precisam ser otimizados se quisermos investigar a eficácia dos níveis de Fibonacci na criação da variável-alvo e em sua aplicação ao machine learning de forma geral.
Considerações finais
Os níveis de retração de Fibonacci podem ser uma ferramenta eficaz para a criação de variáveis-alvo em tarefas de machine learning, como demonstra o relatório obtido no testador de estratégias com o modelo de regressão. Mesmo utilizando um conjunto mínimo de atributos, composto apenas por Open, High, Low e Close, que por si só não oferece uma grande quantidade de padrões consistentes, os modelos conseguiram identificar determinadas regularidades e apresentar resultados superiores ao acaso com base nas informações extraídas dos níveis de Fibonacci.
Independentemente de como os resultados obtidos sejam interpretados, na minha opinião eles são bastante impressionantes.
Ainda assim, neste estágio a ideia precisa ser desenvolvida com mais profundidade. É necessário ampliar o conjunto de atributos, adicionando valores de indicadores técnicos e confirmações de estratégias de negociação, para ajudar o modelo baseado nos níveis de Fibonacci a identificar padrões de mercado mais complexos. Também recomendo explorar outros níveis de Fibonacci.
Com o desenvolvimento dessa abordagem, ela pode se mostrar especialmente eficaz nos mercados de ações e de índices, onde as correções ocorrem regularmente dentro de tendências de alta de longo prazo, bem como em timeframes mais altos, como o diário, nos quais os dados de mercado apresentam menos ruído.
Tabela de anexos
| Nome e caminho do arquivo | Descrição e finalidade |
|---|---|
| Experts\Fibonacci AI based.mq5 | EA principal para testar os modelos de machine learning. |
| Include\Random Forest.mqh | Contém classes para carregar e implantar o classificador e o modelo de regressão Random Forest no formato .ONNX. |
| Files\*.onnx | Modelos de machine learning no formato ONNX. |
| Files\*.csv | Arquivos CSV contendo os conjuntos de dados que serão utilizados para treinar os modelos de machine learning. |
| Python\fibbonanci-in-ml.ipynb | Script em Python para processamento dos dados e treinamento dos modelos de floresta aleatória. |
Fontes e referências
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/18078
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
Machine Learning e Data Science (Parte 39): Testando a combinação de notícias com IA
Está chegando o novo MetaTrader 5 e MQL5
Trading com o Calendário Econômico MQL5 (Parte 8): Otimizando o teste de estratégias baseadas em notícias com filtros e logs
- 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
