
Formulando um EA Dinâmico de Múltiplos Pares (Parte 1): Correlação e Correlação Inversa entre Moedas
Introdução
Quando você tem uma estratégia ou sistema de negociação sólido, com uma boa taxa de acerto ou fator de lucro, diversificar as operações entre pares de moedas correlacionados e inversamente correlacionados pode melhorar o desempenho geral. Vou demonstrar como desenvolver um sistema que identifica correlações e correlações inversas entre vários pares de moedas, permitindo que os traders aproveitem essas relações para melhores oportunidades de negociação.
Durante grandes eventos de negociação, como os anúncios do Payroll Não Agrícola (NFP), o mercado frequentemente se move rapidamente em uma direção predefinida. Nesses cenários, a execução entre múltiplos pares de moedas pode ser simplificada designando-se um par de moedas primário. As operações iniciadas nesse par principal determinariam as negociações correspondentes nos demais pares, aproveitando as relações de correlação e correlação inversa entre eles. Essa abordagem pode aumentar significativamente a eficiência e a consistência durante eventos de grande impacto no mercado.
O que será abordado:
- A capacidade de alterar e modificar os pares de moedas.
- A indexação do par de moedas que servirá como provedor de sinal para os outros pares.
- A determinação das moedas base e cotada a serem negociadas.
No trading, correlação refere-se à relação entre os movimentos de preço de diferentes pares de moedas. Quando dois pares de moedas são positivamente correlacionados, eles tendem a se mover na mesma direção. Por exemplo, GBPUSD e EURUSD são frequentemente positivamente correlacionados, o que significa que, quando GBPUSD sobe, o EURUSD também tende a subir. Isso ocorre porque ambos os pares compartilham o USD como moeda cotada, e qualquer fraqueza ou força generalizada no USD provavelmente impactará ambos os pares de forma semelhante.
Por outro lado, correlação inversa ocorre quando dois pares de moedas se movem em direções opostas. Um exemplo clássico é a relação entre GBPUSD e USDCAD. Quando o GBPUSD sobe (tendência de alta), o USDCAD geralmente cai (tendência de baixa). Isso acontece porque, no primeiro par (GBPUSD), o USD é a moeda cotada, enquanto no segundo par (USDCAD), o USD é a moeda base. À medida que o USD enfraquece, o GBPUSD sobe, enquanto o USDCAD tende a cair.
Vamos formular um EA dinâmico de múltiplos pares para lidar simultaneamente com vários pares de moedas. O sistema fornecerá flexibilidade, permitindo que você insira, altere e modifique os pares de moedas conforme a sua estratégia de negociação. Uma característica chave desse sistema é a capacidade de definir um par de moedas primário ou "principal", que atuará como provedor de sinal para os outros pares.
No núcleo do sistema está a capacidade de ajustar dinamicamente a lista de pares de moedas sendo negociados. Os traders podem facilmente personalizar quais pares serão incluídos na estratégia, tornando-a adaptável a diferentes condições de mercado ou planos de negociação. O EA aceita entradas para diferentes pares de moedas, permitindo que o usuário adicione, remova ou alterne entre pares conforme necessário.
Um dos aspectos mais inovadores é a designação de um par de moedas principal. Esse par não apenas é negociado ativamente, mas também serve como ponto de referência para gerar sinais para os outros pares. Ao monitorar esse par principal, o EA identifica sinais de negociação — sejam de compra ou venda — e os aplica aos pares selecionados correlacionados ou inversamente correlacionados.
O sistema também suporta ajustes dinâmicos com base na força das correlações entre os pares de moedas. Por exemplo, se for detectado um forte sinal de alta no par principal, o EA poderá automaticamente abrir negociações correspondentes em pares que historicamente se movem na mesma direção. Por outro lado, para pares que tipicamente se movem de forma inversa ao par principal, o EA pode abrir posições opostas, efetivamente realizando uma proteção contra eventuais oscilações do mercado.
Formulação
#include <Trade\Trade.mqh>
CTrade trade;
Isso importa a biblioteca de operações de trading do MetaTrader 5 e cria uma instância da classe CTrade, permitindo que você gerencie operações como abrir, fechar e modificar ordens.
int handles[];
Esta matriz é usada para armazenar os identificadores de vários indicadores ou objetos, que são necessários para rastrear indicadores de análise técnica em vários pares de moedas. Esta matriz é usada para armazenar os identificadores de vários indicadores ou objetos, que são necessários para rastrear indicadores de análise técnica em vários pares de moedas.
MqlTick previousTick, currentTick;
Essas variáveis armazenam dados de ticks dos preços dos símbolos. A variável previousTick guarda o último dado de tick, enquanto currentTick armazena o dado atual.
inputstring Symbols = "XAUUSD, GBPUSD, USDCAD, USDJPY"; inputstring Base_Quote = "USD"; inputint Currecy_Main = 0;
Essas entradas permitem ao usuário personalizar o EA:
- `Symbols`: Uma lista separada por vírgulas dos pares de moedas que o EA irá monitorar e negociar.
- `Base-Quote`: A moeda usada para determinar as correlações.
- `Currency-Main`: Um índice que especifica o par de moedas principal a ser usado para gerar sinais.
string symb_List[]; string Formatted_Symbs[]; int Num_symbs = 0;
- `symb-List`: Um array que contém a lista bruta de símbolos a serem processados.
- `Formatted-Symbs`: Um array que armazena os símbolos já processados.
- `Num-symb`: Armazena o número total de símbolos a serem usados após o processamento da entrada Symbols.
intOnInit(){ string sprtr = ","; ushort usprtr; usprtr = StringGetCharacter(sprtr, 0); StringSplit(Symbols, usprtr, symb_List); Num_symbs = ArraySize(symb_List); ArrayResize(Formatted_Symbs, Num_symbs);
A função `OnInit` é chamada uma vez quando o EA é carregado, configurando os valores e parâmetros iniciais. Em seguida, definimos a vírgula como o separador (`sprtr`), que será usado para dividir a string de entrada. A função `StringGetCharacter()` converte o separador em um `ushort` (unsigned short), necessário para a função `StringSplit()`. A função `StringSplit()` divide a entrada `Symbols`(uma string separada por vírgulas) em um array de símbolos individuais. O array `Symb-List[]` armazena os símbolos processados. O array `Formatted-Symbs[]` é redimensionado para corresponder ao número de símbolos processados. Usaremos esse array para processamentos adicionais, como adicionar formatações ou ajustes necessários para a lógica de negociação.
for(int i = 0; i < Num_symbs; i++){ Formatted_Symbs[i] = symb_List[i]; }
Fazemos um loop através do número de símbolos e transferimos os símbolos do array symb-List[] para o array Formatted-Symbs[]. Neste estágio, ainda não é feita nenhuma formatação adicional.
ArrayResize(handles, ArraySize(Formatted_Symbs));
Aqui, redimensionamos o array `handles[]` para corresponder ao tamanho do array `Formatted-Symbs[]`. Cada elemento em `handles[]` armazenará o handle do indicador RSI para o símbolo correspondente.
for(int i = 0; i < ArraySize(Formatted_Symbs); i++){ handles[i] = iRSI(Formatted_Symbs[i], PERIOD_CURRENT, 14, PRICE_CLOSE); }
Esse loop inicializa o handle do indicador RSI para cada símbolo.
void OnTick(){ if(isNewBar()){ for(int i = 0; i < ArraySize(Formatted_Symbs); i++){ Sig_trade(Formatted_Symbs[Currecy_Main], handles[Currecy_Main]); } } }
Aqui, primeiro verificamos se há uma nova barra, e então utilizamos um loop for para detectar o índice do par de moedas principal que irá gerar os sinais. Em seguida, simplesmente chamamos a função 'Sig-trade()', que contém a lógica de negociação, recebendo como parâmetros uma string para o símbolo e um inteiro para o handle do RSI.
void Sig_trade(string symb, int handler){ double rsi[]; CopyBuffer(handler, MAIN_LINE, 1, 1, rsi); bool RSIBuy = rsi[0] < 30; bool RSISell = rsi[0] > 70; // Check if the current symbol is a base USD pair bool isBaseUSD = StringSubstr(symb, 0, 3) == Base_Quote; bool isQuoteUSD = StringSubstr(symb, 3, 3) == Base_Quote; string Bcurr = SymbolInfoString(symb, SYMBOL_CURRENCY_BASE); string Qcurr = SymbolInfoString(symb, SYMBOL_CURRENCY_PROFIT);
Utilizaremos uma estratégia relativamente simples: comprar quando o RSI cair abaixo do nível 30 e vender quando ultrapassar o nível 70.
- 'StringSubstr(symb, 0, 3) == Base-Quote`: Extrai os três primeiros caracteres do símbolo do par de moedas (symb) e verifica se são iguais a "USD". Isso determina se o símbolo é um par com USD como moeda base.
- `StringSubstr(symb, 3, 3) == Base-Quote`: Extrai três caracteres a partir da quarta posição do símbolo do par de moedas (symb) e verifica se são iguais a "USD". Isso determina se o símbolo é um par com USD como moeda cotada.
- `Bcurr = SymbolInfoString(symb, SYMBOL-CURRENCY-BASE)`: Recupera a moeda base do símbolo (a primeira moeda no par) e a armazena na variável `Bcurr`.
- `Qcurr = SymbolInfoString(symb, SYMBOL-CURRENCY-PROFIT)`: Recupera a moeda cotada do símbolo (a segunda moeda no par) e a armazena na variável `Qcurr`.
for(int i = PositionsTotal() - 1; i >= 0; i--){ ulong posTicket = PositionGetTicket(i); if(PositionGetString(POSITION_SYMBOL) == symb){ if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){ if(RSISell){ trade.PositionClose(posTicket); } RSIBuy = false; }elseif(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){ if(RSIBuy){ trade.PositionClose(posTicket); } RSISell = false; } } }
Para gerenciar todas as posições, fazemos um loop através de todas as posições abertas. A função `PositionsTotal()` retorna o número total de posições atualmente abertas. O loop começa da última posição (`PositionsTotal() - 1`) e itera para trás. Utilizamos a iteração reversa para evitar problemas ao modificar a lista de posições abertas enquanto iteramos. Usamos a função `PositionGetTicket()` para recuperar o número do ticket da posição no índice `i`. O ticket é um identificador único para fechar ou modificar uma posição específica.
Em seguida, usamos a função PositionGetString() para recuperar o símbolo da posição atual. A partir daí, comparamos esse símbolo com symb (o símbolo sendo analisado). Se eles corresponderem, a posição é relevante. Depois verificamos se a posição atual é uma ordem de compra, utilizando a função `PositionGetInteger()`. Se a posição for de compra e o RSI indicar venda (`RSISell` for verdadeiro), a posição é fechada usando `trade.PositionClose(posTicket)`. Depois disso, atribuímos `RSIBuy = false` para garantir que nenhuma nova operação de compra seja aberta, já que o sinal atual indica venda.
O mesmo se aplica às posições de venda: verificamos se a posição atual é uma ordem de venda. Se a posição for de venda e o RSI indicar um sinal de compra (`RSIBuy` for verdadeiro), a posição é fechada usando `trade.PositionClose(posTicket)`. Também atribuímos `RSISell = false` para evitar que novas operações de venda sejam abertas, já que o sinal agora é de compra. Utilizamos o código acima para gerenciar todas as posições abertas, pois não usamos stop loss nem take profit. Portanto, o código abrirá e fechará posições dependendo exclusivamente do RSI.
for(int i = 0; i < ArraySize(Formatted_Symbs); i++){ string currSymb = Formatted_Symbs[i]; // Get base and quote currencies for the looped symbol string currBaseCurr = SymbolInfoString(currSymb, SYMBOL_CURRENCY_BASE); string currQuoteCurr = SymbolInfoString(currSymb, SYMBOL_CURRENCY_PROFIT);
Para de fato abrir negociações entre todos os pares de moedas, fazemos um loop através do tamanho (número de elementos) no array `Formatted-Symbs[]`. O loop percorre cada elemento (par de moedas) no array `Formatted-Symbs`. Armazenamos o símbolo atual no gráfico na variável `currSymb`, extraída do array `Formatted-Symbs`. Este símbolo será utilizado para buscar informações relevantes sobre o par de moedas.
if(RSIBuy){ if(currQuoteCurr == Base_Quote){ trade.PositionOpen(currSymb, ORDER_TYPE_BUY, volume, currentTick.ask, NULL, NULL, "Correlation"); } if(currBaseCurr == Base_Quote){ trade.PositionOpen(currSymb, ORDER_TYPE_SELL, volume, currentTick.bid, NULL, NULL, "Correlation"); } }
Aqui verificamos e executamos apenas se o indicador RSI gerar um sinal de compra (normalmente quando o valor do RSI está abaixo de um certo limite, indicando condição de sobrevenda). Em seguida, verificamos se a moeda cotada do símbolo atual corresponde à moeda especificada em `Base-Quote`. Em seguida, verificamos se a moeda cotada do símbolo atual corresponde à moeda especificada em Base-Quote. A lógica por trás disso é que, ao comprar um par de moedas, você está comprando a moeda base e vendendo a moeda cotada. Portanto, se sua estratégia estiver otimista (bullish) em pares onde a moeda cotada é a Base-Quote, você compra aquele par.
Prosseguimos para verificar se a moeda base do símbolo atual corresponde à moeda especificada em `Base-Quote`. Se corresponder, uma ordem de venda é aberta para aquele par de moedas. A lógica aqui é que, se sua estratégia for otimista em pares onde a moeda base é a `Base-Quote`, você venderia aquele par. Vender o par efetivamente significa vender a moeda base e comprar a moeda cotada.
if(RSISell){ if(currBaseCurr == Base_Quote){ trade.PositionOpen(currSymb, ORDER_TYPE_SELL, volume, currentTick.bid, NULL, NULL, "Correlation"); } if(currQuoteCurr == Base_Quote){ trade.PositionOpen(currSymb, ORDER_TYPE_BUY, volume, currentTick.ask, NULL, NULL, "Correlation"); } }
Aqui tratamos da lógica quando um sinal de venda pelo RSI é detectado. Este bloco é executado se o indicador RSI gerar um sinal de venda (normalmente quando o RSI está acima de um certo limite, indicando condição de sobrecompra). Verificamos se a moeda base do símbolo atual corresponde à `Base-Quote` utilizando `currBaseCurr == Base-Quote`. Se corresponder, uma ordem de venda é executada para aquele par de moedas. A lógica continua a mesma: se você está pessimista (bearish) em pares onde a moeda base é a `Base-Quote`. Então deseja vender aquele par. Vender o par significa vender a moeda base e comprar a moeda cotada.
Em seguida, verificamos se a moeda cotada do símbolo atual corresponde à moeda especificada em `Base-Quote`. Se corresponder, uma ordem de compra é aberta para aquele par de moedas. O raciocínio por trás disso é que, se sua estratégia for de baixa em pares onde a moeda de cotação é a `Base-Quote` especificada, você abriria uma negociação de compra naquele par. Isso ocorre porque comprar o par envolve comprar a moeda base e vender a moeda cotada.
bool isNewBar() { //--- memorize the time of opening of the last bar in the static variable staticdatetime last_time=0; //--- current time datetime lastbar_time= (datetime) SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE); //--- if it is the first call of the function if(last_time==0) { //--- set the time and exit last_time=lastbar_time; return(false); } //--- if the time differs if(last_time!=lastbar_time) { //--- memorize the time and return true last_time=lastbar_time; return(true); } //--- if we passed to this line, then the bar is not new; return false return(false); }
Acima está a função `isNewBar` para que o EA não execute ou execute múltiplas ordens.
Resultados no testador de estratégia
Com base nos resultados dos testes acima, podemos confirmar que o sistema abre negociações com sucesso de acordo com as correlações de moedas especificadas e correlações inversas. Conforme discutido anteriormente, quando um sinal de compra é gerado e a moeda principal é um par de cotações USD, todos os pares de cotações USD no array `Formatted-Symbs` executam ordens de compra, enquanto os pares de bases USD executam ordens de venda. Esse comportamento é consistente com a funcionalidade esperada, demonstrando que o sistema implementa efetivamente a lógica de correlação que buscamos alcançar.
Para usar o sistema de forma eficaz e correta, é crucial considerar o uso de agrupamento baseado em pares iguais. Por exemplo, ao negociar pares baseados em EUR, como EURUSD, EURGBP e EURJPY, definir "EUR" como a entrada `Base-Quote` permitiria que a moeda base guiasse a lógica de negociação quando um sinal fosse detectado. Essa abordagem pode ser aplicada a outros grupos de moedas, como USDEUR, ou quaisquer outros pares personalizados permitidos pela sua corretora, garantindo que a lógica do sistema esteja corretamente alinhada com sua estratégia de negociação.
O sistema é dinâmico, permitindo que você escolha facilmente o principal par de moedas que fornecerá ou gerará sinais, simplesmente indexando o par desejado. Essa flexibilidade é particularmente útil, pois o indicador RSI é usado para gerar sinais, e o buffer e o identificador RSI são aplicados a todos os pares de moedas. Isso garante que o par principal selecionado direcione efetivamente as decisões de negociação para os outros pares correlacionados no sistema.
Conclusão
Em resumo, exploramos e desenvolvemos um EA dinâmico de múltiplos pares que processa sinais de negociação com base no indicador RSI e os aplica a diversos pares de moedas correlacionados e inversamente correlacionados. O EA permite entradas para personalização dos pares de moedas e designa um par principal para direcionar as decisões de negociação dos demais pares. Por meio da análise das moedas base e cotada, o EA abre negociações alinhadas com a tendência geral do mercado, utilizando a lógica de correlação.
Em conclusão, um Expert Advisor dinâmico de múltiplos pares pode alcançar resultados de negociação mais consistentes ao aplicar sistematicamente estratégias de correlação e correlação inversa. Essa abordagem não apenas otimiza a eficiência da negociação automatizando a propagação de sinais. Ao integrar correlação e correlação inversa no sistema de negociação, os traders podem aproveitar as relações entre os pares de moedas correlacionados.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15378
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- 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
Confira o novo artigo: Formulação de um EA dinâmico para vários pares (Parte 1): Correlação de moedas e correlação inversa.
Autor: Hlomohang John Borotho
Obrigado por este artigo @Hlomohang John Borotho
Esta parte do código. Parece que o looping gera a mesma saída.
Você definiu currecy_Main como entrada do usuário. currecy_Main=0.
Portanto, obtemos algo parecido com isso em todo o loop.
Podemos remover o loop do código e ainda assim obter os mesmos resultados?