---
title: "Microstructure Invariance"
description: "Kyle-Obizhaeva market microstructure invariance: bet sizing, trading activity, and informed trade detection."
icon: "equals"
---

<Note>
  **Pro Feature.** Requires a Pro or Ultra subscription. [Get started at api.mathematicalcompany.com](https://api.mathematicalcompany.com)
</Note>

<Tip>
  **What is this?** Microstructure invariance gives you a model-free way to estimate 'normal' trade sizes and price impact for any market. The key insight: when you adjust for volatility and volume, the distribution of bet sizes is the same across all liquid markets. Use it to detect unusually large (potentially informed) trades and estimate your own market impact.
</Tip>

# Microstructure Invariance

Horizon implements the Kyle-Obizhaeva (2016) microstructure invariance framework. The invariance hypothesis states that the distribution of risk transferred per bet, measured in units of business time, is constant across markets and time periods. This provides a model-free approach to estimating natural bet sizes, market impact, and detecting informed trading. All computation runs in Rust via PyO3.

<CardGroup cols={2}>
  <Card title="Trading Activity" icon="chart-line">
    Estimate the rate of bet arrivals from volume, volatility, and price data.
  </Card>
  <Card title="Invariant Bet Size" icon="ruler">
    Compute the natural bet size implied by the invariance hypothesis.
  </Card>
  <Card title="Market Impact" icon="arrow-trend-up">
    Kyle-Obizhaeva square-root impact model calibrated from trading activity.
  </Card>
  <Card title="Informed Trade Detection" icon="user-secret">
    Flag trades whose size exceeds the invariant bet size threshold.
  </Card>
</CardGroup>

---

## Why Invariance?

Traditional market impact models require calibration to specific venues. The invariance hypothesis provides a universal scaling law: markets that differ in volume, volatility, and tick size all share the same distribution of bets when measured in the right units. This means you can estimate impact and detect informed trading without venue-specific calibration.

The key scaling relationships are:

- **Trading activity**: `gamma = volume * volatility / price` (dollar-risk per unit time)
- **Invariant bet size**: `V* = volume / (gamma^(2/3))` (natural trade size)
- **Impact coefficient**: `lambda ~ gamma^(1/3)` (Kyle's lambda from invariance)

<Note>
  Invariance is especially useful in prediction markets where historical calibration data is sparse. The framework transfers impact estimates from liquid markets to illiquid ones through the universal scaling law.
</Note>

---

## API

### hz.trading_activity

Compute the Kyle-Obizhaeva trading activity measure (gamma) from market observables.

```python
import horizon as hz

gamma = hz.trading_activity(
    volume=50000.0,       # daily volume in contracts
    volatility=0.02,      # daily return volatility
    price=0.55,           # current market price
)
print(f"Trading activity: {gamma:.4f}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `volume` | `float` | Trading volume over the period (positive) |
| `volatility` | `float` | Return volatility over the same period (positive) |
| `price` | `float` | Current market price (positive) |

Returns `float`: the trading activity measure gamma.

### hz.invariant_bet_size

Compute the natural bet size implied by the invariance hypothesis.

```python
import horizon as hz

v_star = hz.invariant_bet_size(
    volume=50000.0,
    volatility=0.02,
    price=0.55,
)
print(f"Invariant bet size: {v_star:.1f} contracts")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `volume` | `float` | Trading volume over the period (positive) |
| `volatility` | `float` | Return volatility over the same period (positive) |
| `price` | `float` | Current market price (positive) |

Returns `float`: the invariant bet size in contracts.

### hz.kyle_obizhaeva_impact

Estimate price impact using the Kyle-Obizhaeva square-root model. Impact scales as `lambda * sqrt(size / V*)` where lambda is derived from trading activity.

```python
import horizon as hz

impact = hz.kyle_obizhaeva_impact(
    size=500.0,           # trade size in contracts
    volume=50000.0,
    volatility=0.02,
    price=0.55,
)
print(f"Expected impact: {impact:.4f}")  # in price units
print(f"Impact in bps: {impact / 0.55 * 10000:.1f}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `size` | `float` | Trade size to evaluate (positive) |
| `volume` | `float` | Trading volume over the period (positive) |
| `volatility` | `float` | Return volatility (positive) |
| `price` | `float` | Current market price (positive) |

Returns `float`: estimated price impact in price units.

### hz.is_informed_trade

Test whether a trade size exceeds a multiple of the invariant bet size, flagging potential informed trading.

```python
import horizon as hz

informed = hz.is_informed_trade(
    size=2000.0,
    volume=50000.0,
    volatility=0.02,
    price=0.55,
    threshold=3.0,        # flag if size > 3x invariant bet size
)
print(f"Informed trade: {informed}")  # True or False
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `size` | `float` | Observed trade size (positive) |
| `volume` | `float` | Trading volume over the period (positive) |
| `volatility` | `float` | Return volatility (positive) |
| `price` | `float` | Current market price (positive) |
| `threshold` | `float` | Multiple of invariant bet size to flag (default: 2.0) |

Returns `bool`.

### hz.invariance_analysis

Run a complete invariance analysis, returning all derived quantities in a single call.

```python
import horizon as hz

result = hz.invariance_analysis(
    volume=50000.0,
    volatility=0.02,
    price=0.55,
    trade_size=500.0,
)
print(f"Trading activity:    {result.trading_activity:.4f}")
print(f"Invariant bet size:  {result.invariant_bet_size:.1f}")
print(f"Impact coefficient:  {result.impact_coefficient:.6f}")
print(f"Expected impact:     {result.expected_impact:.4f}")
print(f"Size ratio:          {result.size_ratio:.2f}")
print(f"Is informed:         {result.is_informed}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `volume` | `float` | Trading volume (positive) |
| `volatility` | `float` | Return volatility (positive) |
| `price` | `float` | Current market price (positive) |
| `trade_size` | `float` | Trade size to evaluate (positive) |

### InvarianceResult Type

| Field | Type | Description |
|-------|------|-------------|
| `trading_activity` | `float` | Kyle-Obizhaeva gamma measure |
| `invariant_bet_size` | `float` | Natural bet size V* in contracts |
| `impact_coefficient` | `float` | Kyle's lambda from invariance scaling |
| `expected_impact` | `float` | Estimated price impact for the given trade size |
| `size_ratio` | `float` | `trade_size / invariant_bet_size` |
| `is_informed` | `bool` | Whether size_ratio exceeds 2.0 |

---

## Pipeline Integration

### hz.invariance_monitor

Pipeline function that computes invariance metrics each cycle and injects them into `ctx.params["invariance"]`.

```python
import horizon as hz

def impact_aware_strategy(ctx):
    inv = ctx.params.get("invariance")
    if inv is None:
        return []

    mid = ctx.feed.price

    # Scale position size inversely with impact
    base_size = 50
    if inv["expected_impact"] > 0.01:
        size = max(5, int(base_size * 0.01 / inv["expected_impact"]))
    else:
        size = base_size

    # Widen spread when informed trading is detected
    spread = 0.05 if inv["is_informed"] else 0.02

    return [
        hz.quote(ctx, hz.Side.Yes, hz.OrderSide.Buy, mid - spread, size),
        hz.quote(ctx, hz.Side.Yes, hz.OrderSide.Sell, mid + spread, size),
    ]

hz.run(
    name="invariance-mm",
    markets=["0xcondition..."],
    pipeline=[
        hz.invariance_monitor(),
        impact_aware_strategy,
    ],
    interval=1.0,
)
```

The `ctx.params["invariance"]` dict contains:

| Key | Type | Description |
|-----|------|-------------|
| `trading_activity` | `float` | Current gamma measure |
| `invariant_bet_size` | `float` | Current V* estimate |
| `impact_coefficient` | `float` | Kyle's lambda |
| `expected_impact` | `float` | Impact for a 1x V* trade |
| `is_informed` | `bool` | Whether recent flow exceeds 2x V* |

---

## Mathematical Background

<AccordionGroup>
  <Accordion title="The Invariance Hypothesis">
    Kyle and Obizhaeva (2016) propose that the distribution of a "bet" -- a portfolio decision by an informed trader -- is invariant across markets and time when measured in business time. Business time is defined by trading activity gamma = sigma * V / P, where sigma is volatility, V is volume, and P is price.

    The key predictions are:
   - Bet size scales as `V * gamma^(-2/3)`
   - Number of bets per period scales as `gamma^(2/3)`
   - Price impact per bet scales as `gamma^(1/3)`

    These scaling laws have been validated empirically across equities, futures, and FX markets.
  </Accordion>
  <Accordion title="Square-Root Impact">
    The Kyle-Obizhaeva impact model predicts that temporary price impact scales as the square root of trade size normalized by the invariant bet size:

    `Delta_P = lambda * sigma * sqrt(Q / V*)`

    where lambda is a universal constant (approximately 1), sigma is volatility, Q is trade size, and V* is the invariant bet size. The square-root law arises from the assumption that informed traders optimally split their bets.
  </Accordion>
  <Accordion title="Informed Trade Detection">
    Under invariance, the natural trade size V* represents the equilibrium bet of an informed trader. Trades significantly larger than V* (e.g., 2-3x) are unlikely to come from informed traders optimally splitting orders. Instead they suggest either: (1) highly informed traders with very short-lived information, or (2) uninformed institutional flow. Both cases warrant wider spreads.
  </Accordion>
</AccordionGroup>
