messy work. backtests / mock-data
This commit is contained in:
parent
4e4a048988
commit
fa70ada2bb
51 changed files with 2576 additions and 887 deletions
|
|
@ -1,83 +1,150 @@
|
|||
/**
|
||||
* Stock Bot Orchestrator Service
|
||||
* Coordinates between Rust core, data feeds, and analytics
|
||||
*/
|
||||
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import { initializeStockConfig } from '@stock-bot/stock-config';
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { Server as SocketIOServer } from 'socket.io';
|
||||
import { createServer } from 'http';
|
||||
import { logger } from '@stock-bot/logger';
|
||||
import { ModeManager } from './core/ModeManager';
|
||||
import { createOrderRoutes } from './api/rest/orders';
|
||||
import { createPositionRoutes } from './api/rest/positions';
|
||||
import { createAnalyticsRoutes } from './api/rest/analytics';
|
||||
import { createBacktestRoutes } from './api/rest/backtest';
|
||||
import { setupWebSocketHandlers } from './api/websocket';
|
||||
import { container } from './container';
|
||||
import { createRoutes } from './routes/create-routes';
|
||||
import { createContainer } from './simple-container';
|
||||
|
||||
const PORT = process.env.PORT || 3002;
|
||||
// Initialize configuration with service-specific overrides
|
||||
const config = initializeStockConfig('orchestrator');
|
||||
const logger = getLogger('orchestrator');
|
||||
|
||||
// Get service-specific config
|
||||
const serviceConfig = config.services?.orchestrator || {
|
||||
port: 2004,
|
||||
defaultMode: 'paper',
|
||||
paperTradingCapital: 100000,
|
||||
enableWebSocket: true
|
||||
};
|
||||
|
||||
const PORT = serviceConfig.port;
|
||||
|
||||
// Log the configuration
|
||||
logger.info('Service configuration:', {
|
||||
port: PORT,
|
||||
defaultMode: serviceConfig.defaultMode,
|
||||
enableWebSocket: serviceConfig.enableWebSocket,
|
||||
backtesting: serviceConfig.backtesting,
|
||||
strategies: serviceConfig.strategies
|
||||
});
|
||||
|
||||
async function main() {
|
||||
// Initialize Hono app
|
||||
const app = new Hono();
|
||||
let server: any; // Declare server in outer scope for shutdown
|
||||
|
||||
// Middleware
|
||||
app.use('*', cors());
|
||||
app.use('*', async (c, next) => {
|
||||
const start = Date.now();
|
||||
await next();
|
||||
const ms = Date.now() - start;
|
||||
logger.debug(`${c.req.method} ${c.req.url} - ${ms}ms`);
|
||||
});
|
||||
|
||||
// Health check
|
||||
app.get('/health', (c) => {
|
||||
const modeManager = container.get('ModeManager');
|
||||
return c.json({
|
||||
status: 'healthy',
|
||||
mode: modeManager.getCurrentMode(),
|
||||
timestamp: new Date().toISOString()
|
||||
try {
|
||||
// Initialize container with all services using configuration
|
||||
const services = await createContainer(config);
|
||||
|
||||
// Initialize Hono app
|
||||
const app = new Hono();
|
||||
|
||||
// CORS middleware - use config for origins
|
||||
app.use('*', cors({
|
||||
origin: config.services?.webApi?.cors?.origins || ['http://localhost:4200', 'http://localhost:3000', 'http://localhost:5173', 'http://localhost:5174'],
|
||||
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: config.services?.webApi?.cors?.credentials ?? true,
|
||||
}));
|
||||
|
||||
// Logging middleware
|
||||
app.use('*', async (c, next) => {
|
||||
const start = Date.now();
|
||||
await next();
|
||||
const ms = Date.now() - start;
|
||||
services.logger.debug(`${c.req.method} ${c.req.url} - ${ms}ms`);
|
||||
});
|
||||
});
|
||||
|
||||
// Mount routes
|
||||
app.route('/api/orders', createOrderRoutes());
|
||||
app.route('/api/positions', createPositionRoutes());
|
||||
app.route('/api/analytics', createAnalyticsRoutes());
|
||||
app.route('/api/backtest', createBacktestRoutes());
|
||||
// Create and mount routes (without Socket.IO for now)
|
||||
const routes = createRoutes(services);
|
||||
app.route('/', routes);
|
||||
|
||||
// Create HTTP server and Socket.IO
|
||||
const server = createServer(app.fetch);
|
||||
const io = new SocketIOServer(server, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
methods: ['GET', 'POST']
|
||||
// Start Bun server
|
||||
try {
|
||||
server = Bun.serve({
|
||||
port: PORT,
|
||||
hostname: '0.0.0.0', // Explicitly bind to all interfaces
|
||||
fetch: async (req) => {
|
||||
services.logger.debug(`Incoming request: ${req.method} ${req.url}`);
|
||||
try {
|
||||
const response = await app.fetch(req);
|
||||
return response;
|
||||
} catch (error) {
|
||||
services.logger.error('Request handling error:', error);
|
||||
return new Response('Internal Server Error', { status: 500 });
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
services.logger.error('Server error:', error);
|
||||
return new Response('Internal Server Error', { status: 500 });
|
||||
},
|
||||
});
|
||||
|
||||
services.logger.info(`Orchestrator service started on port ${server.port}`);
|
||||
services.logger.info(`Server hostname: ${server.hostname}`);
|
||||
services.logger.info(`Server URL: http://${server.hostname}:${server.port}`);
|
||||
|
||||
// Test that server is actually listening
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const testResponse = await fetch(`http://localhost:${server.port}/health`);
|
||||
services.logger.info(`Server self-test: ${testResponse.status} ${testResponse.statusText}`);
|
||||
} catch (error) {
|
||||
services.logger.error('Server self-test failed:', error);
|
||||
}
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
services.logger.error('Failed to start Bun server:', error);
|
||||
throw error;
|
||||
}
|
||||
services.logger.info('Service metadata:', {
|
||||
version: '1.0.0',
|
||||
description: 'Trading System Orchestrator',
|
||||
defaultMode: serviceConfig.defaultMode,
|
||||
enableWebSocket: serviceConfig.enableWebSocket,
|
||||
endpoints: {
|
||||
health: '/health',
|
||||
orders: '/api/orders',
|
||||
positions: '/api/positions',
|
||||
analytics: '/api/analytics',
|
||||
backtest: '/api/backtest',
|
||||
}
|
||||
});
|
||||
|
||||
// Note: Socket.IO with Bun requires a different setup
|
||||
// For now, we'll disable Socket.IO to avoid the CORS error
|
||||
if (serviceConfig.enableWebSocket) {
|
||||
services.logger.info('WebSocket support is enabled but Socket.IO integration with Bun requires additional setup');
|
||||
}
|
||||
});
|
||||
|
||||
// Setup WebSocket handlers
|
||||
setupWebSocketHandlers(io, container);
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', async () => {
|
||||
services.logger.info('Orchestrator service shutting down...');
|
||||
|
||||
// Cleanup any active trading sessions
|
||||
const modeManager = services.custom?.ModeManager;
|
||||
if (modeManager) {
|
||||
await modeManager.shutdown();
|
||||
}
|
||||
|
||||
if (server) {
|
||||
server.stop();
|
||||
}
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// Initialize mode manager
|
||||
const modeManager = container.get('ModeManager') as ModeManager;
|
||||
|
||||
// Default to paper trading mode
|
||||
await modeManager.initializeMode({
|
||||
mode: 'paper',
|
||||
startingCapital: 100000
|
||||
});
|
||||
|
||||
// Start server
|
||||
server.listen(PORT, () => {
|
||||
logger.info(`Trading orchestrator running on port ${PORT}`);
|
||||
});
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', async () => {
|
||||
logger.info('Shutting down trading orchestrator...');
|
||||
await modeManager.shutdown();
|
||||
server.close();
|
||||
process.exit(0);
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to start orchestrator service:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
logger.error('Failed to start trading orchestrator:', error);
|
||||
// Start the service
|
||||
main().catch(error => {
|
||||
logger.error('Unhandled error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue