Paper trading is a simulation of real trading without using real capital. Unlike backtesting (testing on historical data), paper trading runs in real time: the strategy receives live exchange data, generates signals, and sends virtual orders to a broker simulator. This reveals issues invisible in backtesting: data latency, order execution problems, technical failures. We build such systems turnkey so that your AI algorithm passes all validation stages without risking capital.
Why Paper Trading Is a Must
Even a perfectly tuned backtest can give false confidence. Look-ahead bias, overfitting on history, underestimated commissions—typical pitfalls. Paper trading in real time removes these risks: your AI model sees only the data that would have been available at decision time. The divergence in metrics between paper trading and backtest should not exceed 15% in Sharpe ratio—if larger, the strategy needs refinement.
According to the Wikipedia definition, paper trading is a simulation of trading, but in practice it gives much more: mistakes caught at the paper stage can cost up to $15,000 in real trading—that's how much our clients save on average. Paper trading is 3 times more accurate at uncovering execution problems than backtesting due to working with real latency and slippage.
System Architecture
[Market Data Feed] → [Data Normalizer] → [Feature Pipeline]
↓
[AI Model Inference]
↓
[Signal Generator]
↓
[Risk Management Layer]
↓
[Paper Broker Simulator]
↓
[Portfolio State] → [P&L Calculator]
↓
[Monitoring Dashboard]
Components
Market Data Integration:
import asyncio
import websockets
import json
from dataclasses import dataclass
@dataclass
class MarketTick:
symbol: str
timestamp: float
bid: float
ask: float
last: float
volume: float
class AlpacaMarketDataFeed:
def __init__(self, api_key: str, secret_key: str):
self.ws_url = "wss://stream.data.alpaca.markets/v2/sip"
self.headers = {
"APCA-API-KEY-ID": api_key,
"APCA-API-SECRET-KEY": secret_key
}
async def stream_quotes(self, symbols: list, callback):
async with websockets.connect(self.ws_url, extra_headers=self.headers) as ws:
# Subscribe to quotes
await ws.send(json.dumps({
"action": "subscribe",
"quotes": symbols
}))
async for message in ws:
data = json.loads(message)
for item in data:
if item['T'] == 'q': # quote
tick = MarketTick(
symbol=item['S'],
timestamp=item['t'],
bid=item['bp'],
ask=item['ap'],
last=(item['bp'] + item['ap']) / 2,
volume=item.get('bs', 0)
)
await callback(tick)
Paper Broker Simulator:
class PaperBroker:
def __init__(self, initial_capital: float = 100_000):
self.cash = initial_capital
self.positions = {} # symbol -> quantity
self.orders = []
self.fill_probability = 0.95 # 95% orders are filled
def submit_order(self, symbol: str, qty: int, side: str,
order_type: str = 'market', limit_price: float = None):
order_id = str(uuid.uuid4())
order = {
'id': order_id, 'symbol': symbol, 'qty': qty,
'side': side, 'type': order_type,
'limit_price': limit_price, 'status': 'pending',
'submitted_at': datetime.utcnow()
}
self.orders.append(order)
return order_id
def process_tick(self, tick: MarketTick):
for order in self.orders:
if order['status'] != 'pending':
continue
if order['symbol'] != tick.symbol:
continue
# Simulate fill
if order['type'] == 'market':
fill_price = tick.ask if order['side'] == 'buy' else tick.bid
self._fill_order(order, fill_price, tick.timestamp)
elif order['type'] == 'limit':
if (order['side'] == 'buy' and tick.ask <= order['limit_price']):
self._fill_order(order, order['limit_price'], tick.timestamp)
elif (order['side'] == 'sell' and tick.bid >= order['limit_price']):
self._fill_order(order, order['limit_price'], tick.timestamp)
def _fill_order(self, order: dict, price: float, timestamp):
commission = price * order['qty'] * 0.0001
if order['side'] == 'buy':
cost = price * order['qty'] + commission
if self.cash >= cost:
self.cash -= cost
self.positions[order['symbol']] = \
self.positions.get(order['symbol'], 0) + order['qty']
order['status'] = 'filled'
order['fill_price'] = price
elif order['side'] == 'sell':
if self.positions.get(order['symbol'], 0) >= order['qty']:
self.cash += price * order['qty'] - commission
self.positions[order['symbol']] -= order['qty']
order['status'] = 'filled'
How the Broker Simulator Works
The broker simulator is a key component. It mimics order execution with a realistic fill probability (95% in our example) and commissions of 0.01%. This allows you to evaluate real slippage and spread impact. In live trading, latency-sensitive strategies may face worse execution—paper mode helps adjust the algorithm before going to market.
Real-Time Monitoring
The dashboard shows: realized and unrealized P&L in real time, open positions, trade log, equity curve, drawdown, benchmark comparison.
Key Metrics: Paper Trading vs Backtest
| Metric | Backtest (typical) | Paper Trading (expected) | Deviation |
|---|---|---|---|
| Sharpe Ratio | 2.5 | 2.1-2.3 | <15% |
| Max Drawdown | -12% | -14% | <2% |
| Win Rate | 62% | 58% | <5% |
| Avg Trade Return | 0.15% | 0.12% | <0.05% |
If paper trading results are significantly worse than backtesting, it indicates: overfitting to historical data, look-ahead bias in backtest, or underestimated transaction costs. Goal: deviation in Sharpe ratio < 15%.
Development Stages
| Stage | Duration | Result |
|---|---|---|
| Analytics and requirements | 3-5 days | Technical specification |
| Exchange data integration | 5-10 days | API connection (Alpaca/IB/Binance) |
| Feature pipeline and inference | 7-14 days | Normalization and feature calculation |
| Broker simulator and risk management | 10-15 days | Broker with commissions and stop-losses |
| Dashboard and monitoring | 5-10 days | UI with real-time metrics |
| Documentation and training | 2-5 days | Instructions for your team |
More about risks
In paper trading, you may encounter metric misinterpretation due to insufficient statistics. We recommend testing for at least 3 months across different market regimes.What's Included
- Integration with exchange APIs (Alpaca, Interactive Brokers, Binance—your choice)
- Data normalization and feature pipeline module
- Interface for AI model (PyTorch/TensorFlow/JAX) with inference via vLLM or Triton
- Broker simulator with realistic fill probability and commissions
- Risk management: stop-loss, take-profit, position limits
- Real-time metrics dashboard (React + WebSockets)
- Documentation, team training, and 2 months post-launch support
How to Spot a Quality System
Request a demo run on 1-2 weeks of live data. A quality system will show stable p99 latency below 50 ms, 99% uptime, and correct order execution under high volatility. We guarantee these parameters—over 5 years we have delivered 30+ paper trading projects for funds and prop trading firms.
Timeline and Cost
Turnkey system development takes 30 to 60 business days depending on strategy complexity and number of instruments. Cost is calculated individually—contact us and we will estimate your project within 2 days. Get a no-obligation consultation. Contact us to discuss the details of your project.







