Files
investor-flow/app/server/src/risk/__tests__/sizingRiskApi.test.ts
T
Investor Flow Build e262187c3c fix: backfill symbol_demand for sidebar-added symbols + analyst ratings schema fix
- Add await ctx.cache.subscribe() to addSymbol mutation so symbols
  added via the sidebar get registered in symbol_demand and yfinance
  jobs are queued immediately
- Backfill PEP, WYNN, STZ, CELH into symbol_demand + adapter_queue
- Upgrade yahoo-finance2 3.15.3 -> 3.15.4 and pass validateResult:false
  to quoteSummary() to handle Yahoo schema drift
- Add error detail logging for analyst ratings schema failures
- Update .gitignore with common ignores
2026-07-23 18:02:24 -04:00

41 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Unit coverage for sizing/risk product contracts used by tRPC routers.
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { sizePosition } from '../../sizing/SizingEngine.ts';
import { assessRisk, ADR_0007_FOOTER } from '../RiskEngine.ts';
test('sizing.compute contract: math implies shares, ADR-0007 footer-ready', () => {
const result = sizePosition(
{ symbol: 'NVDA', tier: 'B', riskFraction: 0.01, stopPerShare: 5 },
{ equity: 100_000, complexity: 'beginner' },
{
holdings: [],
regime: 'trending-up',
clusterCaps: { uncategorized: 25_000 },
aStarUnlocked: false,
},
);
// 100000 * 0.01 / 5 = 200 shares * B(×1) = 200
assert.equal(result.shares, 200);
assert.equal(result.blocked, false);
assert.ok(result.explanations.some((e) => /math implies/i.test(e)));
assert.ok(result.explanations.some((e) => /not investment advice/i.test(e)));
});
test('risk.posture contract: peak breach yields halt + consideration', () => {
const posture = assessRisk({
portfolio: [
{ symbol: 'NVDA', shares: 100, avgCost: 100, cluster: 'uncategorized', stopPrice: 90, rewardTarget: 130 },
],
account: { equity: 80_000, drawdownTolerancePct: 15, complexity: 'beginner' },
peakEquity: 100_000,
regime: 'trending-down',
sizingContext: { clusterCaps: { uncategorized: 20_000 } },
});
assert.equal(posture.halted, true);
assert.ok(posture.recommendedActions.length > 0);
assert.ok(posture.recommendedActions.every((a) => a.explanation.includes(ADR_0007_FOOTER)
|| a.explanation.toLowerCase().includes('trade-off')));
assert.ok(!JSON.stringify(posture.recommendedActions).toLowerCase().includes('you should sell'));
});