---
title: "Bootstrap Methods"
description: "Non-parametric confidence intervals and hypothesis testing for prediction market edge estimation. 11 bootstrap variants + jackknife bias correction."
icon: "arrows-rotate"
---

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

<Tip>
  **What is this?** Monte Carlo simulation assumes you know the data-generating distribution. Bootstrap methods don't - they resample your actual data to estimate confidence intervals, standard errors, and p-values. Use bootstrap when you want to know if your edge is statistically real without making distributional assumptions.
</Tip>

# Bootstrap Methods

Horizon provides 11 bootstrap variants and jackknife bias estimation, all implemented in Rust for performance. These are non-parametric alternatives to Monte Carlo that work directly from observed data. The bootstrap is especially valuable in prediction markets where returns are non-normal and sample sizes are small.

<CardGroup cols={2}>
  <Card title="IID Bootstrap" icon="dice">
    `bootstrap_mean()`, `bootstrap_sharpe()`, `bootstrap_var()`, `bootstrap_edge()` - classic resampling with replacement.
  </Card>
  <Card title="Time-Series Bootstrap" icon="chart-line">
    `block_bootstrap()`, `circular_block_bootstrap()`, `stationary_bootstrap()` - preserve autocorrelation structure.
  </Card>
  <Card title="Hypothesis Testing" icon="flask-vial">
    `bootstrap_hypothesis_test()` - permutation test to compare two strategies without distributional assumptions.
  </Card>
  <Card title="Jackknife" icon="scissors">
    `jackknife_bias()` - leave-one-out bias and variance estimation with pseudovalues.
  </Card>
</CardGroup>

---

## IID Bootstrap Functions

### hz.bootstrap_mean

Confidence interval for the mean via IID resampling.

```python
import horizon as hz

returns = [0.02, -0.01, 0.03, 0.01, -0.005, 0.015, 0.025, -0.008]
r = hz.bootstrap_mean(returns, n_resamples=10000, confidence=0.95, seed=42)
print(f"Mean: {r.point_estimate:.4f}")
print(f"95% CI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
print(f"Std error: {r.std_error:.4f}")
```

### hz.bootstrap_sharpe

Confidence interval for the Sharpe ratio. Particularly useful because the Sharpe ratio's sampling distribution is highly non-normal for small samples.

```python
r = hz.bootstrap_sharpe(returns, n_resamples=10000, confidence=0.95, seed=42)
print(f"Sharpe: {r.point_estimate:.4f}")
print(f"95% CI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
# If CI includes zero, your Sharpe isn't significantly different from zero
```

### hz.bootstrap_var

Confidence interval for Value-at-Risk.

```python
r = hz.bootstrap_var(returns, var_level=0.05, n_resamples=10000, seed=42)
print(f"5% VaR: {r.point_estimate:.4f}")
print(f"95% CI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
```

### hz.bootstrap_correlation

Confidence interval for Pearson correlation (paired resampling).

```python
x = [0.5, 0.6, 0.7, 0.55, 0.65]
y = [0.48, 0.62, 0.71, 0.52, 0.68]
r = hz.bootstrap_correlation(x, y, n_resamples=10000, seed=42)
print(f"Correlation: {r.point_estimate:.4f}")
print(f"95% CI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
```

### hz.bootstrap_edge

Confidence interval for prediction edge `mean(outcome - prediction)`. This is the core bootstrap for prediction market edge estimation.

```python
predictions = [0.55, 0.60, 0.45, 0.70, 0.50]
outcomes =    [1.0,  1.0,  0.0,  1.0,  0.0]
r = hz.bootstrap_edge(predictions, outcomes, n_resamples=10000, seed=42)
print(f"Edge: {r.point_estimate:.4f}")
print(f"95% CI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
if r.ci_lower > 0:
    print("Statistically significant positive edge!")
```

---

## Time-Series Bootstrap

For autocorrelated data (e.g., cumulative returns, price series), IID resampling destroys the dependence structure. These variants preserve it.

### hz.block_bootstrap

Moving block bootstrap (Kunsch 1989). Resamples contiguous blocks of data.

```python
prices = [0.50, 0.51, 0.52, 0.51, 0.53, 0.54, 0.52, 0.55]
r = hz.block_bootstrap(prices, block_size=3, n_resamples=5000, seed=42)
print(f"Mean: {r.point_estimate:.4f}, CI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `data` | `list[float]` | Time series data |
| `block_size` | `int` | Size of each contiguous block |
| `n_resamples` | `int` | Number of bootstrap resamples (default 10000) |
| `confidence` | `float` | Confidence level (default 0.95) |
| `seed` | `int` | RNG seed (default 42) |

### hz.circular_block_bootstrap

Politis-Romano circular variant. Wraps the data circularly so blocks can span the boundary. Reduces bias from edge effects.

```python
r = hz.circular_block_bootstrap(prices, block_size=3, n_resamples=5000, seed=42)
```

### hz.stationary_bootstrap

Politis-Romano stationary bootstrap. Block lengths are geometric random variables, making the resampled series stationary.

```python
r = hz.stationary_bootstrap(prices, expected_block_size=5.0, n_resamples=5000, seed=42)
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `expected_block_size` | `float` | Expected block length (geometric distribution) |

---

## Hypothesis Testing

### hz.bootstrap_hypothesis_test

Two-sample permutation test. Tests whether two samples come from distributions with the same mean.

```python
strategy_a = [0.02, 0.01, 0.03, -0.01, 0.015]
strategy_b = [0.005, -0.01, 0.01, -0.005, 0.002]

r = hz.bootstrap_hypothesis_test(strategy_a, strategy_b, n_resamples=10000, seed=42)
print(f"Test statistic: {r.test_statistic:.4f}")
print(f"P-value: {r.p_value:.4f}")
print(f"Reject H0: {r.reject}")  # True if p < 0.05
```

---

## Prediction Intervals

### hz.bootstrap_prediction_interval

Build prediction intervals from residual resampling. Useful for forecasting.

```python
residuals = [-0.05, -0.02, 0.01, 0.03, -0.01, 0.04, -0.03]
forecast = 0.65
r = hz.bootstrap_prediction_interval(residuals, forecast, n_resamples=10000, seed=42)
print(f"Forecast: {r.point_estimate:.4f}")
print(f"95% PI: [{r.ci_lower:.4f}, {r.ci_upper:.4f}]")
```

---

## Jackknife

### hz.jackknife_bias

Leave-one-out jackknife for bias and variance estimation.

```python
data = [0.02, 0.01, 0.03, -0.01, 0.015, 0.025]
r = hz.jackknife_bias(data, statistic="mean")
print(f"Estimate: {r.estimate:.4f}")
print(f"Bias: {r.bias:.6f}")
print(f"Std error: {r.std_error:.4f}")
print(f"Pseudovalues: {len(r.pseudovalues)}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `data` | `list[float]` | Input data |
| `statistic` | `str` | One of `"mean"`, `"sharpe"`, `"var"` (default `"mean"`) |

---

## Result Types

### BootstrapResult

| Field | Type | Description |
|-------|------|-------------|
| `point_estimate` | `float` | Original sample statistic |
| `ci_lower` | `float` | Lower confidence bound |
| `ci_upper` | `float` | Upper confidence bound |
| `std_error` | `float` | Bootstrap standard error |
| `n_resamples` | `int` | Number of resamples used |
| `bias` | `float` | Bootstrap bias estimate |

### BootstrapHypothesisResult

| Field | Type | Description |
|-------|------|-------------|
| `test_statistic` | `float` | Observed difference in means |
| `p_value` | `float` | Two-sided p-value |
| `ci_lower` | `float` | Lower CI of permutation distribution |
| `ci_upper` | `float` | Upper CI of permutation distribution |
| `reject` | `bool` | True if p-value < 0.05 |

### JackknifeResult

| Field | Type | Description |
|-------|------|-------------|
| `estimate` | `float` | Full-sample statistic |
| `bias` | `float` | Jackknife bias estimate |
| `std_error` | `float` | Jackknife standard error |
| `pseudovalues` | `list[float]` | Leave-one-out pseudovalues |

---

## Pipeline Integration

### hz.bootstrap_edge_tracker

Tracks bootstrap CI for prediction edge in a live pipeline. Accumulates (prediction, outcome) pairs per market and computes CIs when the window fills.

```python
hz.run(
    pipeline=[
        my_model,
        my_quoter,
        hz.bootstrap_edge_tracker(window=100, n_resamples=5000, confidence=0.95),
    ],
    ...
)
# Injects into ctx.params: "bootstrap_edge" = {edge, ci_lower, ci_upper, is_significant}
```

### hz.bootstrap_strategy_test

Compares two strategies' returns using a permutation test.

```python
hz.run(
    pipeline=[
        hz.bootstrap_strategy_test("returns_a", "returns_b"),
    ],
    ...
)
# Reads "returns_a" and "returns_b" from ctx.params
# Injects: "strategy_test" = {test_statistic, p_value, reject}
```
