As developers, we're often tempted to test our trading strategies using paper trading platforms. These tools allow us to simulate trades without risking any real money. But what happens when we start analyzing the data from these simulations? Do they accurately reflect what would happen in the real world?
I ran a 6-week experiment simulating trades across multiple strategies on various assets using TradeSight, my Python paper trading bot. The results were eye-opening.
Slippage: The Silent Killer
When executing trades, brokers incur slippage due to market conditions and order books. Paper trading platforms often assume perfect fill rates or don't account for this spread at all. In reality, even the best traders can expect some level of slippage.
Here's how I started accounting for it in Python:
import yfinance as yf
# Simulate slippage: assume 0.05% on each fill
def apply_slippage(price, direction='buy', slippage_pct=0.0005):
if direction == 'buy':
return price * (1 + slippage_pct)
return price * (1 - slippage_pct)
data = yf.download('AAPL', period='1d')
raw_price = data['Close'].iloc[-1]
actual_buy = apply_slippage(raw_price, 'buy')
print(f'Raw: ${raw_price:.2f}, After Slippage: ${actual_buy:.2f}')
Over 6 weeks, slippage ate roughly 0.3% of total simulated returns — small per trade, huge compounded.
Fill Assumptions: The Unrealistic Benchmark
Paper platforms assume every trade fills at the exact price requested. Real brokers don't. I added a fill simulation layer to TradeSight that randomly rejects ~3% of orders and fills another 5% at a worse price:
import random
def simulate_fill(requested_price, fill_rate=0.97, slippage_range=0.001):
if random.random() > fill_rate:
return None # rejected
actual_fill = requested_price * (1 + random.uniform(0, slippage_range))
return actual_fill
When I turned this on, my best backtest strategy dropped from 12% simulated returns to 9.4% — a 22% gap just from realistic fills.
Spread Modeling: The Hidden Cost
Most paper trading setups ignore bid-ask spread entirely. I calculated average spreads from 6 weeks of tick data:
import numpy as np
# Load tick data and calculate average spread per asset
spreads = {
'AAPL': 0.03, # percent
'SPY': 0.01,
'TSLA': 0.08,
}
avg_spread = np.mean(list(spreads.values()))
print(f'Average Spread Cost: {avg_spread:.2%}')
For high-frequency or short-holding strategies, a 0.04% average spread compounded across 50+ trades/week adds up fast.
What This Means for Strategy Development
After 6 weeks of realistic simulation, the takeaways were clear:
- Never trust returns from platforms with perfect fill assumptions — add 10-20% haircut
- Slippage matters most for volatile assets (TSLA, small caps)
- Longer holding periods dilute these costs — overnight strategies survive better
TradeSight now models all three by default. If you want to see the full simulation code, it's on GitHub: github.com/rmbell09-lang/tradesight
Curious what hidden costs you've found in your own paper trading setups — drop a comment below.
Top comments (0)