English Русский 中文 Español Deutsch 日本語
preview
Exemplo de Análise de Rede de Causalidade (CNA) e Modelo de Autorregressão Vetorial para Predição de Eventos de Mercado

Exemplo de Análise de Rede de Causalidade (CNA) e Modelo de Autorregressão Vetorial para Predição de Eventos de Mercado

MetaTrader 5Sistemas de negociação |
85 4
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

Introdução

Análise de Rede de Causalidade (CNA) é um método usado para compreender e modelar relacionamentos causais complexos entre variáveis em um sistema. Quando aplicado aos mercados financeiros, pode ajudar a identificar como diferentes eventos e fatores de mercado influenciam uns aos outros, potencialmente levando a previsões mais precisas.

Descoberta Causal: Descoberta causal é o processo de inferir relacionamentos causais a partir de dados observacionais. No contexto dos mercados financeiros, isso significa identificar quais variáveis (como indicadores econômicos, preços de mercado ou eventos externos) têm efeitos causais sobre outras. Existem vários algoritmos para descoberta causal, mas um dos mais populares é o algoritmo PC (Peter-Clark).

Este bot de negociação não implementa explicitamente um sistema chamado “Análise de Rede de Causalidade para Predição de Eventos de Mercado” como um componente nomeado. No entanto, o bot incorpora elementos de análise causal e abordagens baseadas em rede que são conceitualmente similares. Vamos detalhar isso:

Análise Causal: O bot utiliza um algoritmo de descoberta causal, especificamente o algoritmo Fast Causal Inference (FCI) (em vez do algoritmo PC). Isso é implementado na função FCIAlgorithm().

Análise de Rede: O bot utiliza uma estrutura de rede para representar relacionamentos entre diferentes instrumentos financeiros ou indicadores. Isso é evidente a partir da struct Node e da função SetupNetwork().

Predição de Eventos: Embora não seja explicitamente chamado de “predição de eventos”, o bot usa um modelo de Autorregressão Vetorial (VAR) para fazer previsões sobre estados futuros do mercado. Isso é implementado em funções como TrainVARModel() e PredictVARValue().


Análise de Rede de Causalidade: Uma Nova Fronteira na Predição de Eventos de Mercado

No mundo do trading algorítmico, uma nova abordagem está ganhando força entre quants e traders: Análise de Rede de Causalidade para Previsão de Eventos de Mercado. Esse método sofisticado combina o poder da inferência causal, da teoria de redes e da análise preditiva para prever eventos significativos de mercado com precisão sem precedentes.

Imagine o mercado financeiro como uma vasta teia interconectada. Cada fio representa um relacionamento entre diferentes variáveis de mercado – preços de ações, indicadores econômicos, eventos geopolíticos e mais. A análise tradicional frequentemente se concentra em correlações, mas, como todo trader experiente sabe, correlação nem sempre implica causalidade.

É aqui que a Análise de Rede de Causalidade entra em cena. Ela tem como objetivo revelar as verdadeiras relações de causa e efeito dentro dessa teia complexa. Ao fazer isso, proporciona aos traders um entendimento mais profundo da dinâmica do mercado, permitindo antecipar eventos que podem ser invisíveis à análise convencional.

No seu cerne, a Análise de Rede de Causalidade envolve três etapas principais:

1. Construção da Rede: Primeiro, construímos uma rede onde cada nó representa uma variável de mercado. Essas podem ser desde preços de ativos e volumes de negociação até indicadores econômicos e índices de sentimento.

2. Descoberta de Ligações Causais: Em seguida, usamos algoritmos avançados para determinar os relacionamentos causais entre esses nós. É aqui que a mágica acontece – não estamos apenas observando quais variáveis se movem juntas, mas quais realmente impulsionam mudanças em outras.

3. Predição de Eventos: Por fim, usamos essa rede causal para prever eventos significativos de mercado. Ao compreender os verdadeiros motores dos movimentos de mercado, podemos antecipar melhor grandes mudanças, quedas ou altas.


As Vantagens para os Traders

Para traders em MQL5, implementar a Análise de Rede de Causalidade pode mudar o jogo. Veja por quê:

  • Gestão de Risco Melhorada: Ao identificar as causas raiz da volatilidade do mercado, você pode se preparar melhor para possíveis quedas.
  • Previsões Mais Precisas: Compreender relacionamentos causais leva a previsões mais confiáveis do que aquelas baseadas apenas em correlações.
  • Descoberta de Oportunidades Ocultas: A rede causal pode revelar conexões que não são óbvias à primeira vista, levando a oportunidades de negociação únicas.
  • Estratégias Adaptativas: À medida que o mercado evolui, a rede causal também evolui, permitindo que suas estratégias se ajustem em tempo real.


Implementação no MQL5

Embora implementar um sistema completo de Análise de Rede de Causalidade seja complexo, o MQL5 oferece uma plataforma robusta para esse tipo de análise avançada. Você pode começar por:

  1. Usar a função iCustom() para criar indicadores para cada nó em sua rede.
  2. Implementar algoritmos de descoberta causal como o algoritmo PC ou testes de Causalidade de Granger (neste caso, usamos algoritmos FCI).
  3. Aproveitar as capacidades de rede neural do MQL5 para construir modelos preditivos com base em sua rede causal.


Por que usamos FCI em vez de PC?

FCI (Fast Causal Inference) e PC (Peter-Clark) são ambos algoritmos de descoberta causal usados no campo da inferência causal. Eles são projetados para inferir relacionamentos causais a partir de dados observacionais. Veja por que alguém pode escolher FCI em vez de PC:

  1. Variáveis latentes confundidoras: A principal vantagem do FCI sobre o PC é sua capacidade de lidar com confundidores latentes. O FCI pode inferir a presença de causas comuns ocultas, enquanto o PC assume suficiência causal (sem confundidores latentes).
  2. Viés de seleção: O FCI também pode levar em conta o viés de seleção nos dados, o que o PC não consegue.
  3. Modelo mais geral: O FCI produz um modelo gráfico mais geral, chamado de Grafo Ancestral Parcial (PAG), que pode representar uma classe mais ampla de estruturas causais do que os Grafos Acíclicos Dirigidos (DAGs) produzidos pelo PC.
  4. Solidez e completude: O FCI é sólido e completo para a classe de sistemas causalmente insuficientes, o que significa que pode identificar corretamente todos os possíveis relacionamentos causais, dado um tamanho de amostra infinito.
  5. Robustez: Devido à sua capacidade de lidar com confundidores latentes e viés de seleção, o FCI é geralmente mais robusto ao lidar com dados do mundo real, onde variáveis ocultas são comuns.

No entanto, vale notar que o FCI apresenta algumas desvantagens em comparação ao PC:

  1. Complexidade computacional: O FCI é geralmente mais custoso computacionalmente do que o PC, especialmente para grandes conjuntos de dados.
  2. Saída menos definitiva: Os PAGs produzidos pelo FCI frequentemente contêm mais direções de arestas indeterminadas do que os DAGs do PC, refletindo a incerteza adicional resultante de possíveis confundidores latentes.
  3. Interpretação: Os PAGs podem ser mais desafiadores de interpretar do que os DAGs para não especialistas.

Na prática, a escolha entre FCI e PC frequentemente depende dos requisitos específicos de sua tarefa de inferência causal, da natureza dos seus dados e das suas suposições sobre o sistema causal. Se você estiver confiante de que não há confundidores ocultos e nenhum viés de seleção, o PC pode ser suficiente e mais eficiente. Se você suspeitar de variáveis latentes ou viés de seleção, o FCI seria a escolha mais adequada.Modelo de Autorregressão Vetorial (VAR)


Modelo de Autorregressão Vetorial (VAR)

VAR é um algoritmo de previsão multivariada utilizado quando duas ou mais séries temporais influenciam umas às outras. Neste sistema de negociação, provavelmente é usado para modelar os relacionamentos entre diferentes instrumentos financeiros ou indicadores econômicos.

Principais características do VAR:

  1. Ele captura interdependências lineares entre múltiplas séries temporais.
  2. Cada variável é uma função linear de defasagens passadas de si mesma e de defasagens passadas de outras variáveis.
  3. Ele permite dinâmicas ricas em um sistema de séries temporais múltiplas.

No contexto deste sistema de negociação:

  • O modelo VAR é treinado usando a função TrainVARModel.
  • A função PredictVARValue usa o modelo treinado para fazer previsões.
  • O sistema otimiza o modelo VAR selecionando a defasagem ideal e as variáveis significativas usando a função OptimizeVARModel.


Representação matemática:

Para um modelo VAR de duas variáveis com lag 1:

y1,t = c1 + φ11y1,t-1 + φ12y2,t-1 + ε1,t

y2,t = c2 + φ21y1,t-1 + φ22y2,t-1 + ε2,t

onde:

  • y1,t e y2,t são os valores das duas variáveis no tempo t
  • c1 e c2 são constantes
  • φij são os coeficientes
  • ε1,t e ε2,t são termos de erro

O sistema estima esses coeficientes para fazer previsões.

Imagine que você não está apenas prevendo o preço futuro de um único ativo, mas simultaneamente projetando múltiplas variáveis financeiras inter-relacionadas. É aí que o VAR se destaca. É como ter uma bola de cristal que não mostra apenas um futuro, mas múltiplos futuros interconectados de uma só vez.

No seu cerne, o VAR é um algoritmo de previsão multivariada utilizado quando duas ou mais séries temporais influenciam umas às outras. Em termos mais simples, é uma forma de capturar as dependências lineares entre múltiplas séries temporais.


Como o VAR Faz sua Mágica?

Vamos detalhar isso:

  1. Coleta de Dados: Você começa reunindo dados históricos para todas as variáveis que deseja incluir no seu modelo. Isso pode ser dados de preços de vários pares de moedas, commodities ou até indicadores econômicos.
  2. Especificação do Modelo: Você decide quantos lags (períodos passados) incluir. É aqui que sua experiência em trading é útil!
  3. Estimação: O modelo estima como cada variável é influenciada por seus próprios valores passados e pelos valores passados de outras variáveis.
  4. Previsão: Uma vez estimado, o modelo VAR pode gerar previsões para todas as variáveis incluídas simultaneamente.


Implementando VAR em MQL5

Embora o MQL5 não possua uma função VAR embutida, você pode implementá-la você mesmo. Aqui está um exemplo simplificado de como estruturar seu código:

// Define your VAR model
struct VARModel {
    int lag;
    int variables;
    double[][] coefficients;
};

// Estimate VAR model
VARModel EstimateVAR(double[][] data, int lag) {
    // Implement estimation logic here
    // You might use matrix operations for efficiency
}

// Make predictions
double[] Forecast(VARModel model, double[][] history) {
    // Implement forecasting logic here
}

// In your EA or indicator
void OnTick() {
    // Collect your multivariate data
    double[][] data = CollectData();
    
    // Estimate model
    VARModel model = EstimateVAR(data, 5); // Using 5 lags
    
    // Make forecast
    double[] forecast = Forecast(model, data);
    
    // Use forecast in your trading logic
    // ...
}


A Vantagem do VAR em Ação

Imagine que você está negociando EUR/USD. Uma abordagem tradicional poderia olhar apenas os preços passados do EUR/USD. Mas com VAR, você poderia incluir:

  • Preços de EUR/USD
  • Preços de USD/JPY (para capturar a força geral do USD)
  • Preços do petróleo (um fator significativo para muitas moedas)
  • Índice S&P 500 (para avaliar o sentimento geral do mercado)
  • Diferencial de taxa de juros EUA-UE

Agora seu modelo captura um panorama muito mais rico do mercado Forex, potencialmente levando a decisões de negociação mais bem informadas.


Desafios e Considerações

Como qualquer ferramenta poderosa, o VAR traz seus desafios:

  1. Requisitos de Dados: Modelos VAR podem consumir muitos dados. Certifique-se de ter dados históricos suficientes para estimativas confiáveis.
  2. Intensidade Computacional: À medida que você aumenta variáveis e defasagens, os requisitos computacionais crescem. Otimize seu código para eficiência.
  3. Estacionariedade: VAR assume séries temporais estacionárias. Você pode precisar pré-processar seus dados (por exemplo, diferenciação) para atender a essa suposição.
  4. Interpretação: Com múltiplas variáveis e defasagens, interpretar os resultados do VAR pode ser complexo. Não deixe de combinar insights estatísticos com seu conhecimento de trading.


Análise de Rede no Sistema de Negociação CNA

A análise de rede implementada neste Expert Advisor (EA) é um componente fundamental de sua estratégia de análise e predição de mercado. Ela foi projetada para representar e analisar as relações complexas entre diferentes instrumentos financeiros ou variáveis de mercado.

Para resumir os pontos-chave sobre a análise de rede usada neste EA:

  1. Estrutura: A rede é composta por nós, cada um representando um instrumento financeiro (tipicamente um par de moedas).
  2. Propósito: Foi projetada para modelar as relações e interdependências entre diferentes instrumentos financeiros no mercado.
  3. Descoberta Causal: O EA usa o algoritmo Fast Causal Inference (FCI) para descobrir possíveis relações causais entre esses instrumentos.
  4. Representação: Essas relações são representadas em uma matriz de adjacência, que mostra quais instrumentos estão diretamente ligados em termos de influência causal.
  5. Análise: O EA realiza várias análises nessa rede, incluindo a identificação de v-estruturas (um padrão específico em grafos causais) e a aplicação de regras de orientação para refinar ainda mais o entendimento das relações causais.
  6. Integração com Predição: A estrutura da rede e as relações descobertas por meio dessa análise servem como insumos para o modelo de Autorregressão Vetorial (VAR), usado para fazer predições.
  7. Natureza Adaptativa: A análise de rede não é estática. Ela pode ser atualizada ao longo do tempo, permitindo que o EA se adapte a condições de mercado e relações entre instrumentos em evolução.

A ideia central dessa abordagem é que instrumentos financeiros não se movem isoladamente. Modelando e analisando a rede de relacionamentos entre diferentes instrumentos, o EA busca obter uma compreensão mais ampla da dinâmica do mercado. Isso, em teoria, deve levar a predições mais precisas e decisões de negociação mais bem fundamentadas.

No entanto, é importante notar que, embora essa abordagem seja sofisticada, os mercados financeiros são extremamente complexos e influenciados por muitos fatores. A eficácia dessa análise de rede dependerá de quão bem ela captura a dinâmica real do mercado e de como é integrada a outros componentes da estratégia de negociação.


Estrutura da Rede

A rede é representada pelas seguintes estruturas:

struct Node
{
    string name;
    double value;
};

Node g_network[];
int g_node_count = 0;

Cada Node na rede representa um instrumento financeiro específico ou variável de mercado. O campo name identifica o instrumento (por exemplo, “EURUSD”, “GBPUSD”), e o campo value pode armazenar dados relevantes para esse nó.


Configurando a Rede

A rede é inicializada na função SetupNetwork():

void SetupNetwork()
{
    string symbols[] = {"EURUSD", "GBPUSD", "USDCAD", "USDCHF", "USDJPY", "AUDUSD"};
    for(int i = 0; i < ArraySize(symbols); i++)
    {
        AddNode(symbols[i]);
    }
}

void AddNode(string name)
{
    ArrayResize(g_network, g_node_count + 1);
    g_network[g_node_count].name = name;
    g_network[g_node_count].value = 0; // Initialize with default value
    g_node_count++;
}

Este setup cria uma rede onde cada nó representa um par de moedas diferente.


Propósito da Rede

A rede serve a vários propósitos-chave neste EA:

  1. Representação da Estrutura de Mercado: Modela as interconexões entre diferentes pares de moedas, permitindo que o EA considere como movimentos em um par podem afetar outros.
  2. Base para Análise Causal: A estrutura da rede é usada como base para o algoritmo Fast Causal Inference (FCI), que tenta descobrir relações causais entre os nós.
  3. Insumo para Modelagem Preditiva: A estrutura da rede e as relações descobertas por meio da análise causal servem como insumos para o modelo VAR usado nas predições.


Análise de Rede em Ação

O EA executa vários tipos de análise nessa rede:

  1. Descoberta Causal: A função FCIAlgorithm() aplica o algoritmo Fast Causal Inference para revelar possíveis relações causais entre os nós.
  2. Matriz de Adjacência: As relações causais são representadas em uma matriz de adjacência, onde cada entrada indica se há um link causal direto entre dois nós.
  3. Orientação de V-Estruturas: A função OrientVStructures() identifica e orienta v-estruturas na rede, padrões importantes em grafos causais.
  4. Análise de Grafo: A estrutura final do grafo é analisada para informar decisões de negociação, assumindo-se que instrumentos causalmente ligados podem fornecer informação preditiva uns aos outros.


Implicações para o Trading

Essa abordagem baseada em rede permite que o EA:

  1. Considere dinâmicas de mercado complexas que podem não ser aparentes ao analisar instrumentos isoladamente.
  2. Potencialmente identifique indicadores líderes entre os instrumentos analisados.
  3. Faça predições mais bem informadas considerando o contexto de mercado mais amplo.
  4. Adapte-se a condições de mercado mutáveis, pois a estrutura causal é reavaliada periodicamente.

Ao aproveitar essa análise de rede, o EA visa obter um entendimento mais profundo da dinâmica do mercado, levando potencialmente a predições mais precisas e decisões de negociação melhor fundamentadas.


Exemplo de Código

Este código segue estes dois diagramas de fluxo:

Diagrama de fluxo

Diagrama de fluxo de função



Explicação Detalhada das Funções-Chave no Programa de Negociação em MQL5

Este EA de negociação é bastante sofisticado e combina várias abordagens avançadas:

  1. Ele usa um modelo de Autorregressão Vetorial (VAR) para predições.
  2. Implementa um algoritmo de descoberta causal (FCI – Fast Causal Inference) para entender relações entre diferentes variáveis de mercado.
  3. Emprega uma estrutura de rede para representar e analisar vários instrumentos financeiros simultaneamente.
  4. Incorpora vários filtros técnicos, como volatilidade, RSI e força de tendência.
  5. Utiliza gerenciamento adaptativo de risco e dimensionamento de posição.
  6. Implementa uma estratégia de janela deslizante para atualizar e re-treinar o modelo continuamente.
  7. Inclui técnicas de validação cruzada e otimização de modelo.

A estrutura do EA permite análise e tomada de decisão complexas, mantendo flexibilidade para melhorias futuras ou adaptações a diferentes condições de mercado.


Explicação Detalhada das Funções-Chave no EA de Negociação

1. OnInit()

int OnInit()
  {
// Step 1: Set up your network structure
   SetupNetwork();

// Step 2: Run the causal discovery algorithm (e.g., PC or FCI)
   FCIAlgorithm();

// Step 3: Train the optimized causal model
   TrainOptimizedVARModel();

   ArrayResize(g_previous_predictions, g_node_count);
   ArrayInitialize(g_previous_predictions, 0);  // Initialize with zeros

   return(INIT_SUCCEEDED);
  }

Esta é a função de inicialização que roda quando o EA é carregado ou recarregado em um gráfico.

Responsabilidades principais:

  • Configura a estrutura de rede chamando SetupNetwork()
  • Executa o algoritmo de descoberta causal (FCI) com FCIAlgorithm()
  • Treina o modelo causal otimizado usando TrainOptimizedVARModel()
  • Inicializa o array de predições anteriores

Essa função estabelece a base para toda a análise e predição que o EA realizará.

2. OnTick()

void OnTick()
  {
   ENUM_TIMEFRAMES tf = ConvertTimeframe(InputTimeframe);

   static datetime lastBarTime = 0;
   datetime currentBarTime = iTime(Symbol(), tf, 0);

   if(currentBarTime == lastBarTime)
      return;

   lastBarTime = currentBarTime;

   Print("--- New bar on timeframe ", EnumToString(tf), " ---");

   UpdateModelSlidingWindow();

   for(int i = 0; i < g_node_count; i++)
     {
      string symbol = g_network[i].name;
      Print("Processing symbol: ", symbol);

      double prediction = PredictVARValue(i);
      Print("Prediction for ", symbol, ": ", prediction);

      int signal = GenerateSignal(symbol, prediction);
      Print("Signal for ", symbol, ": ", signal);

      // Imprimir más detalles sobre las condiciones
      Print("RSI: ", CustomRSI(symbol, ConvertTimeframe(InputTimeframe), 14, PRICE_CLOSE, 0));
      Print("Trend: ", DetermineTrend(symbol, ConvertTimeframe(InputTimeframe)));
      Print("Trend Strong: ", IsTrendStrong(symbol, ConvertTimeframe(InputTimeframe)));
      Print("Volatility OK: ", VolatilityFilter(symbol, ConvertTimeframe(InputTimeframe)));
      Print("Fast MA > Slow MA: ", (iMA(symbol, PERIOD_CURRENT, 14, 0, MODE_EMA, PRICE_CLOSE) > iMA(symbol, PERIOD_CURRENT, 24, 0, MODE_EMA, PRICE_CLOSE)));

      if(signal != 0)
        {
         Print("Attempting to execute trade for ", symbol);
         ExecuteTrade(symbol, signal);
        }
      else
        {
         g_debug_no_signal_count++;
         Print("No trade signal generated for ", symbol, ". Total no-signal count: ", g_debug_no_signal_count);
        }
      ManageOpenPositions();
      ManageExistingOrders(symbol);


      Print("Current open positions for ", symbol, ": ", PositionsTotal());
      Print("Current pending orders for ", symbol, ": ", OrdersTotal());
     }

   Print("--- Bar processing complete ---");
   Print("Total no-signal count: ", g_debug_no_signal_count);
   Print("Total failed trade count: ", g_debug_failed_trade_count);
  }

Esta função é chamada a cada tick do mercado.

Principais tarefas:

  • Converte o timeframe de entrada
  • Atualiza o modelo usando janela deslizante com UpdateModelSlidingWindow()
  • Para cada símbolo na rede:
    • Prevê valores usando PredictVARValue()
    • Gera sinais de negociação com GenerateSignal()
    • Executa trades se sinais forem gerados
    • Gerencia posições abertas
    • Gerencia ordens existentes

Este é o coração operacional do EA, onde as decisões de negociação são tomadas.

3. OnCalculate()

Embora não apareça explicitamente no código fornecido, essa função tipicamente seria usada para calcular valores de indicadores customizados. Neste EA, parte dessa funcionalidade parece estar integrada em OnTick().

4. CheckMarketConditions()

int GenerateSignal(string symbol, double prediction)
  {
   int node_index = FindNodeIndex(symbol);
   if(node_index == -1)
      return 0;

   static bool first_prediction = true;
   if(first_prediction)
     {
      first_prediction = false;
      return 0; // No generar señal en la primera predicción
     }

   double current_price = SymbolInfoDouble(symbol, SYMBOL_BID);

// Calculate predicted change as a percentage
   double predicted_change = (prediction - current_price) / current_price * 100;

   bool volatility_ok = VolatilityFilter(symbol, ConvertTimeframe(InputTimeframe));
   double rsi = CustomRSI(symbol, ConvertTimeframe(InputTimeframe), 14, PRICE_CLOSE, 0);
   bool trend_strong = IsTrendStrong(symbol, ConvertTimeframe(InputTimeframe));
   int trend = DetermineTrend(symbol, ConvertTimeframe(InputTimeframe));

   double fastMA = iMA(symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, PRICE_CLOSE);
   double slowMA = iMA(symbol, PERIOD_CURRENT, 24, 0, MODE_EMA, PRICE_CLOSE);

   Print("Debugging GenerateSignal for ", symbol);
   Print("Current price: ", current_price);
   Print("Prediction diff: ", prediction);
   Print("predicted_change: ", predicted_change);
   Print("RSI: ", rsi);
   Print("Trend: ", trend);
   Print("Trend Strong: ", trend_strong);
   Print("Volatility OK: ", volatility_ok);
   Print("Fast MA: ", fastMA, ", Slow MA: ", slowMA);

   bool buy_condition =  prediction >  0.00001 && rsi < 30 && trend_strong  && volatility_ok && fastMA > slowMA;
   bool sell_condition = prediction < -0.00001 && rsi > 70 && trend_strong && volatility_ok && fastMA < slowMA;

   Print("Buy condition met: ", buy_condition);
   Print("Sell condition met: ", sell_condition);

// Buy conditions
   if(buy_condition)
     {
      Print("Buy signal generated for ", symbol);
      int signal = 1;
      return signal;  // Buy signal
     }
// Sell conditions
   else
      if(sell_condition)
        {
         Print("Sell signal generated for ", symbol);
         int signal = -1;
         return signal; // Sell signal
        }
      else
        {
         Print("No signal generated for ", symbol);
         int signal = 0;
         return signal; // No signal
        }


  }

Essa função não é explicitamente definida no código, mas sua funcionalidade está distribuída em várias partes, principalmente dentro de GenerateSignal():

  • Verifica a volatilidade com VolatilityFilter()
  • Verifica o RSI
  • Verifica a força da tendência com IsTrendStrong()
  • Determina a direção da tendência com DetermineTrend()
  • Compara médias móveis rápidas e lentas

Essas verificações determinam se as condições de mercado são favoráveis para operar.

5. ExecuteTrade()

void ExecuteTrade(string symbol, int signal)
  {
   if(!IsMarketOpen(symbol) || !IsTradingAllowed())
     {
      Print("Market is closed or trading is not allowed for ", symbol);
      return;
     }

   double price = (signal == 1) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID);

   double stopLoss, takeProfit;
   CalculateAdaptiveLevels(symbol, signal, stopLoss, takeProfit);

   double lotSize = CalculateDynamicLotSize(symbol, stopLoss);

   if(lotSize <= 0)
     {
      Print("Invalid lot size for symbol: ", symbol);
      return;
     }

   trade.SetExpertMagicNumber(123456);
   trade.SetTypeFilling(ORDER_FILLING_FOK);

   bool result = false;
   int attempts = 3;

   for(int i = 0; i < attempts; i++)
     {
      if(signal == 1)
        {
         result = trade.Buy(lotSize, symbol, price, stopLoss, takeProfit, "CNA Buy");
         Print("Attempting Buy order: Symbol=", symbol, ", Lot Size=", lotSize, ", Price=", price, ", SL=", stopLoss, ", TP=", takeProfit);
        }
      else
         if(signal == -1)
           {
            result = trade.Sell(lotSize, symbol, price, stopLoss, takeProfit, "CNA Sell");
            Print("Attempting Sell order: Symbol=", symbol, ", Lot Size=", lotSize, ", Price=", price, ", SL=", stopLoss, ", TP=", takeProfit);
           }

      if(result)
        {
         Print("Order executed successfully for ", symbol, ", Type: ", (signal == 1 ? "Buy" : "Sell"), ", Lot size: ", lotSize);
         break;
        }
      else
        {
         int lastError = GetLastError();
         Print("Attempt ", i+1, " failed for ", symbol, ". Error: ", lastError, " - ", GetErrorDescription(lastError));

         if(lastError == TRADE_RETCODE_REQUOTE || lastError == TRADE_RETCODE_PRICE_CHANGED || lastError == TRADE_RETCODE_INVALID_PRICE)
           {
            price = (signal == 1) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID);
            CalculateAdaptiveLevels(symbol, signal, stopLoss, takeProfit);
           }
         else
            break;
        }
     }

   if(!result)
     {
      Print("All attempts failed for ", symbol, ". Last error: ", GetLastError(), " - ", GetErrorDescription(GetLastError()));
     }
  }

Essa função lida com a execução real das operações

Aspectos principais:

  • Verifica se o mercado está aberto e se a negociação é permitida
  • Calcula níveis adaptativos de stop loss e take profit
  • Determina o tamanho do lote com base na gestão de risco
  • Tenta executar a ordem, com tentativas de reenvio em caso de falha
  • Gerencia erros e fornece feedback detalhado

6. OnDeinit()

void OnDeinit(const int reason)
  {
   if(atr_handle != INVALID_HANDLE)
      IndicatorRelease(atr_handle);
   if(rsi_handle != INVALID_HANDLE)
      IndicatorRelease(rsi_handle);
   if(momentum_handle != INVALID_HANDLE)
      IndicatorRelease(momentum_handle);
   GenerateFinalSummary();
  }

Essa função é chamada quando o EA é removido do gráfico ou quando o terminal é fechado.

Principais responsabilidades:

  • Libera os identificadores dos indicadores
  • Gera um resumo final do desempenho do EA chamando GenerateFinalSummary()


Funções Importantes Adicionais

UpdateModelSlidingWindow()

void UpdateModelSlidingWindow()
  {
   static int bars_since_update = 0;
   ENUM_TIMEFRAMES tf = ConvertTimeframe(InputTimeframe);

// Check if it's time to update
   if(bars_since_update >= g_update_frequency)
     {
      // Collect new data
      double training_data[];
      CollectTrainingData(training_data, g_window_size, tf);

      // Retrain model
      TrainModel(training_data);

      // Validate model
      double validation_score = ValidateModel();
      Print("Model updated. Validation score: ", validation_score);

      bars_since_update = 0;
     }
   else
     {
      bars_since_update++;
     }
  }

Atualiza o modelo VAR usando uma janela deslizante de dados, permitindo que o modelo se adapte às mudanças nas condições de mercado.


TrainOptimizedVARModel()

void TrainOptimizedVARModel()
  {
   OptimizationResult opt_result = OptimizeVARModel();

   Print("Lag óptimo encontrado: ", opt_result.optimal_lag);
   Print("AIC: ", opt_result.aic);
   Print("Variables seleccionadas: ", ArraySize(opt_result.selected_variables));

// Usar opt_result.optimal_lag y opt_result.selected_variables para entrenar el modelo final
   TrainVARModel(opt_result.optimal_lag, opt_result.selected_variables);
  }
Otimiza e treina o modelo VAR, selecionando o número ideal de defasagens e variáveis significativas.


PredictVARValue()

double PredictVARValue(int node_index)
{
   if(node_index < 0 || node_index >= g_node_count)
   {
      Print("Error: Invalid node index: ", node_index);
      return 0;
   }

   double prediction = 0;
   int lag = g_var_params[node_index].lag;

   Print("Predicting for node: ", g_network[node_index].name, ", Lag: ", lag);

   // Retrieve the previous prediction
   double previous_prediction = g_previous_predictions[node_index];

   // Verify if there are enough coefficients
   int expected_coefficients = g_node_count * lag + 1; // +1 for the intercept
   if(ArraySize(g_var_params[node_index].coefficients) < expected_coefficients)
   {
      Print("Error: Not enough coefficients for node ", node_index, ". Expected: ", expected_coefficients, ", Actual: ", ArraySize(g_var_params[node_index].coefficients));
      return 0;
   }

   prediction = g_var_params[node_index].coefficients[0]; // Intercept
   Print("Intercept: ", prediction);

   double sum_predictions = 0;
   double sum_weights = 0;
   double current_price = iClose(g_network[node_index].name, PERIOD_CURRENT, 0);

   for(int l = 1; l <= lag; l++)
   {
      double time_weight = 1.0 - (double)(l-1) / lag; // Time-based weighting
      sum_weights += time_weight;

      double lag_prediction = 0;
      for(int j = 0; j < g_node_count; j++)
      {
         int coeff_index = (l - 1) * g_node_count + j + 1;
         if(coeff_index >= ArraySize(g_var_params[node_index].coefficients))
         {
            Print("Warning: Coefficient index out of range. Skipping. Index: ", coeff_index, ", Array size: ", ArraySize(g_var_params[node_index].coefficients));
            continue;
         }

         double coeff = g_var_params[node_index].coefficients[coeff_index];
         double raw_value = iClose(g_network[j].name, PERIOD_CURRENT, l);

         if(raw_value == 0 || !MathIsValidNumber(raw_value))
         {
            Print("Warning: Invalid raw value for ", g_network[j].name, " at lag ", l);
            continue;
         }

         // Normalize the value as a percentage change
         double normalized_value = (raw_value - current_price) / current_price;

         double partial_prediction = coeff * normalized_value;
         lag_prediction += partial_prediction;

         Print("Lag ", l, ", Node ", j, ": Coeff = ", coeff, ", Raw Value = ", raw_value,
               ", Normalized Value = ", normalized_value, ", Partial prediction: ", partial_prediction);
      }

      sum_predictions += lag_prediction * time_weight;
      Print("Lag ", l, " prediction: ", lag_prediction, ", Weighted: ", lag_prediction * time_weight);
   }

   Print("Sum of weights: ", sum_weights);

   // Calculate the final prediction
   if(sum_weights > 1e-10)
   {
      prediction = sum_predictions / sum_weights;
   }
   else
   {
      Print("Warning: sum_weights is too small (", sum_weights, "). Using raw sum of predictions.");
      prediction = sum_predictions;
   }

   // Calculate the difference between the current prediction and the previous prediction
   double prediction_change = prediction - previous_prediction;

   Print("Previous prediction: ", previous_prediction);
   Print("Current prediction: ", prediction);
   Print("Prediction change: ", prediction_change);

   // Convert the prediction to a percentage change
   double predicted_change_percent = (prediction - current_price) / current_price * 100;

   Print("Final prediction (as percentage change): ", predicted_change_percent, "%");

   // Update the current prediction for the next iteration
   g_previous_predictions[node_index] = prediction;

   // Return the difference in basis points
   return prediction_change * 10000; // Multiply by 10000 to convert to basis points
}

Realiza previsões usando o modelo VAR treinado, considerando valores históricos e coeficientes do modelo.


ManageOpenPositions() and ManageExistingOrders()

void ManageOpenPositions()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
        {
         string symbol = PositionGetString(POSITION_SYMBOL);
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
         double stopLoss = PositionGetDouble(POSITION_SL);
         ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

         // Implement trailing stop
         if(positionType == POSITION_TYPE_BUY && currentPrice - openPrice > 2 * CustomATR(symbol, PERIOD_CURRENT, 14, 0))
           {
            double newStopLoss = NormalizeDouble(currentPrice - CustomATR(symbol, PERIOD_CURRENT, 14, 0), SymbolInfoInteger(symbol, SYMBOL_DIGITS));
            if(newStopLoss > stopLoss)
              {
               trade.PositionModify(ticket, newStopLoss, 0);
              }
           }
         else
            if(positionType == POSITION_TYPE_SELL && openPrice - currentPrice > 2 * CustomATR(symbol, PERIOD_CURRENT, 14, 0))
              {
               double newStopLoss = NormalizeDouble(currentPrice + CustomATR(symbol, PERIOD_CURRENT, 14, 0), SymbolInfoInteger(symbol, SYMBOL_DIGITS));
               if(newStopLoss < stopLoss || stopLoss == 0)
                 {
                  trade.PositionModify(ticket, newStopLoss, 0);
                 }
              }
        }
     }
  }


void ManageExistingOrders(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == symbol)
        {
         double stopLoss = PositionGetDouble(POSITION_SL);
         double takeProfit = PositionGetDouble(POSITION_TP);
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
         ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

         double atr = CustomATR(symbol, PERIOD_CURRENT, 14, 0);
         double newStopLoss, newTakeProfit;

         if(positionType == POSITION_TYPE_BUY)
           {
            newStopLoss = NormalizeDouble(currentPrice - 2 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS));
            newTakeProfit = NormalizeDouble(currentPrice + 3 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS));
            if(newStopLoss > stopLoss && currentPrice - openPrice > atr)
              {
               trade.PositionModify(ticket, newStopLoss, newTakeProfit);
              }
           }
         else
            if(positionType == POSITION_TYPE_SELL)
              {
               newStopLoss = NormalizeDouble(currentPrice + 2 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS));
               newTakeProfit = NormalizeDouble(currentPrice - 3 * atr, SymbolInfoInteger(symbol, SYMBOL_DIGITS));
               if(newStopLoss < stopLoss && openPrice - currentPrice > atr)
                 {
                  trade.PositionModify(ticket, newStopLoss, newTakeProfit);
                 }
              }

         // Implementar cierre parcial
         double profit = PositionGetDouble(POSITION_PROFIT);
         double volume = PositionGetDouble(POSITION_VOLUME);
         if(profit > 0 && MathAbs(currentPrice - openPrice) > 2 * atr)
           {
            double closeVolume = volume * 0.5;
            if(IsValidVolume(symbol, closeVolume))
              {
               ClosePosition(ticket, closeVolume);
              }
           }
        }
     }
  }

Gerencia posições abertas e ordens existentes, implementando estratégias como trailing stops e fechamentos parciais.

Este EA combina análise técnica tradicional com modelagem estatística avançada (VAR) e técnicas de machine learning (descoberta causal) para tomar decisões de negociação. A estrutura modular permite a fácil modificação e melhoria dos componentes individuais.


Resultados

Estes são os resultados para alguns símbolos, as configurações e entradas permanecerão as mesmas para todos os símbolos estudados:

Configurações

Entradas


EURUSD

EURUSD


GBPUSD

GBPUSD


AUDUSD

AUDUSD

USDJPY

USDJPY


USDCAD

USDCAD


USDCHF

USDCHF


Como obter melhores resultados?

Melhores resultados podem ser alcançados se, no nó de símbolos, você adicionar mais símbolos e também utilizar símbolos co-integrados e correlacionados. Para saber quais são esses símbolos, você pode usar meu script em Python deste artigo: Aplicação da Teoria dos Jogos de Nash com Filtragem HMM no Trading - Artigos MQL5.

Além disso, melhores resultados podem ser obtidos se você adicionar deep learning à estratégia. Há alguns exemplos disso em artigos como este: Análise de Sentimento e Deep Learning para Trading com EA e Backtesting com Python - Artigos MQL5 

Também, otimizações não foram feitas para os filtros, e você também poderia tentar adicionar mais filtragem.

Exemplo de como o gráfico muda ao adicionar mais símbolos à rede

void SetupNetwork()
  {
   string symbols[] = {"EURUSD", "GBPUSD", "USDCAD", "USDCHF", "USDJPY", "AUDUSD", "XAUUSD", "SP500m", "ND100m"};
   for(int i = 0; i < ArraySize(symbols); i++)
     {
      AddNode(symbols[i]);
     }
  }


EURUSD modificado

EURUSD modificado

Apenas adicionando mais símbolos à rede, conseguimos melhorar em:

  1. Atividade de trading (mais negociações totais)
  2. Taxa de acerto em operações de venda
  3. Percentual de negociações lucrativas
  4. Tamanho da maior operação lucrativa
  5. Lucro médio por operação vencedora
  6. Percentual menor de negociações perdedoras
  7. Prejuízo médio menor por operação perdedora

Essas melhorias sugerem uma melhor gestão geral das operações e controle de risco, apesar de alguns indicadores-chave de desempenho (como fator de lucro e fator de recuperação) serem menores.


Conclusão

Este artigo discute um sistema de negociação avançado que integra Análise de Rede de Causalidade (CNA) e Vetor Auto-Regressivo (VAR) para prever eventos de mercado e tomar decisões de negociação. O sistema utiliza técnicas sofisticadas de estatística e machine learning para modelar relações entre instrumentos financeiros. Embora promissor, enfatiza a importância de combinar essa abordagem com uma gestão de risco robusta e uma compreensão profunda dos mercados.

Para traders que buscam melhores resultados, o artigo sugere expandir a rede com mais símbolos correlacionados, incorporar deep learning e otimizar os métodos de filtragem. O aprendizado contínuo e a adaptação são cruciais para o sucesso a longo prazo no trading.

Boas negociações, e que seus algoritmos estejam sempre um passo à frente do mercado!


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

Arquivos anexados |
CNA_Final_v4.mq5 (179.13 KB)
Últimos Comentários | Ir para discussão (4)
Javier Santiago Gaston De Iriarte Cabrera

Se esse EA apresentar problemas, você pode tentar com este (é uma versão mais antiga e os gráficos não são iguais, mas acabei de testá-lo e funciona).

Por favor, avise-me quando um EA não funcionar corretamente, pois de vez em quando eu formato o computador e perco todas as outras versões.

Javier Santiago Gaston De Iriarte Cabrera

Este também funciona

Javier Santiago Gaston De Iriarte Cabrera

Desculpe, mas este deve funcionar

Javier Santiago Gaston De Iriarte Cabrera
Esse não apresenta erros, e é o que usarei para começar a trabalhar.
Algoritmo de busca orbital atômica — Atomic Orbital Search (AOS): Modificação Algoritmo de busca orbital atômica — Atomic Orbital Search (AOS): Modificação
Na segunda parte do artigo, continuaremos o desenvolvimento da versão modificada do algoritmo AOS (Atomic Orbital Search), focando em operadores específicos para aumentar sua eficiência e adaptabilidade. Após analisar as bases e mecânicas do algoritmo, discutiremos ideias para melhorar o desempenho e a capacidade de análise de espaços de soluções complexos, propondo novas abordagens para expandir sua funcionalidade como ferramenta de otimização.
Criando um Expert Advisor Integrado MQL5-Telegram (Parte 4): Modularizando Funções de Código para Maior Reutilização Criando um Expert Advisor Integrado MQL5-Telegram (Parte 4): Modularizando Funções de Código para Maior Reutilização
Neste artigo, reformulamos o código existente usado para enviar mensagens e capturas de tela do MQL5 para o Telegram, organizando-o em funções modulares reutilizáveis. Isso tornará o processo mais eficiente, permitindo uma execução mais rápida e uma gestão de código mais fácil em múltiplas instâncias.
Aprendendo MQL5 do iniciante ao profissional (Parte VI):  Fundamentos da criação de EAs Aprendendo MQL5 do iniciante ao profissional (Parte VI): Fundamentos da criação de EAs
O artigo dá continuidade à série para iniciantes. Aqui serão abordados os princípios básicos da construção de EAs. Primeiro, criaremos um EA que operará sem indicadores, usando ordens pendentes, depois, criaremos um segundo EA, baseado no indicador padrão MA, operando com ordens a preço atual. Parto do princípio de que você já não é totalmente iniciante e domina o material dos artigos anteriores.
Reimaginando Estratégias Clássicas (Parte VII): Mercados de Forex e Análise da Dívida Soberana no USDJPY Reimaginando Estratégias Clássicas (Parte VII): Mercados de Forex e Análise da Dívida Soberana no USDJPY
No artigo de hoje, analisaremos a relação entre as taxas de câmbio futuras e os títulos do governo. Os títulos estão entre as formas mais populares de títulos de renda fixa e serão o foco da nossa discussão. Junte-se a nós enquanto exploramos se podemos melhorar uma estratégia clássica usando IA.