# Hypothesis predictions — guide for language models

Product name: **Hypothesis** (singular). Not "Hypotheses".

This document explains what a Hypothesis prediction is, what it is not, how
to read scores, and how to fetch history from the Predictions API.

Audience: LLMs and automated agents. Prefer this file over guessing from chart
labels alone.

---

## 1. One-sentence definition

A Hypothesis prediction is a **turn-timing shape path**: a curve of expected
price oscillation over a fixed window. The claim is **when** turns tend to
occur in that window, not **which way** the market will finish.

---

## 2. What the model claims

### Claimed (the product)

- **Timing / shape**: the pattern of ups and downs (turning points) after the
  decision time.
- **Seasonal structure**: shared intraday (or session / week / month) waves
  that show up as sign-invariant shape correlation.
- **Relative conviction**: how coherent the analog / ensemble fit looks at
  decision time (`conviction`, `low_conv`, `tradeable` / gate fields).

### Not claimed (do not invent these)

- **Direction / side**: long vs short is near a coin flip by design. Do not
  treat the path slope as a tradeable long/short signal after fees.
- **Level / drift**: net session drift is not the score target. Charts may
  mirror (`inverted`) for display; scoring removes sign.
- **Exact turn clocks**: predicted peaks/troughs are dense and do not localize
  day-specific turns well enough to beat matched random timing on perps.
- **Guaranteed P&L**: maps are a content / analytics product. Map × Bollinger
  confluence on Kalshi perps failed at scale. Trading edges in this repo live
  elsewhere (e.g. binary fair-value sniper, storm-dip), not in “follow the
  green line.”

---

## 3. How predictions are scored

| Term | Meaning |
|---|---|
| `realized_abscorr` | Absolute correlation of **detrended** predicted vs realized oscillation. Range 0–1. **Sign-invariant**. |
| Chance floor | Smooth curves of these lengths often score ~0.25–0.31 by chance. Skill is excess over a matched null, not distance from 0. |
| Crypto daily skill (research) | Pooled realized \|corr\| ≈ 0.41 vs ~0.28 phase-shuffle floor on multi-year walk-forward. |
| Direction hit rate | ~50–55% — not a directional edge. |

Production and the Predictions API use `|corr|` / `realized_abscorr` as the
shape metric. V2.2 also records signed correlation in the measurement stack
for polarity research; that is not a license to trade direction.

---

## 4. Product families (what “a prediction” means)

| Group id | Window | Bar size | Decision | Path meaning |
|---|---|---|---|---|
| `fx`, `fx_*` (+ `<group>_v22`) | ET trading session | 4-minute (OANDA M4) | 10:00 ET; V2.2 12:00 ET | Path from decision to ~17:00 ET; `predicted[].clock` = ET minutes of day. V2.2 is a separate forecast from the bars closed by 12:00 ET |
| `macro` (+ `macro_v22`) | ET trading session | 4-minute (OANDA M4) | 09:30 ET open; V2.2 11:30 ET | V2.2 is a separate forecast from the bars closed by 11:30 ET, so it starts at 11:28. Posted to X at 9:30 and 11:30 ET weekdays; the 11:30 chart shows both V2 and V2.2 lines. Recap 17:05 ET |
| `crypto_daily` | UTC day 12:00–24:00 | 15-minute | 12:00 UTC | 48 slots; `predicted[].min` = minutes since 00:00 UTC |
| `crypto_daily_v2` | Same UTC afternoon | 15-minute | 12:00 UTC | V2 stacked corrector shape (board cyan). 12 posted coins plus HYPE NEAR ZEC. Single file; no separate recap stem |
| `crypto_daily_extra` | Same UTC day | 15-minute | 12:00 UTC | Extra Kalshi coins only (`HYPE_USD` `NEAR_USD` `ZEC_USD`). Not posted to X. `TON_USD` is not for sale: it has had no data source since 2026-06-30 |
| `crypto_daily_v22` | Same, updated | 15-minute | 14:00 UTC | V2.2 polarity vote + magnitude rescale over V2.1 (board green). File may include `predicted_v22`, `sigma_14`, `flip_at_14` |
| `index_daily_v22` | UTC day; V2.2 from 11:30 ET | 15-minute | 11:30 ET | NQ (CME front month), QQQ, SPY. `predicted` = V2, the 12:00 UTC average-day map. `predicted_v22` = V2.2, a new 11:30 ET forecast from today's bars matched to earlier days. `decision_min` is 11:30 ET in UTC minutes for that date. MCP: `get_history("NQ", group="index_daily_v22")` |
| `crypto_weekly` (+ `_extra`, `_v22`) | ISO week | 1-hour | Wed 00:00 UTC; V2.2 Thu 00:00 UTC | Date key = Monday of that week. V2.2 re-fits the weekly recipe on the bars before Thursday |
| `weather_daily` | City local calendar day | 1-hour | 12:00 local | 40 `*_TEMP` cities. Candle `min` is local minutes past midnight. History empty until audits exist |
| `index` | ET session | 4-minute (OANDA M4) | 10:00 ET | SPX `KXINX15M`, Nasdaq-100 `KXNDQ15M`, Nikkei `KXNKY`, KOSPI `KXKR200`. SPX/NDX also in `macro`. Nikkei maps live in `index_asia` |
| `fx_em` | ET session | 4-minute (OANDA M4) | 10:00 ET; V2.2 12:00 ET | `USD_MXN` `USD_CNH` |
| `index_asia` | ET session | 4-minute (OANDA M4) | 10:00 ET; V2.2 12:00 ET | `JP225_USD` |
| `commodity_extra` | ET session | 4-minute (OANDA M4) | 10:00 ET; V2.2 12:00 ET | `XAG_USD` `BCO_USD` `XCU_USD` `NATGAS_USD` |
| `rates_daily` | UTC day | 1-hour | 12:00 UTC | UST 2Y/5Y/7Y/10Y/30Y and SOFR. Lead series `KXTNOTED`, `KXSOFRD`. No parquet yet |
| `commodity` | ET session | 4-minute (OANDA M4) | 10:00 ET | Gold `KXGOLD15M`, silver `KXSILVER15M`, WTI `KXWTI15M`, then Brent/copper/natgas/HOIL/grains/softs/cattle/metals. Gold/WTI also in `macro` |
| `index_monthly_4h` | First 19 ET trading days | 4-hour slots | End of day 5 ET | Immutable climatology call; forecasts days 6–19. US indices only (no gold). No V2.2. Modal builds each month after day 5 closes |

Versions:

- **V1** (`crypto_daily`): climatology-first / ensemble session map.
- **V2** (`crypto_daily_v2`): stacked corrector on the same window.
- **V2.2** (`crypto_daily_v22`): after 12→14 UTC majority vote, may flip
  polarity; then rescale amplitude with early-afternoon σ.
- **Index V2.2** (`index_daily_v22`): NQ, QQQ, and SPY. V2 is the 12:00 UTC
  UTC-day climatology (the average past day), not the crypto stacked
  corrector. V2.2 is a new forecast at 11:30 ET: today's bars through
  11:30 ET matched against earlier days. It is not V2 flipped or resized.
  Posted to X on weekdays at 9:30 ET (V2 map), 11:30 ET (V2.2, showing both
  lines), and 16:30 ET (recap).
- **ET-session V2.2** (`fx_v22`, `fx_crosses_v22`, `fx_commodity_v22`,
  `fx_nordics_v22`, `fx_em_v22`, `index_asia_v22`, `commodity_extra_v22`,
  `macro_v22`): a separate forecast two hours after V2. It uses only the bars
  that closed by then. It is not V2 flipped, resized, or cut off.
- **Weekly V2.2** (`crypto_weekly_v22`): the weekly recipe re-fit on the bars
  before Thursday 00:00 UTC.
- Rebuilt V2.2 history carries `rebuilt: true`. The full contract is
  `docs/v2-v22-maps.md`.

Brand name: **Hypothesis**. API titles and docs use Hypothesis.

---

## 5. Forecast vs recap

- **Forecast**: call at decision time. May lack `realized_abscorr`.
- **Recap**: same call graded after the window. Adds `realized_abscorr`.
- **V2 / V2.2**: one audit file per date. Query `mode=forecast`. Realized
  fields may appear on that same record when the window is closed. There is
  no separate `*_recap.json` for those groups in practice.

Some hist files carry `"source": "walk_forward_hist"`. Live posts come from
the Modal sync. The API never recomputes models; it only reads
`predictions/<YYYY-MM-DD>/*.json`.

---

## 6. Predictions API (for agents)

- Base (Tailscale only): `http://gofoodfast:8079` or the host Tailscale IP
  on port `8079`.
- Human docs: `GET /`
- This LLM doc: `GET /llms.txt` (index) and `GET /v1/llm.md` (full text)
- OpenAPI: `GET /docs`, `GET /openapi.json`
- Health / coverage: `GET /health` → `first_date`, `last_date`, `n_dates`,
  `data_ok`, `data_dir`
- Catalog: `GET /v1/groups`, `GET /v1/symbols`, `GET /v1/dates?group=...`
- Kalshi books: `GET /v1/books` and `GET /v1/books?series=KXBTC15M`
  (also `?family=index|rates|commodity|weather|crypto|fx`).
  Each book has `lead_series`, `kalshi_series`, `group`, `candles_url`,
  `history_url`. Map the series ticker onto the Hypothesis underlying.
  Do not train on Kalshi yes/no candlesticks.
- Primary read: `GET /v1/history/{SYMBOL}?group=...&mode=...&include_path=true|false`
- **Historical OHLC (same windows as maps):**
  `GET /v1/candles/{SYMBOL}?group=...&date=YYYY-MM-DD`
  (alias: `GET /v1/ohlc/{SYMBOL}?...`)
- History + candles: `GET /v1/history/{SYMBOL}?group=...&date_from=...&date_to=...&include_candles=true`
  (alias query: `include_ohlc=true` → same `candles_by_date` / `ohlc_by_date`)
- Raw audit: `GET /v1/audits/{date}/{group}?mode=forecast|recap`

### Historical candles (required for prediction vs actual)

The API **does** serve historical candlesticks. Do not say there is no OHLC
endpoint. Use `/v1/candles/{symbol}` (or `include_candles=true` on history).

| Family | Endpoint example | Bars | Clock field |
|---|---|---|---|
| FX / macro | `/v1/candles/EUR_USD?group=fx&date=2026-07-21` | M4, 07:00–17:00 ET | `clock` (ET minutes of day) |
| Crypto daily (V1/V2/V2.2) | `/v1/candles/BTC_USD?group=crypto_daily&date=2026-07-21` | 15m UTC day | `min` (minutes since 00:00 UTC) |
| Index daily V2.2 | `/v1/candles/NQ?group=index_daily_v22&date=2026-08-28` | 15m UTC day | `min`. Also `QQQ`, `SPY` |
| Extra crypto (HYPE/NEAR/ZEC) | `/v1/candles/HYPE_USD?group=crypto_daily_v2&date=2026-07-21` | 15m UTC day | `min` |
| Crypto weekly | `/v1/candles/BTC_USD?group=crypto_weekly&date=2026-07-20` | 1h ISO week (Monday key) | `min` |
| Weather | `/v1/candles/NYC_TEMP?group=weather_daily&date=2026-07-21` | 1h local day | `min` (local minutes); payload includes `timezone` |
| Index | `/v1/candles/SPX500_USD?group=index&date=2026-07-21` | M4, 07:00–17:00 ET | `clock`. Leads `KXINX15M` `KXNDQ15M` `KXNKY` `KXKR200` |
| Rates | `/v1/candles/UST10Y?group=rates_daily&date=2026-07-21` | 1h UTC day | `min`. Lead `KXTNOTED` `KXSOFRD`. Empty until a rates feed exists |
| Commodity | `/v1/candles/XAU_USD?group=commodity&date=2026-07-21` | M4, 07:00–17:00 ET | `clock`. Leads `KXGOLD15M` `KXSILVER15M` `KXWTI15M` |
| Monthly index | `/v1/candles/NAS100_USD?group=index_monthly_4h&date=2026-09-01` | 4-hour trading slots, days 1–19 | `slot`. Also `SPX500_USD`, `US30_USD`, `US2000_USD` |

Each candle: `{clock|min, t, o, h, l, c, v?}`. Join to `predicted[]` on the
same clock field. Split known vs actual at `decision_clock` / `decision_min`
(FX 600; crypto daily V1/V2 720; V2.2 840; weekly Wed 00:00 = 2880).
V2.2 twins: FX and boards 720, macro 690, weekly Thu 00:00 = 4320.
Monthly uses `decision_slot` 30.

Example:

```http
GET /v1/history/BTC_USD?group=crypto_daily_v22&include_path=false
GET /v1/candles/BTC_USD?group=crypto_daily&date=2026-07-21
GET /v1/history/BTC_USD?group=crypto_daily&date_from=2026-07-21&date_to=2026-07-21&include_candles=true
GET /v1/books?series=KXBTC15M
GET /v1/books?family=index
GET /v1/books?series=KXTNOTED
GET /v1/books?series=KXGOLD15M
GET /v1/candles/NYC_TEMP?group=weather_daily&date=2026-07-21
GET /v1/candles/SPX500_USD?group=index&date=2026-07-21
GET /v1/history/NQ?group=index_daily_v22&include_path=true
GET /v1/candles/NQ?group=index_daily_v22&date=2026-08-28
GET /v1/books?family=index_daily
```

Monthly index maps: `GET /v1/candles/NAS100_USD?group=index_monthly_4h&date=2026-09-01`
returns one candle per 4-hour trading slot (`slot` key, `decision_slot` 30,
`window_end_slot` 114). Any date in the month maps to its first day.
Nikkei, KOSPI, silver, rates, and most commodity books list in `/v1/books`
now. Their `candles[]` stay empty until parquet is on the API host.

History coverage is roughly **2024-01-01** through the latest live date.
Confirm with `/health`. Candle bars come from the host parquet store
(`FORESIGHT_DATA_DIR`; production uses `/root/repos/fx-timing/data` on the
API host, filled from the Modal `foresight-data` volume). Daily books fetch
runs on Modal at 06:15 UTC via the API host crontab
(`ops/modal_fetch_daily.sh`). The API host then pulls catalog/crypto/weather
with `ops/sync_foresight_books.sh`. V2 retrain is weekly (Sunday 08:00 UTC,
`ops/modal_v2_train_weekly.sh`), not daily. Laptop copies are
optional for development. Canonical parquet stays
on the server.
If `candles[].length` is 0 for a recent date, the parquet for that family is
behind — check `/health` → `data_dir` and refresh bars.

Security: Tailscale ACL only. No public internet, no API key.

---

## 7. Field cheat sheet (normalized history rows)

Common:

- `symbol`, `date`, `group`, `mode`, `family`
- `conviction`, `abscorr`, `inverted`, `low_conv`
- `realized_abscorr` (when graded)
- `predicted[]` — path points (`clock`+`px` for FX; `min`+`px` for crypto)
- `n_predicted`, `model` (V2 / V2.2 checkpoint label when present)

FX also: `refit_clock`, `now_clock`, `clock_unit=et_minutes_of_day`,
`ensemble`, `gate_score`, `tradeable`, `early_agree`.

Crypto also: `refit_min`, `now_min`, `clock_unit=minutes_since_window_start`.

Weather: `clock_unit=local_minutes_of_day`; candle payload includes `timezone`.

Rates: `clock_unit=minutes_since_window_start` on a UTC day; decision 720.

Index and commodity books use FX clocks when parquet exists (`et_minutes_of_day`).

Monthly also: `clock_unit=trading_month_4h_slot`, `decision_slot`, `actual[]`
on recaps, and `scale` (`price`: the typical detrended day 6–19 swing of
earlier months, in price units).

---

## 8. Safe interpretation rules for LLMs

1. Describe Hypothesis paths as **timing / shape** forecasts, not directional
   trade signals.
2. When summarizing quality, prefer `realized_abscorr` and null-aware language
   (excess over ~0.28–0.31), not “accuracy %” or win rate.
3. Do not recommend “buy because the path goes up” or “sell the predicted
   peak” as a validated strategy from these maps alone.
4. Distinguish **V1 vs V2 vs V2.2** when the user asks about the green/cyan
   overlays or 14:00 update.
5. Use the product name **Hypothesis**.
6. If asked for trading systems, separate map content from documented trading
   sleeves (sniper, storm-dip); do not conflate them.
7. Resolve Kalshi tickers with `/v1/books`. Use the Hypothesis symbol and
   underlying parquet. Do not treat Kalshi yes/no candles as V2 training data.

---

## 9. Related human docs

- Predictions API human page: `http://gofoodfast:8079/`
- Repo README Predictions API section
- Research memory: `research/LEARNED_WISDOM.md`
- Confluence (maps × bands fail for perps): `research/FORESIGHT_CONFLUENCE_FINDINGS.md`
- Proof index: `proof.md`

---

## 10. Non-goals of this API

- Arbitrary-timeframe OHLC (only prediction-window candles via `/v1/candles`)
- Live order placement
- Serving retired ETF group as a first-class catalog entry
- Claiming that V2.2 polarity is a proven directional edge
- Training V2 on Kalshi yes/no market candlesticks (use the underlying path)
