Files
investor-flow/app/server/src/risk/__tests__/sizingRiskApi.test.ts
T

41 lines
1.7 KiB
TypeScript
Raw Normal View History

// 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'));
});