Add smart-money option signal path and tape filters

This commit is contained in:
dirtydishes 2026-04-28 16:29:44 -04:00
parent 758f111d7e
commit 27b0a399e6
23 changed files with 1827 additions and 175 deletions

View file

@ -8,7 +8,21 @@ import {
describe("live protocol types", () => {
it("builds stable keys for generic and parameterized subscriptions", () => {
expect(getSubscriptionKey({ channel: "flow" })).toBe("flow");
expect(getSubscriptionKey({ channel: "flow" })).toBe("flow|{}");
expect(
getSubscriptionKey({
channel: "options",
filters: {
view: "signal",
securityTypes: ["stock"],
nbboSides: ["A", "AA"],
optionTypes: ["call", "put"],
minNotional: 25000
}
})
).toBe(
'options|{"view":"signal","securityTypes":["stock"],"nbboSides":["A","AA"],"optionTypes":["call","put"],"minNotional":25000}'
);
expect(
getSubscriptionKey({
channel: "equity-candles",
@ -25,7 +39,7 @@ describe("live protocol types", () => {
const parsed = LiveClientMessageSchema.parse({
op: "subscribe",
subscriptions: [
{ channel: "flow" },
{ channel: "flow", filters: { nbboSides: ["AA", "A"], minNotional: 50000 } },
{ channel: "equity-candles", underlying_id: "SPY", interval_ms: 60000 }
]
});

View file

@ -0,0 +1,132 @@
import { describe, expect, it } from "bun:test";
import {
deriveOptionPrintMetadata,
evaluateOptionSignal,
resolveSyntheticMarketModes,
type OptionsSignalConfig
} from "../src/options-flow";
const baseConfig: OptionsSignalConfig = {
mode: "smart-money",
minNotional: 10_000,
etfMinNotional: 50_000,
bidSideMinNotional: 25_000,
midMinNotional: 20_000,
missingNbboMinNotional: 50_000,
largePrintMinSize: 500,
largePrintMinNotional: 10_000,
sweepMinNotional: 25_000,
autoKeepMinNotional: 100_000,
nbboMaxAgeMs: 1_500,
etfUnderlyings: new Set(["SPY", "QQQ"])
};
describe("options-flow helpers", () => {
it("resolves synthetic modes with per-service overrides", () => {
expect(
resolveSyntheticMarketModes({
syntheticMarketMode: "active",
syntheticOptionsMode: "firehose"
})
).toEqual({
market: "active",
options: "firehose",
equities: "active"
});
});
it("derives underlying, notional, nbbo side, and etf metadata", () => {
const metadata = deriveOptionPrintMetadata(
{
option_contract_id: "SPY-2025-01-17-450-C",
price: 2.5,
size: 100,
ts: 5_000
},
{
bid: 2.3,
ask: 2.5,
ts: 4_500
},
baseConfig
);
expect(metadata.underlying_id).toBe("SPY");
expect(metadata.option_type).toBe("call");
expect(metadata.notional).toBe(25_000);
expect(metadata.nbbo_side).toBe("A");
expect(metadata.is_etf).toBe(true);
});
it("accepts and rejects smart-money thresholds at boundaries", () => {
const acceptedAsk = evaluateOptionSignal(
{
size: 100,
conditions: [],
underlying_id: "AAPL",
option_type: "call",
notional: 10_000,
nbbo_side: "A",
is_etf: false
},
baseConfig
);
expect(acceptedAsk.signalPass).toBe(true);
const rejectedLow = evaluateOptionSignal(
{
size: 100,
conditions: [],
underlying_id: "AAPL",
option_type: "call",
notional: 9_999,
nbbo_side: "A",
is_etf: false
},
baseConfig
);
expect(rejectedLow.signalPass).toBe(false);
const rejectedBid = evaluateOptionSignal(
{
size: 100,
conditions: [],
underlying_id: "AAPL",
option_type: "put",
notional: 24_999,
nbbo_side: "B",
is_etf: false
},
baseConfig
);
expect(rejectedBid.signalPass).toBe(false);
const acceptedSweep = evaluateOptionSignal(
{
size: 100,
conditions: ["SWEEP"],
underlying_id: "AAPL",
option_type: "call",
notional: 25_000,
nbbo_side: "MID",
is_etf: false
},
baseConfig
);
expect(acceptedSweep.signalPass).toBe(true);
const rejectedEtf = evaluateOptionSignal(
{
size: 100,
conditions: [],
underlying_id: "SPY",
option_type: "call",
notional: 49_999,
nbbo_side: "A",
is_etf: true
},
baseConfig
);
expect(rejectedEtf.signalPass).toBe(false);
});
});