English Русский 中文 Español Deutsch 日本語
preview
Arbitragem Estatística via Reversão à Média no Trading de Pares: Superando o Mercado com Matemática

Arbitragem Estatística via Reversão à Média no Trading de Pares: Superando o Mercado com Matemática

MetaTrader 5Sistemas de negociação |
36 16
Jocimar Lopes
Jocimar Lopes

Introdução

“Posso calcular os movimentos dos corpos celestes, mas não a loucura das pessoas.” (Sir Isaac Newton, já na casa dos noventa anos, após perder quase toda a sua aposentadoria investindo no mercado de ações.)

Em 10 de maio do ano passado, o mundo perdeu Jim Simons, o gestor de hedge fund mais bem-sucedido de todos os tempos.

Jim Simons era um matemático reconhecido, com diversos prêmios e conquistas acadêmicas nas áreas de geometria diferencial e criptografia. No entanto, foi seu papel na análise financeira quantitativa que tornou seu nome famoso até mesmo entre pessoas sem interesse em matemática ou finanças.

Ele foi tema de diversas biografias, dezenas de livros sobre sua vida e carreira, centenas de programas de televisão e milhares de artigos e publicações em blogs ao redor do mundo. The Man Who Solved the Market: How Jim Simons Launched the Quant Revolution é sua biografia mais conhecida.

No início da década de 1980, Simons fundou a Renaissance Technologies (RenTech) e começou a reunir uma equipe altamente qualificada composta por "matemáticos, físicos, especialistas em processamento de sinais e estatísticos". Trabalhando juntos durante décadas, eles demonstraram que, com dados suficientes e poder computacional para encontrar padrões estatísticos e anomalias nesses padrões, o mercado poderia ser "superado com o uso da matemática".

“Em 1988, a empresa estabeleceu seu portfólio mais lucrativo, o Medallion Fund, que utilizava uma forma aprimorada e expandida dos modelos matemáticos de Leonard Baum, aperfeiçoados pelo algebrista James Ax, para explorar correlações das quais pudesse obter lucro.” (Wikipedia)

O Medallion Fund apresentou um retorno médio anual de 66% entre 1988 e 2018, acumulando mais de 104 bilhões de dólares em lucros com operações ao longo dessas três décadas. O Medallion Fund da RenTech continua ativo até hoje, gerando enormes lucros. Como você pode imaginar, muitas pessoas gostariam de saber como eles operam, quais são os detalhes, o algoritmo secreto, o código oculto... o que quer que seja. Mas, até onde qualquer mortal sabe, sua fórmula secreta permanece protegida como um segredo corporativo de altíssimo sigilo. Quando questionado pelo autor de sua biografia sobre a estratégia operacional do Medallion Fund, Simons respondeu com a mesma resposta lacônica que repetiria a vários entrevistadores nos anos seguintes: arbitragem estatística em nível de portfólio. Ele também revelou que utilizam "uma espécie de aprendizado de máquina" desde o início para encontrar anomalias no mercado.

A arbitragem estatística, por si só, já é um amplo campo de pesquisa. Quando adicionamos aprendizado de máquina a isso, o trader de varejo comum, sem uma sólida formação em matemática e estatística, acaba ficando de fora. Muito menos um trader iniciante. Mas, embora seja verdade que implementar uma arbitragem estatística em nível de portfólio totalmente baseada em aprendizado de máquina exija muitos recursos e conhecimento especializado, também é verdade que é perfeitamente possível compreender o que é a arbitragem estatística em nível de portfólio, como ela funciona e, mais importante, que é possível começar pequeno, com paciência, dedicação e tempo para crescer.

Este artigo não pretende, de forma alguma, reproduzir, ou pior ainda, "revelar o código secreto" da RenTech ou de Jim Simons. Como mencionado anteriormente, isso seria impossível para qualquer pessoa que não estivesse diretamente envolvida em suas operações. Trata-se de um esforço para compartilhar minha compreensão dos princípios gerais que sustentam seus modelos. Esses princípios podem servir de base para o sistema de negociação até mesmo do mais modesto trader de varejo. A diferença estará na escala dos resultados, que será proporcional à quantidade de recursos investidos no sistema e na operação.

Portanto, o que você lerá a seguir é resultado de pesquisas em livros, documentários em vídeo e comunidades especializadas na internet, combinadas com minha experiência pessoal de alguns anos no segmento financeiro (mais voltada ao lado dos negócios do que ao desenvolvimento). O que a RenTech executa é gigantesco, mas o que veremos aqui é uma versão em miniatura, digamos, uma figura de ação de um super-herói, uma maquete de um arranha-céu. 

O objetivo é contribuir com um método de análise de baixo custo, leve e fácil de desenvolver, que possa ser testado e aprimorado pelo trader de varejo comum utilizando apenas as ferramentas já disponíveis na plataforma MetaTrader 5, executada em um notebook comum, possivelmente até mesmo um modelo de entrada. O método deve ser útil tanto para traders algorítmicos quanto para traders discricionários. Começaremos com a configuração mais simples possível, suficiente apenas para descrever o processo.

Após compreender os conceitos gerais por trás do modelo, construiremos um portfólio mínimo para a forma mais simples de arbitragem estatística, negociaremos esse portfólio de forma automatizada por meio de um Expert Advisor, faremos algumas observações sobre os resultados e, por fim, refletiremos sobre os próximos passos necessários. Espero que esta experiência ajude você a dar os primeiros passos com essa poderosa técnica de negociação e que, posteriormente, seja capaz de expandir esse conhecimento, adicionando outros símbolos ao portfólio e testando algoritmos além daquele descrito aqui, construindo gradualmente sua própria estratégia completa de Arbitragem Estatística (StatArb), adequada aos seus recursos e objetivos.


Conceitos gerais por trás do modelo

Antes de criar a RenTech, Jim Simons trabalhou como decifrador de códigos para a inteligência dos Estados Unidos / criptanalista. Quando começou a negociar nos mercados financeiros, tentou prever os preços de ações e commodities, mas fracassou. Então mudou sua abordagem. Ele assumiu que jamais seria capaz de antecipar o futuro do mercado. Compreendeu que precisava aceitar que o mercado é um enigma. Esse é o primeiro conceito relevante por trás do modelo.

O outro conceito é que o mercado está em um estado contínuo de mudança. Ou seja, não existe algo como um mercado de alta ou de baixa, padrões de velas/barras ou "ações correlacionadas que sempre se comportam bem juntas". Tudo está mudando agora e continuará mudando para sempre.

Se você refletir por um momento, perceberá que ambos os conceitos costumam ser negligenciados.

O mercado é um enigma

O mercado é um enigma, mas, ao contrário da máquina Enigma da Segunda Guerra Mundial, cujo código foi decifrado por Alan Turing e sua equipe, o enigma do mercado não possui um algoritmo determinístico que possa ser revertido e decifrado. Entre a entrada e a saída, eventos inesperados podem ocorrer. Embora um aumento da taxa de juros por um banco central normalmente fortaleça a moeda daquele país, a eclosão de um conflito político em outro país distante pode produzir o efeito oposto, compensando o impacto da alta dos juros, anulando-o ou até mesmo enfraquecendo essa moeda.

O mercado é um enigma porque, entre a entrada e a saída, existe a irracionalidade dos agentes econômicos, a natureza imprevisível da política e o aspecto caótico da interação entre as forças que o movimentam. Entre um mercado de ouro em alta durante um ano inteiro e sua queda abrupta de um mês na semana seguinte, existe o comportamento humano. Não foi por outro motivo que um psicólogo, Daniel Kahneman, recebeu o Prêmio Nobel de Ciências Econômicas. Foi justamente por abordar essa questão.
Mesmo sendo um enigma governado por agentes econômicos irracionais em um ambiente caótico, bancos de investimento compram e vendem ações com base em modelos financeiros, hedge funds utilizam o modelo Black-Scholes para precificar opções e praticamente todos os maiores participantes do mercado investem milhões de dólares no desenvolvimento de estratégias quantitativas de negociação. Por quê? Porque funciona, naturalmente. Por que funciona se o mercado é incerto, imprevisível, irracional e caótico?
Jim Simons, juntamente com milhares de outros traders quantitativos, algorítmicos e discricionários bem-sucedidos, oferece a resposta mais simples para essa pergunta. Uma lição que qualquer aspirante a trader deveria repetir como um mantra todas as manhãs antes de entrar no mercado:
“O sucesso no trading não consiste em estar certo o tempo todo. Consiste em maximizar os ganhos e minimizar as perdas.”
Esse é o objetivo dos modelos financeiros, da equação de Black-Scholes e das estratégias quantitativas de negociação: maximizar ganhos e minimizar perdas. Nada de novo. A resposta dos traders bem-sucedidos ao enigma do mercado é uma verdade amplamente conhecida muito antes de o comerciante japonês de arroz Munehisa Homma inventar os gráficos de velas: gerenciamento de risco.

Mas, com ou sem o uso de modelos financeiros, qualquer estratégia de negociação pode funcionar muito bem durante algum tempo, um período desconhecido. Ela pode ser lucrativa por um dia, um mês, um ano... não sabemos. A única garantia é que funcionou no passado e foi lucrativa para aqueles símbolos, naquele período e com aqueles valores de parâmetros utilizados no backtest. Ela pode deixar de ser lucrativa no minuto seguinte, na primeira execução ou continuar funcionando para sempre. Novamente, não sabemos. Não podemos saber, porque o mercado é um enigma. Não podemos resolver esse enigma. Não existe um código a ser decifrado. Existe apenas um estado contínuo de mudança.

O mercado está em um estado contínuo de mudança

O mercado está mudando o tempo todo. A única constante no mercado é a mudança. Os valores dos nossos parâmetros não são escolhidos porque representam o melhor ajuste para um estado específico do mercado, mas porque representaram o melhor ajuste para uma determinada mudança no mercado. Entre o momento em que abrimos uma operação vencedora e o momento em que ela foi encerrada, o mercado mudou da forma que esperávamos. Da mesma forma, entre o momento em que abrimos uma operação perdedora e o momento em que ela foi encerrada, o mercado mudou de uma maneira que não esperávamos. Isso é verdade mesmo que não sejamos capazes de identificar qual mudança teve maior influência no resultado final.

Para deixar claro: jamais conseguiremos identificar precisamente qual mudança transformou uma estratégia lucrativa em uma estratégia que drena capital, ou vice-versa. Ao aprimorar uma estratégia de negociação, o que faremos será buscar padrões que aumentem a probabilidade de repetir as escolhas corretas quando enfrentarmos mudanças semelhantes no estado do mercado no futuro. Encontrar, aprender e compreender esses padrões é exatamente o que um trader experiente faz ao longo de meses ou anos negociando o mesmo ativo ou grupo de ativos. Não é por acaso que mantemos diários de negociação. Eles existem para registrar quais eram nossas hipóteses sobre as mudanças esperadas no mercado e possibilitar revisá-las posteriormente para aprimorar essas hipóteses.

Graças ao enorme volume de dados disponível atualmente e aos computadores cada vez mais poderosos para processá-los, podemos reduzir esses anos de aprendizado para identificar padrões a apenas horas ou até minutos. Podemos automatizar a coleta de dados, a análise e a execução das operações. Podemos automatizar os testes e a geração de relatórios. Podemos até automatizar a escolha do símbolo ou ativo a ser negociado e da estratégia a ser utilizada, treinando um modelo abrangente de aprendizado de máquina para aprender esses padrões. Com recursos financeiros adequados, profissionais qualificados e tempo, sim, podemos.

Mas, como mencionado anteriormente, o foco destas notas é o trader de varejo comum. Com esses dois princípios simples, porém frequentemente negligenciados, em mente, vamos entender como podemos começar a compreender o que é a Arbitragem Estatística (StatArb) e como ela funciona.


Construindo o portfólio

Como o mercado é um enigma em constante estado de mudança, construiremos nosso portfólio sem ideias preconcebidas, não faremos suposições sobre aquilo que acreditamos ser verdadeiro e o atualizaremos regularmente. O intervalo de atualização será determinado pela estratégia de negociação e limitado pelo poder computacional disponível.

Devemos levar em consideração que a construção de portfólios, ou gestão de portfólios, é por si só um amplo campo de pesquisa. De acordo com uma abrangente revisão da literatura acadêmica, há dez anos existiam pelo menos quatro abordagens principais para construir um portfólio de arbitragem estatística baseada em negociação de pares: distância, cointegração, séries temporais e controle estocástico. Além dessas quatro abordagens principais, o autor também identificou outras abordagens que incluem aprendizado de máquina, previsões combinadas, cópulas e Análise de Componentes Principais.

Para manter nosso foco na simplicidade e nos fundamentos, vamos começar com um portfólio simples de negociação de pares. Para alguns autores, a negociação de pares é um subconjunto da arbitragem estatística; para outros, "a negociação de pares é amplamente considerada a ancestral da arbitragem estatística", sendo a diferença o tamanho do portfólio e a complexidade dos algoritmos estatísticos. Como o próprio nome indica, a negociação de pares limita-se a dois ativos, enquanto a arbitragem estatística pode envolver dezenas ou até centenas de símbolos a serem monitorados e eventualmente negociados. 

A negociação de pares, como você provavelmente já sabe, consiste simplesmente em, dado um par de ativos com preços historicamente correlacionados ou cointegrados, vender simultaneamente o ativo cuja tendência está em alta e comprar o ativo cuja tendência está em baixa quando o spread histórico entre seus preços se amplia além de um limite previamente definido. A premissa subjacente é que os preços irão "retornar à média", convergindo em torno do spread histórico entre eles.

Em uma arbitragem estatística completa, não estamos limitados à correlação ou à cointegração entre preços. Como nosso principal objetivo neste artigo é simplificar as complexidades da arbitragem estatística para o trader de varejo comum, começaremos coletando dados históricos para construir um portfólio mínimo de negociação de pares no mercado Forex. Posteriormente, você poderá expandir para outros mercados e explorar outras relações estatísticas além da correlação entre preços.

Escolha um grupo de ativos para começar

No momento da redação deste artigo, minha conta do terminal MetaTrader 5 exibe mais de dez mil símbolos disponíveis. Utilizaremos a integração do Python com o MetaTrader 5 em nossa análise.

print("Total symbols =",mt5.symbols_total()) # display all symbols
Total symbols = 10563
Assim, por razões práticas, primeiro precisamos escolher um subconjunto de todos os símbolos disponíveis. Vamos começar com os pares do XAU.
# get symbols containing XAU in their names
xau_symbols=mt5.symbols_get("*XAU*")
print('len(*XAU*): ', len(xau_symbols))
for s in xau_symbols:
    print(s.name)

len(*XAU*):  6
XAUUSD
XAUEUR
XAUAUD
* XAUG
XAUCHF
XAUGBP

* XAUG é um ETF, portanto podemos excluí-lo por enquanto e concentrar nossa análise nos outros cinco pares. Vamos verificar como cada um deles se correlaciona com o XAUUSD.

Agora precisamos calcular a correlação histórica entre seus preços. Em um cenário real, poderíamos explorar todas as permutações possíveis entre os símbolos escolhidos, possivelmente centenas de ações, já que estamos partindo da premissa de que não temos conhecimento prévio sobre elas. Mas aqui filtraremos os resultados para visualizar apenas a correlação entre a cotação do ouro em dólares americanos (XAUUSD) e a cotação do ouro em euros, dólares australianos, francos suíços e libras esterlinas.
Queremos dados dos preços de fechamento diários de um ano até a data atual, o que corresponde aproximadamente a 250 dias de negociação no mercado Forex.
# get 250 D1 bars from the current day
xauusd_rates = mt5.copy_rates_from_pos("XAUUSD", mt5.TIMEFRAME_D1, 0, 250)
xaueur_rates = mt5.copy_rates_from_pos("XAUEUR", mt5.TIMEFRAME_D1, 0, 250)
xauaud_rates = mt5.copy_rates_from_pos("XAUAUD", mt5.TIMEFRAME_D1, 0, 250)
xauchf_rates = mt5.copy_rates_from_pos("XAUCHF", mt5.TIMEFRAME_D1, 0, 250)
xaugbp_rates = mt5.copy_rates_from_pos("XAUGBP", mt5.TIMEFRAME_D1, 0, 250)

(...)

# calculate correlation coefficients
import numpy as np
usd_eur_corr = np.corrcoef(xauusd_close['close'], xaueur_close['close'])
usd_aud_corr = np.corrcoef(xauusd_close['close'], xauaud_close['close'])
usd_chf_corr = np.corrcoef(xauusd_close['close'], xauchf_close['close'])
usd_gbp_corr = np.corrcoef(xauusd_close['close'], xaugbp_close['close'])

Isso nos fornecerá os seguintes resultados:


Correlação do XAUUSD (Pearson)
XAUEUR
0.9692368
XAUAUD
0.96677962
XAUCHF
0.8418827
XAUGBP
0.90490282

Tabela 1 - Correlação dos preços de fechamento diários do ouro cotado em dólares americanos (XAUUSD) e do ouro cotado em euros, dólares australianos, francos suíços e libras esterlinas entre 09/04/2024 e 26/03/2025.

Podemos visualizar no gráfico abaixo como é uma correlação de preços próxima de 0,97.

Um ano de preços de fechamento diários do ouro cotado em dólares americanos e euros

Fig. 1 - Um ano de preços de fechamento diários do ouro cotado em dólares americanos e euros

Observe que o gráfico acima pode ser enganoso. Podemos ser tentados a "negociar o spread" entre os pares, mas esse não é o spread real, caso ele exista. Vamos converter o XAUEUR para dólares americanos de acordo com a taxa de câmbio do dia.
adjusted_for_dollars = pd.concat([xauusd_close, xaueur_close['close'], eurusd_close['close']], join='inner', axis=1)
adjusted_for_dollars.columns = ['time', 'xauusd', 'xaueur', 'eurusd']
adjusted_for_dollars['xaueur_dollars'] = adjusted_for_dollars['xaueur'] * adjusted_for_dollars['eurusd']
adjusted_for_dollars['diff'] = abs(adjusted_for_dollars['xauusd'] - adjusted_for_dollars['xaueur_dollars'])

print(adjusted_for_dollars)

         time   xauusd   xaueur   eurusd  xaueur_dollars       diff
0   2024-04-12  2344.22  2202.92  1.06237     2340.316120   3.903880
1   2024-04-15  2383.10  2242.90  1.06181     2381.533649   1.566351
2   2024-04-16  2382.85  2243.81  1.06720     2394.594032  11.744032
3   2024-04-17  2361.16  2212.14  1.06425     2354.269995   6.890005
4   2024-04-18  2378.86  2234.79  1.06557     2381.325180   2.465180
..         ...      ...      ...      ...             ...        ...
245 2025-03-25  3019.81  2797.81  1.07918     3019.340596   0.469404
246 2025-03-26  3018.85  2807.50  1.07370     3014.412750   4.437250
247 2025-03-27  3056.42  2829.26  1.07975     3054.893485   1.526515
248 2025-03-28  3084.20  2847.12  1.08276     3082.747651   1.452349
249 2025-03-31  3118.19  2882.78  1.08152     3117.784226   0.405774

[250 rows x 6 columns]
adjusted_for_dollars.plot(title = 'One Year of XAUUSD and XAUEUR in US Dollars (D1)', x='time', y=['xauusd', 'xaueur_dollars'])
plt.show()

Um ano de preços de fechamento diários do ouro cotado em dólares americanos e euros ajustados para dólares americanos
Fig. 2 - Um ano de preços de fechamento diários do ouro cotado em dólares americanos e euros ajustados para dólares americanos

Observando a diferença entre a cotação do ouro em dólares americanos e a cotação do ouro em euros... 

print("median: ", adjusted_for_dollars['diff'].median())
adjusted_for_dollars['diff'].describe()

median:  4.052404150000029
count    250.000000
mean       5.894673
std        6.238511
min        0.050646
25%        1.279615
50%        4.052404
75%        8.587763
max       51.483719
median:  4.052404150000029

... perceberemos que o spread médio real durante esse período de um ano foi de aproximadamente 5,9 dólares, com um desvio padrão de aproximadamente 6,2 dólares. Se simplificarmos excessivamente e assumirmos que a diferença (spread) entre ambas as cotações, após a conversão pela taxa de câmbio vigente, deveria ser próxima de zero, poderemos considerar qualquer spread acima da média como uma anomalia negociável no mercado. 

Escolha a relação estatística a ser utilizada

Em seguida, optamos por começar a construir nosso portfólio de arbitragem estatística com base na elevada correlação encontrada entre XAUUSD e XAUEUR durante o último ano de negociação (aproximadamente 250 dias). Mas será que a correlação entre preços é realmente a relação estatística correta, ou mesmo a melhor, para construir um portfólio de arbitragem estatística?

Quando falamos sobre correlação entre preços históricos, estamos sujeitos a sermos induzidos ao erro pelas diferenças entre o uso popular do termo e seu significado estatístico adequado. Esse fato é ainda mais evidente na comunidade Forex. Uma simples pesquisa por "pares correlacionados no Forex" mostrará diversos materiais listando os pares mais e menos correlacionados, juntamente com dicas sobre como negociá-los. Nosso objetivo aqui não é afirmar que este ou aquele material, lista ou dica de negociação esteja certo ou errado. O que devemos ter em mente é que estamos estabelecendo as bases para uma arbitragem estatística em nível de portfólio, que não deve ficar limitada aos pares de Forex. Em vez disso, nosso sistema deve ser generalizável para qualquer classe de ativos, em qualquer mercado e período gráfico, estando limitado apenas aos requisitos de ser neutro em relação ao mercado e passível de teste.

Segundo os estatísticos, o coeficiente de correlação de Pearson deve ser utilizado em séries estacionárias, e uma série temporal de preços não é estacionária. Ao calcular a correlação em uma série temporal não estacionária, podemos obter o que eles chamam de "correlações espúrias". 

“Dados não estacionários, em regra, são imprevisíveis e não podem ser modelados nem previstos. Os resultados obtidos utilizando séries temporais não estacionárias podem ser espúrios, indicando uma relação entre duas variáveis quando, na realidade, ela não existe. Para obter resultados consistentes e confiáveis, os dados não estacionários precisam ser transformados em dados estacionários.” (Nason, G. P. (2006). Séries temporais estacionárias e não estacionárias. Investopedia)

Assim, como traders que buscam construir um portfólio de arbitragem estatística, precisamos tomar uma decisão: essa "correlação espúria" é suficiente ou precisamos de uma correlação propriamente dita, no sentido estatístico? Por enquanto, aceitaremos essa primeira medida, embora imperfeita, como suficiente para nosso modelo simplificado. Mas não devemos esquecer que pares correlacionados podem continuar ampliando o spread durante longos períodos enquanto sobem ou caem juntos, ou seja, podem não retornar à média por bastante tempo, e ainda assim a correlação estatística continua válida. Essa condição é excepcional ao lidar com moedas, mas muito comum ao trabalhar com séries temporais de preços de commodities, contratos futuros ou ações. Portanto, níveis de stop loss e o momento de entrada nas posições são indispensáveis ao trabalhar com estratégias baseadas no "retorno esperado à média".

Escolha a medida estatística que servirá como gatilho para a negociação

Por que escolher a média ou a mediana como medida do nosso spread histórico? Segundo os estatísticos, devemos utilizar a média quando nossos dados apresentam poucos valores discrepantes (outliers) e a mediana quando o conjunto de dados possui picos extremos, pois a mediana é menos afetada por esses valores. Por exemplo, se você deseja filtrar grandes spreads provocados por notícias de alto impacto, pode optar pela mediana. Por outro lado, se deseja considerar os efeitos dessas notícias de alto impacto sobre o spread, talvez prefira utilizar a média.

Portanto, não existe uma "receita pronta". Você deve decidir por conta própria com base nos seus dados e no seu bom senso. Você pode até mesmo optar por não utilizar nem a média nem a mediana. Em vez disso, poderá investigar e concluir que outra relação estatística é mais adequada ao seu caso de uso.
Eu utilizarei a média e definirei um parâmetro para nossa estratégia de negociação baseado no alargamento do spread médio. Vamos supor que, quando o spread entre XAUUSD e XAUEUR aumentar mais de 50% em relação ao spread médio, a operação seja acionada, comprando o símbolo que está perdendo a corrida e, simultaneamente, vendendo o símbolo que está subindo mais rapidamente.

Como podemos determinar qual símbolo está subindo e qual está caindo? No nosso caso específico, como assumimos que ambas as cotações do ouro deveriam ser iguais após a conversão, podemos simplesmente considerar o símbolo com o maior preço como o que está subindo e o outro como o que está caindo. Se estivéssemos trabalhando com o retorno à média do spread entre preços de ações, poderíamos utilizar uma média móvel exponencial de período muito curto e assumir que o ativo negociado acima da EMA está em alta e vice-versa.

bool IsRising(const int symbol)
  {
   switch(symbol)
     {
      case BASE_PAIR:
         //Print("Base pair is rising? ", quotes_base[0] > ema_base[0]);
         return quotes_base[0] > ema_base[0];
      case CORR_PAIR:
         //Print("Corr pair is rising? ", quotes_corr[0] > ema_corr[0]);
         return quotes_corr[0] > ema_corr[0];
      default:
         return false;
     }
  }

bool IsFalling(const int symbol)
  {
   switch(symbol)
     {
      case BASE_PAIR:
         //Print("Base pair is falling? ", quotes_base[0] < ema_base[0]);
         return quotes_base[0] < ema_base[0];
      case CORR_PAIR:
         //Print("Corr pair is falling? ", quotes_corr[0] < ema_corr[0]);
         return quotes_corr[0] < ema_corr[0];
      default:
         return false;
     }
  }
Ou podemos utilizar a inclinação.

void CalculateSlopes(double & slope_b[], double & slope_c[])
  {
   slope_b[0] = MathAbs((quotes_base[0] - quotes_base[SlopePeriod]) / SlopePeriod);
   slope_c[0] = MathAbs((quotes_corr[0] - quotes_corr[SlopePeriod]) / SlopePeriod);
  }
No nosso caso, estamos simplesmente utilizando o símbolo com o maior preço.

if(quotes_base[0] > quotes_corr[0])



Negociando o portfólio

Construímos um EA simples para testar nossa hipótese em um backtest. 

Obtivemos as cotações iniciais em OnInit() e as atualizamos em OnTimer(). Isso ocorre porque não podemos confiar no manipulador de eventos OnTick() para atualizar as cotações do outro ativo do par que não corresponde ao gráfico atual, já que OnTick() é chamado apenas para o símbolo e gráfico em execução. Consulte os Expert Advisors multimoeda ou multissímbolo.

int OnInit()
  {
   ArrayResize(quotes_base, CountQuotes);
   ArrayResize(quotes_corr, CountQuotes);
   ArrayResize(quotes_conv, CountQuotes);
//--- Get start quotes for both pairs
   GetQuotes();
//--- EMA indicators
   EMA_Handle_Base = iMA(BasePair, _Period, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   EMA_Handle_Corr = iMA(CorrPair, _Period, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(EMA_Handle_Base == INVALID_HANDLE ||
      EMA_Handle_Corr == INVALID_HANDLE)
     {
      printf(__FUNCTION__ + ": EMA initialization failed");
      return(INIT_FAILED);
     }
//--- create timer
   EventSetTimer(5); // seconds
//---
   return(INIT_SUCCEEDED);
  }

bool GetQuotes()
  {
   if(CopyClose(BasePair, _Period, 0, CountQuotes, quotes_base) != CountQuotes)
     {
      Print(__FUNCTION__ + ": CopyClose failed. No data");
      //printf("Size quotes base pair %i ", ArraySize(quotes_base));
      return false;
     }
   if(CopyClose(CorrPair, _Period, 0, CountQuotes, quotes_corr) != CountQuotes)
     {
      Print(__FUNCTION__ + ": CopyClose failed. No data");
      //printf("Size quotes corr pair %i ", ArraySize(quotes_corr));
      return false;
     }
   if(CheckMode == PRICE)
     {
      if(CopyClose(ConvPair, _Period, 0, CountQuotes, quotes_conv) != CountQuotes)
        {
         Print(__FUNCTION__ + ": CopyClose failed. No data");
         //printf("Size quotes conv pair %i ", ArraySize(quotes_conv));
         return false;
        }
      //---
      for(int i = 0; i < CountQuotes; i++)
        {
         quotes_corr[i] *= quotes_conv[i];
        }
     }
   return true;
  }

void OnTimer()
  {
   UpdateQuotes();
   CalculateMeanSpread();
   if(CheckMode == EMA)
     {
      GetEMAs();
     }
  }

void UpdateQuotes()
  {
   ArrayRemove(quotes_base, ArraySize(quotes_base) - 1);
   double new_quote_base[1];
   CopyClose(BasePair, _Period, 0, 1, new_quote_base);
   ArrayInsert(quotes_base, new_quote_base, 0, 0);
//---
   ArrayRemove(quotes_corr, ArraySize(quotes_corr) - 1);
   double new_quote_corr[1];
   CopyClose(CorrPair, _Period, 0, 1, new_quote_corr);
   ArrayInsert(quotes_corr, new_quote_corr, 0, 0);
//---
   if(CheckMode == PRICE)
     {
      ArrayRemove(quotes_conv, ArraySize(quotes_conv) - 1);
      double new_quote_conv[1];
      CopyClose(ConvPair, _Period, 0, 1, new_quote_conv);
      ArrayInsert(quotes_conv, new_quote_conv, 0, 0);
      quotes_corr[0] *= quotes_conv[0];
     }
  }

Calculando o spread médio

bool CalculateMeanSpread()
  {
   int sz_base_p = ArraySize(quotes_base);
   int sz_corr_p = ArraySize(quotes_corr);
   int sz_conv_p = ArraySize(quotes_conv);
   if(sz_base_p != sz_corr_p ||
      sz_corr_p != sz_conv_p)
     {
      Print(__FUNCTION__ + " Failed: Arrays must be of same size");
      return false;
     }
//---
   ArrayResize(pairs_spread, CountQuotes);
   for(int i = 0; i < sz_base_p; i++)
     {
      pairs_spread[i] = MathAbs(quotes_base[i] - quotes_corr[i]);
     }
   double max_spread = pairs_spread[ArrayMaximum(pairs_spread)];
   double min_spread = pairs_spread[ArrayMinimum(pairs_spread)];
   mean_spread = MathMean(pairs_spread);
//---
//printf("Last quote XAUUSD %f ", quotes_base[0]);
//printf("Last quote XAUEUR %f ", quotes_corr[0]);
//printf("Last spread %f ", pairs_spread[0]);
//printf("Max  spread %f ", max_spread);
//printf("Min  spread %f ", min_spread);
//printf("Mean spread %f ", mean_spread);
   return true;
  }

Verificamos os sinais de negociação em OnTick().

void OnTick()
  {
//---
   CheckForClose();
   CheckForOpen();
  }

Quando o spread for maior que a média em pelo menos a porcentagem definida por nós.

bool HasSpreadTrigger()
  {
   double trigger_spread = mean_spread + (mean_spread * (PercentTrigger / 100.0));
//printf(" trigger spread %f ", trigger_spread);
   double current_spread = pairs_spread[0];
//printf(" current spread %f ", current_spread);
   return current_spread >= trigger_spread;
  }

Compramos o símbolo com o menor preço e vendemos o símbolo com o maior preço. No nosso exemplo, essa decisão é realizada por meio da enumeração (enum) CheckMode. 

void CheckForOpen()
  {
   if(PositionsTotal() == 0 && HasSpreadTrigger())
     {
      switch(CheckMode)
        {
         case EMA:
            if(IsRising(BASE_PAIR) && IsFalling(CORR_PAIR))
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            if(IsFalling(BASE_PAIR) && IsRising(CORR_PAIR))
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
            break;
         case SLOPE:
            CalculateSlopes(slope_base, slope_corr);
            if(slope_base[0] > slope_corr[0])
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            else
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
            break;
         case PRICE:
            if(quotes_base[0] > quotes_corr[0])
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            else
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
        }
     }
  }

As posições serão encerradas por stop loss, take profit ou pelo retorno à média na função CheckForClose().

void CheckForClose()
  {
   int total = PositionsTotal();
   ulong ticket = 0;
   if(total > 0)
     {
      if(PositionSelect(BasePair) || PositionSelect(CorrPair))
        {
         for(int i = 0; i < total; i++)
           {
            ticket = PositionGetTicket(i);
            if(ticket == 0)
               continue;
            if(pairs_spread[0] <= mean_spread)
              {
               ExtTrade.PositionClose(ticket);
              }
           }
        }
     }
  }

O backtest confirma que a estratégia de retorno à média é viável para negociação de pares.

Fig. 31 - Gráfico de patrimônio (equity) do backtest

Fig 3. Gráfico de patrimônio (equity) do backtest

Embora o backtest valide nossa hipótese, é possível observar que esse algoritmo específico necessita de melhorias para suavizar a curva de capital. Talvez um tamanho de ordem dinâmico (o volume de negociação utilizado aqui é fixo no mínimo de 0,01 lote, ou microlote) e otimizações na relação entre stop loss e take profit. Entretanto, a lucratividade não é nossa principal preocupação neste artigo. Dito isso, vamos analisar alguns resultados interessantes que, segundo alguns autores, parecem ser comuns em operações de arbitragem estatística.

Fig. 4 - Resultados do backtest

Fig 4. Resultados do backtest

Há um grande número de operações, a diferença entre ganhos e perdas é pequena (~55/~45) e o drawdown máximo do saldo é relativamente baixo.

Fig. 5 - Horários das operações no backtest

Fig 5. Horários das operações no backtest

A concentração das operações ocorre em períodos específicos (horários, dias da semana etc.). No nosso caso, a concentração está em torno da abertura da sessão dos Estados Unidos, com um pico em abril de 2024.

Fig 6. Tempo de permanência das posições no backtest × lucro

Fig 6. Tempo de permanência das posições no backtest × lucro

O grande número de operações de curtíssima duração indica que nosso sistema vem explorando momentos de instabilidade do mercado, reentrando após operações vencedoras.

O que poderia ser melhor?

Agora, gostaria de chamar sua atenção para o fato de que o vendedor de uma estratégia ou setup de negociação tentará mostrar os melhores resultados possíveis do passado para estimular seu interesse pelo produto. Eventualmente, ele selecionará os parâmetros com melhor desempenho após uma cuidadosa otimização para destacar os ganhos potenciais e minimizar a percepção do risco de perdas.

Mas, exceto pela ideia de que você pode compreender os princípios e começar aos poucos com arbitragem estatística, não estou "vendendo" nada aqui. Pelo contrário, diria que fico satisfeito em ver que o backtest demonstra que estamos lidando com um algoritmo que precisa de melhorias. Porque esse é o alicerce de qualquer sistema de arbitragem estatística.

Ou seja, até este ponto, nesta automação simplificada, estamos limitados a parâmetros escolhidos arbitrariamente para gerenciar o risco. Em vez disso, precisamos de:

  1. Controlar o número de posições abertas de acordo com o risco avaliado em cada momento.
  2. Ter um percentual de gatilho do spread flutuante que leve em consideração a volatilidade.
  3. Desenvolver uma estratégia dinâmica de stop loss/take profit que derive a probabilidade de ganho a partir do valor do spread de gatilho e, possivelmente, de outras variáveis.

Essas são algumas possibilidades de melhoria futura para este EA.

Resumo do modelo em escala reduzida

1. Comece com uma hipótese

O spread entre pares correlacionados tende a retornar à média. Essa é a nossa hipótese neste artigo.

Do ponto de vista do trader, o conceito de retorno à média é simples e intuitivo: quando o preço atual está abaixo do preço médio, pode-se esperar que ele suba; quando o preço atual está acima do preço médio, pode-se esperar que ele caia. Como diz o ditado, o preço está sempre "buscando a média".

Ativos sobrecomprados ou sobrevendidos tendem a retornar ao preço médio.

Fig 7. Ativos sobrecomprados ou sobrevendidos tendem a retornar ao preço médio (Fonte: ResearchGate CC BY 4.0)

Em mercados com tendência, a média transforma-se em um suporte dinâmico para tendências de alta e em uma resistência dinâmica para tendências de baixa. Em mercados de consolidação, a média tende a permanecer dentro do canal, no ponto médio entre as máximas mais altas e as mínimas mais baixas.

Essa característica é mais perceptível em períodos gráficos curtos para taxas de câmbio, pois, enquanto o preço de qualquer outro ativo pode, ao menos em teoria, subir ou cair indefinidamente, as taxas de câmbio entre moedas são "limitadas" pelas regras do comércio entre as nações. 

Por exemplo: "A Apple abriu seu capital em 12 de dezembro de 1980 a US$ 22,00 por ação. Desde o IPO, as ações passaram por cinco desdobramentos; portanto, ajustando pelos desdobramentos, o preço da ação no IPO foi de US$ 0,10."

No momento da redação deste artigo, a Apple é cotada a US$ 192,00 (aproximadamente 875%). E continua subindo. Não existe um limite teórico.

Por outro lado, não é razoável esperar uma valorização ou desvalorização de 50% na taxa de câmbio entre duas moedas sem considerar, ao mesmo tempo, fatores extremos como hiperinflação ou até mesmo uma guerra em grande escala. Em condições normais, a taxa de câmbio que define o "preço" de um par no mercado Forex tende a retornar à média muito antes disso.

2. Procure padrões nos dados para testar a hipótese

A correlação de Pearson de 0,97 entre XAUUSD e XAUEUR representa o nosso padrão: os preços desses dois ativos tendem a subir ou cair simultaneamente.

3. Monitore anomalias nos padrões

O afastamento do spread entre XAUUSD e XAUEUR em relação ao seu valor médio representa nossa anomalia. Encontrar anomalias nos padrões do mercado é o feijão com arroz da arbitragem estatística em nível de portfólio, conforme utilizada pela equipe de Jim Simons.

4. Desenvolva uma automação para negociar as anomalias

O EA simplificado representa nossa automação, mas, como mencionado anteriormente, o algoritmo necessita de muitas melhorias; ele é apenas uma ferramenta para nos ajudar a compreender melhor os princípios. Além disso, o próprio EA ainda precisa incorporar todas as verificações de erro normalmente exigidas.


Conclusão

A arbitragem estatística em nível de portfólio, da forma como é realizada pelos grandes participantes do mercado, é praticamente inviável para o trader de varejo comum. Isso porque precisaríamos operar com High-Frequency Trading (HFT), contar com uma equipe altamente qualificada, grandes volumes de dados de alta qualidade e muito capital. Para transformar nosso modelo em escala reduzida em algo semelhante, ou ao menos próximo, da operação de um hedge fund como o de Jim Simons, eu diria, com certa ironia, que tudo o que precisaríamos seria conseguir:

  • Realizar análises de mercado em granularidade de subsegundos para centenas de ativos em cada portfólio, em tempo real. (Em determinado momento, a equipe de Simons analisava mais de oito mil ações diferentes, distribuídas por uma dúzia de mercados e regiões.)
  • Enviar ordens de um milhão de dólares e tê-las executadas em milionésimos de segundo.
  • Atualizar o modelo regularmente. 

Bem, suponho que possamos começar atualizando o modelo regularmente. 🙂

Mas, falando sério, o que a citação de Isaac Newton apresentada anteriormente nos ensina é que a matemática, por si só, não é suficiente para prosperar nos mercados financeiros. Muitos matemáticos fracassaram onde Simons obteve sucesso. Mas Simons não entrou nesse campo apenas com matemática. Ele iniciou sua carreira no mercado financeiro operando como qualquer outro trader, procurando tendências, confiando na análise técnica e na intuição, ganhando e perdendo dinheiro. Experimentou diversos métodos, aprendeu as regras do mercado, conversou, fez parcerias e trabalhou com traders profissionais enquanto buscava uma forma sustentável de negociar.

Ainda assim, sua estrutura conceitual está ao alcance de qualquer pessoa disposta a fazer o esforço necessário para selecionar o portfólio adequado, escolher corretamente as características que serão estudadas, procurar padrões e anomalias, criar protótipos utilizando dados gratuitos e adquirir dados de alta qualidade quando o protótipo demonstrar potencial suficiente para alcançar o modelo mais equilibrado para um determinado portfólio. Provavelmente, muitos traders de varejo ao redor do mundo estão pagando esse preço diariamente por meio de trabalho sério e consistente. A maioria deles não se tornará bilionária, mas certamente muitos conseguiram transformar sua atividade de negociação em um negócio sustentável.

Podemos inclusive seguir o caminho do aprendizado de máquina para descobrir esses padrões e anomalias. Essa tecnologia está acessível aos mortais e parece representar um futuro que já chegou, aqui e agora. Existem, literalmente, centenas de artigos de alta qualidade sobre o uso de aprendizado de máquina no ambiente MetaTrader 5. Hoje, NÃO é necessário dominar a matemática de baixo nível para utilizar aprendizado de máquina em um sistema de negociação. Podemos utilizar MQL5 ou Python, ambos já vêm com tudo incluído, incluindo bibliotecas de aprendizado de máquina de alto nível. 

Em resumo, este artigo propõe aos traders de varejo com recursos limitados uma maneira estruturada e esquemática de compreender os fundamentos da arbitragem estatística em nível de portfólio.

Como diz o velho ditado, resultados passados não garantem resultados futuros. Mas podemos tomar decisões mais bem fundamentadas se analisarmos esses resultados passados utilizando as ferramentas corretas e dados objetivos.


Arquivos anexados Descrição
 pairs-trading.mq5 Este arquivo contém o código de exemplo do Expert Advisor utilizado para reproduzir o experimento. Ele requer (#<include>) o arquivo PairsTradingFunctions.mqh.
 PairsTradingFunctions.mqh Este arquivo é o include exigido pelo arquivo anterior desta lista e, no momento, contém apenas uma enumeração (enum) do modo de verificação utilizada pelo EA para identificar qual símbolo está em alta e qual está em baixa no par.
 pairs-trading.ipynb Este arquivo é um notebook Jupyter contendo o código em Python utilizado para executar a análise estatística.
 stat_arb_pairs_trading_GOLD_XAUEUR.ini  Este arquivo contém as configurações do Testador do MetaTrader 5 utilizadas para reproduzir o experimento.


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

Últimos Comentários | Ir para discussão (16)
Janis Ozols
Janis Ozols | 16 set. 2025 em 15:20

A pergunta não tem a ver com o tema do artigo, mas é muito interessante...

Como é que aconteceu que o artigo foi publicado hoje (16 de setembro), mas os primeiros comentários sobre ele datam de 11 de abril?

Roman Shiredchenko
Roman Shiredchenko | 16 set. 2025 em 15:28
Janis Ozols #:

A pergunta não tem a ver com o tema do artigo, mas é muito interessante...

Como é que aconteceu que o artigo foi publicado hoje (16 de setembro), mas os primeiros comentários sobre ele datam de 11 de abril?

Pelo que entendi, trata-se de uma tradução de outro idioma do fórum... Parece que foi publicada antes no idioma original... publicada

Aleksey Nikolayev
Aleksey Nikolayev | 16 set. 2025 em 16:23

> Sir Isaac Newton, aos noventa anos...

Newton viveu 84 anos (tradução incorreta para o russo?).

Roman Shiredchenko
Roman Shiredchenko | 28 nov. 2025 em 12:33

Obrigado pelo artigo. Estou adaptando a abordagem para 3, 4 e 6 caracteres!!! Estou analisando o seu código. Mais uma vez, obrigado, o conteúdo está ótimo!

Thomas Olof Gardling
Thomas Olof Gardling | 15 jan. 2026 em 13:56

Erro de índice fora do intervalo ao acessar pairs_spread[0];

bool HasSpreadTrigger()
  {
   double trigger_spread = mean_spread + (mean_spread * (PercentTrigger / 100.0));
//printf(" spread do gatilho %f ", trigger_spread);
   double current_spread = pairs_spread[0];
//printf(" spread atual %f ", current_spread);
   return current_spread >= trigger_spread;
  }
Introdução ao MQL5 (Parte 15): Criando Indicadores Personalizados com MQL5 — Guia para Iniciantes (IV) Introdução ao MQL5 (Parte 15): Criando Indicadores Personalizados com MQL5 — Guia para Iniciantes (IV)
Neste artigo, você aprenderá a criar um indicador de Price Action em MQL5, com foco em pontos-chave como mínima (L), máxima (H), mínima mais alta (HL), máxima mais alta (HH), mínima mais baixa (LL) e máxima mais baixa (LH) para análise de tendências. Você também aprenderá a identificar as zonas de prêmio e desconto, marcar o nível de retração de 50% e utilizar a relação risco-retorno para calcular metas de lucro. O artigo aborda a determinação dos pontos de entrada, stop loss (SL) e take profit (TP) com base na estrutura da tendência.
Redes neurais no trading: uma visão unificada sobre espaço e tempo (Extralonger) Redes neurais no trading: uma visão unificada sobre espaço e tempo (Extralonger)
O framework Extralonger demonstra uma abordagem para integrar fatores espaciais e temporais em um único modelo, permitindo considerar simultaneamente padrões locais e ciclos de longo prazo. Essa arquitetura torna a previsão de séries temporais mais robusta ao ruído de mercado e abre a possibilidade de analisar dados em diferentes horizontes. Neste artigo, examinamos em detalhes como implementar essas ideias na prática com OpenCL e MQL5.
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.
Trading algorítmico de arbitragem com teoria dos grafos Trading algorítmico de arbitragem com teoria dos grafos
Neste artigo, tratamos a arbitragem triangular como um problema de busca de ciclos em um grafo orientado, no qual os vértices representam moedas e as arestas representam pares de moedas com pesos correspondentes às taxas de câmbio. Um ciclo lucrativo ocorre quando o produto dos pesos é > 1. Os algoritmos Floyd-Warshall e DFS que desenvolvemos encontram os caminhos ideais de conversão de moedas com retorno ao ponto inicial e geração de lucro.