
Otimização de Portfólio em Python e MQL5
Introdução
Apresentando dois programas inovadores de otimização de portfólio projetados para revolucionar as estratégias de negociação e maximizar os retornos, enquanto minimizam o risco. O primeiro, uma solução baseada em Python, aproveita o poder da integração com o MetaTrader 5, juntamente com bibliotecas avançadas como pandas, Numpy e cvxpy, para analisar dados históricos, otimizar a alocação de ativos e visualizar os resultados com Matplotlib. O segundo, uma implementação similar criada em MQL5, aproveita as capacidades nativas da plataforma MetaTrader 5, oferecendo aos traders uma experiência integrada diretamente em seu ambiente de negociação preferido. Ambos os programas exemplificam a interseção de ponta entre finanças quantitativas e tecnologia, capacitando os traders com ferramentas sofisticadas para tomar decisões baseadas em dados em um cenário de mercado em constante evolução.
Por que precisamos da Otimização de Portfólio?
Programas de otimização de portfólio são ferramentas essenciais na gestão financeira moderna, atendendo à necessidade crítica de retornos ajustados ao risco de maneira eficiente, em um cenário de investimentos cada vez mais complexo e volátil. Ao utilizar modelos matemáticos avançados e poder computacional, esses programas permitem que investidores e profissionais financeiros tomem decisões baseadas em dados, adaptadas às suas tolerâncias de risco e objetivos de investimento específicos. Esses programas analisam sistematicamente grandes volumes de dados históricos, tendências de mercado e correlações entre ativos para determinar alocações ótimas de ativos que maximizem os retornos potenciais, enquanto minimizam o risco geral do portfólio.
Essa abordagem científica para a construção de portfólios ajuda a mitigar os vieses humanos e as decisões emocionais frequentemente associadas às estratégias tradicionais de investimento. Além disso, programas de otimização de portfólio facilitam o reequilíbrio dinâmico, permitindo que os investidores se adaptem rapidamente às mudanças nas condições de mercado e mantenham a conformidade com seus objetivos financeiros de longo prazo. Em uma era de interconectividade econômica global e fluxo rápido de informações, essas ferramentas sofisticadas oferecem uma vantagem competitiva, permitindo que os investidores naveguem por incertezas e capitalizem oportunidades em diversas classes de ativos, promovendo, por fim, estratégias de investimento mais robustas e resilientes.
Por que devemos usar Python?
Python é uma boa maneira de testar rapidamente estratégias ou ideias; tem uma grande comunidade e é rápido. Além disso, conta com a biblioteca MetaTrader5, para baixar dados ou até realizar operações. Portanto, vamos usar primeiro o Python para ver se a ideia é consistente, e devemos usar diferentes % da conta com diferentes símbolos.
Este é o script em Python que vamos usar:
# Import necessary libraries import MetaTrader5 as mt5 import pandas as pd import numpy as np import cvxpy as cp import matplotlib.pyplot as plt from datetime import datetime # Function to obtain historical data from MT5 def get_mt5_data(symbols, from_date, to_date): # Establish connection with MetaTrader 5 if not mt5.initialize(): print("Error: Could not connect to MetaTrader 5") mt5.shutdown() return None data = {} for symbol in symbols: # Get historical price data rates = mt5.copy_rates_range(symbol, mt5.TIMEFRAME_D1, from_date, to_date) if rates is not None: # Convert to Pandas DataFrame df = pd.DataFrame(rates) df['time'] = pd.to_datetime(df['time'], unit='s') df.set_index('time', inplace=True) df.drop(['tick_volume', 'spread', 'real_volume'], axis=1, inplace=True) # Calculate daily returns df['return'] = df['close'].pct_change().fillna(0) # Save in the data dictionary data[symbol] = df # Close the connection with MetaTrader 5 mt5.shutdown() return data # Function to optimize the portfolio def optimize_portfolio(data): symbols = list(data.keys()) n_assets = len(symbols) # Find the minimum data length among all assets min_length = min(len(data[symbol]) for symbol in symbols) # Adjust and normalize returns returns = np.zeros((min_length, n_assets)) for i, symbol in enumerate(symbols): # Adjust data length df = data[symbol].iloc[:min_length] returns[:, i] = df['return'].values # Calculate covariance matrix and expected returns cov_matrix = np.cov(returns, rowvar=False) expected_returns = np.mean(returns, axis=0) # Optimization variables weights = cp.Variable(n_assets) risk = cp.quad_form(weights, cov_matrix) objective = cp.Maximize(expected_returns @ weights - 0.5 * risk) # Constraints constraints = [cp.sum(weights) == 1, weights >= 0] # Solve the optimization problem prob = cp.Problem(objective, constraints) prob.solve() # Display optimization results print("\nOptimization Results:") for i, symbol in enumerate(symbols): print(f"{symbol}: {weights.value[i]}") # Calculate minimum variance and expected return for the portfolio min_variance = cp.sqrt(cp.quad_form(weights.value, cov_matrix)).value expected_return_portfolio = expected_returns @ weights.value print(f"\nExpected portfolio return: {expected_return_portfolio:.4f}") print(f"Minimum portfolio variance: {min_variance:.4f}") return symbols, weights.value # Function to visualize results def visualize_results(symbols, weights): # Plot weights of each asset in the portfolio plt.figure(figsize=(10, 6)) plt.bar(symbols, weights, color='blue') plt.xlabel('Assets') plt.ylabel('Weights') plt.title('Asset Weights in Optimized Portfolio') plt.show() # Execute the main script if __name__ == "__main__": # Define parameters symbols = ["EURUSD", "GBPUSD", "#AMZN", "#AAPL"] # Asset symbols from_date = datetime(2023, 1, 1) # Start date to_date = datetime(2023, 12, 31) # End date # Get historical data from MT5 print(f"Obtaining historical data from {from_date} to {to_date}...") data = get_mt5_data(symbols, from_date, to_date) if data: # Optimize the portfolio symbols, weights = optimize_portfolio(data) # Visualize the results visualize_results(symbols, weights)
Os resultados ficam assim:
Obtaining historical data from 2023-01-01 00:00:00 to 2023-12-31 00:00:00... Optimization Results: EURUSD: 1.9303305369616842e-23 GBPUSD: 1.9417113191106993e-23 #AMZN: 1.0 #AAPL: -1.3370355361690525e-23 Expected portfolio return: 0.0025 Minimum portfolio variance: 0.0205
E este é o gráfico:
Esses resultados nos dizem para investir apenas na Amazon, mas vamos adicionar uma estratégia ao script, para ver se os valores mudam, e os resultados nos pedem para investir em outros símbolos.
Podemos fazer isso adicionando o seguinte ao script (vamos usar uma estratégia simples de cruzamento de duas médias móveis), você pode modificar essa estratégia para usar a que precisar:
# Function to apply the moving average crossover strategy def apply_sma_strategy(data, short_window=12, long_window=26): for symbol, df in data.items(): df['SMA_50'] = df['close'].rolling(window=short_window).mean() df['SMA_200'] = df['close'].rolling(window=long_window).mean() df['signal'] = 0 df.loc[df.index[short_window:], 'signal'] = np.where( df.loc[df.index[short_window:], 'SMA_50'] > df.loc[df.index[short_window:], 'SMA_200'], 1, 0 ) df['position'] = df['signal'].shift(1).fillna(0) return data # Function to adjust returns according to the strategy def adjust_returns(data): for symbol, df in data.items(): df['adjusted_return'] = df['return'] * df['position'] return data
E também adicionando isso no principal:
# Apply the moving average crossover strategy data = apply_sma_strategy(data) # Adjust returns according to the strategy data = adjust_returns(data)
Os resultados são apresentados assim:
Obtaining historical data from 2023-01-01 00:00:00 to 2023-12-31 00:00:00... Optimization Results: EURUSD: -5.669275045708089e-25 GBPUSD: 5.494697501444607e-23 #AMZN: 1.0 #AAPL: -5.59465620602481e-23 Expected portfolio return: 0.0006 Minimum portfolio variance: 0.0151
Houve algumas pequenas mudanças, mas, no geral, os resultados permanecem os mesmos.
Isso ocorre porque a AMZN teve uma tendência gigante durante todo esse período.
Você deve estar ciente disso e observar quando a tendência parar, mas pode entender por que a gestão de risco é tão importante.
Script MQL5
Acabamos de ver como desenvolver a gestão de risco em Python, agora vamos reproduzir o mesmo script em MQL5, pois o MQL5 é mais preciso.
Aqui está o script:
//+------------------------------------------------------------------+ //| optimizacion_carteras.mq5 | //| Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" // Define the assets to consider string symbols[] = {"EURUSD", "GBPUSD", "#AAPL", "#AMZN"}; // Date parameters to obtain historical data datetime from_date = D'2023.01.01 00:00'; datetime to_date = D'2024.01.01 00:00'; //+------------------------------------------------------------------+ //| Function to obtain historical data from MetaTrader 5 | //+------------------------------------------------------------------+ void obtenerDatosHistoricos(string symbol, datetime from, datetime to, double &out[][6]) { // Declare an array to store the historical rates MqlRates rates[]; // Copy historical data for the specified symbol and date range int copied = CopyRates(symbol, PERIOD_D1, from, to, rates); // Check if data copying was successful if(copied <= 0) Print("Failed to copy price data ", GetLastError()); else Print("Copied ", ArraySize(rates), " bars"); // Resize the output array to match the size of copied data ArrayResize(out, copied); Print("Copied ", copied, " data points for ", symbol); // Transfer data to the output array for(int i = 0; i < copied; i++) { out[i][0] = (double)rates[i].time; out[i][1] = rates[i].open; out[i][2] = rates[i].high; out[i][3] = rates[i].low; out[i][4] = rates[i].close; out[i][5] = (double)rates[i].tick_volume; } } //+------------------------------------------------------------------+ //| Function to calculate daily returns | //+------------------------------------------------------------------+ void calcularRendimientos(double &data[][6], double &returns[]) { // Determine the number of data points int total = ArrayRange(data, 0); // Resize the returns array to accommodate the calculated returns ArrayResize(returns, total - 1); Print("Calculating returns for ", total, " data points"); // Initialize variables to track maximum and minimum returns double max_return = -DBL_MAX; double min_return = DBL_MAX; int problematic_index = -1; int valid_returns_count = 0; // Iterate through the data points to calculate returns for(int i = 1; i < total; i++) { // Ensure the previous closing price is not zero to avoid division by zero if(data[i - 1][4] != 0.0) { // Calculate the return as the percentage change in closing prices double retorno = (data[i][4] - data[i - 1][4]) / data[i - 1][4]; returns[i - 1] = retorno; valid_returns_count++; // Update maximum and minimum returns if applicable if(retorno > max_return) max_return = retorno; if(retorno < min_return) min_return = retorno; // Identify and log suspicious returns if(MathAbs(retorno) > 1.0) { Print("Suspicious return at index ", i, ": ", retorno); Print("Data[", i - 1, "][4] = ", data[i - 1][4], ", Data[", i, "][4] = ", data[i][4]); problematic_index = i; } // Periodically print return values for verification if(i % 50 == 0 || i == total - 1) { Print("Return for index ", i - 1, ": ", retorno); } } else { // If the previous closing price is zero, set the return to zero returns[i - 1] = 0.0; Print("Zero price found at index ", i - 1); } } // Print the maximum and minimum returns Print("Max return: ", max_return, ", Min return: ", min_return); // Log the index of any problematic returns if(problematic_index != -1) { Print("Problematic return found at index: ", problematic_index); } } //+------------------------------------------------------------------+ //| Main function | //+------------------------------------------------------------------+ void OnStart() { // Declare arrays to store historical data and returns double data[][6]; double returns[]; // Loop through each symbol to obtain historical data and calculate returns for(int i = 0; i < ArraySize(symbols); i++) { obtenerDatosHistoricos(symbols[i], from_date, to_date, data); // Determine the size of the data array int data_size = ArraySize(data); Print("Data size for ", symbols[i], ": ", data_size); // Ensure there is enough data to calculate returns if(data_size > 1 && ArrayRange(data, 1) == 6) { calcularRendimientos(data, returns); int returns_size = ArraySize(returns); Print("Returns size for ", symbols[i], ": ", returns_size); // Initialize variables to calculate the expected return and variance double sum_returns = 0; int valid_returns = 0; // Sum the valid returns and count them for(int j = 0; j < returns_size; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { sum_returns += returns[j]; valid_returns++; } else { Print("Invalid or extreme return at index ", j, ": ", returns[j]); } } // Calculate the mean return double mean_return = (valid_returns > 0) ? sum_returns / valid_returns : 0; // Calculate the variance of the returns double variance = 0; for(int j = 0; j < valid_returns; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { variance += MathPow(returns[j] - mean_return, 2); } } variance = (valid_returns > 0) ? variance / valid_returns : 0; // Display the results in the console Print("Results for ", symbols[i]); Print("Expected return: ", mean_return); Print("Variance: ", variance); Print("Sum of returns: ", sum_returns); Print("Valid returns: ", valid_returns, " out of ", returns_size); Print("-----------------------"); } else { // Log if there were insufficient data or an incorrect data format Print("Could not obtain enough data for ", symbols[i], " or the data format is incorrect"); Print("-----------------------"); } } }
Primeiramente, o script define uma lista de ativos a serem considerados, representados pelos seus símbolos. Também define o intervalo de datas para obter os dados históricos, especificando uma data de início e uma data de término.
A função obtenerDatosHistoricos é responsável por buscar os dados históricos de um determinado ativo dentro do intervalo de datas especificado. Ela utiliza a função CopyRates para recuperar os dados e armazená-los em um array de estruturas MqlRates. A função então copia esses dados para um array de saída, garantindo o formato e tamanho corretos. Se a recuperação de dados falhar, uma mensagem de erro é impressa, enquanto uma recuperação bem-sucedida resulta em uma mensagem de confirmação indicando o número de pontos de dados copiados.
A função calcularRendimientos calcula os retornos diários a partir dos dados históricos. Ela percorre os pontos de dados, calculando o retorno como a mudança percentual nos preços de fechamento entre os dias consecutivos. A função lida com erros potenciais, como preços de fechamento zero, e registra retornos suspeitos que excedem um limite pré-definido. Ela rastreia os retornos máximos e mínimos encontrados durante os cálculos e imprime atualizações periódicas para verificar os retornos calculados.
A função principal OnStart inicializa arrays para armazenar dados históricos e retornos. Ela percorre cada símbolo de ativo, chamando obtenerDatosHistoricos para buscar os dados e, em seguida, calcularRendimientos para calcular os retornos. Após calcular os retornos, a função prossegue para calcular o retorno esperado e a variância. Ela soma os retornos válidos, calcula o retorno médio e, em seguida, calcula a variância dos retornos. Os resultados, incluindo o retorno esperado, a variância, a soma dos retornos e a contagem dos retornos válidos, são impressos no console para cada ativo. Se os dados forem insuficientes ou o formato dos dados for incorreto, uma mensagem apropriada é registrada.
Ao longo do script, um extenso registro de log é implementado para garantir transparência e facilitar a depuração. Mensagens indicam o progresso e os resultados da recuperação de dados, cálculo de retornos e análise estatística, permitindo que o usuário acompanhe o fluxo de execução e identifique quaisquer problemas que surgirem.
Resultados
Para rodar este script, basta carregá-lo em uma janela, e você verá os seguintes resultados:
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 data points for EURUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for EURUSD: 1554
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 259 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.008422556659553942
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: 0.0005552522233225886
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.0016251305097825213
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: -0.0018138190337636214
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 249: 0.002726296367691935
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 257: -0.0023503674709141444
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.016843640170492922, Min return: -0.014629419109562279
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for EURUSD: 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for EURUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.00014629557982735741
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.000021906221916670055
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.03774425959545821
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 258 out of 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 data points for GBPUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for GBPUSD: 1554
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 259 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.01253428642673093
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: -0.00020901161622245828
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.0009419054513750523
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: 0.00011442115156718484
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 249: -0.0024846582214581455
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 257: 0.000015710672259594492
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.01795095252445456, Min return: -0.016589470883191758
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for GBPUSD: 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for GBPUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.0002283507472210021
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.000026680765574142948
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.058914492783018545
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 258 out of 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 data points for #AAPL
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for #AAPL: 1500
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 250 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.026341719766143464
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: 0.010473614547965662
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.006613315549627641
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: -0.0011390170283046702
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 248: -0.006298074441174946
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.047845736667670974, Min return: -0.04621826746924895
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for #AAPL: 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for #AAPL
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.0018199882676706617
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.00016500191971009266
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.4531770786499948
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 249 out of 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 data points for #AMZN
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for #AMZN: 1500
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 250 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.04365079365079357
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: 0.04105902777777781
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.00952790314492451
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: -0.0033604251328539594
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 248: -0.009568443663346995
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.08595143898844165, Min return: -0.07525053686471019
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for #AMZN: 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for #AMZN
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.002502188742255484
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.0004212375364322232
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.6230449968216155
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 249 out of 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
Como pode ser visto nos resultados, a AAPL deve ter cerca de 40% de investimento, a AMZN 60%, EURUSD 3% e GBPUSD 6%. Esses valores são orientativos, e nenhuma estratégia foi utilizada.
Adicionando uma Estratégia ao Script MQL5
Você deve adicionar isto ao primeiro script:
Função de Cálculo da Média Móvel
Esta função calcula a média móvel para um conjunto de dados dado, durante um período especificado. Ela percorre os pontos de dados, somando os preços de fechamento ao longo do período definido, e então divide pelo período para obter a média. Se não houver dados suficientes para calcular a média móvel, a função define o valor como zero.
//+------------------------------------------------------------------+
//| Function to calculate moving average |
//+------------------------------------------------------------------+
void calcularMediaMovil(double &data[][6], int period, double &ma[])
{
int total = ArrayRange(data, 0);
ArrayResize(ma, total);
for(int i = 0; i < total; i++)
{
if(i >= period - 1)
{
double sum = 0;
for(int j = i; j > i - period; j--)
{
sum += data[j][4]; // Closing price
}
ma[i] = sum / period;
}
else
{
ma[i] = 0.0; // Not enough data for moving average
}
}
}
//+------------------------------------------------------------------+
//| Function to generate trading signals based on moving average cross |
//+------------------------------------------------------------------+
void generarSenales(double &data[][6], double &ma_rapida[], double &ma_lenta[], double &senales[])
{
int total = ArrayRange(data, 0);
ArrayResize(senales, total);
for(int i = 1; i < total; i++)
{
if(ma_rapida[i - 1] <= ma_lenta[i - 1] && ma_rapida[i] > ma_lenta[i])
{
senales[i] = 1; // Buy signal
}
else if(ma_rapida[i - 1] >= ma_lenta[i - 1] && ma_rapida[i] < ma_lenta[i])
{
senales[i] = -1; // Sell signal
}
else
{
senales[i] = 0; // No signal
}
}
}
E integrar isso ao OnStart:
void OnStart() { double data[][6]; double returns[]; for(int i = 0; i < ArraySize(symbols); i++) { obtenerDatosHistoricos(symbols[i], from_date, to_date, data); int data_size = ArraySize(data); if(data_size > 1 && ArrayRange(data, 1) == 6) { calcularRendimientos(data, returns); int returns_size = ArraySize(returns); double sum_returns = 0; int valid_returns = 0; for(int j = 0; j < returns_size; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { sum_returns += returns[j]; valid_returns++; } } double mean_return = (valid_returns > 0) ? sum_returns / valid_returns : 0; double variance = 0; for(int j = 0; j < valid_returns; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { variance += MathPow(returns[j] - mean_return, 2); } } variance = (valid_returns > 0) ? variance / valid_returns : 0; Print("Results for ", symbols[i]); Print("Expected return: ", mean_return); Print("Variance: ", variance); Print("Sum of returns: ", sum_returns); Print("Valid returns: ", valid_returns, " out of ", returns_size); Print("-----------------------"); // Calculate moving averages and trading signals double ma_rapida[]; double ma_lenta[]; double senales[]; int periodo_rapido = 10; // Short period moving average int periodo_lento = 50; // Long period moving average calcularMediaMovil(data, periodo_rapido, ma_rapida); calcularMediaMovil(data, periodo_lento, ma_lenta); generarSenales(data, ma_rapida, ma_lenta, senales); // Log trading signals for(int k = 0; k < ArraySize(senales); k++) { if(senales[k] != 0) { string tipo_senal = (senales[k] == 1) ? "Compra" : "Venta"; Print("Signal for ", symbols[i], " on ", TimeToString((datetime)data[k][0]), ": ", tipo_senal); } } } else { Print("Could not obtain enough data for ", symbols[i], " or the data format is incorrect"); Print("-----------------------"); } } }
Esta função gera sinais de negociação com base no cruzamento de duas médias móveis (um período curto e um longo). Ela percorre os dados, verificando instâncias onde a média móvel de curto período cruza acima ou abaixo da média móvel de longo período. Um cruzamento para cima gera um sinal de compra, enquanto um cruzamento para baixo gera um sinal de venda. Se não houver cruzamento, nenhum sinal é gerado.
Integração na Função Principal OnStart
Na função principal, os dados históricos são obtidos para cada símbolo e os retornos são calculados. Em seguida, as médias móveis e os sinais de negociação são calculados para cada símbolo. As médias móveis são obtidas utilizando a função calcularMediaMovil para ambos os períodos, curto e longo. A função generarSenales é usada para gerar sinais de compra e venda com base nos cruzamentos das médias móveis. Os resultados, incluindo os sinais calculados, são impressos no console para revisão.
Este código agora inclui uma estratégia simples de cruzamento de média móvel que gera sinais de compra e venda. Os sinais de negociação são impressos no console para revisão, permitindo ajustes nos períodos das médias móveis conforme necessário.Os resultados ficam assim:
2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 data points for EURUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 259 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.008422556659553942 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: 0.0005552522233225886 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.0016251305097825213 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: -0.0018138190337636214 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 249: 0.002726296367691935 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 257: -0.0023503674709141444 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.016843640170492922, Min return: -0.014629419109562279 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for EURUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.00014629557982735741 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.000021906221916670055 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.03774425959545821 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 258 out of 258 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.01.13 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.03.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.03.27 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.05.19 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.06.22 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.08.14 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.11.08 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 data points for GBPUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 259 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.01253428642673093 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: -0.00020901161622245828 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.0009419054513750523 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: 0.00011442115156718484 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 249: -0.0024846582214581455 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 257: 0.000015710672259594492 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.01795095252445456, Min return: -0.016589470883191758 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for GBPUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.0002283507472210021 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.000026680765574142948 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.058914492783018545 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 258 out of 258 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.01.13 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.03.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.03.23 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.05.26 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.06.12 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.08.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.11.14 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 data points for #AAPL 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 250 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.026341719766143464 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: 0.010473614547965662 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.006613315549627641 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: -0.0011390170283046702 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 248: -0.006298074441174946 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.047845736667670974, Min return: -0.04621826746924895 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for #AAPL 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.0018199882676706617 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.00016500191971009266 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.4531770786499948 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 249 out of 249 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.01.17 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.08.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.10.18 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.10.20 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.11.10 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 data points for #AMZN 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 250 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.04365079365079357 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: 0.04105902777777781 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.00952790314492451 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: -0.0033604251328539594 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 248: -0.009568443663346995 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.08595143898844165, Min return: -0.07525053686471019 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for #AMZN 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.002502188742255484 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.0004212375364322232 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.6230449968216155 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 249 out of 249 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.01.17 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.03.15 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.03.24 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.09.27 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.11.07 00:00: Compra
O artigo apresenta uma exploração abrangente das técnicas de otimização de portfólio utilizando as linguagens de programação Python e MQL5 com a plataforma MetaTrader 5, enfatizando o papel crítico da tomada de decisões orientada por dados na gestão financeira moderna. Ele esclarece o processo de desenvolvimento e implementação de algoritmos sofisticados que analisam dados históricos, otimizam a alocação de ativos e geram sinais de negociação com base em cruzamentos de médias móveis.
Os autores destacam a importância da otimização de portfólio como uma ferramenta essencial para alcançar retornos ajustados ao risco de maneira eficiente em um cenário de investimentos cada vez mais complexo e volátil. Ao aproveitar modelos matemáticos avançados e o poder computacional, esses programas permitem que os investidores tomem decisões informadas, adaptadas às suas tolerâncias de risco e objetivos de investimento específicos. O artigo demonstra como tais técnicas de otimização podem analisar sistematicamente grandes volumes de dados históricos, tendências de mercado e correlações entre ativos para determinar alocações ótimas de ativos que maximizem os retornos potenciais, enquanto minimizam o risco geral do portfólio.
A abordagem dual de usar Python para testes iniciais de estratégias e MQL5 para integração sem costura com o MetaTrader 5 mostra a versatilidade e o poder de combinar diferentes ambientes de programação. Essa metodologia permite que os traders se beneficiem das bibliotecas extensivas e das capacidades analíticas do Python, enquanto aproveitam as funcionalidades nativas da plataforma MetaTrader 5.
A necessidade de empregar a otimização de portfólio na negociação não pode ser exagerada, pois ela oferece uma abordagem científica para a construção do portfólio, ajudando a mitigar os vieses humanos e a tomada de decisões emocionais frequentemente associadas às estratégias tradicionais de investimento. Em uma era de interconectividade econômica global e fluxo rápido de informações, essas ferramentas sofisticadas oferecem uma vantagem competitiva, permitindo que os investidores naveguem por incertezas e capitalizem oportunidades em diversas classes de ativos.
O artigo fornece um passo a passo detalhado do processo de implementação, incluindo trechos de código tanto para Python quanto para MQL5, ilustrando como obter dados históricos, calcular retornos, gerar sinais de negociação com base em cruzamentos de médias móveis e otimizar a alocação de ativos. Ele também demonstra como visualizar os resultados, o que é crucial para interpretar e comunicar as descobertas de forma eficaz.
Em resumo, o artigo serve como um recurso valioso para traders e profissionais financeiros que buscam aprimorar suas estratégias de investimento por meio de técnicas avançadas de otimização de portfólio. Ele destaca a sinergia entre finanças quantitativas e tecnologia, oferecendo insights práticos sobre o desenvolvimento de sistemas de negociação robustos e adaptáveis. A conclusão dos autores enfatiza a natureza indispensável de tais ferramentas para alcançar retornos ajustados ao risco de maneira eficiente e construir estratégias de investimento resilientes nos mercados financeiros dinâmicos de hoje.
Conclusão
Em conclusão, a integração de Python e MQL5 para otimização de portfólio representa um avanço significativo no desenvolvimento de estratégias de negociação, combinando o poder analítico do Python com as capacidades de negociação sem costura do MetaTrader 5. Esses programas inovadores são projetados para capacitar os traders com a capacidade de analisar dados históricos, otimizar a alocação de ativos e visualizar resultados de maneira eficaz, melhorando assim a tomada de decisões orientada por dados nos mercados financeiros.
Ao utilizar as bibliotecas extensivas do Python, incluindo Pandas, Numpy e cvxpy, juntamente com a programação nativa em MQL5 do MetaTrader 5, os traders podem gerenciar e adaptar seus portfólios de maneira eficiente às condições de mercado em mudança. Essa abordagem dual não só facilita os testes iniciais de estratégias em Python, mas também garante sua aplicação prática e precisão dentro do ambiente MetaTrader 5. À medida que o cenário financeiro se torna cada vez mais complexo e volátil, tais ferramentas sofisticadas são indispensáveis para alcançar retornos ajustados ao risco de maneira eficiente. Ao mitigar os vieses humanos e aproveitar modelos matemáticos avançados, esses programas de otimização de portfólio oferecem uma estrutura robusta para construir estratégias de investimento resilientes.
Agradecemos seu interesse neste artigo e incentivamos você a explorar mais essas ferramentas para melhorar o desempenho de suas negociações e a gestão financeira estratégica. Obrigado e melhores cumprimentos.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15288





- 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