Skip to content

IvSkew

Preview on the public Rust client. The analytic ships in the engine and is reachable today through the Python wheel and the TypeScript / Node addon; a per-analytic builder on the public Rust thin client (kairos::Client) is tracked on the roadmap. The output tick schema below is stable.

What it computes

For each subscribed underlying, per-expiration 25-delta risk-reversal and 25-delta butterfly skew metrics — the same quote-quartet Bloomberg's OVDV and SKEW pages render against the chain.

text
RR_25  =  IV(call, Δ = +0.25)  −  IV(put, Δ = −0.25)
BF_25  = (IV(call, Δ = +0.25)  +  IV(put, Δ = −0.25)) / 2  −  IV(ATM)

One tick per (symbol, watermark) with one IvSkewLeg per forward expiration on the chain, sorted ascending by tenor.

Methodology

For each (symbol, expiration) pair:

  1. Resolves three legs from the chain registry: the +25Δ call, the −25Δ put, the ATM call.
  2. Solves implied volatility on each leg via the same closed-form Black–Scholes bisection used by Greeks.
  3. Computes the risk-reversal and butterfly per the formulas above.

References:

  • Black & Scholes (1973). The Pricing of Options and Corporate Liabilities. Journal of Political Economy 81(3): 637–654.
  • Hull, Options, Futures, and Other Derivatives (10th ed.) §20.4 — volatility smile / skew.
  • Derman & Kani (1994). Riding on a Smile. RISK 7(2): 32–39 — local volatility surfaces.

See /methodology/black-scholes for the formula derivation.

Inputs

  • Option QuoteTick on the three legs per expiration.
  • Stock TradeTick (populates the shared engine spot-price cache).
  • A engine rate provider and optional annual_dividend.
  • A engine market calendar for the option-trading cutoff per session.

Per-expiration leg (IvSkewLeg)

Each legs[i] row carries the expiration, tenor_days, atm_iv, iv_25d_call, iv_25d_put, rr_25d (risk-reversal), and bf_25d (butterfly). f64::NAN propagates on legs whose required strike has not yet quoted.

Output schema (IvSkewTick)

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

FieldTypeDescription
symbolArc<str>Underlying symbol.
datei32Trading-session date (YYYYMMDD).
ms_of_dayi32ms_of_day at emission time.
spotf64Spot used for IV solving.
legsVec<IvSkewLeg>Per-expiration skew ladder. Ordered ascending by tenor_days.

Configuration (IvSkewRequest)

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

FieldTypeDescription
contractsSecurityFilterContracts the subscription tracks.
rateArc<dyn RateService>Risk-free rate provider.
annual_dividendOption<f64>Optional continuous dividend yield. None falls back to zero.
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.
venuesExchangeFilterExchange / venue admission policy.
emitEmitPolicyEmission policy. Defaults to [EmitPolicy::OnExchangeInterval] at one row per second per symbol: the per-expiration skew ladder is a property of the whole chain snapshot, so the per-second event-time cadence carries the full signal without paying a chain sweep per inbound quote. OnEveryTick fires per admitted Quote; OnClose accumulates and fires on watermark.
target_deltaf64Wing-delta magnitude the picker targets. Default [DEFAULT_TARGET_DELTA] (0.25). The 25-delta convention is the institutional standard (Bloomberg, trade-alert.com, Hull §19.6); raising to 0.10 produces a 10Δ wing sample, lowering to 0.40 produces a near-ATM sample. Calls are picked at +target_delta, puts at -target_delta. Must lie in (0, 0.5) — outside that range the picker silently falls back to the default since a wing delta ≥ 0.5 would collide with the ATM strike.
delta_tolerancef64Acceptance band around target_delta. Default [DEFAULT_DELTA_TOLERANCE] (0.05). A listed contract is admitted as the wing sample only when its delta lies within target_delta ± delta_tolerance. Sparse legs where no contract sits inside the band drop out cleanly rather than reporting an off-delta sample. A non-positive / non-finite value is treated as "exact match only" — useful for tightly-granulated synthetic chains in testing; in production this would mostly suppress emissions because no live contract hits the target exactly.
spot_cacheSpotPriceCacheShared spot price cache.
calendarArc<dyn MarketCalendar>Market calendar provider.

Operational characteristics

  • Per-tick latency. Three Black–Scholes bisections per leg — bounded by chain forward-expiration count.
  • Allocation discipline. Per-symbol leg vector reused across emissions; one allocation per tick for the consumer-facing payload.
  • Replay parity. Deterministic given identical input tick order.

Example

Preview. This analytic ships in the engine and is reachable today through the Python wheel and the TypeScript / Node addon. A per-analytic builder on the public Rust thin client (kairos::Client) is tracked on the roadmap — bare-string symbol filters passed to the analytic accessor will match the other analytics already exposed there. The output tick rows are stable and documented above.

Cross-language surface

python
import kairos_thetadata as kt

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

def on_event(tick):
    for leg in tick.legs:
        print(
            f"{tick.symbol} {leg.expiration} "
            f"rr25={leg.rr_25d:+.3f} bf25={leg.bf_25d:+.3f}"
        )

sub = client.live().iv_skew(["SPX"]).on_event(on_event)
sub.wait(timeout_seconds=60.0)
typescript
import { Client, Credentials } from "kairos-thetadata";

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

const sub = await client.live().ivSkew(["SPX"]).onEvent((tick) => {
  for (const leg of tick.legs) {
    console.log(
      `${tick.symbol} ${leg.expiration} ` +
        `rr25=${leg.rr25d.toFixed(3)} bf25=${leg.bf25d.toFixed(3)}`,
    );
  }
});

Proprietary. All rights reserved.