Python SDK
Install
Section titled “Install”pip install therminal-py # corepip install therminal-py[pandas] # + DataFrame + Parquet supportpip install therminal-py[ml] # + scikit-learn ML featurespip install therminal-py[torch] # + PyTorch Datasetpip install therminal-py[cli] # + CLI toolpip install therminal-py[all] # pandas + ml + cliRequires Python 3.11+. Current version: v1.0.9. Published on PyPI.
What’s new in v1.0.9
Section titled “What’s new in v1.0.9”- Fix: parquet null-to-zero: Nullable observation fields (wind_gust_kt, feels_like_f, sky layers, etc.) now correctly produce
NaNin parquet DataFrames instead of being silently coerced to0. The API’s parquet schema now usesOptionalfor nullable columns. - 7 new regression tests for parquet null preservation
- 213 unit tests + 45 integration tests pass before publish
Quick example
Section titled “Quick example”from therminal.weather import WeatherHistory, WeatherLivefrom therminal.markets import MarketsClient
# Historical data (via therminal-api)weather = WeatherHistory()obs = weather.observations(station="NYC", units="metric", as_dataframe=True)
# Live METAR (direct from AWC — same schema as historical)live = WeatherLive()current = live.current("NYC")print(current[0].temp_f) # attribute accessprint(current[0]["temp_f"]) # dict access also works
# Batch: one AWC request for multiple stationsbatch = live.current(["NYC", "ATL", "MDW"])
# Market datamarkets = MarketsClient()candles = markets.candles(market="KXHIGHNY-26MAR20-T50", from_date="2026-03-01")Backward-compatible usage
Section titled “Backward-compatible usage”The TherminalClient facade still works exactly as before:
from therminal import TherminalClient
client = TherminalClient()candles = client.candles(market="KXHIGHNY-26MAR20-T50", from_date="2026-03-01")obs = client.observations(station="NYC", units="metric", as_dataframe=True)Configuration
Section titled “Configuration”Create ~/.therminal.toml to set defaults:
[defaults]units = "metric" # raw | metric | imperialtz = "UTC" # UTC | station | IANA namestation = "NYC" # default station for weather calls
[api]base_url = "https://api.mostlyright.xyz"timeout = 30.0
[live]timeout = 10.0max_retries = 3Resolution order (last wins):
- Built-in defaults (
units="raw",tz="UTC") ~/.therminal.toml(or$THERMINAL_CONFIGpath)- Environment variables:
THERMINAL_UNITS,THERMINAL_TZ,THERMINAL_STATION - Per-call keyword arguments
from therminal.config import TherminalConfig
# Auto-loads from ~/.therminal.tomlconfig = TherminalConfig()
# Or explicitconfig = TherminalConfig(units="metric", tz="America/New_York")
# Pass to any clientweather = WeatherHistory(config=config)live = WeatherLive(config=config)Live METAR (AWC direct)
Section titled “Live METAR (AWC direct)”WeatherLive fetches real-time METAR observations directly from the Aviation Weather Center. The returned Observation objects are schema-identical to what WeatherHistory.observations() returns, so your training features and live signals use the same types.
from therminal.weather import WeatherLive
live = WeatherLive()
# Latest observation for one stationobs = live.current("NYC")
# Batch: multiple stations in one requestobs = live.current(["NYC", "ATL", "MDW", "LAX"])
# Last 3 hours of observationshistory = live.latest("NYC", hours=3)
# With unit conversion (same as API)obs_metric = live.current("NYC", units="metric")| Method | Description |
|---|---|
current(station) | Latest METAR. Accepts str or list[str] for batch. |
latest(station, hours=1) | Recent observations (1-360 hours). |
Both methods accept optional units and tz overrides.
Typed models
Section titled “Typed models”All API responses return frozen dataclasses with both attribute and dict-style access:
obs = weather.observations(station="NYC")[0]
# Attribute accessprint(obs.temp_f)print(obs.station_code)
# Dict-style access (backward compatible)print(obs["temp_f"])print(obs.get("wind_speed_kt", 0))print("raw_metar" in obs)
# Convert to dictd = obs.to_dict() # all 29 fields, None values includedAvailable models:
Observation— METAR/SPECI weather data (29 fields)Candle— OHLCV market dataMarket,Series— market metadataClimate— daily high/low reportsLOBSnapshot,Level— order book data
Export formats
Section titled “Export formats”All data methods support format and columns:
# Save as CSV with specific columnspath = weather.observations( station="NYC", from_date="2024-01-01", to_date="2024-12-31", format="csv", columns=["observed_at", "temp_f", "wind_speed_kt"], save_path="nyc_2024.csv",)
# Save as Parquetpath = markets.candles( market="KXHIGHNY-26MAR20-T50", format="parquet", save_path="candles.parquet",)
# Parquet directly into DataFramedf = weather.observations(station="NYC", format="parquet", as_dataframe=True)| Parameter | Type | Description |
|---|---|---|
format | str | None (JSON default), "csv", "parquet" |
columns | list | Column names to include (e.g., ["temp_f", "wind_speed_kt"]) |
save_path | str/Path | File path for CSV/Parquet output |
as_dataframe | bool | Return Pandas DataFrame (JSON or load saved Parquet) |
therminal healththerminal series --limit 5therminal candles KXHIGHNY-26MAR20-T50 --from 2026-03-01 --limit 10therminal observations NYC --units metrictherminal observations LAX --resolution 1mintherminal climate NYC --from 2026-03-15 --to 2026-03-20therminal lob KXHIGHNY-26MAR04-B51 --date 2026-03-01ML Features (scikit-learn)
Section titled “ML Features (scikit-learn)”pip install therminal-py[ml] adds WeatherFeatures — a scikit-learn Transformer that fetches weather data and engineers features for supervised learning.
from therminal.ml import WeatherFeaturesfrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import StandardScalerfrom sklearn.ensemble import GradientBoostingRegressor
pipe = make_pipeline( WeatherFeatures(station="ATL", sources=["omo", "metar"], lookback_hours=24), StandardScaler(), GradientBoostingRegressor(),)pipe.fit(dates_train, y_train)pipe.predict(dates_test)Configuration
Section titled “Configuration”| Parameter | Type | Default | Description |
|---|---|---|---|
station | str | "ATL" | Station code |
sources | list | ["omo", "metar"] | Data sources: "omo" (1-min ASOS), "metar" (hourly) |
lookback_hours | int | 24 | Hours of data before each target date |
omo_aggs | tuple | ("min","max","mean","std") | Aggregations on OMO numeric fields |
metar_fields | tuple | all available | METAR fields to include |
include_calendar | bool | True | Day-of-year, month, weekday + cyclical encodings |
cache | bool | True | Cache API responses locally (1h TTL) |
LOB Features
Section titled “LOB Features”from therminal.ml import LOBFeaturesfrom sklearn.pipeline import make_pipelinefrom sklearn.ensemble import GradientBoostingClassifier
pipe = make_pipeline( LOBFeatures(market="KXHIGHNY-26MAR04-B51", interval=60, levels=10), GradientBoostingClassifier(),)PyTorch (optional)
Section titled “PyTorch (optional)”pip install therminal-py[torch]
from therminal.ml import TherminalDatasetimport torch
ds = TherminalDataset(dates=dates, station="ATL", lookback_hours=24)loader = torch.utils.data.DataLoader(ds, batch_size=32, shuffle=True)Error handling
Section titled “Error handling”from therminal import NotFoundError, RateLimitErrorfrom therminal.weather import WeatherHistoryimport time
weather = WeatherHistory()
try: data = weather.observations(station="NONEXISTENT")except NotFoundError: print("Station not found")except RateLimitError as e: time.sleep(e.retry_after)WeatherLive maps AWC errors to the same exception types:
- AWC 429 →
RateLimitError - AWC 5xx →
ServerError(retries automatically, max 3) - Timeout →
TherminalError - Unknown station → empty list (not an error)
Module reference
Section titled “Module reference”| Import | Class | Purpose |
|---|---|---|
therminal.weather | WeatherHistory | Historical observations, climate, climate gaps |
therminal.weather | WeatherLive | Real-time METAR from AWC |
therminal.markets | MarketsClient | Series, markets, candles, LOB |
therminal.config | TherminalConfig | SDK configuration |
therminal.models | Observation, Candle, Market, Series, Climate, LOBSnapshot | Typed data models |
therminal.ml | WeatherFeatures, LOBFeatures, TherminalDataset | ML transformers |
therminal | TherminalClient | Backward-compatible facade (composes Weather + Markets) |