/** * Paper Trading Controller * Handles paper trading account and position endpoints */ import type { Request, Response, NextFunction } from 'express'; import { paperTradingService, TradeDirection } from '../services/paper-trading.service'; import type { AuthenticatedRequest } from '../../../core/guards/auth.guard'; // ============================================================================ // Account Endpoints // ============================================================================ export async function getAccount(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const account = await paperTradingService.getOrCreateAccount(authReq.user.id); res.json({ success: true, data: account }); } catch (error) { next(error); } } export async function getAccounts(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const accounts = await paperTradingService.getUserAccounts(authReq.user.id); res.json({ success: true, data: accounts }); } catch (error) { next(error); } } export async function createAccount(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { name, initialBalance, currency } = req.body; const account = await paperTradingService.createAccount(authReq.user.id, { name, initialBalance, currency, }); res.status(201).json({ success: true, data: account }); } catch (error) { next(error); } } export async function resetAccount(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { accountId } = req.params; const account = await paperTradingService.resetAccount(accountId, authReq.user.id); if (!account) { res.status(404).json({ success: false, error: 'Account not found or unauthorized' }); return; } res.json({ success: true, data: account, message: 'Account reset successfully' }); } catch (error) { next(error); } } export async function getAccountSummary(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { accountId } = req.params; const summary = await paperTradingService.getAccountSummary(authReq.user.id, accountId); if (!summary) { res.status(404).json({ success: false, error: 'Account not found' }); return; } res.json({ success: true, data: summary }); } catch (error) { next(error); } } // ============================================================================ // Position Endpoints // ============================================================================ export async function openPosition(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { symbol, direction, lotSize, entryPrice, stopLoss, takeProfit } = req.body; if (!symbol || !direction || !lotSize) { res.status(400).json({ success: false, error: 'Symbol, direction, and lotSize are required', }); return; } const validDirections: TradeDirection[] = ['long', 'short']; if (!validDirections.includes(direction)) { res.status(400).json({ success: false, error: `Invalid direction. Must be one of: ${validDirections.join(', ')}`, }); return; } if (lotSize <= 0) { res.status(400).json({ success: false, error: 'Lot size must be greater than 0', }); return; } const position = await paperTradingService.openPosition(authReq.user.id, { symbol, direction, lotSize, entryPrice, stopLoss, takeProfit, }); res.status(201).json({ success: true, data: position }); } catch (error) { next(error); } } export async function closePosition(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { positionId } = req.params; const { exitPrice, closeReason } = req.body; const position = await paperTradingService.closePosition(positionId, authReq.user.id, { exitPrice, closeReason, }); if (!position) { res.status(404).json({ success: false, error: 'Position not found or already closed' }); return; } res.json({ success: true, data: position }); } catch (error) { next(error); } } export async function getPosition(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { positionId } = req.params; const position = await paperTradingService.getPosition(positionId, authReq.user.id); if (!position) { res.status(404).json({ success: false, error: 'Position not found' }); return; } res.json({ success: true, data: position }); } catch (error) { next(error); } } export async function getPositions(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { accountId, status, symbol, limit } = req.query; const positions = await paperTradingService.getPositions(authReq.user.id, { accountId: accountId as string, status: status as 'open' | 'closed' | 'pending', symbol: symbol as string, limit: limit ? parseInt(limit as string, 10) : undefined, }); res.json({ success: true, data: positions }); } catch (error) { next(error); } } export async function updatePosition(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { positionId } = req.params; const { stopLoss, takeProfit } = req.body; const position = await paperTradingService.updatePosition(positionId, authReq.user.id, { stopLoss, takeProfit, }); if (!position) { res.status(404).json({ success: false, error: 'Position not found or not open' }); return; } res.json({ success: true, data: position }); } catch (error) { next(error); } } // ============================================================================ // Trade History & Analytics // ============================================================================ export async function getTradeHistory(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { accountId, symbol, startDate, endDate, limit } = req.query; const trades = await paperTradingService.getTradeHistory(authReq.user.id, { accountId: accountId as string, symbol: symbol as string, startDate: startDate ? new Date(startDate as string) : undefined, endDate: endDate ? new Date(endDate as string) : undefined, limit: limit ? parseInt(limit as string, 10) : undefined, }); res.json({ success: true, data: trades }); } catch (error) { next(error); } } export async function getPerformanceStats(req: Request, res: Response, next: NextFunction): Promise { try { const authReq = req as AuthenticatedRequest; const { accountId } = req.query; const stats = await paperTradingService.getPerformanceStats( authReq.user.id, accountId as string | undefined ); res.json({ success: true, data: stats }); } catch (error) { next(error); } }