Implement scoped live 24h feed visibility

This commit is contained in:
dirtydishes 2026-05-04 05:52:38 -04:00
parent f28c8e641f
commit 48b0d980a6
11 changed files with 547 additions and 49 deletions

View file

@ -55,14 +55,20 @@ export type LiveGenericChannel = z.infer<typeof LiveGenericChannelSchema>;
export const LiveSubscriptionSchema = z.discriminatedUnion("channel", [
z.object({
channel: z.literal("options"),
filters: OptionFlowFiltersSchema.optional()
filters: OptionFlowFiltersSchema.optional(),
underlying_ids: z.array(z.string().min(1)).optional(),
option_contract_id: z.string().min(1).optional()
}),
z.object({
channel: z.literal("flow"),
filters: OptionFlowFiltersSchema.optional()
}),
z.object({
channel: z.enum(["nbbo", "equities", "equity-quotes", "equity-joins", "classifier-hits", "alerts", "inferred-dark"])
channel: z.enum(["nbbo", "equity-quotes", "equity-joins", "classifier-hits", "alerts", "inferred-dark"])
}),
z.object({
channel: z.literal("equities"),
underlying_ids: z.array(z.string().min(1)).optional()
}),
z.object({
channel: z.literal("equity-candles"),
@ -181,9 +187,23 @@ export type LiveServerMessage = z.infer<typeof LiveServerMessageSchema>;
export const getSubscriptionKey = (subscription: LiveSubscription): string => {
switch (subscription.channel) {
case "options":
case "options": {
const underlyings = subscription.underlying_ids?.length
? `|underlyings:${[...subscription.underlying_ids].sort().join(",")}`
: "";
const contract = subscription.option_contract_id
? `|contract:${subscription.option_contract_id}`
: "";
return `${subscription.channel}|${optionFlowFilterKey(subscription.filters)}${underlyings}${contract}`;
}
case "flow":
return `${subscription.channel}|${optionFlowFilterKey(subscription.filters)}`;
case "equities": {
const underlyings = subscription.underlying_ids?.length
? `|underlyings:${[...subscription.underlying_ids].sort().join(",")}`
: "";
return `${subscription.channel}${underlyings}`;
}
case "equity-candles":
return `${subscription.channel}|${subscription.underlying_id}|${subscription.interval_ms}`;
case "equity-overlay":

View file

@ -23,6 +23,19 @@ describe("live protocol types", () => {
).toBe(
'options|{"view":"signal","securityTypes":["stock"],"nbboSides":["A","AA"],"optionTypes":["call","put"],"minNotional":25000}'
);
expect(
getSubscriptionKey({
channel: "options",
filters: { view: "signal" },
underlying_ids: ["NVDA", "AAPL"],
option_contract_id: "AAPL-2025-01-17-200-C"
})
).toBe(
'options|{"view":"signal"}|underlyings:AAPL,NVDA|contract:AAPL-2025-01-17-200-C'
);
expect(getSubscriptionKey({ channel: "equities", underlying_ids: ["NVDA", "AAPL"] })).toBe(
"equities|underlyings:AAPL,NVDA"
);
expect(
getSubscriptionKey({
channel: "equity-candles",