Product
Live data Historical data Chrome extension
Asset classes
Weather Prediction markets Financial data soon
Docs
Quickstart API reference
Company
About Our mission

Settlement-grade history,
cached on your disk.

GHCNh climate, ASOS archive, NWS CLI products, and deterministic settlement backtests, fetched on demand and written byte-stable to an optional local cache on first call, so research and backtest are identical, run after run.

parquet / JSON cache byte-equivalent runs source-stamped rows
backtest.py
1from mostlyright import weather
2
3# one row per LST settlement date
4df = weather.pairs("KNYC", "2025-01-06", "2025-01-12")
5df[["cli_high_f", "obs_high_f"]].describe()
1import { dataset } from "mostlyright";
2
3// same 20-col shape Python emits
4const rows = await dataset("KNYC", "2025-01-06", "2025-01-12");
// what's covered

Four historical layers, one schema

GHCNh climate

NCEI hourly historical observations: the long record behind the climate normals.

ASOS archive

Iowa Mesonet's full ASOS archive: every reported cycle, parsed and normalized.

NWS CLI products

Official daily climate text products: the source many contracts settle on.

Settlement backtests

Join climate + observations against the contract spec for a deterministic decision.

// local-first cache

Byte-stable across every run

Calls fetch and normalize the upstream sources in your own runtime. The first call can write a parquet (Python) or JSON envelope (Node) to an optional local cache at ~/.mostlyright. Subsequent calls in the same window are local-only: no network, no drift. Your backtest in March reproduces exactly in September.

Deterministic: same bytes, same rows, every run.
Source-stamped: every row carries its origin (iem.archive, cli…).
Train/infer parity: the validator fails loudly on a source mismatch.
~/.mostlyright/cache
# written on first call, reused after
cache/
├─ NYC/2025-01.parquet   # obs + cli
├─ AUS/2025-01.parquet
└─ _manifest.json       # schema + source ids

# pin a single source (provenance)
train = weather.obs("KNYC", ..., source="iem")
validate_dataframe(train, "schema.observation.v1")
// vs rolling your own

What you skip by not stitching it yourself

Concern Hand-rolled scrapers Mostly Right
Reproducibility drifts with live endpoints byte-stable cache
Schema discipline ad-hoc per source schema.*.v1 + validator
Train / infer parity silent corruption fails loudly on mismatch
Python ↔ TypeScript two codebases byte-equivalent peers
// reproducible by default

Backtest on history you can trust.

Read the docs
// request access

Request early access

Mostly Right is currently available by request. Tell us a bit about you and what you are building, and we will be in touch.

I'm a

One email from the team. No spam.