Machine Learning e Data Science (Parte 38): Aplicação de Transfer Learning nos mercados de câmbio
Conteúdo
- O que é Transfer Learning?
- Como funciona?
- Vantagens
- Modelo-base simples
- O problema das variáveis contínuas
- Transfer Learning - aprendizado por transferência
- Transfer Learning no robô de negociação
- Considerações finais
O que é Transfer Learning?
Transfer Learning (aprendizado por transferência) é uma técnica de machine learning em que um modelo treinado para uma determinada tarefa é usado como base para resolver outra.
Em vez de treinar um modelo de machine learning do zero, transferimos o conhecimento adquirido por um modelo previamente treinado e realizamos uma atualização incremental do modelo para adaptá-lo a uma nova tarefa específica. Essa abordagem é especialmente útil quando:
- Não dispomos de dados rotulados suficientes para uma tarefa específica.
- Treinar um modelo do zero levaria tempo demais ou exigiria recursos computacionais excessivos.
- A tarefa atual apresenta semelhanças com aquela em que o modelo original foi treinado.
Veja um exemplo prático de uso de Transfer Learning:
Suponha que você esteja criando um classificador de imagens para distinguir "gato" de "cachorro", mas disponha de apenas 1.000 imagens. Treinar uma CNN profunda do zero seria difícil. Em vez disso, podemos usar um modelo como o ResNet50 ou o VGG16, já treinado no ImageNet, com milhões de imagens distribuídas em 1.000 classes, utilizar suas camadas convolucionais como extratores de atributos, adicionar nossas próprias camadas de classificação e realizar uma atualização incremental do modelo com um conjunto menor de imagens de gatos e cachorros.
Esse procedimento permite reutilizar o conhecimento adquirido pelo modelo, simplificando significativamente o desenvolvimento. Não é necessário reinventar a roda a cada vez: em vez de treinar um modelo do zero, podemos escalar o desenvolvimento aproveitando modelos existentes voltados a tarefas semelhantes.
Em geral, quem sabe patinar ou pratica patinação regularmente também consegue se sair razoavelmente bem no esqui, e vice-versa, mesmo sem treinamento intensivo em ambas as modalidades. Isso acontece porque os dois esportes compartilham elementos semelhantes.
O mesmo princípio se aplica aos mercados financeiros. Embora existam diferentes instrumentos (símbolos) representando diferentes ativos ou mercados financeiros, a maioria dos mercados apresenta comportamentos semelhantes, pois todos são movidos pela oferta e pela demanda.
Se analisarmos o mercado do ponto de vista técnico, veremos que todos os mercados sobem e descem, apresentam padrões de candles semelhantes, e os indicadores geram sinais parecidos em diferentes instrumentos, entre outros exemplos. É justamente por isso que muitas vezes estudamos uma estratégia de negociação baseada em análise técnica usando um determinado instrumento e depois aplicamos o conhecimento adquirido a outros mercados, independentemente das diferenças de escala de preços.
No entanto, os modelos de machine learning muitas vezes não reconhecem que esses mercados são comparáveis. Neste artigo, veremos como usar Transfer Learning para ajudar os modelos a identificar padrões em diferentes instrumentos financeiros e, assim, tornar o treinamento mais eficiente. Também analisaremos as vantagens e desvantagens desse método, além de aspectos importantes que devem ser considerados ao aplicá-lo.
Como funciona o Transfer Learning?
Transfer Learning é uma forma eficiente de reutilizar o conhecimento adquirido por um modelo ao resolver uma tarefa e aplicá-lo a outra tarefa relacionada. Isso economiza tempo e, muitas vezes, melhora o desempenho do modelo.

O que é um modelo pré-treinado?
Começamos com um modelo que já foi treinado em um grande conjunto de dados para executar a tarefa A. Esse modelo aprendeu a reconhecer padrões e atributos gerais que também podem ser úteis em tarefas semelhantes.
No trading, por exemplo, pode ser um modelo treinado com uma determinada estratégia ou com dados de um símbolo e que já compreende comportamentos típicos do mercado também presentes em outros instrumentos de câmbio.
Como o conhecimento é transferido?
Quando usamos uma rede neural, como uma CNN ou RNN, podemos aproveitar as camadas iniciais, responsáveis por capturar atributos mais gerais, e reutilizá-las. Essas camadas funcionam como uma base, identificando padrões amplos que são úteis tanto para a tarefa original quanto para a nova.
Atualização incremental do modelo para a nova tarefa
Em seguida, adaptamos o modelo à tarefa B, por exemplo, a outro instrumento ou estratégia, e ajustamos determinadas camadas ou parâmetros para que ele funcione corretamente com os novos dados. Essa etapa adapta o modelo às características da nova situação.
Por que usar Transfer Learning?
1. Treinamento mais rápido
Em vez de começar do zero, reutilizamos atributos que já foram extraídos anteriormente. Isso reduz significativamente o tempo de treinamento, especialmente em deep learning, em que essa abordagem pode economizar horas ou até mesmo dias.
2. Frequentemente melhora a acurácia
Modelos que utilizam Transfer Learning costumam apresentar resultados melhores, principalmente quando há poucos dados rotulados disponíveis. Um modelo pré-treinado já sabe identificar sinais importantes, como setups de trading ou indicadores, o que ajuda a produzir decisões mais bem fundamentadas na nova tarefa.
3. Funciona mesmo com conjuntos de dados pequenos ou ruidosos
Em alguns símbolos, pode ser difícil obter dados históricos ou dados de ticks de boa qualidade no MetaTrader 5. Alguns instrumentos simplesmente não dispõem de um volume de dados suficiente. Ao usar um modelo treinado em um conjunto de dados mais rico, podemos evitar o sobreajuste e construir um modelo robusto mesmo quando os dados disponíveis são limitados.
4. Reutilização do conhecimento entre instrumentos
Os mercados frequentemente apresentam comportamentos semelhantes do ponto de vista técnico. Em vez de treinar um novo modelo para cada símbolo, podemos reutilizar o mesmo conhecimento em diferentes instrumentos. Isso economiza tempo e aumenta a consistência dos resultados.
Modelo-base simples
Vamos treinar um classificador Random Forest simples como ponto de partida, ou seja, como modelo-base. Para simplificar, podemos usar os valores OHLC (Open, High, Low, Close).
Primeiro, vamos coletar dados OHLC dos principais e secundários pares de moedas e incluir também metais.
#include <pandas.mqh> //https://www.mql5.com/en/articles/17030 input datetime start_date = D'2005.01.01'; input datetime end_date = D'2023.01.01'; input string symbols = "EURUSD|GBPUSD|AUDUSD|USDCAD|USDJPY|USDCHF|NZDUSD|EURNZD|AUDNZD|GBPNZD|NZDCHF|NZDJPY|NZDCAD|XAUUSD|XAUJPY|XAUEUR|XAUGBP"; input ENUM_TIMEFRAMES timeframe = PERIOD_D1; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { string SymbolsArr[]; ushort sep = StringGetCharacter("|",0); if (StringSplit(symbols, sep, SymbolsArr)<0) { printf("%s failed to split the symbols, Error %d",__FUNCTION__,GetLastError()); return; } //--- vector open, high, low, close; for (uint i=0; i<SymbolsArr.Size(); i++) { string symbol = SymbolsArr[i]; if (!SymbolSelect(symbol, true)) { printf("%s failed to select symbol %s, Error = %d",__FUNCTION__,symbol,GetLastError()); continue; } //--- open.CopyRates(symbol, timeframe, COPY_RATES_OPEN, start_date, end_date); high.CopyRates(symbol, timeframe, COPY_RATES_HIGH, start_date, end_date); low.CopyRates(symbol, timeframe, COPY_RATES_LOW, start_date, end_date); close.CopyRates(symbol, timeframe, COPY_RATES_CLOSE, start_date, end_date); CDataFrame df; df.insert("Open", open); df.insert("High", high); df.insert("Low", low); df.insert("Close", close); df.to_csv(StringFormat("Fxdata.%s.%s.csv",symbol,EnumToString(timeframe)), true); } }
Depois de coletar os dados, podemos carregar diretamente os arquivos CSV em um script Python.
def getXandY(symbol: str, timeframe: str, lookahead: int) -> tuple: df = pd.read_csv(f"/kaggle/input/ohlc-eurusd/Fxdata.{symbol}.{timeframe}.csv") # Target variable df["future_close"] = df["Close"].shift(-lookahead) df.dropna(inplace=True) df["Signal"] = (df["future_close"] > df["Close"]).astype(int) # Splitting data into X and y X = df.drop(columns=[ "future_close", "Signal" ]) y = df["Signal"] return (X, y)
Após a leitura do arquivo CSV, a função getXandY gera a variável-alvo com base em uma lógica simples: se o fechamento da próxima barra estiver acima do fechamento atual, temos um sinal de alta; se estiver abaixo, temos um sinal de baixa.
Vamos criar uma função para treinar o modelo com base em X e y e retornar o modelo treinado na forma de um pipeline do Scikit-learn.
def trainSymbol(X_train: pd.DataFrame, y_train: pd.DataFrame) -> Pipeline: # Training a model classifier = RandomForestClassifier(n_estimators=100, min_samples_split=3, max_depth = 5) pipeline = Pipeline([ ("scaler", RobustScaler()), ("classifier", classifier) ]) pipeline.fit(X_train, y_train) return pipeline
Também é útil implementar uma função para avaliar o modelo em diferentes instrumentos.
def evalSymbol(model: Pipeline, X: pd.DataFrame , y: pd.Series) -> int: # evaluating the model preds = model.predict(X) acc = accuracy_score(y, preds) return acc
Vamos treinar o modelo-base no EURUSD e, em seguida, avaliar seus resultados nos demais símbolos.
symbols = ["EURUSD","GBPUSD","AUDUSD","USDCAD","USDJPY","USDCHF","NZDUSD","EURNZD","AUDNZD","GBPNZD","NZDCHF","NZDJPY","NZDCAD","XAUUSD","XAUJPY","XAUEUR","XAUGBP"] # training on EURUSD lookahead = 1 X, y = getXandY(symbol=symbols[0], timeframe="PERIOD_H4", lookahead=lookahead) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, shuffle=True) model = trainSymbol(X_train, y_train) # Evaluating on the rest of symbols trained_symbol = symbols[0] print(f"Trained on {trained_symbol}") for symbol in symbols: X, y = getXandY(symbol=symbol, timeframe="PERIOD_H4", lookahead=1) acc = evalSymbol(model, X, y) print(f"--> {symbol} | acc: {acc}")
Resultados.
Trained on EURUSD --> EURUSD | acc: 0.5478518727715607 --> GBPUSD | acc: 0.5009182736455464 --> AUDUSD | acc: 0.5026133634694165 --> USDCAD | acc: 0.4973701860284514 --> USDJPY | acc: 0.49477401129943505 --> USDCHF | acc: 0.5078731817539895 --> NZDUSD | acc: 0.4976826463824518 --> EURNZD | acc: 0.5071507150715071 --> AUDNZD | acc: 0.5005597760895641 --> GBPNZD | acc: 0.503459397596629 --> NZDCHF | acc: 0.4990389436737423 --> NZDJPY | acc: 0.4908841561794127 --> NZDCAD | acc: 0.5023507681974645 --> XAUUSD | acc: 0.48674396277970605 --> XAUJPY | acc: 0.4816082121471343 --> XAUEUR | acc: 0.4925268155442237 --> XAUGBP | acc: 0.49455864570737607
O modelo apresentou acurácia de 0,54 no instrumento em que foi treinado e entre 0,48 e 0,50 nos demais. À primeira vista, pode parecer que os resultados não diferem muito e que o modelo também funciona em outros instrumentos. No entanto, esse desempenho é extremamente ruim.
Uma acurácia de 0,5 (50%) equivale a lançar uma moeda.
Embora o modelo-base aparentemente consiga fazer previsões em outros instrumentos, surge um problema importante relacionado aos atributos contínuos, ou seja, aos valores OHLC.
O problema das variáveis contínuas
Como queremos criar um modelo-base robusto e universal, capaz de funcionar em diferentes símbolos, atributos contínuos como Open, High, Low e Close não são adequados. Isso ocorre porque eles não contêm padrões estáveis, refletindo apenas o movimento histórico dos preços.
Além disso, cada instrumento possui sua própria escala de preços. Por exemplo, os preços de fechamento de hoje são os seguintes:
| SYMBOL | DAILY CLOSING PRICE |
|---|---|
| USDJPY | 142.17 |
| EURUSD | 1.13839 |
| XAUUSD | 3305.02 |
Isso significa que um modelo treinado em um instrumento pode apresentar desempenho ruim em outros devido às diferenças entre as faixas de preço.
Além de não conterem padrões transferíveis, modelos baseados em variáveis contínuas precisam ser treinados novamente com frequência, pois os mercados atingem novos máximos regularmente. Isso aumenta o custo computacional, exatamente o que queremos minimizar com Transfer Learning.
Somente variáveis estacionárias podem ajudar os modelos de machine learning a identificar padrões relevantes em diferentes mercados, pois seu valor esperado, sua variância e sua autocorrelação não se alteram ao longo do tempo, permanecendo constantes. Essa estabilidade estatística pode ser observada em diferentes instrumentos.
Para usar Transfer Learning, todos os atributos, incluindo indicadores e padrões, devem ser constantes ou estacionários.
Por exemplo, os valores do indicador RSI permanecem sempre no intervalo de 0 a 100, independentemente do instrumento, o que é fundamental para a identificação de padrões.
Engenharia de atributos
Existem diversos métodos para obter atributos estacionários. No nosso caso, podemos usar a variação percentual do preço de fechamento, as diferenças (diff) entre valores consecutivos de cada série OHLC ou indicadores estacionários.
(a) Variação percentual do preço de fechamento
res_df["pct_change"] = df["Close"].pct_change()
Apesar das diferenças na escala de preços, as variações percentuais permanecem comparáveis e são adequadas para identificar padrões de forma consistente entre diferentes instrumentos.

(b) Diferença entre os valores OHLC
res_df["diff_open"] = df["Open"].diff() res_df["diff_high"] = df["High"].diff() res_df["diff_low"] = df["Low"].diff() res_df["diff_close"] = df["Close"].diff()
O método diff() calcula, por padrão, a diferença entre o valor atual e o anterior. Isso permite acompanhar como o preço de cada barra varia em relação à barra precedente em cada instrumento.

(c) Indicadores estacionários
Também podemos adicionar osciladores e indicadores de momentum que produzam valores estacionários.
Indicador | Intervalo de valores |
|---|---|
# Relative Strength Index (RSI) res_df['rsi'] = ta.momentum.RSIIndicator(df["Close"], window=14).rsi() | De 0 a 100. |
# Stochastic Oscillator (Stoch) res_df['stoch_k'] = ta.momentum.StochasticOscillator(df['High'], df['Low'], df['Close'], window=14).stoch() | De 0 a 100. |
# Moving Average Convergence Divergence (MACD) res_df['macd'] = ta.trend.MACD(df["Close"]).macd() | Pequenos valores positivos e negativos, geralmente entre -0,1 e +0,1. |
# Commodity Channel Index (CCI) res_df['cci'] = ta.trend.CCIIndicator(df['High'], df['Low'], df['Close'], window=20).cci() | Geralmente entre -300 e +300. |
# Rate of Change (ROC) res_df['roc'] = ta.momentum.ROCIndicator(df["Close"], window=12).roc() | Valor sem limite definido, podendo ser negativo ou positivo. |
# Ultimate Oscillator (UO) res_df['uo'] = ta.momentum.UltimateOscillator(df['High'], df['Low'], df['Close'], window1=7, window2=14, window3=28).ultimate_oscillator() | De 0 a 100. |
# Williams %R res_df['williams_r'] = ta.momentum.WilliamsRIndicator(df['High'], df['Low'], df['Close']).williams_r() | De -100 a 0. |
# Average True Range (ATR) res_df['atr'] = ta.volatility.AverageTrueRange(df['High'], df['Low'], df['Close'], window=14).average_true_range() | Pequenos valores positivos sem limite definido. |
# Awesome Oscillator (AO) res_df['ao'] = ta.momentum.AwesomeOscillatorIndicator(df['High'], df['Low']).awesome_oscillator() | Pequenos valores sem limite definido, geralmente entre -0,1 e +0,1. |
# Average Directional Index (ADX) res_df['adx'] = ta.trend.ADXIndicator(df['High'], df['Low'], df['Close'], window=14).adx() | De 0 a 100. |
# True Strength Index (TSI) res_df['tsi'] = ta.momentum.TSIIndicator(df['Close'], window_slow=25, window_fast=13).tsi() | Geralmente entre -100 e +100. |
Esses são alguns exemplos de variáveis estacionárias. Você pode acrescentar outras de sua preferência.
Todas essas operações podem ser reunidas em uma função separada.
def getStationaryVars(df: pd.DataFrame) -> pd.DataFrame: res_df = pd.DataFrame() res_df["pct_change"] = df["Close"].pct_change() res_df["diff_open"] = df["Open"].diff() res_df["diff_high"] = df["High"].diff() res_df["diff_low"] = df["Low"].diff() res_df["diff_close"] = df["Close"].diff() # Relative Strength Index (RSI) res_df['rsi'] = ta.momentum.RSIIndicator(df["Close"], window=14).rsi() # Stochastic Oscillator (Stoch) res_df['stoch_k'] = ta.momentum.StochasticOscillator(df['High'], df['Low'], df['Close'], window=14).stoch() # Moving Average Convergence Divergence (MACD) res_df['macd'] = ta.trend.MACD(df["Close"]).macd() # Commodity Channel Index (CCI) res_df['cci'] = ta.trend.CCIIndicator(df['High'], df['Low'], df['Close'], window=20).cci() # .... See the code in the notebook in the attachments and above # .... # .... # True Strength Index (TSI) res_df['tsi'] = ta.momentum.TSIIndicator(df['Close'], window_slow=25, window_fast=13).tsi() return res_df
Agora vamos criar um modelo-base para transferir conhecimento entre diferentes instrumentos.
Transfer Learning
O Transfer Learning é aplicado com mais frequência a modelos de deep learning, principalmente a redes neurais convolucionais (CNN), por sua eficácia na extração de padrões.
Vamos encapsular o modelo CNN em uma função trainCNN.
import tensorflow as tf from tensorflow.keras import layers, models, Model from tensorflow.keras.callbacks import EarlyStopping
def trainCNN(train_set: tuple, val_set: tuple, learning_rate: float=1e-3, epochs: int=100, batch_size: int=32): X_train, y_train = train_set X_val, y_val = val_set input_shape = X_train.shape[1:] num_classes = len(np.unique(y_train)) model = models.Sequential([ layers.Input(shape=input_shape), layers.Conv1D(64, kernel_size=3, activation='relu', padding='same'), layers.Conv1D(64, kernel_size=3, activation='relu', padding='same'), layers.GlobalAveragePooling1D(), layers.Dense(32, activation='tanh'), layers.Dense(num_classes, activation='softmax') ]) # Compile with Adam optimizer model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), loss='categorical_crossentropy', metrics=['accuracy'] ) # Early stopping callback early_stop = EarlyStopping( monitor='val_loss', # Watch validation loss patience=10, # Stop if no improvement restore_best_weights=True ) # Train the model model.fit( X_train, y_train, validation_data=(X_val, y_val), epochs=epochs, batch_size=batch_size, callbacks=[early_stop], verbose=1 ) # Save trained weights model.save_weights('cnn_pretrained.weights.h5') return model
Esse modelo sequencial contém duas camadas convolucionais unidimensionais (Conv1D) para extrair atributos da sequência de entrada.
A camada de global average pooling reduz a dimensionalidade antes que os dados sejam encaminhados para uma camada totalmente conectada (FNN
) com ativação tanh. A última camada utiliza softmax para obter as probabilidades das classes.
Salvamos os pesos do modelo, pois eles representam os padrões aprendidos e podem ser transferidos para outro modelo.
Usando o EURUSD no timeframe H4, obtemos os dados OHLC.
lookahead = 1 trained_symbol = symbols[0] timeframe = "PERIOD_H4" df = pd.read_csv(f"/kaggle/input/ohlc-eurusd/Fxdata.{trained_symbol}.{timeframe}.csv") stationary_df = getStationaryVars(df) stationary_df["Close"] = df["Close"] # add the close price for crafting the target variable X, y = getXandY(df=stationary_df, lookahead=lookahead)
A função getXandY volta a gerar a variável-alvo com base no valor de Close e no parâmetro lookahead (1).
def getXandY(df: pd.DataFrame, lookahead: int) -> tuple: # Target variable df["future_close"] = df["Close"].shift(-lookahead) df.dropna(inplace=True) df["Signal"] = (df["future_close"] > df["Close"]).astype(int) # if next bar closed above the current one, thats a bullish signal otherwise bearish # Splitting data into X and y X = df.drop(columns=[ "Close", "future_close", "Signal" ]) y = df["Signal"] return (X, y)
Os dados são divididos em conjuntos de treinamento e validação e, em seguida, escalados com um scaler. No nosso caso, usamos o Robust Scaler.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=False, random_state=42) # Scalling the data scaler = RobustScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)
Como a CNN exige dados de entrada em três dimensões, podemos reorganizá-los em janelas temporais para que o modelo identifique padrões dentro de cada janela.
def create_sequences(X, Y, time_step): if len(X) != len(Y): raise ValueError("X and y must have the same length") X = np.array(X) Y = np.array(Y) Xs, Ys = [], [] for i in range(X.shape[0] - time_step): Xs.append(X[i:(i + time_step), :]) # Include all features with slicing Ys.append(Y[i + time_step]) return np.array(Xs), np.array(Ys)
# Prepare data within a window window = 10 X_train_seq, y_train_seq = create_sequences(X_train_scaled, y_train, window) X_test_seq, y_test_seq = create_sequences(X_test_scaled, y_test, window)
Neste caso, aplicamos codificação one-hot à variável-alvo para representar as diferentes classes, pois isso permite distinguir as diferentes classes.
# One-hot encode the labels for multi-class classification
y_train_encoded = to_categorical(y_train_seq, num_classes=num_classes)
y_test_encoded = to_categorical(y_test_seq, num_classes=num_classes)
Por fim, podemos treinar o modelo-base.
base_model = trainCNN(train_set=(X_train_seq, y_train_encoded), val_set=(X_test_seq, y_test_encoded), learning_rate = 0.01, epochs = 1000, batch_size =32) print("Test acc: ", base_model.evaluate(X_test_seq, y_test_encoded)[1])
Resultados.
Epoch 1/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 4s 4ms/step - accuracy: 0.4994 - loss: 0.6990 - val_accuracy: 0.5023 - val_loss: 0.6938 Epoch 2/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.4976 - loss: 0.6939 - val_accuracy: 0.5023 - val_loss: 0.6936 Epoch 3/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.4977 - loss: 0.6940 - val_accuracy: 0.5023 - val_loss: 0.6938 Epoch 4/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.5034 - loss: 0.6937 - val_accuracy: 0.4977 - val_loss: 0.6962 ... ... Epoch 16/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.5039 - loss: 0.6934 - val_accuracy: 0.5023 - val_loss: 0.6932 Epoch 17/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.4988 - loss: 0.6940 - val_accuracy: 0.4977 - val_loss: 0.6937 Epoch 18/1000 620/620 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.5013 - loss: 0.6943 - val_accuracy: 0.5023 - val_loss: 0.6931 266/266 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.5037 - loss: 0.6931 Test acc: 0.5022971034049988
Acabamos de treinar o modelo-base no EURUSD e obtivemos uma acurácia geral de 0,502.
Agora vamos usar esse modelo para aplicar Transfer Learning e transferir o conhecimento adquirido para modelos destinados a diferentes instrumentos. Vamos ver quais resultados serão obtidos.
for symbol in symbols: if symbol == trained_symbol: # skip transfer learning on the trained symbol continue print(f"Symbol: {symbol}") df = pd.read_csv(f"/kaggle/input/ohlc-eurusd/Fxdata.{symbol}.{timeframe}.csv") stationary_df = getStationaryVars(df) stationary_df["Close"] = df["Close"] # we add the close price for crafting the target variable X, y = getXandY(df=stationary_df, lookahead=lookahead) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=False, random_state=42) # Scalling the data scaler = RobustScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # Prepare data within a window window = 10 X_train_seq, y_train_seq = create_sequences(X_train_scaled, y_train, window) X_test_seq, y_test_seq = create_sequences(X_test_scaled, y_test, window) # One-hot encode the labels for multi-class classification y_train_encoded = to_categorical(y_train_seq, num_classes=num_classes) y_test_encoded = to_categorical(y_test_seq, num_classes=num_classes) # Freeze all layers except the last one for layer in base_model.layers[:-1]: layer.trainable = False # Create new model using the base model's architecture model = models.clone_model(base_model) model.set_weights(base_model.get_weights()) # Recompile with lower learning rate model.compile(optimizer=tf.keras.optimizers.Adam(0.01), loss='categorical_crossentropy', metrics=['accuracy']) early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit(X_train_seq, y_train_encoded, validation_data=(X_test_seq, y_test_encoded), epochs=1000, # More epochs for fine-tuning batch_size=32, callbacks=[early_stop], verbose=1) print("Test acc:", model.evaluate(X_test_seq, y_test_encoded)[1])
As mesmas etapas são repetidas para dividir os dados, criar as sequências temporais e codificar a variável-alvo. Essas etapas são executadas separadamente para cada símbolo.
Para transferir o conhecimento, criamos um novo modelo com base no modelo-base e congelamos algumas camadas da CNN.
Congelamos todas as camadas da CNN, exceto a última, para que o modelo preserve os padrões aprendidos com os dados-base. Isso permite manter o conhecimento já adquirido e evita que esses padrões sejam alterados durante a atualização incremental do modelo.
Mantemos apenas a última camada descongelada para que seus pesos sejam recalibrados de acordo com os novos limites de decisão de cada símbolo. Em essência, fornecemos ao modelo novas distribuições da variável-alvo e permitimos que ele estabeleça relações entre os padrões aprendidos pelo modelo-base e as informações contidas na variável-alvo desses novos dados.
A arquitetura é clonada e os pesos são carregados a partir do modelo salvo. Vale lembrar que salvamos os pesos na função trainCNN. Você pode carregar os pesos de um arquivo ao importar o modelo de outra origem ou carregá-los diretamente do objeto do modelo, caso o modelo-base esteja no mesmo script ou arquivo Python, como descrito anteriormente.
Em seguida, compilamos o modelo usando dados de mercado obtidos de um instrumento diferente daquele utilizado no treinamento do modelo-base. Outros parâmetros também podem ser alterados.
Acurácia para diferentes símbolos:
| SYMBOL | GBPUSD | AUDUSD | USDCAD | USDJPY | USDCHF | NZDUSD | EURNZD | AUDNZD | GBPNZD | NZDCHF | NZDJPY | NZDCAD | XAUUSD | XAUJPY | XAUEUR | XAUGBP |
| ACCURACY | 0.505 | 0.506 | 0.501 | 0.516 | 0.506 | 0.497 | 0.505 | 0.502 | 0.504 | 0.505 | 0.51 | 0.505 | 0.506 | 0.514 | 0.507 | 0.504 |
Esse resultado, por si só, não nos diz muita coisa. Vamos analisar o relatório de classificação com mais detalhes.
preds = base_model.predict(X_test_seq) pred_indices = preds.argmax(axis=1) pred_class_labels = [classes_in_y[i] for i in pred_indices] print("Classification report\n", classification_report(pred_class_labels, y_test_seq))
Relatório do modelo-base.
Classification report precision recall f1-score support 0 1.00 0.50 0.66 8477 1 0.00 0.00 0.00 0 accuracy 0.50 8477 macro avg 0.50 0.25 0.33 8477 weighted avg 1.00 0.50 0.66 8477
Os resultados de acurácia nos diferentes símbolos foram muito ruins. O modelo apresentou um forte viés.
Isso indica que existe um problema de viés no nosso modelo, que pode ter origem tanto na própria arquitetura quanto nos dados.
Existem várias formas de lidar com esse problema, como vimos no artigo anterior. Por enquanto, vamos fazer alguns ajustes:
(a) Adicionar pesos às classes para corrigir o desbalanceamento.
from sklearn.utils.class_weight import compute_class_weight
def trainCNN: #.... #.... y_train_integers = np.argmax(y_train, axis=1) # return to non-one hot encoded class_weights = compute_class_weight('balanced', classes=np.unique(y_train_integers), y=y_train_integers) class_weight_dict = {i: weight for i, weight in enumerate(class_weights)} # Train the model model.fit( X_train, y_train, validation_data=(X_val, y_val), epochs=epochs, batch_size=batch_size, callbacks=[early_stop], class_weight=class_weight_dict, verbose=1 )
(b) Adicionar mais uma camada convolucional e aumentar o número de neurônios na camada totalmente conectada.
def trainCNN: # ... # ... model = models.Sequential([ layers.Input(shape=input_shape), layers.Conv1D(64, kernel_size=3, activation='relu', padding='same'), layers.Conv1D(64, kernel_size=3, activation='relu', padding='same'), layers.Conv1D(32, kernel_size=3, activation='relu', padding='same'), layers.GlobalAveragePooling1D(), layers.Dense(128, activation='relu'), layers.Dense(num_classes, activation='softmax') ])
(c) Como se trata de uma tarefa de classificação binária, nossa variável-alvo possui apenas duas classes: 0 para sinais de venda e 1 para sinais de compra. Vamos alterar a função de perda para binary_crossentropy e a métrica de avaliação para binary_accuracy.
# Compile with Adam optimizer model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), loss='binary_crossentropy', metrics=['binary_accuracy'] )
Depois de treinar novamente o modelo CNN, os resultados melhoraram significativamente.
.... .... 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - binary_accuracy: 0.5257 - loss: 0.6920 - val_binary_accuracy: 0.5043 - val_loss: 0.6933 Epoch 7/100 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - binary_accuracy: 0.5259 - loss: 0.6918 - val_binary_accuracy: 0.5027 - val_loss: 0.6934 Epoch 8/100 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - binary_accuracy: 0.5283 - loss: 0.6915 - val_binary_accuracy: 0.5042 - val_loss: 0.6936 Epoch 9/100 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - binary_accuracy: 0.5284 - loss: 0.6912 - val_binary_accuracy: 0.5028 - val_loss: 0.6937 Epoch 10/100 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - binary_accuracy: 0.5315 - loss: 0.6909 - val_binary_accuracy: 0.5036 - val_loss: 0.6938 Epoch 11/100 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - binary_accuracy: 0.5295 - loss: 0.6907 - val_binary_accuracy: 0.5042 - val_loss: 0.6940 Epoch 12/100 310/310 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - binary_accuracy: 0.5298 - loss: 0.6904 - val_binary_accuracy: 0.5074 - val_loss: 0.6941 619/619 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - binary_accuracy: 0.5101 - loss: 0.6926 265/265 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - binary_accuracy: 0.5018 - loss: 0.6933 Train acc: 0.5114434361457825 Test acc: 0.5050135850906372 265/265 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step Classification report precision recall f1-score support 0 0.58 0.50 0.54 4870 1 0.43 0.51 0.47 3607 accuracy 0.51 8477 macro avg 0.51 0.51 0.50 8477 weighted avg 0.52 0.51 0.51 8477
Não houve um motivo específico para alterar esses parâmetros. Minha intenção foi apenas mostrar que, assim como em qualquer outro modelo baseado em redes neurais, a otimização e o ajuste dos parâmetros são extremamente importantes.
O resultado obtido talvez ainda não represente a solução ideal, pois existem inúmeras alternativas tanto para redes neurais convolucionais quanto para redes neurais em geral.
Por enquanto, vamos manter os parâmetros atuais, mas você pode experimentar outros valores.
Agora que temos um modelo-base razoavelmente satisfatório, podemos usá-lo para transferir conhecimento para outros instrumentos e salvar todos esses modelos no formato ONNX para testá-los no ambiente de trading.
Transfer Learning no EA
Para testar os modelos no ambiente de trading do MetaTrader 5, precisamos salvá-los no formato ONNX e carregá-los por meio da linguagem de programação MQL5.
Importação.
import onnxmltools import tf2onnx from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType
Funções
def saveCNN(model, window: int, features: int, filename: str): model.output_names = ["output"] # Specifying the input signature for the model spec = (tf.TensorSpec((None, window, features), tf.float16, name="input"),) # Convert the Keras model to ONNX format onnx_model, _ = tf2onnx.convert.from_keras(model, input_signature=spec, opset=14) # Save the ONNX model to a file with open(filename, "wb") as f: f.write(onnx_model.SerializeToString())
Os modelos Keras não dispõem de um pipeline compatível com o que usamos para integrar todas as etapas de pré-processamento ao modelo Scikit-learn. Esse pipeline permitiria salvar o modelo e todas as etapas em um único arquivo ONNX. Por isso, será necessário salvar separadamente o modelo Keras e o scaler utilizado, em arquivos ONNX independentes.
def saveScaler(scaler, features: int, filename: str): # Convert to ONNX format initial_type = [("input", FloatTensorType([None, features]))] onnx_model = convert_sklearn(scaler, initial_types=initial_type, target_opset=14) with open(filename, "wb") as f: f.write(onnx_model.SerializeToString())
Chamamos essas funções ao salvar o modelo-base e os demais modelos.
Salvamento do modelo-base.
# .... # .... base_model = trainCNN(train_set=(X_train_seq, y_train_encoded), val_set=(X_test_seq, y_test_encoded), learning_rate = 0.01, epochs = 1000, batch_size =32) saveCNN(model=base_model, window=window, features=X_train_seq.shape[2], filename=f"{trained_symbol}.basemodel.{timeframe}.onnx") saveScaler(scaler=scaler, features=X_train.shape[1], filename=f"{trained_symbol}.{timeframe}.scaler.onnx")
Salvamento dos modelos treinados com Transfer Learning.
for symbol in symbols: # ... # ... history = model.fit(X_train_seq, y_train_encoded, validation_data=(X_test_seq, y_test_encoded), epochs=1000, # More epochs for fine-tuning batch_size=32, callbacks=[early_stop], verbose=1) saveCNN(model=model, window=window, features=X_train_seq.shape[2], filename=f"basesymbol={trained_symbol}.symbol={symbol}.model.{timeframe}.onnx") saveScaler(scaler=scaler, features=X_train.shape[1], filename=f"{symbol}.{timeframe}.scaler.onnx")
Depois de salvar os arquivos na pasta comum, podemos carregá-los no EA.
#include <ta.mqh> //similar to ta in Python --> https://www.mql5.com/en/articles/16931 #include <pandas.mqh> //similar to Pandas in Python --> https://www.mql5.com/en/articles/17030 #include <CNN.mqh> //For loading Convolutional Neural networks in ONNX format --> https://www.mql5.com/en/articles/15259 #include <preprocessing.mqh> //For loading the scaler transformer #include <Trade\Trade.mqh> //The trading module #include <Trade\PositionInfo.mqh> //Position handling module CCNNClassifier cnn; RobustScaler scaler; CTrade m_trade; CPositionInfo m_position; input string base_symbol = "EURUSD"; input string symbol_ = "USDJPY"; input ENUM_TIMEFRAMES timeframe = PERIOD_H4; input uint window_ = 10; input uint lookahead = 1; input uint magic_number = 28042025; input uint slippage = 100; long classes_in_y_[] = {0, 1}; int OldNumBars = -1; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if (!MQLInfoInteger(MQL_TESTER)) if (!ChartSetSymbolPeriod(0, symbol_, timeframe)) { printf("%s Failed to set symbol_ = %s and timeframe = %s, Error = %d",__FUNCTION__,symbol_,EnumToString(timeframe), GetLastError()); return INIT_FAILED; } //--- string filename = StringFormat("basesymbol=%s.symbol=%s.model.%s.onnx",base_symbol, symbol_, EnumToString(timeframe)); if (!cnn.Init(filename, ONNX_COMMON_FOLDER)) { printf("%s failed to load a CNN model in ONNX format from the common folder '%s', Error = %d",__FUNCTION__,filename,GetLastError()); return INIT_FAILED; } //--- filename = StringFormat("%s.%s.scaler.onnx", symbol_, EnumToString(timeframe)); if (!scaler.Init(filename, ONNX_COMMON_FOLDER)) { printf("%s failed to load a scaler in ONNX format from the common folder '%s', Error = %d",__FUNCTION__,filename,GetLastError()); return INIT_FAILED; } }
Temos um módulo TA em MQL5, baseado na abordagem utilizada em Python, apresentado no artigo anterior. Com ele, podemos chamar funções de indicadores e armazenar os resultados em uma estrutura semelhante a um DataFrame do Pandas.
CDataFrame getStationaryVars(uint start = 1, uint bars = 50) { CDataFrame df; //Dataframe object vector open, high, low, close; open.CopyRates(Symbol(), Period(), COPY_RATES_OPEN, start, bars); high.CopyRates(Symbol(), Period(), COPY_RATES_HIGH, start, bars); low.CopyRates(Symbol(), Period(), COPY_RATES_LOW, start, bars); close.CopyRates(Symbol(), Period(), COPY_RATES_CLOSE, start, bars); vector pct_change = df.pct_change(close); vector diff_open = df.diff(open); vector diff_high = df.diff(high); vector diff_low = df.diff(low); vector diff_close = df.diff(close); df.insert("pct_change", pct_change); df.insert("diff_open", open); df.insert("diff_high", high); df.insert("diff_low", low); df.insert("diff_close", close); // Relative Strength Index (RSI) vector rsi = CMomentumIndicators::RSIIndicator(close); df.insert("rsi", rsi); // Stochastic Oscillator (Stoch) vector stock_k = CMomentumIndicators::StochasticOscillator(close,high,low).stoch; df.insert("stock_k", stock_k); // Moving Average Convergence Divergence (MACD) vector macd = COscillatorIndicators::MACDIndicator(close).main; df.insert("macd", macd); // Commodity Channel Index (CCI) vector cci = COscillatorIndicators::CCIIndicator(high,low,close); df.insert("cci", cci); // Rate of Change (ROC) vector roc = CMomentumIndicators::ROCIndicator(close); df.insert("roc", roc); // Ultimate Oscillator (UO) vector uo = CMomentumIndicators::UltimateOscillator(high,low,close); df.insert("uo", uo); // Williams %R vector williams_r = CMomentumIndicators::WilliamsR(high,low,close); df.insert("williams_r", williams_r); // Average True Range (ATR) vector atr = COscillatorIndicators::ATRIndicator(high,low,close); df.insert("atr", atr); // Awesome Oscillator (AO) vector ao = CMomentumIndicators::AwesomeOscillator(high,low); df.insert("ao", ao); // Average Directional Index (ADX) vector adx = COscillatorIndicators::ADXIndicator(high,low,close).adx; df.insert("adx", adx); // True Strength Index (TSI) vector tsi = CMomentumIndicators::TSIIndicator(close); df.insert("tsi", tsi); if (MQLInfoInteger(MQL_DEBUG)) df.head(); df = df.dropna(); //Drop not-a-number variables return df; //return the last rows = window from a dataframe which is the recent information fromthe market }
A cada barra, coletamos as 50 barras anteriores para calcular os indicadores, começando pela última barra fechada, de índice 1.
Escolhemos um limite de 50 barras para manter uma margem suficiente para o cálculo dos indicadores, já que alguns deles geram valores NaN (Not a Number), que não são úteis para o modelo.
O Awesome Oscillator é o indicador que exige a maior janela de dados históricos, com window2 igual a 34. Isso significa que 50 - 34 = 16 é a quantidade de dados restantes disponíveis para o modelo.
Ao executar o EA em modo de depuração, essas informações aparecem na aba Experts do MetaTrader 5.
MD 0 18:17:26.145 Transfer Learning EA (USDJPY,H4) | Index | pct_change | diff_open | diff_high | diff_low | diff_close | rsi | stock_k | macd | cci | roc | uo | williams_r | atr | ao | adx | tsi | FF 0 18:17:26.145 Transfer Learning EA (USDJPY,H4) | 0 | nan | 142.67000000 | 143.08800000 | 142.49100000 | 142.68300000 | nan | nan | nan | nan | nan | nan | nan | nan | nan | 0.00000000 | nan | JO 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 1 | -0.25300842 | 142.68400000 | 142.84900000 | 142.28700000 | 142.32200000 | nan | nan | nan | nan | nan | nan | nan | nan | nan | 0.00000000 | nan | IR 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 2 | 0.09977375 | 142.32300000 | 142.63500000 | 141.89900000 | 142.46400000 | nan | nan | nan | nan | nan | nan | nan | nan | nan | 0.00000000 | nan | HF 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 3 | -0.00070193 | 142.46400000 | 142.71900000 | 142.34400000 | 142.46300000 | nan | nan | nan | nan | nan | nan | nan | nan | nan | 0.00000000 | nan | GJ 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 4 | -0.04702976 | 142.37400000 | 142.47200000 | 142.18600000 | 142.39600000 | nan | nan | nan | nan | nan | nan | nan | nan | nan | 0.00000000 | nan | IJ 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | ... | NR 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 45 | -0.22551954 | 142.33800000 | 142.38800000 | 141.98200000 | 142.01700000 | 28.79606321 | 1.70731707 | 0.20202343 | -149.46898289 | -0.42629273 | 28.03714657 | -48.58934169 | 0.58185714 | 0.84359706 | 29.65580624 | 8.31951160 | NJ 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 46 | 0.16054416 | 141.97800000 | 142.31600000 | 141.96400000 | 142.24500000 | 35.49705652 | 13.58800774 | 0.12993025 | -131.96513868 | -0.57316604 | 34.81743660 | -43.09139137 | 0.56978571 | 0.51217941 | 28.18573720 | 4.78996901 | HQ 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 47 | 0.19543745 | 142.24500000 | 142.58100000 | 142.12400000 | 142.52300000 | 43.03880625 | 27.03094778 | 0.09414295 | -86.63856716 | -0.76174826 | 43.61239023 | -36.38775018 | 0.57742857 | 0.21773529 | 26.19967843 | 3.09202782 | FH 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 48 | 0.04771160 | 142.52300000 | 142.61500000 | 142.29800000 | 142.59100000 | 44.85843867 | 30.31914894 | 0.07045611 | -66.64608781 | -0.57732936 | 49.55462139 | -34.74801061 | 0.56007143 | -0.01222353 | 24.37916904 | 2.01861384 | MQ 0 18:17:26.146 Transfer Learning EA (USDJPY,H4) | 49 | -0.19776844 | 142.59100000 | 142.75800000 | 142.25100000 | 142.30900000 | 38.91058297 | 16.68278530 | 0.02859940 | -70.14493704 | -0.77257229 | 41.99481159 | -41.54810707 | 0.52700000 | -0.13378529 | 23.02215655 | 0.05188403 |
Dentro da função OnTick, a primeira etapa consiste em calcular os atributos estacionários. Em seguida, aplicamos uma operação de slicing para garantir que a quantidade de barras nos dados resultantes corresponda ao tamanho da janela utilizado no treinamento do modelo CNN.
void OnTick() { //--- if (!isNewBar()) return; CDataFrame x_df = getStationaryVars(); //--- Check if the number of rows received after indicator calculation is >= window size if ((uint)x_df.shape()[0]<window_) { printf("%s Fatal, Data received is less than the desired window=%u. Check your indicators or increase the number of bars in the function getSationaryVars()",__FUNCTION__,window_); DebugBreak(); return; } ulong rows = (ulong)x_df.shape()[0]; ulong cols = (ulong)x_df.shape()[1]; //printf("Before scaled shape = (%I64u, %I64u)",rows, cols); matrix x = x_df.iloc((rows-window_), rows-1, 0, cols-1).m_values; }
Agora que temos uma matriz recortada com 10 linhas, de acordo com o tamanho da janela, e 16 atributos usados no treinamento, podemos passar esses dados pelo RobustScaler carregado e, depois, alimentar o modelo CNN para obter as previsões finais.
matrix x_scaled = scaler.transform(x); //Transform the data, very important long signal = cnn.predict(x_scaled, classes_in_y_).cls; //Predicted class
Por fim, com base no sinal gerado pelo modelo, podemos implementar uma estratégia de trading simples: se o sinal for igual a 1, indicando alta, abrimos uma posição de compra; se o sinal for igual a 0, indicando baixa, abrimos uma posição de venda.
Cada operação será encerrada após a formação, no timeframe atual, de um número de barras igual ao valor do parâmetro lookahead.
//--- Trading functionality 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) //Check if there are is atleast a special pattern before opening a trade { if (!PosExists(POSITION_TYPE_BUY) && !PosExists(POSITION_TYPE_SELL)) m_trade.Buy(volume_, Symbol(), ticks.ask,0,0); } if (signal == 0) //Check if there are is atleast a special pattern before opening a trade { if (!PosExists(POSITION_TYPE_SELL) && !PosExists(POSITION_TYPE_BUY)) m_trade.Sell(volume_, Symbol(), ticks.bid,0,0); } CloseTradeAfterTime((Timeframe2Minutes(Period())*lookahead)*60); //Close the trade after a certain lookahead and according the the trained timeframe
É isso. Agora vamos executar esse EA em alguns dos instrumentos utilizados no processo de Transfer Learning e analisar os resultados das previsões no período de 1º de janeiro de 2023 a 1º de janeiro de 2025.
Timeframe: PERIOD_H4. Modelling: 1 Minute OHLC.
Symbol: XAUEUR

Symbol: XAUUSD


Dos 17 instrumentos utilizados no processo de Transfer Learning com base no modelo-base treinado no EURUSD, apenas 2 apresentaram resultados razoáveis. Os demais tiveram desempenho muito ruim.
Isso pode significar duas coisas. Primeiro, os padrões observados no EURUSD podem apresentar uma forte relação ou semelhança com aqueles formados no XAUUSD e no XAUEUR. Isso parece plausível, já que ambos os instrumentos estão relacionados às moedas EUR e USD, que compõem o símbolo-base EURUSD.
Segundo, isso também pode indicar que os modelos CNN utilizados não são ideais, pois não realizamos uma otimização completa da arquitetura nem dos hiperparâmetros. Além disso, não testamos diferentes símbolos-base nem analisamos os resultados obtidos em cada caso.
Seria possível adotar várias etapas adicionais, mas isso foge do escopo deste artigo. Se quiser, você pode explorá-las por conta própria.
Considerações finais
Vivemos na era de ouro da inteligência artificial e do machine learning. Essas tecnologias evoluem mais rapidamente do que se imaginava e, em grande parte graças ao open source, hoje é possível criar modelos poderosos a partir de soluções existentes com apenas algumas linhas de código. É justamente isso que chamamos de Transfer Learning.
Na área de visão computacional e em tarefas de processamento de imagens, já existem modelos open source de grande escala, como ResNet50, MobileNet e outros. Esses modelos permitiram que os desenvolvedores alcançassem um novo patamar e criassem soluções de IA realmente eficientes. No entanto, a área financeira ainda é pouco explorada no que diz respeito a modelos abertos e soluções open source.
O objetivo deste artigo foi mostrar as possibilidades do Transfer Learning e demonstrar como essa abordagem pode ser aplicada ao setor financeiro, servindo como ponto de partida para a criação de modelos de maior escala capazes de auxiliar na análise dos mercados financeiros usando padrões comuns presentes em diferentes instrumentos.
Boa sorte!
Tabela de anexos
Nome do arquivo | Descrição/finalidade |
|---|---|
| Expert\Transfer Learning EA.mq5 | EA principal para testar modelos de Transfer Learning no ambiente de trading. |
| Include\CNN.mqh | Biblioteca para carregar e implantar modelos CNN armazenados em arquivos .onnx no MQL5. |
Include\pandas.mqh | Biblioteca no estilo do Pandas para processamento e armazenamento de dados. |
Include\preprocessing.mqh | Contém classes para carregar, escalar e transformar dados representados no formato .onnx. |
Include\ta.mqh | Biblioteca com uma abordagem simples e prática para trabalhar com indicadores no MQL5. |
Scripts\CollectData.mqh | Script para coletar e salvar em arquivos CSV os dados OHLC obtidos de diferentes instrumentos. |
| Python\forex-transfer-learning.ipynb | Script Python em formato Jupyter Notebook para executar todo o código Python descrito neste artigo. |
Common\Files*scaler.onnx | Os parâmetros de escalonamento usados no pré-processamento dos dados são salvos em arquivos no formato ONNX. |
Common\Files*.onnx | Os modelos CNN são salvos em arquivos no formato ONNX. |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/17886
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.
Criação de um painel administrativo de trading em MQL5 (Parte XI): Interface moderna de mensagens na plataforma (I)
Ferramentas personalizadas de depuração e profiling para desenvolvimento em MQL5 (Parte I): Logging avançado
Automatização de estratégias de negociação em MQL5 (Parte 17): dominando a estratégia de scalping Grid-Mart com painel informativo dinâmico
Operando com o Calendário Econômico do MQL5 (Parte 7): Preparação para Testes de Estratégia com Análise de Eventos de Notícias por Recurso Incorporado
- 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
