9.2 KiB
Admin Trade Control Implementation
Overview
This document describes the implementation of the Admin Trade Control Feature that allows authorized administrators to pause and resume auto-trading from the dashboard. This is a production-grade safety control that prevents new trade entries while allowing existing positions to be managed.
Architecture
Backend (Authoritative)
The backend is the single source of truth for trading control state. All enforcement happens server-side.
1. Trading Control State
Location: bytelyst-trading-bot-service/src/services/healthTracker.ts
export interface TradingControlSnapshot {
mode: 'RUNNING' | 'PAUSED';
lastChangedBy: string;
lastChangedAt: number;
reason?: string;
}
The state is:
- Stored in-memory in
HealthTrackersingleton - Persisted to disk in
bot_state.json - Persisted to Supabase for multi-instance recovery
- Restored on bot restart
2. Enforcement Points (MANDATORY)
Auto-Trading Enforcement:
-
AutoTrader.ts (Line 106-109):
if (healthTracker.isPaused()) { logger.info(`[AutoTrader] 🛑 Entry BLOCKED for ${symbol}: Bot is PAUSED by admin.`); return; } -
TradeExecutor.ts (Line 531-534):
if (healthTracker.isPaused()) { logger.info(`[TradeExecutor] 🛑 Entry BLOCKED for ${symbol}: Bot is PAUSED by admin.`); return { success: false, error: 'Trade execution is paused by administrator' }; }
What Continues When Paused:
- Exit order execution
- Stop-loss monitoring
- Take-profit monitoring
- Position reconciliation
- Order status synchronization
- Health monitoring
3. Admin Control API
Location: bytelyst-trading-bot-service/src/services/apiServer.ts (Lines 1049-1090)
Endpoints:
GET /internal/trading/status
POST /internal/trading/pause
POST /internal/trading/resume
Security:
- All endpoints require authentication (
requireAuthmiddleware) - Pause/Resume require admin role (
requireAdminmiddleware) - Actions are logged with audit trail
Example Request:
curl -X POST http://localhost:5000/internal/trading/pause \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"reason": "Manual admin pause"}'
Response:
{
"success": true,
"status": {
"mode": "PAUSED",
"lastChangedBy": "user@example.com",
"lastChangedAt": 1708200000000,
"reason": "Manual admin pause"
}
}
4. Health & Observability
The trading control state is included in the health snapshot:
export interface HealthSnapshot {
// ... other health metrics
tradingControl: TradingControlSnapshot;
}
This flows through:
- WebSocket
health_updateevents /internal/healthendpoint- Bot state persistence
Frontend (Read-Only Reflection)
The frontend never assumes trading state. It always reflects the backend state.
1. Admin Panel Controls
Location: bytelyst-trading-dashboard-web/src/tabs/AdminTab.tsx
Features:
- Status Banner: Shows current trading mode (PAUSED/RUNNING)
- Pause Button: Calls
/internal/trading/pause - Resume Button: Calls
/internal/trading/resume - Error Display: Shows API errors
- Safety Notice: Explains behavior when paused
UI Rules:
- Buttons are disabled when already in target state
- Loading state shown during API calls
- Status derived from
botState.health.tradingControl - Tooltips explain behavior
2. Header Status Indicator
Location: bytelyst-trading-dashboard-web/src/App.tsx (Lines 195-231)
A global status badge in the header shows:
- ⏸️ Trading Paused (orange) - when paused
- ▶️ Trading Active (green) - when running
- Tooltip with who paused and when
This is visible on all pages, not just Admin.
3. WebSocket Integration
Location: bytelyst-trading-dashboard-web/src/hooks/useWebSocket.ts
The health_update event updates the trading control state:
newSocket.on('health_update', (health: HealthSnapshot) => {
setBotState(prev => ({
...prev,
health
}));
});
Security
Authorization
- Authentication: All endpoints require valid JWT token
- Admin Role: Pause/Resume require
role = 'admin'in user profile - UI Guards: Admin controls hidden for non-admin users
- Backend Re-check: Authorization verified on every request
Audit Trail
All trading control changes are logged:
[Admin] Trading PAUSED by user@example.com. Reason: Manual admin pause
[Admin] Trading RESUMED by user@example.com.
Failure & Edge Cases
API Failure
- Frontend shows error toast
- UI state does not change
- User can retry
WebSocket Delay
- Last-known timestamp shown in status
- User can see staleness
- Status updates when websocket reconnects
Backend Restart
- Trading control mode restored from:
- Supabase snapshot (preferred)
bot_state.json(fallback)
- Default mode:
RUNNING
Race Conditions
- Backend state is authoritative
- UI always reflects backend state
- No client-side assumptions
Testing
Backend Tests
Unit Tests:
describe('HealthTracker', () => {
it('should block entries when paused', () => {
healthTracker.recordTradingControl({ mode: 'PAUSED', ... });
expect(healthTracker.isPaused()).toBe(true);
});
it('should allow exits when paused', () => {
// exits still execute
});
});
Integration Tests:
describe('Trading Control', () => {
it('should block new entries when paused', async () => {
await pauseTrading();
const result = await autoTrader.handleSignal(...);
expect(result).toBeUndefined(); // entry blocked
});
it('should allow entries after resume', async () => {
await resumeTrading();
const result = await autoTrader.handleSignal(...);
expect(result).toBeDefined(); // entry allowed
});
});
Frontend Tests
DOM Tests:
describe('AdminTab', () => {
it('should disable pause button when already paused', () => {
render(<AdminTab botState={{ health: { tradingControl: { mode: 'PAUSED' } } }} />);
expect(screen.getByText('Pause Auto Trading')).toBeDisabled();
});
it('should show paused banner when paused', () => {
render(<AdminTab botState={{ health: { tradingControl: { mode: 'PAUSED' } } }} />);
expect(screen.getByText('AUTO-TRADING: PAUSED')).toBeInTheDocument();
});
});
Deployment Checklist
- Backend enforcement points implemented
- Admin API endpoints secured
- Trading control state persisted
- Frontend UI controls implemented
- Header status indicator added
- WebSocket updates configured
- Error handling implemented
- Security guards in place
- Audit logging enabled
- Backend unit tests written
- Backend integration tests written
- Frontend DOM tests written
- End-to-end testing completed
- Documentation reviewed
Usage
For Admins
- Navigate to Admin tab (🛡️ icon in header)
- Scroll to Trading Control section
- Click Pause Auto Trading to stop new entries
- Click Resume Auto Trading to allow new entries
- Monitor status in header badge (visible on all pages)
For Developers
Check if trading is paused:
if (healthTracker.isPaused()) {
// Block entry logic
return;
}
Programmatically pause trading:
healthTracker.recordTradingControl({
mode: 'PAUSED',
lastChangedBy: 'system',
lastChangedAt: Date.now(),
reason: 'Automated safety pause'
});
Monitoring
Metrics to Track
- Pause/Resume Events: Count and frequency
- Blocked Entry Attempts: How many entries were blocked while paused
- Pause Duration: Time between pause and resume
- Who Paused: Track which admins are using this feature
Alerts
Consider alerting on:
- Trading paused for > 1 hour
- Multiple pause/resume cycles in short time
- Pause during high-volatility periods
Future Enhancements
- Scheduled Pause: Allow scheduling pause/resume
- Profile-Level Control: Pause specific profiles only
- Symbol-Level Control: Pause specific symbols only
- Conditional Resume: Auto-resume based on conditions
- Pause Reasons: Predefined reason dropdown
- Pause History: Log of all pause/resume events
Conclusion
This implementation provides a production-grade safety control for managing auto-trading execution. It prioritizes:
✅ Correctness: Backend enforcement, no shortcuts ✅ Security: Admin-only, audited, idempotent ✅ Observability: Clear status, audit logs, health metrics ✅ Safety: Existing positions continue lifecycle ✅ UX: Clear indicators, tooltips, error handling
The system is designed to handle money-at-risk scenarios with appropriate safeguards and fail-safes.