Appearance
PutCallRatio
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
Per-underlying sentiment ratio aggregating call and put trade volume across the option chain. The analytic fans across every option on the requested symbol, accumulates volume and dollar premium per side, and emits one tick per (symbol, emission cadence) carrying:
call_volume/put_volume(contracts)call_premium/put_premium(dollars notional)pcr_volume = put_volume / call_volumepcr_premium = put_premium / call_premiumsigned_imbalance = (call_volume − put_volume) / (call_volume + put_volume)∈ [−1, +1]
Methodology
text
pcr_volume = put_volume / call_volume (contracts)
pcr_premium = put_premium / call_premium (dollars notional)
signed_imbalance = (call_volume − put_volume)
/ (call_volume + put_volume) ∈ [−1, +1]Classical interpretation: pcr_volume > 1.0 = bearish skew (more puts trading than calls); pcr_volume < 1.0 = bullish skew. The signed imbalance gives a single bounded number for cross-symbol comparison (+1 = pure call flow, −1 = pure put flow).
References:
- CBOE put/call ratio methodology — daily totals of put vs call volume across listed equity / index options.
- Hull, Options, Futures, and Other Derivatives (10th ed.) §10.3 — options-volume sentiment indicators.
Inputs
- Option
TradeTick(stock and index trades skipped). conditionsadmission policy filters OPRA non-regular prints (cancels, openings, late, halt-rule) before accumulation.
Output schema (PutCallRatioTick)
The field / type / description table below is regenerated from the PutCallRatioTick 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 |
|---|---|---|
symbol | Arc<str> | Underlying symbol. |
date | i32 | Trading session date (YYYYMMDD). |
ms_of_day | i32 | Milliseconds since midnight at emission time. |
call_volume | u64 | Total admitted call volume on the symbol so far this session (contracts). |
put_volume | u64 | Total admitted put volume on the symbol so far this session (contracts). |
call_premium | f64 | Call-side premium (dollars: price × size × 100). |
put_premium | f64 | Put-side premium (dollars). |
pcr_volume | f64 | put_volume / call_volume. Always finite: the ratio is undefined while no calls have traded this session, and undefined states suppress the emission — rows publish only when call_volume > 0. |
pcr_premium | f64 | put_premium / call_premium. Same definedness contract as [Self::pcr_volume]. |
signed_imbalance | f64 | (call_volume - put_volume) / (call_volume + put_volume). In [-1, +1]; +1 = pure call flow, -1 = pure put flow. |
Configuration (PutCallRatioRequest)
Regenerated from the PutCallRatioRequest Rust source — see the note above.
| Field | Type | Description |
|---|---|---|
contracts | SecurityFilter | Contracts the subscription tracks. Options only — stock trades on the same symbol are ignored. The institutional idiom is to subscribe by underlying symbol ([SecurityFilter::Symbols]) and let the engine fan out across the chain. |
conditions | ConditionPolicy | Trade-condition admission policy. Default [ConditionPolicy::OpraRegular] — excludes cancels, openings, late, halt-rule prints from the aggregation. |
venues | ExchangeFilter | Exchange / venue admission policy. |
emit | EmitPolicy | Emission policy. Default [EmitPolicy::OnEveryTick] — every admitted option trade fires one tick with the updated running aggregate. Switch to [EmitPolicy::OnClose] to fire one tick per bar-close boundary instead. |
Operational characteristics
- Per-tick latency. O(1) under the engine's single-writer per-subscription invariant — one hash-map lookup + two saturating-add operations per admitted trade.
- Allocation discipline. Aggregator entries are created at most once per symbol per subscription; per-tick path has no allocations.
- Emission cadence.
EmitPolicy::OnEveryTick(default) fires one tick per admitted trade with the updated running aggregate.EmitPolicy::OnClosefires one tick per bar-close boundary, deduped per(symbol, ms_of_day)to avoid wide-chain duplication. - 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):
print(
f"{tick.symbol} pcr_vol={tick.pcr_volume:.3f} "
f"imbalance={tick.signed_imbalance:+.3f}"
)
sub = client.live().put_call_ratio(["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().putCallRatio(["SPX"]).onEvent((tick) => {
console.log(
`${tick.symbol} pcrVol=${tick.pcrVolume.toFixed(3)} imbalance=${tick.signedImbalance.toFixed(3)}`,
);
});