Live Trading Deployment¶
Overview¶
Deploying a trading system from backtest to live production is a critical transition. It requires rigorous validation, risk controls, monitoring, and a phased rollout to ensure the system behaves as expected with real money.
Difficulty advanced
Deployment Pipeline¶
Stages¶
1. Backtest → Historical data, simulated execution
2. Paper Trade → Live data, simulated execution
3. Shadow Trade → Live data, simulated + real execution comparison
4. Small Capital → Live data, real execution, limited capital
5. Full Production → Live data, real execution, full capital
Transition Criteria¶
| Stage | Duration | Success Criteria |
|---|---|---|
| Backtest | 1-4 weeks | Sharpe > 1, Max DD < 15%, Profit factor > 1.3 |
| Paper Trade | 2-4 weeks | Matches backtest within 10%, no system errors |
| Shadow Trade | 1-2 weeks | Slippage modeled accurately, no critical bugs |
| Small Capital | 4-8 weeks | Risk-adjusted returns consistent, all risk controls work |
| Full Production | Ongoing | Stable operation, continuous monitoring |
Architecture Components¶
┌─────────────────────────────────────┐
│ Monitoring & Alerting │
│ (Prometheus, Grafana, PagerDuty) │
└──────────────────┬──────────────────┘
│
┌──────────────────▼──────────────────┐
│ Risk Management │
│ (Position limits, VaR, Kill switch) │
└──────────────────┬──────────────────┘
│
┌─────────────┐ ┌──────────────────▼──────────────────┐ ┌─────────────┐
│ Market Data │────►│ Trading Engine │────►│ Gateway │
│ Feed │ │ (Signal generation, order logic) │ │ (FIX/OUCH) │
└─────────────┘ └──────────────────┬──────────────────┘ └──────┬──────┘
│ │
┌──────────────────▼──────────────────┐ ┌──────▼──────┐
│ Portfolio Manager │ │ Exchange │
│ (Positions, P&L, reconciliation) │ │ │
└──────────────────┬──────────────────┘ └─────────────┘
│
┌──────────────────▼──────────────────┐
│ Data Storage │
│ (Tick data, orders, fills, logs) │
└─────────────────────────────────────┘
Pre-Deployment Checklist¶
System Validation¶
- [ ] Backtest reproducible (same results from same code)
- [ ] Paper trade results match backtest expectations
- [ ] All edge cases tested (gaps, halts, disconnects)
- [ ] Error handling verified (exchange errors, network failures)
- [ ] Order state management correct (pending, filled, canceled, partial)
- [ ] Position reconciliation accurate
- [ ] P&L calculation verified against broker statement
Risk Controls¶
- [ ] Maximum position size limits enforced
- [ ] Maximum order size limits enforced
- [ ] Daily loss limit (circuit breaker) active
- [ ] Maximum drawdown limit active
- [ ] Position concentration limits set
- [ ] Fat-finger protection (reasonable order sizes)
- [ ] Kill switch implemented and tested
Infrastructure¶
- [ ] Server co-location or low-latency connection
- [ ] Redundant internet connections
- [ ] Backup power (UPS, generator)
- [ ] Monitoring dashboards configured
- [ ] Alerting rules set (latency, errors, P&L thresholds)
- [ ] Log rotation and archival configured
- [ ] Database backups automated
Compliance¶
- [ ] Trading licenses/registrations in place
- [ ] Exchange memberships active
- [ ] Regulatory reporting configured
- [ ] Audit trail logging enabled
- [ ] Data retention policy implemented
Deployment Script¶
import logging
from typing import Dict, List, Optional
from datetime import datetime
logger = logging.getLogger('trading_system')
class DeploymentManager:
"""Manage live trading deployment."""
def __init__(self, config: Dict):
self.config = config
self.mode = config.get('mode', 'paper') # paper, shadow, live
self.capital_limit = config.get('capital_limit', 10000)
self.running = False
def pre_flight_checks(self) -> Dict:
"""Run pre-deployment checks."""
checks = {}
# Check market data connection
checks['market_data'] = self._check_market_data()
# Check exchange connectivity
checks['exchange'] = self._check_exchange()
# Check risk management system
checks['risk_system'] = self._check_risk_system()
# Check portfolio reconciliation
checks['reconciliation'] = self._check_reconciliation()
# Check monitoring
checks['monitoring'] = self._check_monitoring()
# All checks passed?
checks['all_passed'] = all(checks.values())
return checks
def start(self):
"""Start trading system."""
checks = self.pre_flight_checks()
if not checks['all_passed']:
failed = [k for k, v in checks.items() if not v]
logger.error(f"Pre-flight checks failed: {failed}")
raise RuntimeError("Pre-flight checks failed")
self.running = True
logger.info(f"Trading system started in {self.mode} mode")
if self.mode == 'live':
logger.warning(f"Capital limit: ${self.capital_limit}")
def stop(self, reason: str = "Manual stop"):
"""Stop trading system gracefully."""
self.running = False
# Flatten all positions or maintain based on policy
logger.info(f"Trading system stopped: {reason}")
def emergency_stop(self):
"""Kill switch - immediate stop and cancel all orders."""
self.running = False
logger.critical("EMERGENCY STOP ACTIVATED")
# Cancel all open orders
self._cancel_all_orders()
# Optionally flatten positions
if self.config.get('flatten_on_emergency', False):
self._flatten_positions()
def _check_market_data(self) -> bool:
"""Verify market data feed is working."""
try:
# Subscribe to test symbol
# Verify data is flowing
# Check timestamp freshness
return True
except Exception as e:
logger.error(f"Market data check failed: {e}")
return False
def _check_exchange(self) -> bool:
"""Verify exchange connectivity."""
try:
# Send test logon
# Verify sequence numbers
# Check latency
return True
except Exception as e:
logger.error(f"Exchange check failed: {e}")
return False
def _check_risk_system(self) -> bool:
"""Verify risk management is active."""
return True
def _check_reconciliation(self) -> bool:
"""Verify position reconciliation."""
return True
def _check_monitoring(self) -> bool:
"""Verify monitoring is active."""
return True
def _cancel_all_orders(self):
"""Cancel all open orders."""
pass
def _flatten_positions(self):
"""Close all open positions."""
pass
class PaperTradingEngine:
"""Paper trading for pre-live validation."""
def __init__(self, strategy, initial_capital: float = 100000):
self.strategy = strategy
self.capital = initial_capital
self.positions = {}
self.orders = []
self.fills = []
def process_market_data(self, data: Dict):
"""Process incoming market data."""
# Generate signals
signals = self.strategy.on_data(data)
# Generate orders
for signal in signals:
order = self._create_paper_order(signal)
self.orders.append(order)
# Simulate fill
fill = self._simulate_fill(order, data)
if fill:
self.fills.append(fill)
self._update_position(fill)
def _simulate_fill(self, order: Dict, market_data: Dict) -> Optional[Dict]:
"""Simulate order fill with realistic slippage."""
current_price = market_data.get('price')
# Add slippage
slippage = current_price * 0.001 # 10bps
if order['side'] == 'buy':
fill_price = current_price + slippage
else:
fill_price = current_price - slippage
return {
'order_id': order['id'],
'price': fill_price,
'quantity': order['quantity'],
'side': order['side'],
'timestamp': datetime.utcnow(),
'commission': fill_price * order['quantity'] * 0.0001
}
def get_performance(self) -> Dict:
"""Calculate paper trading performance."""
total_pnl = sum(f['price'] * f['quantity'] *
(1 if f['side'] == 'sell' else -1)
for f in self.fills)
total_commission = sum(f.get('commission', 0) for f in self.fills)
return {
'capital': self.capital,
'realized_pnl': round(total_pnl - total_commission, 2),
'n_trades': len(self.fills),
'n_orders': len(self.orders),
'fill_rate': len(self.fills) / len(self.orders) if self.orders else 0
}
Monitoring and Alerting¶
Key Metrics to Monitor¶
MONITORING_METRICS = {
'system': {
'cpu_usage': 'Alert if > 80%',
'memory_usage': 'Alert if > 85%',
'disk_usage': 'Alert if > 90%',
'network_latency': 'Alert if > 10ms to exchange',
},
'trading': {
'orders_per_second': 'Alert if abnormal spike',
'order_rejection_rate': 'Alert if > 1%',
'fill_rate': 'Alert if < 80%',
'slippage': 'Alert if > 2x expected',
'position_reconciliation': 'Alert if mismatch',
},
'risk': {
'daily_pnl': 'Alert if < daily_limit',
'drawdown': 'Alert if > threshold',
'position_size': 'Alert if > max_position',
'concentration': 'Alert if > max_concentration',
},
'data': {
'market_data_latency': 'Alert if > 100ms',
'data_gap': 'Alert if any gap detected',
'quote_staleness': 'Alert if > 1s without update',
}
}
Logging¶
import logging
import json
def setup_logging(log_level: str = 'INFO'):
"""Configure structured logging."""
logging.basicConfig(
level=getattr(logging, log_level),
format='%(asctime)s | %(levelname)s | %(name)s | %(message)s',
handlers=[
logging.FileHandler('trading_system.log'),
logging.StreamHandler()
]
)
# Log all orders
order_logger = logging.getLogger('orders')
order_logger.setLevel(logging.INFO)
order_logger.addHandler(logging.FileHandler('orders.log'))
# Log all fills
fill_logger = logging.getLogger('fills')
fill_logger.setLevel(logging.INFO)
fill_logger.addHandler(logging.FileHandler('fills.log'))
# Log risk events
risk_logger = logging.getLogger('risk')
risk_logger.setLevel(logging.WARNING)
risk_logger.addHandler(logging.FileHandler('risk.log'))
Rollback Plan¶
If something goes wrong in production:
1. Immediate: Activate kill switch
2. Cancel all open orders
3. Assess situation (positions, P&L, system state)
4. Decide: flatten positions or hold
5. Fix the issue
6. Test fix in paper trading
7. Gradual restart (small capital first)
8. Monitor closely for 24+ hours
Checklist¶
- [ ] All pre-flight checks pass
- [ ] Paper trading results satisfactory
- [ ] Risk controls tested and verified
- [ ] Monitoring and alerting active
- [ ] Kill switch tested
- [ ] Rollback plan documented
- [ ] Operations team briefed
- [ ] Emergency contacts available
- [ ] Capital limits set appropriately
- [ ] Post-deployment review scheduled
References¶
- Ernest Chan, E.P. (2013). Algorithmic Trading: Winning Strategies and Their Rationale. Wiley.
- Jansen, S. (2020). Machine Learning for Algorithmic Trading (2nd ed.). Packt.
- SEC. (2023). "Market Access Rule (Rule 15c3-5)." Securities and Exchange Commission.