English Русский 中文 Español Deutsch 日本語
preview
Análise Múltipla de Símbolos com Python e MQL5 (Parte I): Fabricantes de Circuitos Integrados do NASDAQ

Análise Múltipla de Símbolos com Python e MQL5 (Parte I): Fabricantes de Circuitos Integrados do NASDAQ

MetaTrader 5Exemplos |
33 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

Existem muitas maneiras de um investidor diversificar seu portfólio. Além disso, há várias métricas diferentes que podem ser usadas como critério para avaliar o quão bem o portfólio foi otimizado. É improvável que qualquer investidor individual tenha tempo ou recursos suficientes para considerar cuidadosamente todas as opções antes de tomar uma decisão tão importante. Nesta série de artigos, vamos guiá-lo pelas inúmeras opções que estão à sua frente na jornada de negociar múltiplos símbolos simultaneamente. Nosso objetivo é ajudar você a decidir quais estratégias manter e quais podem não ser adequadas para você.


Visão Geral da Estratégia de Trading

Nesta discussão, selecionamos uma cesta de ações que estão fundamentalmente relacionadas entre si. Selecionamos 5 ações de empresas que projetam e vendem circuitos integrados em seu ciclo de negócios. Essas empresas são Broadcom, Cisco, Intel, NVIDIA e Comcast. Todas as 5 empresas estão listadas na National Association of Securities Dealers Automated Quotations (NASDAQ). A NASDAQ foi criada em 1971 e é a maior bolsa dos Estados Unidos em volume de negociações.


Os circuitos integrados se tornaram parte fundamental de nossa vida cotidiana. Esses chips eletrônicos permeiam todos os aspectos da vida moderna, desde os servidores proprietários da MetaQuotes que hospedam este site onde você está lendo este artigo, até o dispositivo que você está usando para ler — todos dependem de uma tecnologia que, muito provavelmente, foi desenvolvida por uma dessas 5 empresas. O primeiro circuito integrado do mundo foi desenvolvido pela Intel, batizado de Intel 4004, e lançado em 1971, o mesmo ano da fundação da bolsa NASDAQ. O Intel 4004 possuía aproximadamente 2.600 transistores, bem diferente dos chips modernos que facilmente têm bilhões de transistores..

Como somos motivados pela demanda global por circuitos integrados, queremos obter exposição inteligente ao mercado de chips. Dada uma cesta dessas 5 ações, vamos demonstrar como maximizar o retorno do seu portfólio alocando capital de forma criteriosa entre elas. Uma abordagem tradicional de distribuir igualmente o capital entre todas as 5 ações não é suficiente para os mercados modernos e voláteis. Em vez disso, vamos construir um modelo que nos indique se devemos comprar ou vender cada ação, e as quantidades ideais a serem negociadas. Ou seja, estamos usando os dados disponíveis para aprender, de forma algorítmica, o dimensionamento de posição e quantidades.


Visão Geral da Metodologia

Começamos buscando 100.000 linhas de dados de mercado M1 para cada uma das 5 ações da nossa cesta, a partir do nosso MetaTrader 5 Terminal usando a biblioteca Python do MetaTrader 5. Após converter os dados de preço para variações percentuais, realizamos uma análise exploratória dos dados de retornos de mercado.

Observamos níveis fracos de correlação entre as 5 ações. Além disso, nossos boxplots mostraram claramente que o retorno médio de cada ação estava próximo de 0. Também plotamos os retornos de cada ação de forma sobreposta, e foi possível observar claramente que os retornos da NVIDIA foram os mais voláteis. Por fim, criamos gráficos de dispersão pareados entre todas as 5 ações selecionadas, e infelizmente não foi possível identificar qualquer relação clara que pudesse ser aproveitada.

A partir daí, usamos a biblioteca SciPy para encontrar os pesos ideais para cada uma das 5 ações em nosso portfólio. Permitimos que todos os 5 pesos variem entre -1 e 1. Sempre que o peso do portfólio estiver abaixo de 0, o algoritmo está indicando venda e, inversamente, quando os pesos estiverem acima de 0, os dados sugerem compra.

Após calcular os pesos ideais do portfólio, integramos esses dados em nosso aplicativo de negociação para garantir que ele sempre mantenha um número ótimo de posições abertas em cada mercado. Nosso aplicativo de negociação é projetado para fechar automaticamente qualquer posição aberta se atingir um nível de lucro, especificado pelo usuário final.


Buscando os Dados 

Para começar, vamos importar primeiro as bibliotecas necessárias.

#Import the libraries we need
import pandas              as pd
import numpy               as np
import seaborn             as sns
import matplotlib.pyplot   as plt
import MetaTrader5         as mt5
from   scipy.optimize      import minimize

Agora, vamos inicializar o terminal MetaTrader 5.

#Initialize the terminal
mt5.initialize()
Verdadeiro

Defina a cesta de ações que desejamos negociar.

#Now let us fetch the data we need on chip manufacturing stocks
#Broadcom, Cisco, Comcast, Intel, NVIDIA
stocks = ["AVGO.NAS","CSCO.NAS","CMCSA.NAS","INTC.NAS","NVDA.NAS"]

Vamos criar um data-frame para armazenar nossos dados de mercado.

#Let us create a data frame to store our stock returns
amount = 100000
returns = pd.DataFrame(columns=stocks,index=np.arange(0,amount))

Agora, vamos buscar nossos dados de mercado.

#Fetch the stock returns
for stock in stocks:
    temp = pd.DataFrame(mt5.copy_rates_from_pos(stock,mt5.TIMEFRAME_M1,0,amount))
    returns[[stock]] = temp[["close"]].pct_change()

Vamos formatar nossos dados.

#Format the data set 
returns.dropna(inplace=True)
returns.reset_index(inplace=True,drop=True)
returns

Por fim, multiplique os dados por 100 para salvá-los como percentuais.

#Convert the returns to percentages
returns = returns * 100
returns


Análise Exploratória dos Dados

Às vezes, podemos visualizar a relação entre as variáveis do sistema. Vamos analisar os níveis de correlação em nossos dados para ver se há alguma combinação linear da qual possamos tirar proveito. Infelizmente, nossos níveis de correlação não são impressionantes e, até agora, não parece haver dependências lineares para explorarmos.

#Vamos analisar se há alguma correlação nos dados
sns.heatmap(returns.corr(),annot=True)

Fig 1: Nosso mapa de calor de correlação

Vamos analisar gráficos de dispersão pareados de nossos dados. Ao lidar com grandes conjuntos de dados, relações não triviais podem facilmente passar despercebidas. Os gráficos de pares minimizam a chance disso acontecer. Infelizmente, não houve relações facilmente observáveis nos dados reveladas por nossos gráficos.

#Vamos criar gráficos de pares dos nossos dados
sns.pairplot(returns)

Fig 2: Alguns dos nossos gráficos de dispersão pareados

Ao plotar os retornos observados nos dados, vemos que a NVIDIA aparenta ter os retornos mais voláteis.

#Lets also visualize our returns
returns.plot()

Fig 3: Plotando nossos retornos de mercado

Visualizando nossos retornos de mercado em boxplots, fica claro que o retorno médio de mercado é 0.

#Vamos tentar criar boxplots
sns.boxplot(returns)

Fig 4: Visualizando nossos retornos de mercado em boxplots



Otimização de Portfólio

Agora estamos prontos para começar a calcular os pesos ótimos de alocação de capital para cada ação. Inicialmente, atribuiremos nossos pesos de forma aleatória. Além disso, também criaremos uma estrutura de dados para armazenar o progresso do nosso algoritmo de otimização.

#Define random weights that add up to 1
weights = np.array([1,0.5,0,0.5,-1])
#Create a data structure to store the progress of the algorithm
evaluation_history = []

A função objetivo do nosso procedimento de otimização será o retorno do nosso portfólio com os pesos definidos. Observe que os retornos do nosso portfólio serão calculados usando a média geométrica dos retornos dos ativos. Optamos por empregar a média geométrica em vez da média aritmética porque, ao lidar com valores positivos e negativos, calcular a média deixa de ser uma tarefa trivial. Se abordássemos esse problema de maneira casual e utilizássemos a média aritmética, poderíamos facilmente calcular um retorno de portfólio igual a 0. Podemos usar algoritmos de minimização para problemas de maximização multiplicando o retorno do portfólio por menos 1 antes de retorná-lo para o algoritmo de otimização.

#Agora vamos nos preparar para maximizar nossos retornos
#Primeiro, precisamos definir a função de custo
def cost_function(x):
    #Primeiro, precisamos calcular os retornos do portfólio com os pesos sugeridos
    portfolio_returns = np.dot(returns,x)
    geom_mean         =  ((np.prod( 1 + portfolio_returns ) ** (1.0/99999.0)) - 1)
    #Vamos acompanhar o desempenho do nosso algoritmo
    evaluation_history.append(-geom_mean)
    return(-geom_mean)

Agora, vamos definir a restrição que garante que a soma dos pesos seja igual a 1. Observe que apenas alguns procedimentos de otimização do SciPy suportam restrições de igualdade. Restrições de igualdade informam ao módulo SciPy que queremos que essa função seja igual a 0. Portanto, queremos que a diferença entre o valor absoluto dos pesos e 1 seja igual a 0.

#Agora precisamos definir nossas restrições
def l1_norm_constraint(x):
    return(((np.sum(np.abs(x))) - 1))

constraints = ({'type':'eq','fun':l1_norm_constraint})

Todos os nossos pesos devem estar entre -1 e 1. Isso pode ser imposto definindo limites (bounds) para nosso algoritmo.

#Now we need to define the bounds for our weights
bounds = [(-1,1)] * 5

Executando o procedimento de otimização.

#Perform the optimization
results = minimize(cost_function,weights,method="SLSQP",bounds=bounds,constraints=constraints)

Os resultados do nosso procedimento de otimização.

Resultados
mensagem: Otimização encerrada com sucesso
 success: True
  status: 0
     fun: 0.0024308603411499208
       x: [ 3.931e-01  1.138e-01 -5.991e-02  7.744e-02 -3.557e-01]
     nit: 23
     jac: [ 3.851e-04  2.506e-05 -3.083e-04 -6.868e-05 -3.186e-04]
    nfev: 158
    njev: 23

Vamos armazenar os valores ótimos de coeficientes que calculamos.

optimal_weights = results.x
optimal_weights
array([ 0.39311134,  0.11379942, -0.05991417,  0.07743534, -0.35573973])

Também devemos armazenar os pontos ótimos do procedimento.

optima_y = min(evaluation_history)
optima_x = evaluation_history.index(optima_y)
inputs = np.arange(0,len(evaluation_history))

Vamos visualizar o histórico de desempenho do nosso algoritmo de otimização. Como podemos ver pelo gráfico, nosso algoritmo parece ter tido dificuldades no início, nas primeiras 50 iterações. No entanto, parece ter conseguido encontrar um ponto ótimo que maximiza os retornos do nosso portfólio.

plt.scatter(inputs,evaluation_history)
plt.plot(optima_x,optima_y,'s',color='r')
plt.axvline(x=optima_x,ls='--',color='red')
plt.axhline(y=optima_y,ls='--',color='red')
plt.title("Maximizing Returns")

Fig 5: Desempenho do nosso algoritmo de otimização SLSQP

Vamos verificar se o valor absoluto da soma dos pesos é igual a 1, ou seja, queremos validar que nossa restrição de norma L1 não foi violada.

#Validate the weights add up to 1
np.sum(np.abs(optimal_weights))
1.0

Há uma forma intuitiva de interpretar os coeficientes ótimos. Se assumirmos que queremos abrir 10 posições, primeiro multiplicaremos os coeficientes por 10. Em seguida, vamos realizar uma divisão inteira por 1 para eliminar as casas decimais. Os inteiros restantes podem ser interpretados como o número de posições que devemos abrir em cada mercado. Nossos dados parecem sugerir que devemos abrir 3 posições compradas em Broadcom, 1 posição comprada em Cisco, 1 posição vendida em Comcast, nenhuma posição em Intel e 4 posições vendidas em NVIDIA para maximizar nossos retornos. 

#Aqui está uma forma intuitiva de entender os dados
#Se só podemos abrir 10 posições, nossa melhor escolha pode ser
#3 posições de compra em Broadcom
#1 posição de compra em Cisco
#1 posição de venda em Comcast
#Nenhuma posição em Intel
#4 posições de venda em NVIDIA
(optimal_weights * 10) // 1
array([ 3.,  1., -1.,  0., -4.])


Implementação em MQL5

Agora vamos implementar nossa estratégia de negociação em MQL5. Vamos começar definindo as variáveis globais que usaremos em nossa aplicação.

//+------------------------------------------------------------------+
//|                                                 NASDAQ IC AI.mq5 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/en/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/en/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int    rsi_handler,bb_handler;
double bid,ask;
int    optimal_weights[5] = {3,1,-1,0,-4};
string stocks[5]          = {"AVGO.NAS","CSCO.NAS","CMCSA.NAS","INTC.NAS","NVDA.NAS"};
vector current_close      = vector::Zeros(1);
vector rsi_buffer         = vector::Zeros(1);
vector bb_high_buffer     = vector::Zeros(1);
vector bb_mid_buffer      = vector::Zeros(1);
vector bb_low_buffer      = vector::Zeros(1);

Importando a biblioteca de negociação para nos ajudar a gerenciar nossas posições.

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include  <Trade/Trade.mqh>
CTrade Trade;

O usuário final do nosso programa pode ajustar o comportamento do Expert Advisor através dos parâmetros de entrada que permitimos controlar.

//+------------------------------------------------------------------+
//| User inputs                                                      |
//+------------------------------------------------------------------+
input double profit_target =  1.0; //At this profit level, our position will be closed
input int    rsi_period    =   20; //Adjust the RSI period
input int    bb_period     =   20; //Adjust the Bollinger Bands period
input double trade_size    =  0.3; //How big should our trades be?

Sempre que nosso algoritmo de negociação for configurado pela primeira vez, precisamos garantir que todos os 5 símbolos dos nossos cálculos anteriores estejam disponíveis. Caso contrário, abortaremos o procedimento de inicialização.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Validate that all the symbols we need are available
   if(!validate_symbol())
     {
      return(INIT_FAILED);
     }
//--- Everything went fine
   return(INIT_SUCCEEDED);
  }

Se nosso programa for removido do gráfico, devemos liberar os recursos que não estamos mais utilizando.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Release resources we no longer need
   release_resources();
  }

Sempre que recebermos preços atualizados, primeiro queremos armazenar o bid e o ask atuais em nossas variáveis globais definidas, verificar oportunidades de negociação e, por fim, realizar qualquer lucro já disponível.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- Update market data
   update_market_data();

//--- Check for a trade oppurtunity in each symbol
   check_trade_symbols();

//--- Check if we have an oppurtunity to take ourt profits
   check_profits();
  }

A função responsável por realizar nossos lucros irá iterar sobre todos os símbolos da nossa cesta. Se conseguir encontrar o símbolo com sucesso, irá verificar se temos posições abertas nesse mercado. Supondo que tenhamos posições abertas, verificaremos se o lucro ultrapassa o alvo de lucro definido pelo usuário; se ultrapassar, fecharemos nossas posições. Caso contrário, iremos para o próximo.

//+------------------------------------------------------------------+
//| Check for opportunities to collect our profits                   |
//+------------------------------------------------------------------+
void check_profits(void)
  {
   for(int i =0; i < 5; i++)
     {
      if(SymbolSelect(stocks[i],true))
        {
         if(PositionSelect(stocks[i]))
           {
            if(PositionGetDouble(POSITION_PROFIT) > profit_target)
              {
               Trade.PositionClose(stocks[i]);
              }
           }
        }
     }
  }

Sempre que recebermos preços atualizados, queremos armazená-los em nossas variáveis globais, pois essas variáveis podem ser chamadas em várias partes do programa.

//+------------------------------------------------------------------+
//| Update markte data                                               |
//+------------------------------------------------------------------+
void update_market_data(void)
  {
   ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
  }

Sempre que nosso Expert Advisor não estiver em uso, liberaremos os recursos que não são mais necessários, garantindo uma boa experiência ao usuário final.

//+-------------------------------------------------------------------+
//| Release the resources we no longer need                           |
//+-------------------------------------------------------------------+
void release_resources(void)
  {
   ExpertRemove();
  }
//+------------------------------------------------------------------+

Na inicialização, verificamos se todos os símbolos necessários estão disponíveis. A função abaixo é responsável por essa tarefa. Ela itera por todos os símbolos do nosso array de ações. Se não conseguirmos selecionar algum símbolo, a função retorna falso e interrompe o procedimento de inicialização. Caso contrário, a função retorna verdadeiro.

//+------------------------------------------------------------------+
//| Validate that all the symbols we need are available              |
//+------------------------------------------------------------------+
bool validate_symbol(void)
  {
   for(int i=0; i < 5; i++)
     {
      //--- We failed to add one of the necessary symbols to the Market Watch window!
      if(!SymbolSelect(stocks[i],true))
        {
         Comment("Failed to add ",stocks[i]," to the market watch. Ensure the symbol is available.");
         return(false);
        }
     }

//--- Everything went fine
   return(true);
  }

Esta função é responsável por coordenar o processo de abertura e gerenciamento de posições no nosso portfólio. Ela vai iterar por todos os símbolos do nosso array e verificar se temos posições abertas naquele mercado e se deveríamos ter posições abertas naquele mercado. Se deveríamos, mas não temos, a função iniciará o processo de verificação de oportunidades para ganhar exposição naquele mercado. Caso contrário, não fará nada.

//+------------------------------------------------------------------+
//| Check if we have any trade opportunities                         |
//+------------------------------------------------------------------+
void check_trade_symbols(void)
  {
//--- Loop through all the symbols we have
   for(int i=0;i < 5;i++)
     {
      //--- Select that symbol and check how many positons we have open
      if(SymbolSelect(stocks[i],true))
        {
         //--- If we have no positions in that symbol, optimize the portfolio
         if((PositionsTotal() == 0) && (optimal_weights[i] != 0))
           {
            optimize_portfolio(stocks[i],optimal_weights[i]);
           }
        }
     }
  }

A função de otimização do portfólio recebe 2 parâmetros: a ação em questão e os pesos atribuídos a essa ação. Se os pesos forem positivos, a função iniciará o procedimento para assumir uma posição comprada nesse mercado até que o parâmetro de peso seja atingido; o contrário é verdadeiro para pesos negativos.

//+------------------------------------------------------------------+
//| Optimize our portfolio                                           |
//+------------------------------------------------------------------+
void optimize_portfolio(string symbol,int weight)
  {
//--- If the weight is less than 0, check if we have any oppurtunities to sell that stock
   if(weight < 0)
     {
      if(SymbolSelect(symbol,true))
        {
         //--- If we have oppurtunities to sell, act on it
         if(check_sell(symbol, weight))
           {
            Trade.Sell(trade_size,symbol,bid,0,0,"NASDAQ IC AI");
           }
        }
     }

//--- Otherwise buy
   else
     {
      if(SymbolSelect(symbol,true))
        {
         //--- If we have oppurtunities to buy, act on it
         if(check_buy(symbol,weight))
           {
            Trade.Buy(trade_size,symbol,ask,0,0,"NASDAQ IC AI");
           }
        }
     }
  }

Agora precisamos definir as condições sob as quais podemos entrar em uma posição comprada (long). Vamos nos basear em uma combinação de análise técnica e ação do preço para definir nossas entradas. Só entraremos em posições compradas se os preços estiverem acima da banda superior das Bollinger Bands, nosso RSI estiver acima de 70 e a ação do preço em time-frames maiores for altista. Da mesma forma, acreditamos que isso pode constituir uma configuração de alta probabilidade, permitindo que alcancemos nossas metas de lucro com segurança. Por fim, nossa última condição é que o número total de posições abertas naquele mercado não ultrapasse nossos níveis de alocação ótima. Se as condições forem satisfeitas, retornaremos verdadeiro, o que dará à função "optimize_portfolio" autorização para entrar em uma posição comprada.

//+------------------------------------------------------------------+
//| Check for oppurtunities to buy                                   |
//+------------------------------------------------------------------+
bool check_buy(string symbol, int weight)
  {
//--- Ensure we have selected the right symbol
   SymbolSelect(symbol,true);

//--- Load the indicators on the symbol
   bb_handler  = iBands(symbol,PERIOD_CURRENT,bb_period,0,1,PRICE_CLOSE);
   rsi_handler = iRSI(symbol,PERIOD_CURRENT,rsi_period,PRICE_CLOSE);
//--- Validate the indicators
   if((bb_handler == INVALID_HANDLE) || (rsi_handler == INVALID_HANDLE))
     {
      //--- Something went wrong
      return(false);
     }

//--- Load indicator readings into the buffers
   bb_high_buffer.CopyIndicatorBuffer(bb_handler,1,0,1);
   rsi_buffer.CopyIndicatorBuffer(rsi_handler,0,0,1);
   current_close.CopyRates(symbol,PERIOD_CURRENT,COPY_RATES_CLOSE,0,1);

//--- Validate that we have a valid buy oppurtunity
   if((bb_high_buffer[0] < current_close[0]) && (rsi_buffer[0] > 70))
     {
      return(false);
     }

//--- Do we allready have enough positions
   if(PositionsTotal() >= weight)
     {
      return(false);
     }
//--- We can open a position
   return(true);
  }

Nossa função "check_sell" funciona de forma semelhante à função de compra, exceto pelo fato de multiplicar o peso por menos 1 primeiro, para que possamos contar facilmente quantas posições devemos ter abertas no mercado. A função irá verificar se o preço está abaixo da Banda Inferior das Bollinger Bands e se o RSI está abaixo de 30. Se essas três condições forem atendidas, também precisamos garantir que a ação do preço em time-frames maiores permita que entremos em uma posição vendida (short).

//+------------------------------------------------------------------+
//| Check for oppurtunities to sell                                  |
//+------------------------------------------------------------------+
bool check_sell(string symbol, int weight)
  {
//--- Ensure we have selected the right symbol
   SymbolSelect(symbol,true);

//--- Negate the weight
   weight = weight * -1;

//--- Load the indicators on the symbol
   bb_handler  = iBands(symbol,PERIOD_CURRENT,bb_period,0,1,PRICE_CLOSE);
   rsi_handler = iRSI(symbol,PERIOD_CURRENT,rsi_period,PRICE_CLOSE);
//--- Validate the indicators
   if((bb_handler == INVALID_HANDLE) || (rsi_handler == INVALID_HANDLE))
     {
      //--- Something went wrong
      return(false);
     }

//--- Load indicator readings into the buffers
   bb_low_buffer.CopyIndicatorBuffer(bb_handler,2,0,1);
   rsi_buffer.CopyIndicatorBuffer(rsi_handler,0,0,1);
   current_close.CopyRates(symbol,PERIOD_CURRENT,COPY_RATES_CLOSE,0,1);

//--- Validate that we have a valid sell oppurtunity
   if(!((bb_low_buffer[0] > current_close[0]) && (rsi_buffer[0] < 30)))
     {
      return(false);
     }

//--- Do we have enough trades allready open?
   if(PositionsTotal() >= weight)
     {
      //--- We have a valid sell setup
      return(false);
     }

//--- We can go ahead and open a position
   return(true);
  }

Nosso sistema em ação

Fig 6: Testando nosso algoritmo em forward


Conclusão

Em nossa discussão, demonstramos como você pode determinar, de forma algorítmica, o dimensionamento de posição e a alocação de capital usando IA. Há muitos aspectos diferentes de um portfólio que podemos otimizar, como o risco (variância) do portfólio, a correlação do nosso portfólio com o desempenho de um benchmark da indústria (beta) e os retornos ajustados ao risco do portfólio. No nosso exemplo, mantivemos o modelo simples e consideramos apenas a maximização do retorno. Vamos considerar muitas métricas importantes à medida que avançarmos nesta série. No entanto, esse exemplo simples permite compreender as ideias principais por trás da otimização de portfólio e, mesmo que avancemos para procedimentos mais complexos, o leitor pode abordar o problema com confiança sabendo que os princípios fundamentais apresentados aqui não mudam. Embora não possamos garantir que as informações contidas em nossa discussão gerarão sucesso sempre, certamente vale a pena considerar se você realmente leva a sério operar múltiplos símbolos de forma algorítmica.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15909

Arquivos anexados |
NASDAQ_IC_AI.mq5 (9.45 KB)
Reimaginando Estratégias Clássicas em MQL5 (Parte III): Previsão do FTSE 100 Reimaginando Estratégias Clássicas em MQL5 (Parte III): Previsão do FTSE 100
Nesta série de artigos, vamos revisitar estratégias de negociação já conhecidas para investigar se podemos aprimorá-las utilizando IA. No artigo de hoje, exploraremos o FTSE 100 e tentaremos prever o índice utilizando uma parte das ações individuais que compõem esse índice.
Scalping Orderflow para MQL5 Scalping Orderflow para MQL5
Este Expert Advisor para MetaTrader 5 implementa uma estratégia de Scalping OrderFlow com gerenciamento de risco avançado. Ele utiliza múltiplos indicadores técnicos para identificar oportunidades de negociação com base em desequilíbrios de fluxo de ordens. Os testes de retrocesso (backtesting) mostram potencial de lucratividade, mas destacam a necessidade de mais otimizações, especialmente no gerenciamento de risco e nas taxas de acerto das operações. Adequado para traders experientes, exige testes aprofundados e compreensão antes da utilização em ambiente real.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Simulação de mercado: Position View (III) Simulação de mercado: Position View (III)
Nestes últimos artigos, tenho mencionado o fato de que precisamos em alguns momentos definir um valor para a propriedade ZOrder. Mas por que?!?! Já que muitos dos códigos, que adicionam objetos no gráfico, simplesmente não utilizam, ou melhor, não definem um valor para tal propriedade. Bem, não estou aqui, para dizer, o que cada programador, deve ou não fazer. Como ele deve ou não criar seus códigos. Estou aqui, a fim de mostrar, a você caro leitor, e interessado em realmente compreender como as coisas funcionam, por debaixo dos panos.