Runbook: Listing a New Product

Last updated: 2026-06-09

This runbook covers the full lifecycle of listing a new product: specification, code changes, settlement plumbing, database updates, initial pricing, verification, and business go-live. The mechanical instrument-creation step is documented separately in the internal technical manual (Create new instruments) and is referenced from Phase 4 below.

Phase 1 — Product specification

Collect a complete specification from the business owner before writing any code. Required fields:

Field Example (WTIOIL-PERP)
Symbol WTIOIL-PERP
Description WTI Crude Oil Perpetual Future
Underlying benchmark NYMEX WTI Crude Oil futures daily settlement
Settlement data source Databento (CME daily settlement snapshot)
Contract mark price Average price on AX at 2:30pm ET
Contract size 1 barrel per contract
Tick size 0.001
Funding frequency Daily ~2:30pm ET
Margin 30% IM / 15% MM
Funding rate caps upper/lower pct
Roll schedule (futures-referencing perps) Monthly over 5 days starting 6th business day, 80/20 blend, 100% back contract by 10th
Category energy
Trading/settlement calendar CME holiday calendar

Warning: If the benchmark references a venue we don't already consume (e.g., ICE rather than CME), the settlement data source and holiday calendar are engineering work, not configuration — see Phase 2. Flag this in the spec review before committing to a listing date.

Phase 2 — Code changes

  1. Reserve an instrument ID. Add the new (id, symbol) pair to ax_sdk_internal::constants::INSTRUMENT_IDS (rs/sdk-internal/src/constants.rs). A version containing this constant must be built and deployable before the instrument can go live.

  2. Write the instrument spec. Add the product to the instrument spec YAML in each environment's config repository (instruments.yml). The schema is documented by example in rs/test-utils/fixtures/seed_instruments_spec.yaml and has two sections:

    For perps referencing a futures curve, include cme_future_config (root, roll_start_bd, roll_weights). For products with a Pyth estimated-price feed, include pyth_config.

  3. Assign a routing key (EP3 partition). The routing_key controls which internal EP3 partition the instrument's order flow lands on.

    Warning: Do not default to the category-wide routing keys (ENERGY, EQUITYPERP, …). They concentrate unrelated instruments onto the same partition and have become a load problem. Use the routing-key rebalance planner (admin-cli instruments plan-routing-keys, PR #2085) to pick the lowest-load partition, or — until that lands — manually choose a routing key that does not share a partition with other high-volume instruments.

  4. Check whether the product introduces a new category or calendar. Category determines the mark window shape (rs/sdk-internal/funding-and-settlement/src/mark_window.rs: 5-minute trailing for futures/equities/energy, ±3-minute centered for FX/metals) and which holiday calendar file the settlement engine uses (SETTLEMENT_ENGINE_<CATEGORY>_HOLIDAYS_FILE).

    If the product trades on a calendar different from its category's existing calendar (e.g., an ICE-referencing product in the energy category, which currently maps to the CME holiday file), the settlement engine needs a code change to support a per-instrument calendar override.

  5. Build and deploy. Ship the constants change (and any settlement-engine changes) through the normal release process so the target environment's .env points at a version that knows the new instrument ID.

Phase 3 — Settlement source and estimated funding

  1. Confirm a settlement price downloader exists. The settlement engine sources daily benchmark prices per asset class (rs/settlement-engine/src/downloaders/): Databento for CME futures and US equities, WMR for FX and metals, Ornn for compute. If the benchmark needs a new source (new venue, new vendor), that downloader must be built, licensed, and deployed before listing.

  2. Generate the roll schedule (futures-referencing perps only):

    settlement-engine cme-future generate-roll-schedule \
      --symbol <SYMBOL> --start-date <LIST_DATE> --end-date <HORIZON>

    Insert the generated rows into the cme_future_roll_schedule Postgres table. The blended benchmark price is undefined on any date missing a roll schedule row, so generate well past the listing horizon and extend before it runs out.

  3. Verify benchmark prices are flowing. Before listing day, confirm rows appear in ClickHouse:

    SELECT * FROM ax.benchmark_prices
    WHERE symbol = '<SYMBOL>' ORDER BY benchmark_time DESC LIMIT 5
  4. Verify estimated funding publishes. The settlement engine publishes estimated-funding-rate:<SYMBOL> to Redis every 60 seconds (rs/settlement-engine/src/estimated_funding.rs). This requires a live index/estimated price (e.g., pyth_config). Confirm the key updates once the instrument is created.

Phase 4 — Create the instrument

Follow Create new instruments: preview with admin_cli instruments sync --schema …, review the diff against both EP3 and Postgres, then re-run with --actually. This creates the EP3 product/instrument and the instruments row in Postgres.

Phase 5 — Initial settlement price

Warning: Do not open the instrument for trading before this step. The initial mark price falls back to the last settlement price; without one, margining and liquidation math on day one is garbage.

Confirm a benchmark price exists in ClickHouse (Phase 3), then set the initial settlement price in EP3:

[ec2-user@ax-demo] $ run admin_cli ep3 update-settlement-price <SYMBOL> <price>

Sanity-check the resulting mark price in the GUI or via the API before proceeding.

Phase 6 — Verification (demo first)

Run the full listing on demo before prod. Verify:

  1. Instrument appears in EP3 with the expected state and on the intended partition.
  2. Mark price is sane (matches the initial settlement price before any trading).
  3. Estimated funding rate is publishing and plausible.
  4. A test order can be placed, filled, and margined correctly.
  5. The first scheduled settlement/funding run completes and produces sensible funding transactions.
  6. GUI and public market data show the product correctly.

Phase 7 — Business coordination and go-live

These tracks should start in parallel with the engineering work, not after it:

  1. Market maker and customer readiness. Identify which MMs and customers want to trade the product at launch. Confirm MM connectivity, risk limits, and quoting obligations for the new symbol before the listing date. A product that lists with an empty book is worse than one that lists a week later.

  2. Marketing materials. Produce the launch announcement. Current practice is Hyperframes-generated launch videos (see the architect-xyz/hyperframes-videos repo: attach the Hyperframes skill plus product UI captures, prompt for a short launch video).

  3. Public documentation. Add the contract specification to the public docs (docs/public/guides/perpetual-futures/contract-specs.mdx) and include the listing in the public changelog.

  4. Open for trading. At the announced listing time, transition the instrument to Open in EP3 (optionally via PreOpen). Watch the first funding cycle end-to-end.