PCMCI: descoberta causal em séries temporais criptográficas multivariadas
PCMCI, desenvolvido por Jakob Runge (2018, 2020), é um algoritmo de descoberta causal para séries temporais multivariadas. Ele combina o algoritmo PC para aprendizado de modelo gráfico com um teste de Independência Condicional Momentânea (MCI) cujo conjunto de condicionamento é construído para neutralizar três coisas ao mesmo tempo: drivers comuns, caminhos indiretos e a autocorrelação da variável fonte. Essa última parte é a parte que vale a pena ler com atenção - é a razão pela qual o PCMCI não herda a taxa de falsos positivos que afunda os testes ingênuos de lead-lag em séries com forte impulso.
Este artigo disseca a construção em dois estágios a partir dos primeiros princípios, implementa-a com a biblioteca tigramite e apresenta o estudo de dados reais que o método precisa antes que qualquer um deles se torne um insumo comercial.
O que isso acrescenta ao que já está aqui

O blog já fez o trabalho de correlação. O co-movimento criptográfico é em grande parte um artefato de fator comum - correlação de sinal entre pares mostra que PC1 sozinho absorve 65% da variação em um livro de dez pares. Uma alta correlação entre pares não é um relacionamento negociável, e é por isso que arbitragem estatística e negociação de pares busca a cointegração. E a dependência em si nem sequer é estável: correlação dinâmica DCC-GARCH enumera por que uma correlação de amostra estática assume estacionariedade de dependência, volatilidade marginal constante e simetria entre direções, nenhuma das quais é válida.
Nenhum deles produz um gráfico direcionado. Eles dizem que BTC, ETH e SOL se movem juntos e que um fator comum explica a maior parte disso; eles não informam se o BTC impulsiona o SOL diretamente ou se a associação é mediada inteiramente pela ETH. A causalidade de Granger é o alcance usual de direção, mas o Granger padrão é bivariado – ele não pode separar um fator comum não observado da causalidade genuína.
Existe um terceiro modo de falha que importa mais aqui do que parece. Cada série de retorno criptográfico carrega autocorrelação positiva, e a autocorrelação aumenta a estatística de teste de qualquer teste de dependência executado entre duas dessas séries: dois processos autocorrelacionados independentes parecerão significativamente relacionados em amostras finitas. O trabalho de correlação trata isso como uma correção de tamanho de amostra (a discussão Effective_N no artigo sobre correlação de sinal). Para a descoberta causal não é uma correção, é o problema central do projeto – e é exatamente para isso que o conjunto de condicionamento do Estágio 2 foi construído para resolver.
O Algoritmo PCMCI

O PCMCI opera em duas etapas. O primeiro estágio identifica um conjunto candidato de pais causais para cada variável. A segunda etapa testa cada link candidato com um teste de independência condicional cuidadosamente construído.
Estágio 1: Seleção de condição estável do PC (PC1)
O objetivo do Estágio 1 é encontrar, para cada variável , um superconjunto de seus verdadeiros pais causais. Este conjunto será usado posteriormente como conjunto de condicionamento no Estágio 2.
O algoritmo começa com o conjunto completo de todas as variáveis defasadas como pais potenciais:
Em seguida, ele remove iterativamente variáveis que são condicionalmente independentes de . Na iteração , o algoritmo testa cada pai candidato pela independência com , condicionando o pais remanescentes mais fortes (excluindo em si):
onde é o conjunto de variáveis em com a associação mais forte .
O aspecto "estável" significa que as decisões de remoção dentro de uma única iteração são baseados nos conjuntos pai da iteração anterior, evitando a dependência de ordem nos resultados. Isto é crítico para a reprodutibilidade.
O nível de significância nesta fase é deliberadamente definido liberalmente (geralmente 0,2 ou superior, ou determinado automaticamente através do pc_alpha=None opção em tigramite). O objetivo não é controlar os falsos positivos aqui, mas reter todos os pais verdadeiros enquanto elimina o máximo possível de variáveis irrelevantes. Alguns falsos positivos em são aceitáveis; falsos negativos não são.
Estágio 2: Teste de Independência Condicional Momentânea (MCI)
Assim que tivermos os conjuntos parentais estimados para todas as variáveis, o Estágio 2 testa cada possível nexo causal usando a estatística MCI:
A principal inovação é o conjunto de condicionamento. Nós condicionamos:
- Pais do alvo : Isso remove o efeito de drivers comuns e outros caminhos indiretos para .
- Pais da fonte : isso remove a autocorrelação da variável de origem, evitando estatísticas de teste infladas.
Ao condicionar ambos os conjuntos simultaneamente, o MCI isola efetivamente o efeito causal direto e momentâneo de sobre no atraso específico , sem todos os fatores de confusão, mediadores e efeitos de autocorrelação.
A estatística de teste pode ser qualquer teste de independência condicional válido. Para relacionamentos lineares, a correlação parcial é a escolha padrão. Para dependências não lineares, informações mútuas condicionais (CMI) estimadas via -métodos do vizinho mais próximo ou o teste GPDC (Gaussian Process Distance Correlation) podem ser usados.
Correlação parcial como teste padrão
Para a maioria das aplicações financeiras, o teste de correlação parcial (ParCorr em tigramite) é o burro de carga. Dadas variáveis , e um conjunto de condicionamento , a correlação parcial é:
onde e são os resíduos da regressão e sobre , respectivamente:
Em outras palavras, a correlação parcial mede a associação linear entre e após remover a influência linear das variáveis condicionantes . Sob a hipótese nula de independência condicional com dados gaussianos, a estatística de teste segue uma distribuição conhecida, permitindo cálculo de valor.
Os valores de correlação parcial estão em e fornecer uma classificação natural dos pontos fortes dos vínculos causais. Uma correlação parcial de 0,3 entre BTC no atraso 1 e ETH no atraso 0, condicional a ambos os conjuntos pai, significa: "Depois de remover os efeitos de todos os fatores de confusão e autocorrelação identificados, um choque de um desvio padrão nos retornos do BTC prevê um movimento de desvio padrão de 0,3 nos retornos do ETH um período depois."
Dos resultados do teste a um gráfico causal (DAG)
A saída do PCMCI é um par de matrizes:
- val_matrix: Forma , contendo a estatística de teste MCI (por exemplo, correlação parcial) para cada link direcionado .
- p_matrix: Mesma forma, contendo o correspondente -valores.
Para construir um gráfico causal, limitamos o -matriz em nível de significância corrigido:
Qual correção não é um detalhe que você possa ignorar. Testes PCMCI links que são dependentes por construção - cada link em compartilha um conjunto de condicionamento entre si, e as séries de origem são mutuamente correlacionadas para começar. Esse é precisamente o regime onde o simples Benjamini-Hochberg falha e a penalidade harmônica de Benjamini-Yekutieli é aquele que sobrevive à dependência arbitrária entre testes; Sharpe deflacionado e testes múltiplos mede as taxas nulas de falsas descobertas que tornam isso concreto. Relate o número de links testados e o limite corrigido junto com qualquer gráfico que você publicar.
A estrutura resultante é um gráfico de série temporal (TSG), que é um gráfico direcionado onde:
- Os nós representam variáveis em intervalos de tempo específicos.
- As arestas direcionadas representam ligações causais com defasagens associadas.
- Self-loops representam efeitos autorregressivos.
Este ET pode ser resumido num gráfico de resumo que mostra apenas a existência e a direção das ligações causais entre as variáveis (agregadas entre desfasamentos), o que é muitas vezes mais prático para interpretação.
Implementação com Tigramite

Tigramita é a implementação de referência do PCMCI, desenvolvida e mantida pelo grupo de Jakob Runge no Centro Aeroespacial Alemão (DLR). Ele fornece uma API limpa para manipulação de dados, vários testes de independência condicional, diversas variantes de PCMCI e visualização integrada.
Instalação
pip install tigramite
Verificação de integridade de recuperação (não é um resultado)
Antes de analisar os dados de mercado, vale a pena confirmar se o pipeline encontra a estrutura que você plantou. Este é um teste de unidade para a implementação e nada mais - a verdade básica abaixo é escrita à mão no loop de geração de dados, portanto, recuperá-la prova que o código funciona e não diz absolutamente nada sobre criptografia. Leia assim.
import numpy as np
import tigramite
from tigramite import data_processing as pp
from tigramite.pcmci import PCMCI
from tigramite.independence_tests.parcorr import ParCorr
from tigramite import plotting as tp
np.random.seed(42)
T, N = 2000, 5
var_names = ["BTC", "ETH", "SOL", "BNB", "AVAX"]
data = np.zeros((T, N))
noise = np.random.randn(T, N) * 0.5
for t in range(2, T):
data[t, 0] = 0.5 * data[t-1, 0] + noise[t, 0]
data[t, 1] = 0.5 * data[t-1, 1] + 0.4 * data[t-1, 0] + noise[t, 1]
data[t, 2] = 0.5 * data[t-1, 2] + 0.3 * data[t-1, 1] + noise[t, 2]
data[t, 3] = 0.5 * data[t-1, 3] + 0.25 * data[t-1, 0] + noise[t, 3]
data[t, 4] = 0.5 * data[t-1, 4] + 0.2 * data[t-2, 3] + noise[t, 4]
dataframe = pp.DataFrame(
data,
datatime=np.arange(T),
var_names=var_names,
)
parcorr = ParCorr(significance="analytic")
pcmci = PCMCI(
dataframe=dataframe,
cond_ind_test=parcorr,
verbosity=1,
)
results = pcmci.run_pcmci(
tau_max=4, # test lags up to 4 hours
tau_min=1, # only lagged (not contemporaneous) links
pc_alpha=None, # auto-select alpha for condition selection
alpha_level=0.01, # significance threshold for final MCI test
)
print("\n--- Significant causal links ---")
pcmci.print_significant_links(
p_matrix=results["p_matrix"],
val_matrix=results["val_matrix"],
alpha_level=0.01,
)
tp.plot_graph(
val_matrix=results["val_matrix"],
p_matrix=results["p_matrix"],
var_names=var_names,
link_colorbar_label="MCI (partial corr.)",
node_colorbar_label="Auto-MCI",
alpha_level=0.01,
figsize=(10, 6),
)
tp.plot_time_series_graph(
val_matrix=results["val_matrix"],
p_matrix=results["p_matrix"],
var_names=var_names,
link_colorbar_label="MCI (partial corr.)",
alpha_level=0.01,
figsize=(14, 6),
)
Lendo a saída
No VAR plantado, print_significant_links retorna:
Variable BTC has 0 causal parent(s):
Variable ETH has 1 causal parent(s):
BTC (lag -1): val = 0.38, p = 0.000
Variable SOL has 1 causal parent(s):
ETH (lag -1): val = 0.28, p = 0.000
Variable BNB has 1 causal parent(s):
BTC (lag -1): val = 0.24, p = 0.000
Variable AVAX has 1 causal parent(s):
BNB (lag -2): val = 0.19, p = 0.000
A estrutura plantada volta, incluindo o resultado negativo que importa: não há borda direta BTC -> SOL, embora BTC e SOL estejam fortemente correlacionados nesta amostra. O MCI atribui a associação inteiramente ao mediador ETH. Esse é o comportamento que o conjunto de condicionamento duplo deve produzir, e confirmá-lo é o objetivo deste bloco. É um teste de unidade aprovado, não uma descoberta sobre criptografia.
Trabalhando com dados reais de mercado
O PCMCI precisa de insumos fracamente estacionários, então alimente-o com retornos logarítmicos padronizados em vez de preços - o mecanismo ADF e as razões pelas quais os preços brutos falham são abordados em arbitragem estatística e negociação de pares. Depois de ter uma matriz de retornos padronizada, a parte específica do tigramite consiste em duas linhas:
data = log_returns.values # (T, N) standardized log-returns
var_names = list(log_returns.columns)
dataframe = pp.DataFrame(data, var_names=var_names)
Dois detalhes do tigramite não são transferidos do pipeline de retorno usual:
- Dados ausentes: Tigramite oferece suporte a matrizes mascaradas para lidar com observações ausentes. Usar
dataframe.maskpara sinalizar lacunas - não as preencha, pois uma observação fabricada se propaga em cada conjunto de condicionamento que a contém. - Alinhamento de frequência: Todas as séries devem estar na mesma grade horária. Para criptografia, isso geralmente é simples, uma vez que as exchanges fornecem dados OHLCV sincronizados.
O estudo que este método precisa
Tudo acima são máquinas. O artigo não pode ser publicado neste blog até que a máquina aponte para dados reais e relate o que encontrou, inclusive se a resposta for “nada estável”. A corrida a fazer:
- Configuração: PCMCI+ em retornos por hora para uma cesta real em um intervalo de datas determinado,
tau_maxcorrigido pelo raciocínio de domínio,alpha_level = 0.01com correção de Benjamini-Yekutieli em todos links. Relate a contagem de links testada e o limite corrigido, de acordo com o padrão deflated Sharpe. - Resultado a relatar: quais arestas sobrevivem à correção, suas magnitudes de correlação parcial e quantas sobrevivem fora da amostra.
- Pelo menos uma medição de estabilidade, sem a qual a peça é um README de tigramite com tickers criptográficos: que fração de bordas persiste janela a janela através de janelas rolantes; ou sensibilidade do gráfico recuperado para
tau_maxepc_alpha; ou desacordo entre ParCorr e CMIknn sobre os mesmos dados.
Um gráfico instável é um resultado publicável, não um resultado com falha. "PCMCI em cinco cursos: o gráfico causal não sobrevive a janelas rolantes" se encaixa na linha que este blog já usa um resultado negativo honesto, e é um artigo mais útil do que um tutorial que funciona.
Escolhendo os parâmetros corretos

Atraso máximo
Este parâmetro limita o horizonte temporal da descoberta causal. Definir um valor muito baixo pode perder efeitos de propagação lenta; muito alto aumenta o custo computacional e a carga de testes múltiplos.
Para dados criptográficos por hora, para é um intervalo razoável. Para dados diários, para captura a maioria dos relacionamentos lead-lag. O conhecimento do domínio é importante aqui: se você sabe que os efeitos da taxa de financiamento levam 8 horas para se propagar, defina .
Significado da seleção de condições
Contexto pc_alpha=None permite que o tigramite selecione automaticamente este parâmetro usando o Critério de Informação Akaike, que é o padrão recomendado. Se você quiser defini-lo manualmente, valores entre 0,1 e 0,4 funcionam bem. Valores mais baixos tornam o Estágio 1 mais agressivo (menos pais retidos), o que reduz o custo computacional, mas corre o risco de remover os verdadeiros pais.
Nível de significância final
Este é o limite padrão para testes de hipóteses. Para análise exploratória, está bem. Para qualquer coisa que alimente uma decisão comercial, use ou mais rigoroso, e aplique-o após a correção consciente da dependência descrita anteriormente — o nível nominal não é o nível em que você está realmente testando.
PCMCI+: Adicionando links contemporâneos

O PCMCI padrão descobre apenas ligações causais defasadas (). Mas nos mercados de criptomoedas, onde as informações se propagam pelos ativos em segundos, a frequência de amostragem horária significa que muitos efeitos causais parecem contemporâneos ().
PCMCI+ (Runge, 2020) estende o PCMCI para descobrir ligações causais defasadas e contemporâneas. Os links contemporâneos não são direcionados por padrão (uma vez que a ordenação do tempo não consegue distinguir causa do efeito dentro do mesmo intervalo de tempo), mas alguns podem ser orientados usando as regras de orientação do algoritmo PC padrão (detecção de colisor, restrições de aciclicidade).
results_plus = pcmci.run_pcmciplus(
tau_max=4,
tau_min=0, # include contemporaneous links
pc_alpha=None,
)
Para aplicações de criptografia com frequência horária ou inferior, o PCMCI+ costuma ser mais apropriado do que o PCMCI padrão, já que muitos efeitos entre ativos ocorrem mais rapidamente do que o intervalo de amostragem.
Extensões Não Lineares

As séries temporais financeiras apresentam frequentemente dependências não lineares (por exemplo, agrupamento de volatilidade, efeitos de atraso dependentes do regime). Tigramite fornece vários testes de independência condicional não lineares:
Correlação de Distância do Processo Gaussiano (GPDC)
from tigramite.independence_tests.gpdc import GPDC
gpdc = GPDC(significance="analytic", gp_params=None)
pcmci = PCMCI(dataframe=dataframe, cond_ind_test=gpdc)
O GPDC usa a regressão do processo gaussiano para remover a influência do conjunto de condicionamento e, em seguida, aplica a correlação de distância nos resíduos. É mais poderoso do que ParCorr para detectar efeitos não lineares, mas significativamente mais lento.
Informação Mútua Condicional (CMIknn)
from tigramite.independence_tests.cmiknn import CMIknn
cmiknn = CMIknn(significance="shuffle_test", knn=0.1, shuffle_neighbors=5)
pcmci = PCMCI(dataframe=dataframe, cond_ind_test=cmiknn)
CMIknn estima informações mútuas condicionais usando -métodos do vizinho mais próximo. É totalmente não paramétrico e pode detectar dependências funcionais arbitrárias. A compensação é o custo computacional e a necessidade de mais dados para obter poder estatístico.
Para a maioria das aplicações de negociação de criptografia, comece com ParCorr. Mude para testes não lineares somente quando tiver evidências específicas de mecanismos causais não lineares e dados suficientes (normalmente ).
Onde um gráfico causal se conectaria

Uma coisa que um gráfico causal oferece que uma matriz de correlação não pode: grau superior. Execute o PCMCI em 20 a 50 ativos e os nós com muitas bordas de saída são líderes de informação – seus movimentos carregam conteúdo preditivo para o resto do livro, e essa é uma afirmação direcional que uma matriz de correlação simétrica é estruturalmente incapaz de fazer. Uma decomposição de fatores indica que o BTC domina a variância; uma classificação de grau superior informa se o BTC domina porque lidera ou porque tudo, incluindo o BTC, carrega no mesmo choque macro.
Supondo que um gráfico estável seja recuperado, os locais que ele já anexaria ao trabalho neste blog são claros o suficiente. Mudanças de janela rolante na topologia do gráfico são um sinal de quebra estrutural, que é o assunto de detecção de regime com HMMs — a questão em aberto é se um gráfico causal detecta a transição mais cedo do que um modelo de estado. A aplicação do PCMCI a um ativo em vários locais aborda a liderança de preços entre locais, já medida em resolução de milissegundos em roteamento inteligente de pedidos; um gráfico em barras horárias precisaria superar isso, e não reformulá-lo. E o link periódico perp-spot criado pelo mecanismo de financiamento de 8 horas, coberto em arbitragem de taxa de financiamento, é um caso de teste de resposta conhecida: o PCMCI deve recuperar uma estrutura causal que possamos verificar de forma independente, o que o torna um alvo de validação em vez de uma descoberta.
Nada disso são descobertas. São hipóteses que aguardam o estudo descrito acima.
Limitações e advertências

PCMCI é uma ferramenta poderosa, mas tem limitações importantes que os profissionais devem compreender:
-
Pressuposição de suficiência causal: PCMCI assume que todas as variáveis relevantes são observadas. Se um fator comum oculto (por exemplo, a atividade comercial de uma baleia, notícias não divulgadas) afetar dois ativos observados, o PCMCI pode relatar incorretamente uma ligação causal direta entre eles. A variante LPCMCI aborda parcialmente isso, permitindo confundidores latentes, ao custo de retornar menos arestas orientadas.
-
Suposição de estacionariedade: A estrutura causal é assumida constante ao longo da janela de análise. Na prática, a dinâmica do mercado criptográfico muda rapidamente. Use a análise de janelas rolantes para detectar quebras estruturais.
-
Linear vs. não linear: Com
ParCorr, apenas efeitos causais lineares são detectados. Um mecanismo causal não linear (por exemplo, “o BTC faz com que o ETH caia apenas quando o BTC cai mais de 5%”) seria invisível para o teste linear. -
A frequência de amostragem é importante: Os efeitos causais que ocorrem mais rapidamente do que a frequência de amostragem aparecem como contemporâneos () links no PCMCI padrão e sua direção pode ser ambígua. Use PCMCI+ e considere dados de frequência mais alta.
-
Testes múltiplos: testes dependentes, corrigidos conforme descrito acima - consulte Sharpe deflacionado e testes múltiplos para saber por que a estrutura de dependência exclui a escolha óbvia.
-
Requisitos de tamanho de amostra: A descoberta causal confiável requer dados suficientes. Como orientação aproximada, procure para
ParCorrcom variáveis, e para testes não lineares ou conjuntos de variáveis maiores.
PCMCI versus outros métodos

| Método | Lida com autocorrelação | Lida com drivers comuns | Links contemporâneos | Não linear | Confusões latentes |
|---|---|---|---|---|---|
| Causalidade de Granger | Parcialmente | Não (bivariado) | Não | Com extensões | Não |
| Entropia de transferência | Parcialmente | Não (bivariado) | Não | Sim | Não |
| PCMCI | Sim (MCI) | Sim | Não | Com CMIknn/GPDC | Não |
| PCMCI+ | Sim | Sim | Sim | Com CMIknn/GPDC | Não |
| LPCMCI | Sim | Sim | Sim | Com CMIknn/GPDC | Sim |
| VAR-LiNGAM | Não | Sim | Sim | Não | Não |
A principal vantagem do PCMCI sobre a causalidade de Granger e a entropia de transferência é o teste MCI, que leva em conta corretamente a autocorrelação e os fatores comuns em um ambiente multivariado. Este é precisamente o cenário encontrado nos mercados criptográficos, onde dezenas de ativos correlacionados e autocorrelacionados interagem simultaneamente.
Conclusão

A construção em dois estágios é a contribuição que vale a pena retirar: seleção de condições esparsas para vincular o conjunto pai e, em seguida, um teste MCI cujo conjunto de condicionamento inclui os pais da fonte, bem como o destino. Essa segunda metade é o que separa PCMCI de Granger e transfere entropia, e é o que torna o método viável em séries tão autocorrelacionadas quanto os retornos criptográficos.
O que o método não traz são evidências. Um gráfico recuperado é uma hipótese sobre o fluxo de informações, não um sinal, e neste blog ele não conta para nada até que tenha sido executado em dados reais com uma cesta declarada, um intervalo de datas declarado, uma correção consciente da dependência e pelo menos uma medição para saber se o gráfico permanece imóvel quando a janela se move. Até que essa execução exista, trate tudo aqui como ferramental.
Se o gráfico não for estável, esse é o artigo. Não seria o primeiro resultado negativo aqui que vale mais que um tutorial funcional.
Referências
- Runge, J., Nowack, P., Kretschmer, M., Flaxman, S., e Sejdinovic, D. (2019). Detectando e quantificando associações causais em grandes conjuntos de dados de séries temporais não lineares. Avanços da Ciência, 5(11), eaau4996.
- Runge, J. (2020). Descobrindo relações causais contemporâneas e defasadas em conjuntos de dados de séries temporais não lineares autocorrelacionados. Anais da 36ª Conferência sobre Incerteza em Inteligência Artificial (UAI), PMLR 124:1388-1397.
- Documentação do Tigramite: https://jakobrunge.github.io/tigramite/
- Repositório Tigramite GitHub: https://github.com/jakobrunge/tigramite
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.