---
title: "Oracle"
description: "Ensemble probability forecasting from 6 signal sources. Surface markets where your model sees edge vs market price."
icon: "crystal-ball"
---

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

# Oracle

Combines six independent signal extractors into a single ensemble probability estimate for each market, then surfaces edge opportunities where the forecast diverges materially from the current market price.

<CardGroup cols={3}>
  <Card title="Smart Money Flow" icon="wallet">
    Holder analysis weighted by wallet score.
  </Card>
  <Card title="Microstructure" icon="microscope">
    Kyle's lambda + VPIN for informed trading detection.
  </Card>
  <Card title="Momentum" icon="arrow-trend-up">
    EMA crossover (short/long span ratio).
  </Card>
  <Card title="Volume Profile" icon="chart-bar">
    Buy vs sell volume imbalance.
  </Card>
  <Card title="Holder Concentration" icon="users">
    HHI of top holders as conviction signal.
  </Card>
  <Card title="Temporal Patterns" icon="clock">
    Hour-of-day buy activity patterns.
  </Card>
</CardGroup>

---

## Forecast a Market

```python
import horizon as hz

fc = hz.forecast_market(
    "0xcondition...",
    market_title="Will X happen?",
    market_price=0.65,
)
print(f"Ensemble: {fc.ensemble_prob:.4f}")
print(f"Edge: {fc.edge_bps:.0f} bps")
for s in fc.signals:
    print(f"  {s.name}: {s.normalized_value:.4f} (weight={s.weight:.2f})")
```

---

## Scan for Edges

```python
edges = hz.scan_edges(min_edge_bps=300, max_markets=30)
for e in edges:
    print(f"{e.market_title}: {e.direction} | edge={e.edge_bps:.0f}bps | size=${e.recommended_size:.0f}")
```

---

## Pipeline Mode

```python
hz.run(
    name="oracle-mm",
    markets=["0xcondition..."],
    pipeline=[
        hz.oracle(forecast_interval_cycles=20),
        model,   # reads ctx.params["oracle_edge_bps"]
        quoter,
    ],
    interval=5.0,
)
```

Injects `ctx.params["oracle_forecast"]` and `ctx.params["oracle_edge_bps"]` every N cycles.

---

## Full Report

```python
report = hz.oracle_report(max_markets=20)
print(f"Coverage: {report.coverage} markets")
print(f"Avg confidence: {report.avg_confidence:.4f}")
print(f"Calibration (log loss): {report.model_calibration:.4f}")
for edge in report.top_edges:
    print(f"  {edge.market_title}: {edge.edge_bps:.0f}bps ({edge.direction})")
```

---

## Signal Weights

Default weights (configurable via `OracleConfig`):

| Signal | Weight | Source |
|--------|--------|--------|
| `smart_money_flow` | 0.25 | `get_top_holders()` + `score_wallet()` |
| `microstructure` | 0.20 | `get_market_trades()` + Kyle's lambda + VPIN |
| `momentum` | 0.15 | EMA crossover on trade prices |
| `volume_profile` | 0.15 | Buy/sell volume ratio |
| `holder_concentration` | 0.15 | HHI of top holders |
| `temporal_pattern` | 0.10 | Hour-of-day activity analysis |

---

## OracleConfig

| Parameter | Default | Description |
|-----------|---------|-------------|
| `signal_weights` | See above | Weight per signal in ensemble |
| `min_confidence` | `0.3` | Minimum confidence to report forecast |
| `edge_threshold_bps` | `200.0` | Minimum edge to flag as opportunity |
| `recalibrate_interval` | `50` | Cycles between recalibration |
| `holder_limit` | `50` | Max holders to fetch per market |
| `trade_limit` | `200` | Max trades to fetch per market |
