SPB Git forge

spb/hfmarketdata

Public

Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)

127commits 1branches 0releases
24.7 MBsize
maindefault branch
11 days agolast push
JavaScript 53.7% Python 38.3% CSS 4.6% TypeScript 3.1%

# name: hfmd-term-structure description: Fetch and analyse a futures term structure (curve) from HF Market Data — contango vs backwardation, spreads and annualised roll yield between contracts, curve shape changes between two dates, with a chart. Use when the user asks about the futures curve, contango/backwardation, calendar spreads, roll yield or "plot the CL/NG/VX term structure".

# hfmd-term-structure

The term structure is the set of prices of all listed contracts of one root on one day, ordered by expiry. Its slope is the market's price for time: storage, financing, convenience yield and expected supply.

# Vocabulary

  • Contango: later contracts priced above nearer ones (upward slope). Normal for storable commodities (storage + financing cost) and for VIX most of the time. A long rolling position pays the roll (negative roll yield).
  • Backwardation: later contracts below nearer ones (downward slope). Signals tightness / high convenience yield (e.g. CL in 2022). Long rollers earn the roll.
  • Spread (M2 − M1) in price and in %; annualised roll yield ≈ −(M2 − M1)/M1 × 365/days between expiries (positive = the roll pays you).
  • Curves can be humped (NG winter premium, ZC harvest lows): describe by segment.

# When to use

  • "Plot me the CL term structure", "is natural gas in contango?", "how did the curve change since January?", "what's the VX roll cost right now?"

# Steps

  1. Get the curve: python3 scripts/term_structure.py --root CL [--as-of 2025-09-01] [--compare 2025-01-02] --plot cl_curve.png
    • calls /v1/futures/{root}/term-structure?as_of= (v2). If the endpoint is not deployed (404) the script rebuilds the curve from /v1/futures/{root}/contracts + each contract's last close on as_of (one request per contract — API key recommended).
    • prints: as-of date actually used, contracts with expiry / days-to-expiry / price / spread vs front (points and %) / annualised roll yield per leg / volume / OI, then the verdict (contango, backwardation or mixed with the segments), slope statistics (front–6th %, avg annualised carry), and — with --compare — the parallel shift, twist (front vs back change) and which legs moved most.
  2. Interpret in the user's context (hedger vs long-only roller vs spread trader) using only the numbers printed. Note if a leg has no price (illiquid deferred months) — it is left blank, not interpolated.
  3. Chart: price vs expiry (x = expiry date), both dates when --compare, front-month annotated.

# Examples

bash
python3 scripts/term_structure.py --root CL --plot cl.png
python3 scripts/term_structure.py --root NG --as-of 2025-08-29 --compare 2025-02-28 --plot ng_vs.png
python3 scripts/term_structure.py --root VX --depth 8 --json vx.json      # machine-readable
python3 scripts/term_structure.py --root ES --as-of 2024-06-14             # equity index: slope ≈ rates − dividends

# Gotchas

  • Quote the as-of date the API used (meta.as_of): asking for a weekend returns the previous session.
  • Deferred contracts often have zero volume — their settlement is an exchange mark; say so when OI is tiny.
  • Days-to-expiry uses the contract's expiration_date (rule-based or from data when the rule is unknown — expiration_source says which).
  • Equity index curves (ES, NQ) are about financing minus dividends, not storage; VX is about the variance risk premium — do not talk about "inventories" there.
  • Compare curves in percent of the front, not points, across dates when the price level moved a lot.