messy work. backtests / mock-data

This commit is contained in:
Boki 2025-07-03 08:37:23 -04:00
parent 4e4a048988
commit fa70ada2bb
51 changed files with 2576 additions and 887 deletions

View file

@ -1,8 +1,7 @@
import { Hono } from 'hono';
import { z } from 'zod';
import { logger } from '@stock-bot/logger';
import { IServiceContainer } from '@stock-bot/di';
import { AnalyticsService } from '../../services/AnalyticsService';
import { container } from '../../container';
const DateRangeSchema = z.object({
startDate: z.string().datetime(),
@ -20,9 +19,9 @@ const OptimizationRequestSchema = z.object({
}).optional()
});
export function createAnalyticsRoutes(): Hono {
export function createAnalyticsRoutes(container: IServiceContainer): Hono {
const app = new Hono();
const analyticsService = container.get('AnalyticsService') as AnalyticsService;
const analyticsService = container.custom?.AnalyticsService as AnalyticsService;
// Get performance metrics
app.get('/performance/:portfolioId', async (c) => {
@ -50,7 +49,7 @@ export function createAnalyticsRoutes(): Hono {
}, 400);
}
logger.error('Error getting performance metrics:', error);
container.logger.error('Error getting performance metrics:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get performance metrics'
}, 500);
@ -77,7 +76,7 @@ export function createAnalyticsRoutes(): Hono {
}, 400);
}
logger.error('Error optimizing portfolio:', error);
container.logger.error('Error optimizing portfolio:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to optimize portfolio'
}, 500);
@ -92,7 +91,7 @@ export function createAnalyticsRoutes(): Hono {
return c.json(metrics);
} catch (error) {
logger.error('Error getting risk metrics:', error);
container.logger.error('Error getting risk metrics:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get risk metrics'
}, 500);
@ -109,7 +108,7 @@ export function createAnalyticsRoutes(): Hono {
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Error detecting market regime:', error);
container.logger.error('Error detecting market regime:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to detect market regime'
}, 500);
@ -138,7 +137,7 @@ export function createAnalyticsRoutes(): Hono {
}, 400);
}
logger.error('Error calculating correlation:', error);
container.logger.error('Error calculating correlation:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to calculate correlation'
}, 500);
@ -169,7 +168,7 @@ export function createAnalyticsRoutes(): Hono {
}, 400);
}
logger.error('Error making prediction:', error);
container.logger.error('Error making prediction:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to make prediction'
}, 500);

View file

@ -1,21 +1,48 @@
import { Hono } from 'hono';
import { z } from 'zod';
import { logger } from '@stock-bot/logger';
import { IServiceContainer } from '@stock-bot/di';
import { BacktestConfigSchema } from '../../types';
import { BacktestEngine } from '../../backtest/BacktestEngine';
import { ModeManager } from '../../core/ModeManager';
import { container } from '../../container';
const BacktestIdSchema = z.object({
backtestId: z.string()
});
export function createBacktestRoutes(): Hono {
export function createBacktestRoutes(container: IServiceContainer): Hono {
const app = new Hono();
const backtestEngine = container.get('BacktestEngine') as BacktestEngine;
const modeManager = container.get('ModeManager') as ModeManager;
const backtestEngine = container.custom?.BacktestEngine as BacktestEngine;
const modeManager = container.custom?.ModeManager as ModeManager;
// Run new backtest
// Default POST to / is the same as /run for backward compatibility
app.post('/', async (c) => {
try {
const body = await c.req.json();
const config = BacktestConfigSchema.parse(body);
// Initialize backtest mode
await modeManager.initializeMode(config);
// Run backtest
const result = await backtestEngine.runBacktest(config);
return c.json(result, 201);
} catch (error) {
if (error instanceof z.ZodError) {
return c.json({
error: 'Invalid backtest configuration',
details: error.errors
}, 400);
}
container.logger.error('Error running backtest:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to run backtest'
}, 500);
}
});
// Run new backtest (same as above but at /run)
app.post('/run', async (c) => {
try {
const body = await c.req.json();
@ -36,7 +63,7 @@ export function createBacktestRoutes(): Hono {
}, 400);
}
logger.error('Error running backtest:', error);
container.logger.error('Error running backtest:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to run backtest'
}, 500);
@ -53,7 +80,7 @@ export function createBacktestRoutes(): Hono {
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Error stopping backtest:', error);
container.logger.error('Error stopping backtest:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to stop backtest'
}, 500);
@ -72,7 +99,7 @@ export function createBacktestRoutes(): Hono {
currentTime: new Date().toISOString()
});
} catch (error) {
logger.error('Error getting backtest progress:', error);
container.logger.error('Error getting backtest progress:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get progress'
}, 500);

View file

@ -1,17 +1,16 @@
import { Hono } from 'hono';
import { z } from 'zod';
import { logger } from '@stock-bot/logger';
import { IServiceContainer } from '@stock-bot/di';
import { OrderRequestSchema } from '../../types';
import { ExecutionService } from '../../services/ExecutionService';
import { container } from '../../container';
const OrderIdSchema = z.object({
orderId: z.string()
});
export function createOrderRoutes(): Hono {
export function createOrderRoutes(container: IServiceContainer): Hono {
const app = new Hono();
const executionService = container.get('ExecutionService') as ExecutionService;
const executionService = container.custom?.ExecutionService as ExecutionService;
// Submit new order
app.post('/', async (c) => {
@ -30,7 +29,7 @@ export function createOrderRoutes(): Hono {
}, 400);
}
logger.error('Error submitting order:', error);
container.logger.error('Error submitting order:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to submit order'
}, 500);
@ -50,7 +49,7 @@ export function createOrderRoutes(): Hono {
return c.json({ error: 'Order not found or already filled' }, 404);
}
} catch (error) {
logger.error('Error cancelling order:', error);
container.logger.error('Error cancelling order:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to cancel order'
}, 500);
@ -70,7 +69,7 @@ export function createOrderRoutes(): Hono {
return c.json({ error: 'Order not found' }, 404);
}
} catch (error) {
logger.error('Error getting order status:', error);
container.logger.error('Error getting order status:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get order status'
}, 500);
@ -101,7 +100,7 @@ export function createOrderRoutes(): Hono {
}, 400);
}
logger.error('Error submitting batch orders:', error);
container.logger.error('Error submitting batch orders:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to submit batch orders'
}, 500);

View file

@ -1,16 +1,15 @@
import { Hono } from 'hono';
import { z } from 'zod';
import { logger } from '@stock-bot/logger';
import { IServiceContainer } from '@stock-bot/di';
import { ModeManager } from '../../core/ModeManager';
import { container } from '../../container';
const SymbolSchema = z.object({
symbol: z.string()
});
export function createPositionRoutes(): Hono {
export function createPositionRoutes(container: IServiceContainer): Hono {
const app = new Hono();
const modeManager = container.get('ModeManager') as ModeManager;
const modeManager = container.custom?.ModeManager as ModeManager;
// Get all positions
app.get('/', async (c) => {
@ -23,7 +22,7 @@ export function createPositionRoutes(): Hono {
positions
});
} catch (error) {
logger.error('Error getting positions:', error);
container.logger.error('Error getting positions:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get positions'
}, 500);
@ -41,7 +40,7 @@ export function createPositionRoutes(): Hono {
positions
});
} catch (error) {
logger.error('Error getting open positions:', error);
container.logger.error('Error getting open positions:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get open positions'
}, 500);
@ -69,7 +68,7 @@ export function createPositionRoutes(): Hono {
}, 404);
}
} catch (error) {
logger.error('Error getting position:', error);
container.logger.error('Error getting position:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get position'
}, 500);
@ -92,7 +91,7 @@ export function createPositionRoutes(): Hono {
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Error getting P&L:', error);
container.logger.error('Error getting P&L:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get P&L'
}, 500);
@ -111,7 +110,7 @@ export function createPositionRoutes(): Hono {
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Error getting risk metrics:', error);
container.logger.error('Error getting risk metrics:', error);
return c.json({
error: error instanceof Error ? error.message : 'Failed to get risk metrics'
}, 500);

View file

@ -1,10 +1,9 @@
import { Server as SocketIOServer, Socket } from 'socket.io';
import { logger } from '@stock-bot/logger';
import { z } from 'zod';
import { IServiceContainer } from '@stock-bot/di';
import { MarketDataService } from '../../services/MarketDataService';
import { ExecutionService } from '../../services/ExecutionService';
import { ModeManager } from '../../core/ModeManager';
import { Container } from '@stock-bot/di';
const SubscribeSchema = z.object({
symbols: z.array(z.string()),
@ -15,16 +14,16 @@ const UnsubscribeSchema = z.object({
symbols: z.array(z.string())
});
export function setupWebSocketHandlers(io: SocketIOServer, container: Container): void {
const marketDataService = container.get('MarketDataService') as MarketDataService;
const executionService = container.get('ExecutionService') as ExecutionService;
const modeManager = container.get('ModeManager') as ModeManager;
export function setupWebSocketHandlers(io: SocketIOServer, container: IServiceContainer): void {
const marketDataService = container.custom?.MarketDataService as MarketDataService;
const executionService = container.custom?.ExecutionService as ExecutionService;
const modeManager = container.custom?.ModeManager as ModeManager;
// Track client subscriptions
const clientSubscriptions = new Map<string, Set<string>>();
io.on('connection', (socket: Socket) => {
logger.info(`WebSocket client connected: ${socket.id}`);
container.logger.info(`WebSocket client connected: ${socket.id}`);
clientSubscriptions.set(socket.id, new Set());
// Send initial connection info
@ -44,13 +43,13 @@ export function setupWebSocketHandlers(io: SocketIOServer, container: Container)
subscriptions.add(symbol);
}
logger.debug(`Client ${socket.id} subscribed to: ${symbols.join(', ')}`);
container.logger.debug(`Client ${socket.id} subscribed to: ${symbols.join(', ')}`);
if (callback) {
callback({ success: true, symbols });
}
} catch (error) {
logger.error('Subscription error:', error);
container.logger.error('Subscription error:', error);
if (callback) {
callback({
success: false,
@ -83,13 +82,13 @@ export function setupWebSocketHandlers(io: SocketIOServer, container: Container)
}
}
logger.debug(`Client ${socket.id} unsubscribed from: ${symbols.join(', ')}`);
container.logger.debug(`Client ${socket.id} unsubscribed from: ${symbols.join(', ')}`);
if (callback) {
callback({ success: true, symbols });
}
} catch (error) {
logger.error('Unsubscribe error:', error);
container.logger.error('Unsubscribe error:', error);
if (callback) {
callback({
success: false,
@ -107,7 +106,7 @@ export function setupWebSocketHandlers(io: SocketIOServer, container: Container)
callback({ success: true, result });
}
} catch (error) {
logger.error('Order submission error:', error);
container.logger.error('Order submission error:', error);
if (callback) {
callback({
success: false,
@ -127,7 +126,7 @@ export function setupWebSocketHandlers(io: SocketIOServer, container: Container)
callback({ success: true, positions });
}
} catch (error) {
logger.error('Error getting positions:', error);
container.logger.error('Error getting positions:', error);
if (callback) {
callback({
success: false,
@ -139,7 +138,7 @@ export function setupWebSocketHandlers(io: SocketIOServer, container: Container)
// Handle disconnection
socket.on('disconnect', async () => {
logger.info(`WebSocket client disconnected: ${socket.id}`);
container.logger.info(`WebSocket client disconnected: ${socket.id}`);
// Unsubscribe from all symbols for this client
const subscriptions = clientSubscriptions.get(socket.id);
@ -191,5 +190,5 @@ export function setupWebSocketHandlers(io: SocketIOServer, container: Container)
});
});
logger.info('WebSocket handlers initialized');
container.logger.info('WebSocket handlers initialized');
}