---
title: "Correlation Regime"
description: "Live correlation matrices, regime shift detection, contagion scoring, and decorrelation analysis across prediction markets."
icon: "diagram-project"
---

<Warning>
  **Ultra Feature.** Requires an Ultra subscription. [Get started at api.mathematicalcompany.com](https://api.mathematicalcompany.com)
</Warning>

# Correlation Regime

Markets that were uncorrelated yesterday can suddenly move in lockstep during a crisis. Horizon's correlation regime module tracks live pairwise correlations, detects regime shifts via z-score analysis, scores contagion risk, and finds the most decorrelated markets for diversification. All math is in Rust with O(1) incremental updates.

## Overview

<CardGroup cols={2}>
  <Card title="Live Correlation Matrix" icon="table">
    `hz.live_correlation_matrix()` computes pairwise correlations across markets.
  </Card>
  <Card title="Regime Shift Detection" icon="bolt">
    `hz.detect_regime_shift()` flags when correlations break from historical norms.
  </Card>
  <Card title="Contagion Scoring" icon="virus">
    `hz.contagion_score()` identifies which markets would drag others with them.
  </Card>
  <Card title="Decorrelation Finder" icon="shuffle">
    `hz.find_decorrelated()` ranks markets by diversification value.
  </Card>
</CardGroup>

---

## Core Functions

### hz.live_correlation_matrix

Compute all pairwise Pearson correlations from return series.

```python
import horizon as hz

entries = hz.live_correlation_matrix(
    market_ids=["btc", "eth", "fed_rate"],
    returns_matrix=[btc_returns, eth_returns, fed_returns],
)
for e in entries:
    print(f"{e.market_a} / {e.market_b}: {e.correlation:.4f} (n={e.num_observations})")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `market_ids` | `list[str]` | Market identifiers |
| `returns_matrix` | `list[list[float]]` | Return series for each market |

Returns a list of `CorrelationEntry` objects (one per pair).

### hz.detect_regime_shift

Compare historical correlation distribution to recent window using z-score.

```python
result = hz.detect_regime_shift(
    historical_correlations=[0.3, 0.35, 0.28, 0.32, 0.31],
    recent_correlations=[0.8, 0.85, 0.9],
    threshold=2.0,
)
if result.shifted:
    print(f"Regime shift detected! Confidence: {result.confidence:.2f}")
    print(f"Old mean: {result.old_mean_corr:.4f} -> New mean: {result.new_mean_corr:.4f}")
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `historical_correlations` | `list[float]` | required | Historical correlation values |
| `recent_correlations` | `list[float]` | required | Recent correlation values |
| `threshold` | `float` | `2.0` | Z-score threshold for shift detection |

### hz.contagion_score

Score how much a source market would drag others with it.

```python
alert = hz.contagion_score(
    source_market="btc",
    market_ids=["btc", "eth", "sol"],
    correlations=[1.0, 0.85, 0.3],
    price_changes=[0.05, 0.04, 0.01],
    threshold=0.5,
)
print(f"Contagion score: {alert.contagion_score:.4f}")
print(f"Affected: {alert.affected_markets}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `source_market` | `str` | Market to analyze as contagion source |
| `market_ids` | `list[str]` | All market identifiers |
| `correlations` | `list[float]` | Correlation of each market to the source |
| `price_changes` | `list[float]` | Recent price changes |
| `threshold` | `float` | Minimum correlation to count as affected |

### hz.find_decorrelated

Rank markets by diversification value (low average correlation).

```python
results = hz.find_decorrelated(
    market_ids=["btc", "eth", "fed_rate", "weather"],
    returns_matrix=[...],
    top_n=3,
)
for r in results:
    print(f"{r.market_id}: avg_corr={r.avg_correlation:.4f}, div_score={r.diversification_score:.4f}")
```

### hz.incremental_correlation_update

O(1) single-pass correlation update. Maintain running statistics without recomputing from scratch.

```python
n, sx, sy, sxy, sx2, sy2, corr = hz.incremental_correlation_update(
    n=0, sum_x=0.0, sum_y=0.0,
    sum_xy=0.0, sum_x2=0.0, sum_y2=0.0,
    new_x=1.0, new_y=2.0,
)
print(f"Running correlation after {n} points: {corr:.4f}")
```

---

## Pipeline Functions

### hz.correlation_matrix

Track live correlations across feeds each cycle.

```python
corr = hz.correlation_matrix(
    feed_names=["btc", "eth", "sol", "fed_rate"],
    window=50,
)
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `feed_names` | `list[str]` | required | Feed names to track |
| `window` | `int` | `50` | Rolling window size |

### hz.regime_shift

Detect correlation regime shifts.

```python
shift = hz.regime_shift(
    feed_names=["btc", "eth"],
    lookback=100,
    recent_window=20,
    threshold=2.0,
)
```

### hz.contagion_alert

Monitor for contagion risk across markets.

```python
alert = hz.contagion_alert(
    feed_names=["btc", "eth", "sol"],
    correlation_threshold=0.5,
    window=50,
)
```

### hz.decorrelation_finder

Find the most decorrelated markets for portfolio diversification.

```python
finder = hz.decorrelation_finder(
    feed_names=["btc", "eth", "sol", "fed_rate", "weather"],
    top_n=3,
    window=50,
)
```

---

## Examples

### Correlation-Aware Portfolio

```python
import horizon as hz

def portfolio_strategy(ctx):
    alerts = ctx.params.get("alerts", [])
    if any(a["score"] > 0.8 for a in alerts):
        return []  # high contagion risk, stand aside
    return hz.quotes(fair=ctx.feed.price, spread=0.03, size=10)

hz.run(
    name="corr_aware",
    feeds={
        "btc": hz.PolymarketBook("will-btc-hit-100k"),
        "eth": hz.PolymarketBook("will-eth-hit-10k"),
    },
    pipeline=[
        hz.contagion_alert(feed_names=["btc", "eth"], correlation_threshold=0.5),
        portfolio_strategy,
    ],
)
```

---

## Mathematical Background

<AccordionGroup>
  <Accordion title="Pearson Correlation">
    For two return series X and Y:

    **r = [n*SXY - SX*SY] / sqrt([n*SX2 - SX^2] * [n*SY2 - SY^2])**

    Where SX, SY are sums, SXY is sum of products, SX2, SY2 are sums of squares. The incremental update adds one (x, y) pair and recomputes in O(1).
  </Accordion>
  <Accordion title="Regime Shift Detection">
    Compares the mean of recent correlations to the historical distribution:

    **z = (mean_recent - mean_historical) / std_historical**

    If |z| exceeds the threshold (default 2.0), a regime shift is flagged. The confidence score equals the z-value.
  </Accordion>
  <Accordion title="Contagion Score">
    For a source market, contagion score is the correlation-weighted sum of absolute price changes across affected markets (those with correlation above the threshold).
  </Accordion>
</AccordionGroup>
