| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- import { describe, expect, it } from 'vitest';
- import { RiskEngine } from '../packages/risk/src/riskEngine';
- import type { Order, PositionSnapshot } from '../packages/domain/src/types';
- const baseOrder: Order = {
- clientId: 'risk-1',
- symbol: 'BTC',
- side: 'buy',
- px: 100,
- sz: 0.5,
- tif: 'GTC'
- };
- const position: PositionSnapshot = {
- symbol: 'BTC',
- base: 0,
- quote: 1000,
- ts: Date.now()
- };
- describe('RiskEngine', () => {
- it('blocks orders that exceed size or limits', () => {
- const engine = new RiskEngine({
- maxBaseAbs: 1,
- maxNotionalAbs: 150,
- maxOrderSz: 0.6
- });
- expect(() => engine.preCheck(baseOrder, position, 100)).not.toThrow();
- expect(() =>
- engine.preCheck({ ...baseOrder, sz: 0.7 }, position, 100)
- ).toThrow(/order size/);
- expect(() =>
- engine.preCheck({ ...baseOrder, sz: 0.5 }, { ...position, base: 0.7 }, 100)
- ).toThrow(/inventory/);
- });
- it('triggers kill switch on drawdown and resets when requested', () => {
- const engine = new RiskEngine(
- {
- maxBaseAbs: 2,
- maxNotionalAbs: 1_000,
- maxOrderSz: 1
- },
- {
- drawdownPct: 0.5,
- triggers: [
- { type: 'delta_abs', threshold: 1.6 },
- { type: 'hedge_failure_count', threshold: 3 }
- ]
- }
- );
- engine.updateEquity(100);
- engine.updateEquity(45); // 55% drawdown
- expect(engine.shouldHalt()).toBe(true);
- engine.resetKillSwitch();
- expect(engine.shouldHalt()).toBe(false);
- engine.updateDeltaAbs(2);
- expect(engine.shouldHalt()).toBe(true);
- engine.resetKillSwitch();
- engine.recordHedgeFailure();
- engine.recordHedgeFailure();
- engine.recordHedgeFailure();
- expect(engine.shouldHalt()).toBe(true);
- });
- });
|