Skip to content

SPAN Margin

Family: Risk

What it computes

Emits SpanMarginTick ticks carrying scanning_risk, total_initial_margin off contract + spot + IV.

Available on the live, historical, and replay drives.

Methodology

OCC SPAN 16-scenario grid.

See the methodology overview for the citation index.

Inputs

Contract + spot + IV.

Key outputs

Scanning_risk, total_initial_margin. The full field set is in the tick table below.

Output schema (SpanMarginTick)

The field / type / description table below is regenerated from the SpanMarginTick Rust source by docs-site/scripts/inject-doc-tables.ts on every npm run docs:build. Do not hand-edit between the sentinels.

FieldTypeDescription
contractContractResolved option contract metadata (symbol, expiration, side, strike). Subscribers identify the option by these fields — the wire-level contract id is engine-internal and is not surfaced here.
datei32Trading session date (YYYYMMDD).
ms_of_dayi32Milliseconds since midnight at emission time.
rootArc<str>Underlying symbol (interned). Provided alongside the contract projection so downstream consumers can group margin telemetry by root without unpacking Contract.
expirationi32Option expiration date (YYYYMMDD) projected off the contract.
right&'static strOption right — "C" for calls, "P" for puts.
strikef64Strike price in dollars.
current_pricef64Current option mid ((bid + ask) / 2) used as the baseline price for the scenario comparison.
scanning_risk_per_contractf64SPAN scanning risk — the maximum loss (in dollars per contract) across the sixteen-scenario grid. Positive when at least one scenario produces a loss; zero when every scenario improves the position's value.
short_option_min_per_contractf64Short-option-minimum floor (in dollars per contract). Equal to [SpanMarginParams::short_option_min] for every option, surfaced explicitly so margin-engine consumers can audit the floor.
total_initial_margin_per_contractf64Total per-contract initial margin estimate (max(scanning_risk, 0) + short_option_min).
worst_scenarioArc<str>Human-readable label for the worst scenario, formatted as "spot{±N}% vol{±M}" (e.g. "spot-3% vol+1"). Treasury teams reconcile this against the broker's printed margin call to confirm the scan grid is targeting the same tail.

Configuration (SpanMarginParams)

Regenerated from the SpanMarginParams Rust source — see the note above.

FieldTypeDescription
contractsSecurityFilterContracts the subscription tracks. Include the underlying stock contract so the per-symbol spot cache seats from underlying trades.
conditionsConditionPolicyTrade-condition admission policy applied to admitted option NBBO quotes (the bid-condition byte is gated through the same OPRA admission policy the per-trade conditions use).
venuesExchangeFilterExchange / venue admission policy.
rateArc<dyn RateService>Risk-free rate provider. Looked up per emission with (event_date, expiry_date). Production deployments inject the curvekit-backed CurvekitRateService.
annual_dividendOption<f64>Optional override of the implied dividend yield (annual decimal). None falls back to the hosted convention of zero dividend yield.
dividend_cache`std::sync::Arc<crate::reference_data::dividend_yield::
DividendYieldCache>`Engine-wired per-symbol dividend-yield cache. Seated at subscribe time by DefaultSpec via wire_dividend_yield. Consulted on the dispatch path only when annual_dividend is None — the per-tick lookup resolves the continuous-dividend carry yield q = D / S from the live underlying spot the analytic already holds (O(1), lock-light, non-blocking). An explicit annual_dividend override always wins.
calendarArc<dyn MarketCalendar>Market calendar provider — derives the per-session option-trading cutoff used by the time-to-expiration helper.
spot_cacheSpotPriceCacheShared spot price cache, populated by the analytic from underlying stock trades and read by every option contract on the same subscription. Build via [new_spot_price_cache] and clone the returned Arc into the spec.
price_scan_pctf64Underlying price-scan range as a fraction of spot (e.g. 0.05 = ±5%). Multiplied against {-3, -2, -1, 0, +1, +2, +3} to produce the seven price-shock arms of the SPAN scan grid. Defaults to [DEFAULT_PRICE_SCAN_PCT].
vol_scan_pctf64Volatility-scan range as a fraction of the seated IV (e.g. 0.25 = ±25%). Multiplied against {-1, 0, +1} to produce the three vol-shock arms of the SPAN scan grid. Defaults to [DEFAULT_VOL_SCAN_PCT].
short_option_minf64Short-option minimum charge per contract, in dollars. Defaults to [DEFAULT_SHORT_OPTION_MIN_USD] ($25).
contract_multiplierf64Contract multiplier — shares per contract. Defaults to [DEFAULT_CONTRACT_MULTIPLIER] (100 for US equity options).
min_emit_interval_msi32Minimum interval between emissions per contract, in milliseconds. Defaults to 1_000 (one snapshot per second).

Example

Python

python
import kairos_thetadata as kt

client = kt.Client.connect(kt.Credentials.from_env())

def on_event(row):
    print(row)

sub = client.live().span_margin(["QQQ"]).on_event(on_event)
sub.wait(timeout_seconds=60.0)

TypeScript

typescript
import { Client, Credentials } from "kairos-thetadata";

const client = await Client.connect(Credentials.fromEnv());

await client
  .live()
  .spanMargin(["QQQ"])
  .onEvent((tick) => {
    console.log(tick);
  });

Rust

rust
// Cargo.toml:
//   kairos = "0.1"

use kairos::{Client, SpanMarginRow};

# fn run() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::connect(("me@example.com", "secret"))?;

let sub = client
    .live()
    .span_margin(["QQQ"])
    .on_event(|row: &SpanMarginRow| println!("scanning_risk={} total_initial_margin={}", row.scanning_risk_per_contract, row.total_initial_margin_per_contract))?;
// ... later ...
sub.unsubscribe();
# Ok(())
# }

Proprietary. All rights reserved.