123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /**
- * Integration test for risk breach handling
- * Tests the complete flow of detecting, managing, and resolving risk breaches
- */
- import { describe, it, expect, beforeAll, afterAll, beforeEach } from '@jest/globals';
- import { HedgingManager } from '../../src/core/HedgingManager';
- import { RiskManager } from '../../src/core/RiskManager';
- import { RiskBreach, BreachType, BreachSeverity } from '../../src/types/hedging';
- describe('Risk Breach Handling Integration', () => {
- let hedgingManager: HedgingManager;
- let riskManager: RiskManager;
- let testSessionId: string;
- beforeAll(async () => {
- // Initialize hedging manager
- hedgingManager = new HedgingManager({
- accounts: './config/accounts.json',
- hedging: './config/hedging-config.json',
- marketData: './config/market-data-config.json'
- });
- // Initialize risk manager
- riskManager = new RiskManager({
- riskCheckInterval: 1000,
- alertThresholds: {
- positionSize: 0.08,
- portfolioLoss: 0.03,
- slippage: 0.015
- },
- maxConcurrentBreaches: 10
- });
- await hedgingManager.initialize();
- await riskManager.initialize();
- });
- afterAll(async () => {
- if (hedgingManager) {
- await hedgingManager.shutdown();
- }
- if (riskManager) {
- await riskManager.shutdown();
- }
- });
- beforeEach(async () => {
- // Create a test session for each test
- const sessionRequest = {
- name: 'Risk Breach Test Session',
- accountIds: ['account-1', 'account-2'],
- volumeTarget: 10000,
- strategy: {
- symbol: 'ETH/USD',
- volumeDistribution: 'equal' as const,
- priceRange: { min: 0.001, max: 0.01 },
- timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
- riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
- orderTypes: { primary: 'limit' as const, fallback: 'market' as const }
- }
- };
- try {
- const session = await hedgingManager.createSession(sessionRequest);
- testSessionId = session.id;
- } catch (error) {
- testSessionId = 'mock-session-id';
- }
- });
- describe('Risk Breach Detection', () => {
- it('should detect position size breaches', async () => {
- try {
- // Mock position size breach scenario
- const breach = await riskManager.checkPositionSizeRisk(testSessionId, 'account-1', 0.12);
-
- expect(breach).toBeDefined();
- expect(breach.breachType).toBe('position_size_exceeded');
- expect(breach.severity).toBe('critical');
- expect(breach.sessionId).toBe(testSessionId);
- expect(breach.accountId).toBe('account-1');
- expect(breach.details.currentValue).toBe(0.12);
- expect(breach.details.limitValue).toBe(0.1);
- expect(breach.details.percentage).toBe(120);
- expect(breach.resolved).toBe(false);
- expect(breach.timestamp).toBeInstanceOf(Date);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should detect portfolio loss breaches', async () => {
- try {
- // Mock portfolio loss breach scenario
- const breach = await riskManager.checkPortfolioLossRisk(testSessionId, -0.06);
-
- expect(breach).toBeDefined();
- expect(breach.breachType).toBe('portfolio_loss_exceeded');
- expect(breach.severity).toBe('critical');
- expect(breach.sessionId).toBe(testSessionId);
- expect(breach.accountId).toBeUndefined(); // Portfolio-level breach
- expect(breach.details.currentValue).toBe(-0.06);
- expect(breach.details.limitValue).toBe(-0.05);
- expect(breach.details.percentage).toBe(120);
- expect(breach.resolved).toBe(false);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should detect slippage breaches', async () => {
- try {
- // Mock slippage breach scenario
- const breach = await riskManager.checkSlippageRisk(testSessionId, 'account-1', 0.025);
-
- expect(breach).toBeDefined();
- expect(breach.breachType).toBe('slippage_exceeded');
- expect(breach.severity).toBe('warning');
- expect(breach.sessionId).toBe(testSessionId);
- expect(breach.accountId).toBe('account-1');
- expect(breach.details.currentValue).toBe(0.025);
- expect(breach.details.limitValue).toBe(0.02);
- expect(breach.details.percentage).toBe(125);
- expect(breach.resolved).toBe(false);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should detect margin insufficient breaches', async () => {
- try {
- // Mock margin insufficient breach scenario
- const breach = await riskManager.checkMarginRisk(testSessionId, 'account-1', 0.05);
-
- expect(breach).toBeDefined();
- expect(breach.breachType).toBe('margin_insufficient');
- expect(breach.severity).toBe('critical');
- expect(breach.sessionId).toBe(testSessionId);
- expect(breach.accountId).toBe('account-1');
- expect(breach.details.currentValue).toBe(0.05);
- expect(breach.details.limitValue).toBe(0.1);
- expect(breach.details.percentage).toBe(50);
- expect(breach.resolved).toBe(false);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should detect account liquidation risk', async () => {
- try {
- // Mock liquidation risk breach scenario
- const breach = await riskManager.checkLiquidationRisk(testSessionId, 'account-1', 0.02);
-
- expect(breach).toBeDefined();
- expect(breach.breachType).toBe('account_liquidation_risk');
- expect(breach.severity).toBe('critical');
- expect(breach.sessionId).toBe(testSessionId);
- expect(breach.accountId).toBe('account-1');
- expect(breach.details.currentValue).toBe(0.02);
- expect(breach.details.limitValue).toBe(0.05);
- expect(breach.details.percentage).toBe(40);
- expect(breach.resolved).toBe(false);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- });
- describe('Risk Breach Management', () => {
- let testBreachId: string;
- beforeEach(async () => {
- try {
- // Create a test breach
- const breach = await riskManager.checkPositionSizeRisk(testSessionId, 'account-1', 0.12);
- testBreachId = breach.id;
- } catch (error) {
- testBreachId = 'mock-breach-id';
- }
- });
- it('should store and retrieve risk breaches', async () => {
- try {
- const breach = await riskManager.getBreach(testBreachId);
-
- expect(breach).toBeDefined();
- expect(breach.id).toBe(testBreachId);
- expect(breach.sessionId).toBe(testSessionId);
- expect(breach.breachType).toBe('position_size_exceeded');
- expect(breach.severity).toBe('critical');
- expect(breach.resolved).toBe(false);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should list active breaches for a session', async () => {
- try {
- const breaches = await riskManager.getActiveBreaches(testSessionId);
-
- expect(Array.isArray(breaches)).toBe(true);
- expect(breaches.length).toBeGreaterThan(0);
-
- const testBreach = breaches.find(b => b.id === testBreachId);
- expect(testBreach).toBeDefined();
- expect(testBreach.resolved).toBe(false);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should filter breaches by type', async () => {
- try {
- const positionBreaches = await riskManager.getBreachesByType(testSessionId, 'position_size_exceeded');
-
- expect(Array.isArray(positionBreaches)).toBe(true);
- positionBreaches.forEach(breach => {
- expect(breach.breachType).toBe('position_size_exceeded');
- });
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should filter breaches by severity', async () => {
- try {
- const criticalBreaches = await riskManager.getBreachesBySeverity(testSessionId, 'critical');
-
- expect(Array.isArray(criticalBreaches)).toBe(true);
- criticalBreaches.forEach(breach => {
- expect(breach.severity).toBe('critical');
- });
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- });
- describe('Risk Breach Resolution', () => {
- let testBreachId: string;
- beforeEach(async () => {
- try {
- // Create a test breach
- const breach = await riskManager.checkPositionSizeRisk(testSessionId, 'account-1', 0.12);
- testBreachId = breach.id;
- } catch (error) {
- testBreachId = 'mock-breach-id';
- }
- });
- it('should resolve a risk breach', async () => {
- try {
- const resolvedBreach = await riskManager.resolveBreach(testBreachId, 'Position reduced below limit');
-
- expect(resolvedBreach).toBeDefined();
- expect(resolvedBreach.id).toBe(testBreachId);
- expect(resolvedBreach.resolved).toBe(true);
- expect(resolvedBreach.resolvedAt).toBeDefined();
- expect(resolvedBreach.resolvedAt).toBeInstanceOf(Date);
- expect(resolvedBreach.action).toBe('Position reduced below limit');
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should acknowledge a risk breach without resolving', async () => {
- try {
- const acknowledgedBreach = await riskManager.acknowledgeBreach(testBreachId, 'ignore', 'Monitoring situation');
-
- expect(acknowledgedBreach).toBeDefined();
- expect(acknowledgedBreach.id).toBe(testBreachId);
- expect(acknowledgedBreach.resolved).toBe(false);
- expect(acknowledgedBreach.action).toBe('ignore');
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should prevent operations on resolved breaches', async () => {
- try {
- // First resolve the breach
- await riskManager.resolveBreach(testBreachId, 'Position reduced');
-
- // Try to resolve again
- await riskManager.resolveBreach(testBreachId, 'Another action');
- fail('Should have rejected resolving an already resolved breach');
- } catch (error) {
- expect(error.message).toContain('already resolved');
- }
- });
- });
- describe('Risk Monitoring', () => {
- it('should continuously monitor risk metrics', async () => {
- const riskEvents: string[] = [];
-
- try {
- riskManager.on('breachDetected', (breach) => {
- riskEvents.push('breachDetected');
- expect(breach.sessionId).toBe(testSessionId);
- });
-
- riskManager.on('breachResolved', (breach) => {
- riskEvents.push('breachResolved');
- expect(breach.sessionId).toBe(testSessionId);
- });
-
- // Start monitoring
- await riskManager.startMonitoring(testSessionId);
-
- // Wait for monitoring to detect risks
- await new Promise(resolve => setTimeout(resolve, 2000));
-
- // Stop monitoring
- await riskManager.stopMonitoring(testSessionId);
-
- expect(riskEvents.length).toBeGreaterThan(0);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should calculate overall risk level', async () => {
- try {
- const riskLevel = await riskManager.calculateOverallRisk(testSessionId);
-
- expect(riskLevel).toBeDefined();
- expect(['low', 'medium', 'high']).toContain(riskLevel);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should generate risk status report', async () => {
- try {
- const riskStatus = await riskManager.getRiskStatus(testSessionId);
-
- expect(riskStatus).toBeDefined();
- expect(riskStatus.sessionId).toBe(testSessionId);
- expect(riskStatus.overallRisk).toBeDefined();
- expect(riskStatus.accountRisks).toBeDefined();
- expect(Array.isArray(riskStatus.accountRisks)).toBe(true);
- expect(riskStatus.portfolioRisk).toBeDefined();
- expect(riskStatus.activeBreaches).toBeDefined();
- expect(Array.isArray(riskStatus.activeBreaches)).toBe(true);
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- });
- describe('Risk Breach Notifications', () => {
- it('should emit breach detection events', async () => {
- const events: string[] = [];
-
- try {
- riskManager.on('breachDetected', (breach) => {
- events.push('breachDetected');
- expect(breach).toBeDefined();
- expect(breach.id).toBeDefined();
- expect(breach.sessionId).toBe(testSessionId);
- });
-
- // Trigger a breach
- await riskManager.checkPositionSizeRisk(testSessionId, 'account-1', 0.12);
-
- expect(events).toContain('breachDetected');
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- it('should emit breach resolution events', async () => {
- const events: string[] = [];
- let testBreachId: string;
-
- try {
- riskManager.on('breachResolved', (breach) => {
- events.push('breachResolved');
- expect(breach).toBeDefined();
- expect(breach.id).toBe(testBreachId);
- });
-
- // Create and resolve a breach
- const breach = await riskManager.checkPositionSizeRisk(testSessionId, 'account-1', 0.12);
- testBreachId = breach.id;
- await riskManager.resolveBreach(testBreachId, 'Position reduced');
-
- expect(events).toContain('breachResolved');
- } catch (error) {
- // This test should fail initially since RiskManager doesn't exist yet
- expect(error.message).toContain('RiskManager');
- }
- });
- });
- describe('Error Handling', () => {
- it('should handle non-existent breach operations gracefully', async () => {
- const nonExistentBreachId = 'non-existent-breach-id';
-
- try {
- await riskManager.getBreach(nonExistentBreachId);
- fail('Should have thrown error for non-existent breach');
- } catch (error) {
- expect(error.message).toContain('not found');
- }
- });
- it('should handle invalid breach resolution attempts', async () => {
- const nonExistentBreachId = 'non-existent-breach-id';
-
- try {
- await riskManager.resolveBreach(nonExistentBreachId, 'Test resolution');
- fail('Should have thrown error for non-existent breach');
- } catch (error) {
- expect(error.message).toContain('not found');
- }
- });
- it('should handle monitoring errors gracefully', async () => {
- try {
- await riskManager.startMonitoring('non-existent-session');
- fail('Should have thrown error for non-existent session');
- } catch (error) {
- expect(error.message).toContain('session');
- }
- });
- });
- });
|