Skip to content

Conversion Arb

Family: Stat-arb

What it computes

Emits ConversionArbTick ticks carrying edge_conv / reverse, direction off chain + spot + r + div.

Available on the live, historical, and replay drives.

Methodology

C − P − S + (K + D) · e^(−rT) edge detector.

See the methodology overview for the citation index.

Inputs

Chain + spot + r + div.

Key outputs

Edge_conv / reverse, direction. The full field set is in the tick table below.

Output schema (ConversionArbTick)

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

FieldTypeDescription
rootArc<str>Underlying symbol.
datei32Trading session date (YYYYMMDD).
ms_of_dayi32Milliseconds since midnight at emission time.
expirationi32Expiration date (YYYYMMDD).
dtei32Calendar days from date to expiration.
strikef64Strike (USD).
rightcharThe option leg that triggered the emission (the strike's paired call + put both pass into the edge formula; this records which side's Quote produced the inspection — useful for downstream consumers correlating against the tape).
spotf64Spot price used in the edge arithmetic. f64::NAN when no underlying trade has landed yet on the session.
ratef64Risk-free rate used. f64::NAN when the rate provider returned None.
t_yearsf64Year-fraction time-to-expiry.
call_midf64Call mid at strike.
put_midf64Put mid at strike.
edge_conversionf64Conversion edge: C - P - S + (K + D) · e^(-rT). Positive values are arbitrage opportunities in the conversion direction: discounted (strike + dividend PV) exceeds the net cost of synthesising long stock at K via the option pair.
edge_reversef64Reverse-conversion edge: -edge_conversion. Positive values are arbitrage opportunities in the reverse direction.
direction&'static strWhich side dominates: "Conversion" if edge_conversion >= edge_reverse, "Reverse" otherwise.

Configuration (ConversionArbParams)

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

FieldTypeDescription
contractsSecurityFilterContracts the subscription tracks.
rateArc<dyn RateService>Risk-free rate provider — used in the parity discount factor.
annual_dividendOption<f64>Optional continuous-dividend yield. None falls back to zero — i.e. the per-strike implied-dividend term defaults out. Set the institutional-grade input by subscribing to the sibling implied_dividend analytic and feeding the per-(symbol, expiration) PV back as a Some(...) override on this spec.
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, expiration, strike, right): the parity edge is a property of the whole chain snapshot, so the per-second event-time cadence carries the full signal without paying a chain inspection per inbound quote. OnEveryTick fires per admitted Quote when the threshold clears; OnClose accumulates and fires on watermark.
threshold_usdf64Edge magnitude threshold (USD per share). The analytic emits when `max(
spot_cacheSpotPriceCacheShared spot price cache.
calendarArc<dyn MarketCalendar>Market calendar provider.

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().conversion_arb(["SPX"]).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()
  .conversionArb(["SPX"])
  .onEvent((tick) => {
    console.log(tick);
  });

Rust

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

use kairos::{Client, ConversionArbRow};

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

let sub = client
    .live()
    .conversion_arb(["SPX"])
    .on_event(|row: &ConversionArbRow| {
        println!("spot={} strike={}", row.spot, row.strike)
    })?;
// ... later ...
sub.unsubscribe();
# Ok(())
# }

Proprietary. All rights reserved.