Changelog
v1.4.2 — 2026-03-31
Section titled “v1.4.2 — 2026-03-31”Fix: Parquet Null-to-Zero
Section titled “Fix: Parquet Null-to-Zero”- Fix: parquet nullable columns: Observation parquet files now use
Optionalschema for nullable fields. Previously, the Go API inferred the parquet schema from the first row only and created non-nullable columns — null values were silently written as zero (0 for int, 0.0 for float), skewing downstream analysis. JSON was unaffected. - API:
writeParquetTypednow scans all rows for the full column union and wraps nullable columns withparquet.Optional() - Python SDK: 7 new regression tests verifying nullable parquet columns produce
NaNin DataFrames, not0. No SDK code changes needed — PyArrow handles optional columns correctly. - 213 unit tests + 45 integration tests
v1.4.1 — 2026-03-31
Section titled “v1.4.1 — 2026-03-31”Python SDK v1.0.7 — Quality Gate
Section titled “Python SDK v1.0.7 — Quality Gate”- Integration test suite: 45 parametric E2E tests against the live API + AWC, covering every public function x every output mode (list, DataFrame, CSV, parquet)
- CI publish gate: integration tests must pass before PyPI publish on tag push
- Fix: parquet bytes→str: DataFrame columns from parquet now return
str, notbytes(PyArrowtypes_mapper) - Fix: climate dates tz-naive: climate
observation_dateindex stays tz-naive (calendar dates), not UTC - Fix: LOB numeric index: LOB
tscolumn correctly detected as numeric epoch, not parsed as date string - Fix: empty DataFrame NaN edge case: empty result sets no longer misclassify index timezone
- Fix: DataFrame immutability:
_apply_datetime_indexno longer mutates input DataFrame - CI security:
pypa/gh-action-pypi-publishpinned to commit SHA, publish step gated on tag ref - 206 unit tests + 45 integration tests
v1.4.0 — 2026-03-30
Section titled “v1.4.0 — 2026-03-30”Python SDK v1.0.6 — Ergonomics Rewrite
Section titled “Python SDK v1.0.6 — Ergonomics Rewrite”- Domain-split modules:
therminal.weather(WeatherHistory, WeatherLive) andtherminal.markets(MarketsClient) - Canonical names:
WeatherClientrenamed toWeatherHistory,LiveClientrenamed toWeatherLive - WeatherLive: Real-time METAR from AWC (aviationweather.gov), direct fetch with identical Observation schema to historical data
- Batch support:
live.current(["NYC", "ATL", "MDW"])makes one AWC request as_dataframe=Trueoncurrent()andlatest()- Relative humidity computed via Magnus formula (native Celsius, cross-checked against IEM for 18 stations)
- Feels-like temperature via full NWS algorithm (wind chill + Steadman + Rothfusz + adjustments)
- Precipitation mapped from AWC
precipfield - Peak wind gust/direction/time parsed from raw METAR
PK WNDremarks - Go-matched rounding ensures training/inference parity
- Batch support:
- Auto-pagination: JSON responses transparently paginated,
as_dataframe=Trueuses parquet for full datasets (no 50K JSON cap) - TherminalConfig:
~/.therminal.tomlconfig file with 4-layer resolution (file < env vars < kwargs) - Typed models: Frozen dataclasses with dict-style access (
obs["temp_f"],obs.get(),obs.temp_f) - Security hardening: guarded float() on all AWC numeric fields, direction validation, truncated unbounded strings
- Python 3.11+ required (dropped 3.10)
TherminalClientfacade preserved for backward compatibility- 206 tests, 80% coverage
v1.3.0 — 2026-03-26
Section titled “v1.3.0 — 2026-03-26”Limit Order Book (LOB)
Section titled “Limit Order Book (LOB)”GET /api/v1/lob— Reconstructed order book snapshots from Kalshi and Polymarket delta data- Parameters:
market,series,source(kalshi/polymarket),date/from/to,interval(1–3600s, default 60),levels(1–50, default 10) - Supports JSON, CSV, Parquet, and NDJSON output formats
- Singleflight deduplication for identical concurrent requests
- 4 concurrent LOB requests max (semaphore-bounded)
- Result caps: 50K JSON, 500K CSV/Parquet/NDJSON
NDJSON Format
Section titled “NDJSON Format”?format=ndjsonnow supported on candles, observations, and LOB endpoints- Newline-delimited JSON — one object per line, streamable
- Same 500K row cap as CSV/Parquet
- No pagination, no forward-fill (returns raw sparse data like CSV)
Python SDK v0.5.0
Section titled “Python SDK v0.5.0”client.lob()— LOB snapshots with full format support, DataFrame, save_pathLOBFeaturessklearn transformer — spread, mid, imbalance, depth, weighted_mid, pressure features with lookback aggregation- CLI:
therminal lob MARKET --date 2026-03-01 --interval 60
v1.2.0 — 2026-03-23
Section titled “v1.2.0 — 2026-03-23”1-Minute ASOS Observations (OMO)
Section titled “1-Minute ASOS Observations (OMO)”?resolution=1minon/api/v1/observationsreturns 1-minute ASOS data from NCEI (DSI-6406)- ~166M records, 2000–2026, 19 of 20 stations (NYC excluded — Central Park is not an airport ASOS)
- Response fields:
station_code,observed_at,temp_c,dewpoint_c,pressure1_inhg,pressure2_inhg,pressure3_inhg,precip_type,precip_in ?units=rejected with 400 forresolution=1min(temperatures always integer °C)?type=silently ignored forresolution=1min?format=csv|parquetand?columns=work normally
NCEI CLI Backfill
Section titled “NCEI CLI Backfill”- New report type
ncei_final(priority 2.5) on/api/v1/climate— GHCN-Daily CF6 first-published values from NCEI superghcnd diffs - Source tagged as
ncei
Python SDK v0.3.0
Section titled “Python SDK v0.3.0”- Added
resolutionparameter toobservations()—resolution="1min"for 1-minute ASOS data - CLI:
therminal observations STATION --resolution 1min
v1.1.0 — 2026-03-20
Section titled “v1.1.0 — 2026-03-20”Downloads rework
Section titled “Downloads rework”?format=json|csv|parqueton all data endpoints (candles, observations, climate)?columns=col1,col2for column selection in CSV/Parquet output- Removed old
/api/v1/download/*presigned URL endpoints - CSV streams with
Content-Dispositionheader for browser download - Parquet uses Zstd compression
Documentation
Section titled “Documentation”- Added interactive API playground on every endpoint page
- Added Data Sources page with full provenance details
- Added
llms.txtfor AI agent integration - Replaced splash homepage with introduction
- Fixed playground field alignment and prev/next button sizing
Python SDK v0.2.0
Section titled “Python SDK v0.2.0”- Added
formatandcolumnsparams tocandles(),observations(),climate() - Removed
download_parquet()(useformat="parquet"instead)
v1.0.0 — 2026-03-20
Section titled “v1.0.0 — 2026-03-20”Initial public release.
Endpoints
Section titled “Endpoints”GET /health— API health checkGET /api/v1/series— List and retrieve event seriesGET /api/v1/markets— List and retrieve prediction marketsGET /api/v1/candles— OHLCV candlestick data with forward-fill and aggregationGET /api/v1/observations— Weather observations (METAR/SPECI)GET /api/v1/climate— Daily climate reportsGET /api/v1/analysis/climate-gaps— Climate report gap analysisGET /api/v1/download/observations— Bulk observation parquet downloadGET /api/v1/download/candles— Bulk candle parquet downloadGET /api/v1/download/climate— Bulk climate parquet download
Features
Section titled “Features”- Hot/cold query routing (Supabase 14-day cache + DuckDB historical parquets)
- Forward-fill sparse candle data
- Candle aggregation (1min → hourly, daily)
- Unit conversion (
?units=raw|metric|imperial) - Timezone conversion (
?tz=UTC|station|<IANA>) - Presigned R2 URLs for bulk parquet downloads
- Per-IP rate limiting (100 req/s)
Python SDK
Section titled “Python SDK”therminal-pyv0.1.0 published on PyPI- All endpoints wrapped with optional DataFrame support
- CLI tool included (
pip install therminal-py[cli])