feat: dealer flow, mirror portfolio (M21), options convexity, FINRA short interest, alert producers, vendor gate
CI / Test & Type-Check (push) Canceled after 0s
CI / Test & Type-Check (push) Canceled after 0s
Snapshot of in-progress module work across multiple slices: - Dealer Flow: dealerExposureEngine, dealerMapService, dealerMapExplain, dealerMapIntegrity, dealerMapReplay, dealerStudyEngine, hanStyleLevels - Mirror Portfolio (M21): fundRepository, captureIngest, mirrorAlertProducers, fund holdings strip, live book, position capture ingest - Options: BSM, NormalizedOptionSurface types, OptionsChainRouter, ConvexityGate, option legs panel - Alert producers: vixLevel, rotation, thesis, unlock, portfolioRisk, mirror (fund_capture, fund_13f, mirror_diff) - FINRA short interest adapter + queue integration - SEC company tickers adapter + ingest (symbol search index seed) - Vendor gate (rate-limit-first data plane, ADR-0009) - CUSIP registry, reverse 13F refresh, stock float service - LRU cache, portfolio backtest engine - Frontend: dealer-flow, funds, journal, lab, monitor, plan, portfolio, reports, screener, strategies, theses, guided-start, exits, more pages - Volume profile, workspace profile, visibility-aware poll - ADRs 0010 (mirror math not advice), 0011 (symbol search index) - VENDOR_INTEGRATIONS.md, END_USER_TEST.md - .gitignore: exclude DBs, .DS_Store, local config, agent scratch
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { buildVolumeProfile } from "../lib/volumeProfile.ts";
|
||||
|
||||
describe("buildVolumeProfile", () => {
|
||||
it("returns empty for no candles", () => {
|
||||
const r = buildVolumeProfile([]);
|
||||
assert.equal(r.bins.length, 0);
|
||||
assert.equal(r.totalVolume, 0);
|
||||
assert.equal(r.pocMid, null);
|
||||
});
|
||||
|
||||
it("returns empty for zero volume", () => {
|
||||
const r = buildVolumeProfile([{ h: 10, l: 9, v: 0 }]);
|
||||
assert.equal(r.bins.length, 0);
|
||||
});
|
||||
|
||||
it("preserves total volume across bins", () => {
|
||||
const candles = [
|
||||
{ h: 12, l: 10, v: 100 },
|
||||
{ h: 11, l: 9, v: 200 },
|
||||
{ h: 14, l: 13, v: 50 },
|
||||
];
|
||||
const r = buildVolumeProfile(candles, { bins: 10 });
|
||||
const sum = r.bins.reduce((a, b) => a + b.volume, 0);
|
||||
assert.ok(Math.abs(sum - 350) < 1e-6, `sum=${sum}`);
|
||||
assert.equal(r.totalVolume, 350);
|
||||
});
|
||||
|
||||
it("poc is the max volume bin mid", () => {
|
||||
// All volume at the high end
|
||||
const candles = [
|
||||
{ h: 20, l: 19, v: 1000 },
|
||||
{ h: 11, l: 10, v: 10 },
|
||||
];
|
||||
const r = buildVolumeProfile(candles, { bins: 8 });
|
||||
assert.ok(r.pocMid != null);
|
||||
const maxBin = r.bins.reduce((a, b) => (b.volume > a.volume ? b : a));
|
||||
assert.equal(r.pocMid, maxBin.mid);
|
||||
assert.ok(r.pocMid! >= 15, `poc should sit high, got ${r.pocMid}`);
|
||||
});
|
||||
|
||||
it("sets vah/val around value area", () => {
|
||||
const candles = Array.from({ length: 20 }, (_, i) => ({
|
||||
h: 100 + i * 0.5,
|
||||
l: 99 + i * 0.5,
|
||||
v: i === 10 ? 500 : 20,
|
||||
}));
|
||||
const r = buildVolumeProfile(candles, { bins: 16, valueAreaPct: 0.7 });
|
||||
assert.ok(r.vah != null && r.val != null);
|
||||
assert.ok(r.vah! >= r.val!);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user