ChatGPT Trading Strategy Backtesting Framework Prompt

You are a quantitative analyst who has built backtesting frameworks for hedge funds.

Category
📊 Trading
Difficulty
Advanced
Models
3
Last Updated
2026-06-28
📊 Trading Advanced backtesting quantitative systematic trading python
Works with
📋 Prompt
You are a quantitative analyst who has built backtesting frameworks for hedge funds.

Strategy: [strategy name]
Entry rules: [entry rules — specific, measurable conditions]
Exit rules: [exit rules — TP/SL/trailing/time-based]
Instrument: [instrument]

Task: Build a complete backtesting framework:

1. STRATEGY DEFINITION: Exact entry/exit conditions in code-friendly language

2. PYTHON BACKTEST CODE: Complete script using pandas + vectorised operations

3. PERFORMANCE METRICS: Total return, CAGR, Sharpe ratio, max drawdown, win rate, profit factor, avg RR

4. OPTIMISATION: Parameters to optimise + walk-forward testing approach

5. OVERFITTING SAFEGUARDS: How to distinguish real edge from curve-fitting

6. INTERPRETING RESULTS: What good vs. bad backtest metrics look like for this strategy type
STRATEGY: SMC + EMA200 Trend Filter
Entry: Price below EMA200 + H4 BOS bearish + H1 FVG forms
Exit: 1:2 RR fixed OR trailing stop below swing lows

```python
import pandas as pd
import numpy as np

def backtest_smc_ema(data: pd.DataFrame, risk_pct: float = 0.01) -> dict:
df = data.copy()

# EMA200 filter
df['ema200'] = df['close'].ewm(span=200, adjust=False).mean()
df['below_ema'] = df['close'] < df['ema200']

# Swing low detection (simplified)
window = 5
df['swing_low'] = df['low'][(df['low'] == df['low'].rolling(window*2+1, center=True).min())]
df['last_swing_low'] = df['swing_low'].ffill()

# BOS signal: close below last swing low + below EMA200
df['bos_bearish'] = df['below_ema'] & (df['close'] < df['last_swing_low'])

# FVG: 3-candle bullish imbalance (gap between candle 1 high and candle 3 low)
df['fvg_bearish'] = df['low'] > df['high'].shift(2)

# Entry signal
df['signal'] = df['bos_bearish'] & df['fvg_bearish'].rolling(5).max().astype(bool)

# Simulate trades
trades = []
for idx in df[df['signal']].index:
entry = df.loc[idx, 'close']
sl_dist = entry - (df.loc[idx, 'last_swing_low'] * 0.995)
trades.append({
'entry': entry, 'sl': entry + sl_dist, 'tp': entry - (sl_dist * 2)
})

return {'total_trades': len(trades), 'signals': df['signal'].sum()}
```

PERFORMANCE TARGETS:
✅ Profit Factor > 1.5 (every £1 risked returns £1.50+)
✅ Sharpe Ratio > 1.0
✅ Max Drawdown < 20%
✅ Win rate > 35% at 1:2 RR (expectancy positive)
❌ Win rate 70%+ with tiny RR = likely overfitted
🏆
Best model for this prompt
DeepSeek
DeepSeek V3 / R1
💡 Pro Tips
Walk-forward testing is mandatory — split data 70% training / 30% out-of-sample, trust only the out-of-sample metrics
Transaction costs must be included — spreads, commission, and slippage typically reduce backtest returns by 20–50%
Monte Carlo simulation on your trade list shows probability of live results matching backtest results
More parameters = higher curve-fitting risk — every extra optimisable variable needs 50+ more trades to be meaningful
⚠️ Common Mistakes
Testing on the same data you optimised on — this always produces impressive results that fail live
Ignoring overnight swap costs for multi-day strategies — can turn a winning strategy into a losing one
Lookahead bias — accidentally using future data in entry conditions
Treating backtest results as a guarantee — they're a lower bound on what you need to see before considering live trading
❓ FAQ 🔗 Related Prompts