Русский Español
preview
Arbitragem Forex: painel de avaliação de correlações

Arbitragem Forex: painel de avaliação de correlações

MetaTrader 5Sistemas de negociação |
141 10
Yevgeniy Koshtenko
Yevgeniy Koshtenko

Introdução

Meu caminho no trading algorítmico em Forex já tem sido de muitos anos, repletos de tentativas, erros, noites em claro e vitórias raras, porém marcantes. Nesse período, experimentei de tudo, desde indicadores simples até sistemas complexos baseados em aprendizado de máquina. Mas, uma ideia nunca me deixava em paz: e se o mercado não for tão perfeito assim? E se, por trás da aparente caoticidade das cotações, existissem fissuras pelas quais fosse possível enxergar sua verdadeira estrutura e, quem sabe, extrair algum lucro disso? Foi assim que cheguei à análise de arbitragem, uma abordagem que se tornou uma verdadeira revelação para mim.

Hoje, quero compartilhar com vocês a minha criação: um sistema de análise de preços justos de moedas com avaliação de arbitragem, desenvolvido em MQL5 para o MetaTrader 5. Tudo começou com uma simples pergunta que, certa noite, não me deixou dormir: e se pudéssemos calcular as "taxas corretas" das moedas, não aquelas que o mercado nos oferece, mas aquelas que deveriam ser? Dessa curiosidade nasceu um painel que não apenas mostra os desvios das cotações em relação aos seus valores "ideais", mas também identifica rotas de arbitragem triangular — aqueles raros momentos em que o mercado perde a vigilância e podemos aproveitar.

Transformar a teoria em código foi uma verdadeira aventura, cheia de armadilhas, incontáveis iterações e momentos em que quase desisti. Contarei como os cálculos se transformaram em um sistema funcional, como o mercado me testou repetidas vezes e como aprendi a visualizar os resultados de modo que falassem por si mesmos. Você verá exemplos reais de funcionamento do painel, com números, sinais e triângulos de arbitragem. Falarei abertamente sobre os pontos fortes e fracos do sistema e compartilharei a experiência de adaptação a diferentes estratégias, desde operações individuais até redes multimoeda, que se tornaram um verdadeiro campo de experimentação para mim.

Meu objetivo não é apenas mostrar o código ou impressionar o público. Quero oferecer uma ferramenta, algo concreto, que você possa pegar, explorar e adaptar às suas próprias necessidades. Espero que este painel não apenas o inspire com novas ideias, mas também o ajude a enxergar o mercado sob uma nova perspectiva, não como um caos, mas como um quebra-cabeça que pode ser decifrado.



Fundos hedge de arbitragem e a escala da negociação de arbitragem no Forex

Ao falarmos sobre arbitragem no mercado de câmbio, é impossível não mencionarmos os principais protagonistas dessa área: os fundos hedge especializados, que transformaram a análise matemática de discrepâncias em uma indústria multibilionária. A experiência e a escala de suas operações mostram o quão poderoso o nosso modesto indicador de arbitragem pode ser quando utilizado de forma adequada.

Os titãs da arbitragem cambial

Entre os fundos hedge de arbitragem, destacam-se alguns grandes nomes. Por exemplo, a Millennium Management, com mais de 50 bilhões de dólares em ativos sob gestão, adota uma abordagem multiestratégica, onde a arbitragem estatística nos mercados de câmbio é uma das áreas principais. Suas equipes de analistas quantitativos desenvolvem modelos conceitualmente semelhantes à nossa matriz de preços justos, porém com base matemática e capacidade computacional incomparavelmente mais avançadas.

Citadel Securities, Renaissance Technologies e DE Shaw são outros gigantes que utilizam ativamente a arbitragem de moedas. Sua vantagem não está apenas no capital, mas também na tecnologia, como acesso direto ao mercado interbancário, servidores com latência mínima (co-location) e canais de comunicação dedicados entre as principais bolsas de negociação. Alguns desses fundos investiram centenas de milhões de dólares em infraestrutura para reduzir o tempo de execução das ordens a poucos microssegundos, um campo no qual nosso indicador para o MetaTrader 5, infelizmente, não pode competir.



Fundamentos teóricos da análise de preços justos e da arbitragem

A ideia de analisar os preços justos me cativou quando pensei: e se o mercado às vezes erra? Anos de negociação no mercado Forex me ensinaram que as taxas de câmbio não são apenas números aleatórios em uma tela. Elas representam uma rede complexa de inter-relações, na qual cada par influencia os outros, como fios entrelaçados em uma imensa teia. Se em algum ponto dessa teia surgir uma pequena distorção, uma discrepância, isso pode representar uma oportunidade de lucro.

O preço justo é, essencialmente, o "valor ideal" de um par de moedas, ou seja, o valor que deveria existir se o mercado fosse totalmente racional. Para pares diretos, como EUR/USD, tudo parece simples: pegamos o Bid e o Ask, fazemos a média e temos uma referência. Porém, o Forex não se resume a pares diretos. Existem também os pares cruzados, como o EURJPY, que podem ser calculados a partir de pares base. Foi então que me lembrei da arbitragem triangular, um conceito antigo, mas ainda extremamente atual:

EUR/USD * USD/JPY = EUR/JPY

Se a taxa real de EURJPY não coincide com esse cálculo, significa que o mercado subestimou ou superestimou algo. Lembro-me da primeira vez que testei isso manualmente, sentado com uma calculadora, comparando cotações em uma conta demo. As discrepâncias eram minúsculas, frações de porcento, mas o simples fato de existirem acendeu uma faísca dentro de mim. Era como encontrar uma pequena rachadura em uma parede que todos ignoram, mas pela qual é possível espiar o que há por trás.

Depois, mergulhei mais fundo. As cotações diretas são apenas a ponta do iceberg. Para entender a "justiça" dos preços, é necessário construir uma matriz com todas as relações entre as moedas. Imagine que você tem oito moedas: EUR, USD, GBP, JPY, entre outras. Cada uma delas pode ser expressa em função das outras por meio dos pares disponíveis. Por exemplo, se tenho EURUSD e GBPUSD, posso calcular EURGBP da seguinte forma:

EURGBP = EURUSD / GBPUSD

E se adicionarmos os pares inversos, como USDJPY e JPYUSD, podemos refinar os cálculos indefinidamente. O que mais me fascinou foi a ideia de uma "calibração dinâmica". E se, em vez de depender de um único par, utilizarmos todas as cotações disponíveis e as "fundirmos" em um único sistema? Por exemplo, para o par EURJPY, eu poderia usar não apenas EURUSD e USDJPY, mas também outros caminhos, como EURGBP e GBPJPY, ou até cadeias mais longas que passem por CHF ou AUD. É como montar um quebra-cabeça, em que cada peça precisa se encaixar perfeitamente. 

Mas, como calcular um par a partir de todos os outros que envolvem as mesmas moedas? Vamos pegar o EURUSD. Tenho a cotação direta: 1,10. No entanto, posso verificá-la por meio dos cruzamentos, passando por GBP (EURGBP e GBPUSD), JPY (EURJPY e USDJPY), CHF, entre outros. Teoricamente, todos esses caminhos deveriam levar ao mesmo valor. Se não levarem, aí está o sinal. Comecei a pensar: e se construíssemos uma matriz 8x8, em que cada célula representa a taxa de uma moeda em relação à outra, e fizéssemos essa matriz "convergir" para uma solução única? É como resolver um sistema de equações, em que cada par é uma equação e as variáveis, as taxas de câmbio. Por exemplo: 

EURUSD = 1. 10

USDJPY = 150

EURJPY = EURUSD * USDJPY = 165

Se o EURJPY real = 166, significa que há algum desvio em algum ponto. E há dezenas dessas "equações", uma para cada par. Podemos calcular a média de todos os caminhos, a mediana ou aplicar um método iterativo, como na resolução de sistemas lineares, para encontrar o "melhor" preço. 

A arbitragem se tornou a segunda parte desse quebra-cabeça. A arbitragem triangular acontece quando seguimos um ciclo de três pares (EURUSD -> USDJPY -> EURJPY) e obtemos lucro. Mas, comecei a pensar: e se procurássemos não apenas triângulos, mas também caminhos mais longos? Por exemplo, envolvendo quatro ou cinco pares? A teoria sugere que, quanto mais longo o caminho, maior o ruído, mas também mais interessantes podem ser as descobertas. Eu testava cada conceito na prática: enviava os dados pelo terminal, observava onde os cálculos divergiam da realidade e aprendia com isso. 

Para mim, isso se tornou mais do que apenas um conjunto de fórmulas. É uma filosofia: o mercado é um organismo vivo, repleto de pequenos erros, e se aprendermos a percebê-los, podemos viver em harmonia com ele. Espero que minhas reflexões o inspirem a ir mais fundo e enxergar as mesmas oportunidades.


Implementação do painel de arbitragem: da ideia ao código

Transformar a teoria em código é sempre um desafio. Foi assim que dei vida ao meu painel de arbitragem em MQL5:

void CalculateFairValues() {
    GetCurrentMarketRates();
    InitializeCurrencyMatrix();
    FillCurrencyMatrixFromDirectRates();
    CalculateCrossRatesArbitrage();
    CalculateDiscrepancies();
    FindArbitrageOpportunities();
    GenerateSignals();
    UpdateDisplay();
}
Essa função é o coração do sistema. Ela coleta as cotações atuais, constrói a matriz de preços justos e busca oportunidades. Lembro-me de quão difícil foi trabalhar com a função CalculateCrossRatesArbitrage; o mercado nem sempre fornecia pares diretos, sendo necessário contornar essa limitação com inversões.
if(!g_market_rates[i].is_direct) {
    double temp_bid = 1.0 / g_market_rates[i].ask;
    double temp_ask = 1.0 / g_market_rates[i].bid;
    g_market_rates[i].bid = temp_bid;
    g_market_rates[i].ask = temp_ask;
}
Para a arbitragem, escrevi uma lógica separada:
double CalculateArbitrageProfit(int pair1_idx, int pair2_idx, int pair3_idx, double amount) {
    double result = amount;
    // Логика расчета через Bid/Ask для треугольника
    return result;
}

Esse método calcula o lucro de um ciclo como EURUSD->USDJPY->EURJPY. No início, os resultados eram caóticos, os spreads consumiam todo o ganho. Tive que adicionar o parâmetro InpArbitrageThreshold para filtrar o ruído.

Depois veio a matriz de preços justos. A função InitializeCurrencyMatrix define 1 nas diagonais (EUR/EUR = 1), e FillCurrencyMatrixFromDirectRates a preenche com as cotações diretas. Mas a verdadeira mágica acontece dentro de CalculateCrossRatesArbitrage.

void CalculateCrossRatesArbitrage() {
    for(int iterations = 0; iterations < 3; iterations++) {
        for(int i = 0; i < g_currencies_count; i++) {
            for(int j = 0; j < g_currencies_count; j++) {
                if(i == j) continue;
                for(int k = 0; k < g_currencies_count; k++) {
                    if(k == i || k == j) continue;
                    if(g_currency_matrix[i][k] != 0 && g_currency_matrix[k][j] != 0) {
                        double triangleRate = g_currency_matrix[i][k] * g_currency_matrix[k][j];
                        if(g_currency_matrix[i][j] == 0) g_currency_matrix[i][j] = triangleRate;
                        else g_currency_matrix[i][j] = (g_currency_matrix[i][j] * 0.7 + triangleRate * 0.3);
                        g_currency_matrix[j][i] = 1.0 / g_currency_matrix[i][j];
                    }
                }
            }
        }
    }
}

Aqui, percorro as moedas três vezes, refinando as taxas cruzadas por meio dos triângulos. A ideia é simples: se tenho EURUSD e USDJPY, calculo EURJPY. Se a cotação direta EURJPY já existir, aplico uma média ponderada: 70% do valor anterior e 30% do novo. São três iterações, um compromisso entre precisão e velocidade. Lembro-me de ter testado isso com o par EURJPY: no início, as discrepâncias eram de 0,1%; após três ciclos, caíram para 0,01%. No entanto, o mercado não espera, e foi aí que decidi parar.

E como obter uma única taxa a partir de todas as outras? Suponhamos que eu queira o "preço justo" do EURUSD. Tenho:

  • EURGBP e GBPUSD: EURUSD = EURGBP * GBPUSD
  • EURJPY e USDJPY: EURUSD = EURJPY / USDJPY
  • EURCHF e USDCHF: EURUSD = EURCHF / USDCHF

Posso usar todos esses caminhos e calcular a média ou a mediana. Também posso ir além e aplicar um processo iterativo de convergência, como o método de Gauss-Seidel para sistemas de equações. Por exemplo:

double CalculatePairFairValue(string base, string quote) {
    int baseIdx = GetCurrencyIndex(base);
    int quoteIdx = GetCurrencyIndex(quote);
    double sum = 0.0;
    int count = 0;
    for(int k = 0; k < g_currencies_count; k++) {
        if(k == baseIdx || k == quoteIdx) continue;
        if(g_currency_matrix[baseIdx][k] != 0 && g_currency_matrix[k][quoteIdx] != 0) {
            sum += g_currency_matrix[baseIdx][k] * g_currency_matrix[k][quoteIdx];
            count++;
        }
        if(g_currency_matrix[k][baseIdx] != 0 && g_currency_matrix[quoteIdx][k] != 0) {
            sum += g_currency_matrix[quoteIdx][k] / g_currency_matrix[k][baseIdx];
            count++;
        }
    }
    return (count > 0) ? sum / count : g_currency_matrix[baseIdx][quoteIdx];
}

Cada trecho de código é uma luta com a realidade. Mas quando vi os primeiros sinais e triângulos surgirem, percebi: isso realmente funciona.


Interface gráfica: visualização das oportunidades

Sem uma visualização clara, o código não passaria de um amontoado de números. Coloquei minha alma na interface:

bool CreateGraphics() {
    ObjectCreate(0, "FVPanel_Main", OBJ_RECTANGLE_LABEL, 0, 0, 0);
    ObjectSetInteger(0, "FVPanel_Main", OBJPROP_XDISTANCE, 20);
    ObjectSetInteger(0, "FVPanel_Main", OBJPROP_YDISTANCE, 20);
    ObjectSetInteger(0, "FVPanel_Main", OBJPROP_XSIZE, 900);
    ObjectSetInteger(0, "FVPanel_Main", OBJPROP_YSIZE, 560);
    ObjectSetInteger(0, "FVPanel_Main", OBJPROP_BGCOLOR, InpBgColor);
    CreateText("FVPanel_Header", 220, 30, "АНАЛИЗ СПРАВЕДЛИВЫХ ЦЕН ВАЛЮТ", InpHeaderTextColor, 12, true);
    CreateText("FVPanel_Signals", 60, 60, "СИГНАЛЫ ОТКЛОНЕНИЯ ОТ СПРАВЕДЛИВОЙ ЦЕНЫ", InpBuySignalColor, 10, true);
    CreateText("FVPanel_Arbitrage", 460, 60, "АРБИТРАЖНЫЕ ВОЗМОЖНОСТИ", InpArbitrageColor, 10, true);
    return true;
}

O painel é dividido em três áreas: sinais de desvio, caminhos de arbitragem e a matriz de taxas. Sinais como "EURUSD: +0.04% — VENDA" são destacados em verde ou vermelho, enquanto os triângulos de arbitragem — como "EURUSD->USDJPY->EURJPY: +0.02%" — exibem imediatamente as direções das operações.

A matriz de taxas é o meu fascínio pessoal. Ela exibe as oito moedas em forma de tabela, destacando, por meio de cores, os desvios em relação aos preços justos. Lembro-me de ter passado horas ajustando fontes e espaçamentos para que tudo ficasse visualmente limpo e equilibrado.

A atualização ocorre por meio de um temporizador:

void OnTimer() {
    g_timer_counter++;
    if(g_timer_counter >= InpUpdateInterval) {
        CalculateFairValues();
        g_timer_counter = 0;
    }
}

Isso faz o sistema parecer vivo, os dados fluem em tempo real, como o pulso do mercado.


Resultados e avaliação honesta

Ainda não testei o sistema com dados reais; estou desenvolvendo um robô baseado nele, e esta já é, aproximadamente, a quinta ou sexta tentativa de criar um robô de arbitragem realmente funcional. Aqui está um vídeo mostrando o sistema em funcionamento:



Reflexões sobre preços justos e matrizes

Como obter preços justos a partir das matrizes? Isso se tornou uma obsessão para mim. A matriz 8x8 é como um mapa do mercado. Cada célula representa a taxa de uma moeda em relação a outra. Mas os dados são ruidosos: a corretora não fornece todos os pares, as cotações oscilam, os spreads interferem. Comecei a experimentar.

Abordagem 1: Média dos caminhos

Para o par EURUSD, eu utilizo todos os cruzamentos possíveis:

  • EURGBP * GBPUSD
  • EURJPY / USDJPY
  • EURCHF / USDCHF

Calculo a média. É simples, mas ignora os pesos, afinal, EURJPY pode ter mais liquidez que EURCHF.

Abordagem 2: Convergência iterativa

Como no método de Gauss-Seidel: atualizo cada célula da matriz até que as variações se tornem mínimas. O código mostrado acima (CalculateCrossRatesArbitrage) é uma versão simplificada disso. Mas fui além: e se adicionássemos pesos com base no volume de negociação? Ou considerássemos a volatilidade de cada par?

Abordagem 3: Minimização de erros

É possível formular o problema como uma otimização: minimizar a soma dos quadrados das diferenças entre as cotações atuais e os valores da matriz. Por exemplo:

Ошибка = Σ (MarketRate[i] - MatrixRate[i])^2

Resolver isso por meio de descida de gradiente ou algo como SVD. Isso pode ser lento em MQL5, mas em Python eu certamente tentaria.

Abordagem 4: Caminhos longos

Por que se limitar apenas aos triângulos? Posso calcular EURUSD por meio de uma cadeia como EURGBP->GBPCHF->CHFUSD. Quanto mais caminhos, maior a precisão, mas também maior o ruído. Na prática, porém, as cadeias longas se perdem nos spreads e nas comissões, como se estivessem afundando em um pântano...

Essas reflexões ainda são teóricas. O mercado real não é um livro didático, e os preços ideais continuam sendo uma utopia. Mas chegar perto deles já é um avanço.


Considerações finais

Quando comecei com a ideia dos preços justos, não imaginava que chegaria a um sistema como este. Foi um caminho cheio de tentativas e erros, desde bugs na matriz até decepções com a arbitragem. Mas, cada etapa me ensinou algo...

O mercado não é caótico, mas sim um mecanismo complexo. Os preços justos e a arbitragem funcionam como uma lupa, permitindo enxergar seus detalhes. A visualização torna os dados vivos e a adaptação, flexíveis. O painel não é perfeito, mas já me transmite confiança.

Tenho muitos planos, como integrar aprendizado de máquina e realizar testes reais. O Forex não para, e eu também não. Espero que a minha experiência o inspire a olhar por trás das cortinas do mercado e encontrar as suas próprias "injustiças".

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/17422

Arquivos anexados |
Últimos Comentários | Ir para discussão (10)
Sergey Chalyshev
Sergey Chalyshev | 18 mar. 2025 em 21:03
Vladimir Gulakov #:

Com certeza, tudo já foi verificado. Além disso, a corretora pode ajustar o tamanho do spread a seu favor a qualquer momento, o que ela faz.

Você está confundindo dealers com corretores.

A corretora não pode fazer ajustes - isso é uma ofensa criminal.

Aprenda a lei.

Vitaly Muzichenko
Vitaly Muzichenko | 18 mar. 2025 em 21:09
Sergey Chalyshev #:

Você está confundindo revendedores com corretores.

Um corretor não pode fazer ajustes - isso é um delito criminal.

Aprenda as regras do jogo.

Ordens e posições também são confundidas aqui, nada surpreendente.

Vladimir Gulakov
Vladimir Gulakov | 19 mar. 2025 em 17:04
Sergey Chalyshev #:

Você está confundindo revendedores com corretores.

Um corretor não pode fazer ajustes - isso é um delito criminal.

Aprenda as regras do jogo.

Tudo bem, que seja um dealer.

pivomoe
pivomoe | 22 mar. 2025 em 22:21
Yevgeniy Koshtenko #:

e a discrepância entre o sintético e o real em comparação com o desvio padrão é frequentemente enorme....

Você pode me dar um exemplo do registro de uma enorme discrepância?

pivomoe
pivomoe | 23 mar. 2025 em 11:36
Yevgeniy Koshtenko #:

Haverá um segundo artigo sobre isso

Dei uma olhada no código do segundo artigo. Ele não está relacionado ao primeiro de forma alguma. Em nenhum lugar do código há sequer uma tentativa de entrar abaixo/acima do preço justo. É apenas um usuário comum jogando uma planilha de ordens à mercê do destino.

Redes neurais no trading: Dupla clusterização de séries temporais (DUET) Redes neurais no trading: Dupla clusterização de séries temporais (DUET)
O framework DUET propõe uma abordagem inovadora para a análise de séries temporais, combinando clusterização temporal e de canais para identificar padrões ocultos nos dados analisados. Isso permite adaptar os modelos às mudanças ao longo do tempo e aumentar a precisão das previsões por meio da eliminação de ruídos.
Gerente de risco profissional remoto para Forex em Python Gerente de risco profissional remoto para Forex em Python
Criamos um gerente de risco profissional remoto para Forex em Python e o implantamos em um servidor, passo a passo. Ao longo do artigo, veremos como gerenciar riscos no Forex de maneira programada e como evitar a perda total do depósito.
Do básico ao intermediário: Filas, Listas e Árvores (V) Do básico ao intermediário: Filas, Listas e Árvores (V)
Neste artigo começamos a trabalhar com a implementação do mecanismo de árvore. Como sei que este mecanismo pode ser extremamente complicado de ser compreendido e assimilado, no começo do aprendizado. Iremos implementar as coisas com calma e devagar. Assim todos irão conseguir entender como uma árvore funciona e qual o melhor momento para utiliza-la.
Algoritmo do Restaurateur de Sucesso — Successful Restaurateur Algorithm (SRA) Algoritmo do Restaurateur de Sucesso — Successful Restaurateur Algorithm (SRA)
O Algoritmo do Restaurateur de Sucesso (SRA) é um método inovador de otimização inspirado nos princípios de gestão de um restaurante. Ao contrário das abordagens tradicionais, o SRA não descarta as soluções mais fracas, mas as melhora, combinando-as com elementos das soluções de maior sucesso. O algoritmo apresenta resultados competitivos e traz uma nova perspectiva sobre como equilibrar a diversificação e a intensificação em problemas de otimização.