Appearance
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.
| Field | Type | Description |
|---|---|---|
root | Arc<str> | Underlying symbol. |
date | i32 | Trading session date (YYYYMMDD). |
ms_of_day | i32 | Milliseconds since midnight at emission time. |
expiration | i32 | Expiration date (YYYYMMDD). |
dte | i32 | Calendar days from date to expiration. |
strike | f64 | Strike (USD). |
right | char | The 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). |
spot | f64 | Spot price used in the edge arithmetic. f64::NAN when no underlying trade has landed yet on the session. |
rate | f64 | Risk-free rate used. f64::NAN when the rate provider returned None. |
t_years | f64 | Year-fraction time-to-expiry. |
call_mid | f64 | Call mid at strike. |
put_mid | f64 | Put mid at strike. |
edge_conversion | f64 | Conversion 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_reverse | f64 | Reverse-conversion edge: -edge_conversion. Positive values are arbitrage opportunities in the reverse direction. |
direction | &'static str | Which side dominates: "Conversion" if edge_conversion >= edge_reverse, "Reverse" otherwise. |
Configuration (ConversionArbParams)
Regenerated from the ConversionArbParams Rust source — see the note above.
| Field | Type | Description |
|---|---|---|
contracts | SecurityFilter | Contracts the subscription tracks. |
rate | Arc<dyn RateService> | Risk-free rate provider — used in the parity discount factor. |
annual_dividend | Option<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. | |
venues | ExchangeFilter | Exchange / venue admission policy. |
emit | EmitPolicy | Emission 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_usd | f64 | Edge magnitude threshold (USD per share). The analytic emits when `max( |
spot_cache | SpotPriceCache | Shared spot price cache. |
calendar | Arc<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(())
# }