153 lines
4.8 KiB
TypeScript
153 lines
4.8 KiB
TypeScript
import { describe, expect, it } from "bun:test";
|
|
import { buildSmartMoneyEventFromPacket } from "../src/parent-events";
|
|
import {
|
|
buildSmartMoneyEventsForReplay,
|
|
compareSmartMoneyReplayOutputs,
|
|
evaluateSmartMoneyEvents
|
|
} from "../src/smart-money-evaluation";
|
|
import { buildFlowPacket } from "./helpers";
|
|
|
|
const institutionalPacket = buildFlowPacket({
|
|
id: "flowpacket:eval-institutional",
|
|
seq: 2,
|
|
source_ts: Date.parse("2025-01-15T15:00:01Z"),
|
|
features: {
|
|
option_contract_id: "SPY-2025-02-21-450-C",
|
|
underlying_id: "SPY",
|
|
count: 8,
|
|
window_ms: 450,
|
|
total_size: 2200,
|
|
total_premium: 180_000,
|
|
total_notional: 18_000_000,
|
|
nbbo_coverage_ratio: 0.92,
|
|
nbbo_aggressive_ratio: 0.82,
|
|
nbbo_aggressive_buy_ratio: 0.78,
|
|
nbbo_aggressive_sell_ratio: 0.04,
|
|
nbbo_inside_ratio: 0.08,
|
|
underlying_mid: 448
|
|
}
|
|
});
|
|
|
|
const eventDrivenPacket = buildFlowPacket({
|
|
id: "flowpacket:eval-event-driven",
|
|
seq: 1,
|
|
source_ts: Date.parse("2025-01-15T15:00:00Z"),
|
|
features: {
|
|
option_contract_id: "AAPL-2025-02-07-225-C",
|
|
underlying_id: "AAPL",
|
|
count: 1,
|
|
window_ms: 450,
|
|
total_size: 1800,
|
|
total_premium: 160_000,
|
|
total_notional: 16_000_000,
|
|
nbbo_coverage_ratio: 0.5,
|
|
nbbo_aggressive_ratio: 0.4,
|
|
nbbo_aggressive_buy_ratio: 0.4,
|
|
nbbo_aggressive_sell_ratio: 0.1,
|
|
nbbo_inside_ratio: 0.08,
|
|
underlying_mid: 224
|
|
}
|
|
});
|
|
|
|
const stalePacket = buildFlowPacket({
|
|
id: "flowpacket:eval-stale",
|
|
seq: 3,
|
|
source_ts: Date.parse("2025-01-15T15:00:02Z"),
|
|
features: {
|
|
option_contract_id: "SPY-2025-02-21-450-C",
|
|
underlying_id: "SPY",
|
|
count: 8,
|
|
window_ms: 450,
|
|
total_size: 2200,
|
|
total_premium: 180_000,
|
|
nbbo_coverage_ratio: 0.1,
|
|
nbbo_missing_count: 8
|
|
}
|
|
});
|
|
|
|
const calendarOptions = {
|
|
"flowpacket:eval-event-driven": {
|
|
eventCalendarMatch: {
|
|
underlying_id: "AAPL",
|
|
event_ts: Date.parse("2025-01-31T21:00:00Z"),
|
|
event_kind: "earnings",
|
|
announced_ts: Date.parse("2024-12-20T21:00:00Z"),
|
|
days_to_event: 16.25
|
|
}
|
|
}
|
|
};
|
|
|
|
describe("smart money evaluation utilities", () => {
|
|
it("compares replay-style live and batch outputs with stable event signatures", () => {
|
|
const liveEvents = [institutionalPacket, eventDrivenPacket, stalePacket].map((packet) =>
|
|
buildSmartMoneyEventFromPacket(packet, calendarOptions[packet.id])
|
|
);
|
|
const batchEvents = buildSmartMoneyEventsForReplay(
|
|
[stalePacket, institutionalPacket, eventDrivenPacket],
|
|
calendarOptions
|
|
);
|
|
|
|
const report = compareSmartMoneyReplayOutputs(liveEvents, batchEvents);
|
|
expect(report.consistent).toBe(true);
|
|
expect(report.live_count).toBe(3);
|
|
expect(report.batch_count).toBe(3);
|
|
expect(report.matched_count).toBe(3);
|
|
expect(report.mismatches).toEqual([]);
|
|
});
|
|
|
|
it("reports signature mismatches when live and batch scoring diverge", () => {
|
|
const liveEvent = buildSmartMoneyEventFromPacket(institutionalPacket);
|
|
const batchEvent = {
|
|
...liveEvent,
|
|
primary_profile_id: "retail_whale" as const
|
|
};
|
|
|
|
const report = compareSmartMoneyReplayOutputs([liveEvent], [batchEvent]);
|
|
expect(report.consistent).toBe(false);
|
|
expect(report.mismatches).toHaveLength(1);
|
|
expect(report.mismatches[0]?.field).toBe("signature");
|
|
});
|
|
|
|
it("summarizes precision, recall, calibration, abstention rate, and economic sanity", () => {
|
|
const events = buildSmartMoneyEventsForReplay(
|
|
[institutionalPacket, eventDrivenPacket, stalePacket],
|
|
calendarOptions
|
|
);
|
|
const report = evaluateSmartMoneyEvents(
|
|
events,
|
|
[
|
|
{
|
|
event_id: "smartmoney:single_leg_event:flowpacket:eval-institutional",
|
|
profile_id: "institutional_directional",
|
|
direction: "bullish",
|
|
realized_return_bps: 42
|
|
},
|
|
{
|
|
event_id: "smartmoney:single_leg_event:flowpacket:eval-event-driven",
|
|
profile_id: "event_driven",
|
|
direction: "bullish",
|
|
realized_return_bps: 18
|
|
},
|
|
{
|
|
event_id: "smartmoney:single_leg_event:flowpacket:eval-stale",
|
|
profile_id: null,
|
|
realized_return_bps: -12
|
|
}
|
|
],
|
|
4
|
|
);
|
|
|
|
expect(report.sample_count).toBe(3);
|
|
expect(report.labeled_count).toBe(3);
|
|
expect(report.emitted_count).toBe(2);
|
|
expect(report.abstained_count).toBe(1);
|
|
expect(report.abstention_rate).toBeCloseTo(1 / 3);
|
|
expect(report.profile_precision.institutional_directional).toBe(1);
|
|
expect(report.profile_recall.event_driven).toBe(1);
|
|
expect(report.calibration).toHaveLength(4);
|
|
expect(report.calibration.reduce((sum, bucket) => sum + bucket.count, 0)).toBe(3);
|
|
expect(report.economic_sanity.directional_count).toBe(2);
|
|
expect(report.economic_sanity.direction_hit_rate).toBe(1);
|
|
expect(report.economic_sanity.average_signed_return_bps).toBe(30);
|
|
});
|
|
});
|