Add multi-leg structure tagging for flow packets

This commit is contained in:
dirtydishes 2025-12-30 13:33:50 -05:00
parent 163ab1039e
commit 0b0ffa651e
8 changed files with 291 additions and 93 deletions

View file

@ -1,11 +1,5 @@
import type { ClassifierHit, FlowPacket } from "@islandflow/types";
type ParsedContract = {
root: string;
expiry: string;
strike: number;
right: "C" | "P";
};
import { parseContractId, type ParsedContract } from "./contracts";
export type ClassifierConfig = {
sweepMinPremium: number;
@ -32,81 +26,6 @@ const formatUsd = (value: number): string => {
return `$${value.toFixed(2)}`;
};
const parseDashedContract = (value: string): ParsedContract | null => {
const parts = value.split("-");
if (parts.length < 6) {
return null;
}
const rightRaw = parts.at(-1) ?? "";
if (rightRaw !== "C" && rightRaw !== "P") {
return null;
}
const strikeRaw = parts.at(-2) ?? "";
const strike = Number(strikeRaw);
const expiryParts = parts.slice(-5, -2);
const expiry = expiryParts.join("-");
const root = parts.slice(0, -5).join("-");
if (!root || !expiry || !Number.isFinite(strike)) {
return null;
}
return {
root,
expiry,
strike,
right: rightRaw
};
};
const parseOccContract = (value: string): ParsedContract | null => {
if (value.length < 15) {
return null;
}
const tail = value.slice(-15);
const root = value.slice(0, -15).trim();
const expiryRaw = tail.slice(0, 6);
const right = tail.slice(6, 7);
const strikeRaw = tail.slice(7);
if (!/^\d{6}$/.test(expiryRaw) || !/^\d{8}$/.test(strikeRaw)) {
return null;
}
if (right !== "C" && right !== "P") {
return null;
}
const year = 2000 + Number(expiryRaw.slice(0, 2));
const month = Number(expiryRaw.slice(2, 4)) - 1;
const day = Number(expiryRaw.slice(4, 6));
const expiryDate = new Date(Date.UTC(year, month, day));
const expiry = expiryDate.toISOString().slice(0, 10);
const strike = Number(strikeRaw) / 1000;
if (!root || !Number.isFinite(strike)) {
return null;
}
return {
root,
expiry,
strike,
right
};
};
const parseContractId = (value: string | undefined): ParsedContract | null => {
if (!value) {
return null;
}
return parseDashedContract(value) ?? parseOccContract(value);
};
const getNumberFeature = (packet: FlowPacket, key: string): number => {
const value = packet.features[key];
return typeof value === "number" && Number.isFinite(value) ? value : 0;