How to Run a Backtest
Problem
You've created a trading algorithm and want to test it against historical data to evaluate its performance before risking real capital.
Prerequisites
- A completed trading algorithm (all 5 configuration steps)
- Understanding of your strategy's logic
- Historical market data for your target symbols
Solution
Step 1: Access Backtest Configuration
Navigate to your algorithm and click the "Backtest" button or tab.
// Via API
POST /api/backtest
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
Step 2: Configure Date Range
Select the historical period for testing:
Recommended Date Ranges:
- Short-term strategies (scalping, day trading): 3-6 months
- Swing trading: 6-12 months
- Position trading: 1-3 years
{
"startDate": "2023-01-01",
"endDate": "2023-12-31"
}
Best Practices:
- Include different market conditions (bull, bear, sideways)
- Avoid cherry-picking favorable periods
- Use recent data for relevance
- Ensure sufficient trades (minimum 30-50 for statistical significance)
Step 3: Set Initial Balance
Configure your starting capital:
{
"initialBalance": 100000
}
Guidelines:
- Use realistic capital you plan to trade with
- Match your live trading account size
- Consider minimum balance requirements for your broker
- Account for margin requirements if trading futures/options
Examples:
- Conservative retail trader: ₹50,000 - ₹100,000
- Active trader: ₹200,000 - ₹500,000
- Professional trader: ₹1,000,000+
Step 4: Select Symbols
Choose which instruments to test:
{
"symbols": ["NSE:RELIANCE", "NSE:TCS", "NSE:INFY"]
}
Symbol Selection Tips:
- Test on symbols you plan to trade live
- Include liquid stocks with good volume
- Consider correlation between symbols
- Test single symbol first, then expand
Format Examples:
NSE:RELIANCE # Equity
NSE:NIFTY24DEC24500CE # Options
MCX:CRUDEOIL25JANFUT # Futures
BSE:SENSEX # Index
Step 5: Configure Slippage (Optional)
Set realistic slippage to account for execution delays:
{
"slippage": 0.1
}
Slippage Guidelines:
- Liquid stocks: 0.05% - 0.1%
- Mid-cap stocks: 0.1% - 0.2%
- Small-cap stocks: 0.2% - 0.5%
- Futures: 0.05% - 0.15%
Step 6: Run the Backtest
Execute the backtest:
// Complete backtest configuration
const backtestConfig = {
algorithmId: "algo_123",
startDate: "2023-01-01",
endDate: "2023-12-31",
initialBalance: 100000,
symbols: ["NSE:RELIANCE"],
slippage: 0.1
}
// Submit backtest
const response = await fetch('/api/backtest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(backtestConfig)
})
const backtest = await response.json()
console.log('Backtest ID:', backtest.id)
Step 7: Monitor Progress
Track backtest execution:
// Check backtest status
GET /api/backtest/:id
// Response
{
"id": "backtest_123",
"status": "running", // pending, running, completed, failed
"progress": 45, // percentage
"estimatedTimeRemaining": 120 // seconds
}
Typical Execution Times:
- 3 months, 1 symbol, 15m timeframe: 30-60 seconds
- 1 year, 1 symbol, 15m timeframe: 2-5 minutes
- 1 year, 5 symbols, 5m timeframe: 5-15 minutes
Complete Example
// Full backtest workflow
async function runBacktest() {
// 1. Create backtest
const backtest = await fetch('/api/backtest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
algorithmId: "algo_123",
startDate: "2023-01-01",
endDate: "2023-12-31",
initialBalance: 100000,
symbols: ["NSE:RELIANCE", "NSE:TCS"],
slippage: 0.1
})
}).then(res => res.json())
console.log('Backtest started:', backtest.id)
// 2. Poll for completion
let status = 'running'
while (status === 'running' || status === 'pending') {
await new Promise(resolve => setTimeout(resolve, 5000)) // Wait 5 seconds
const result = await fetch(`/api/backtest/${backtest.id}`, {
headers: { 'Authorization': `Bearer ${token}` }
}).then(res => res.json())
status = result.status
console.log(`Progress: ${result.progress}%`)
}
// 3. Get results
if (status === 'completed') {
const results = await fetch(`/api/backtest/${backtest.id}/results`, {
headers: { 'Authorization': `Bearer ${token}` }
}).then(res => res.json())
console.log('Backtest completed!')
console.log('Total Trades:', results.totalTrades)
console.log('Win Rate:', results.winRate + '%')
console.log('Profit Factor:', results.profitFactor)
console.log('Total Profit:', results.totalProfit)
return results
} else {
console.error('Backtest failed:', status)
}
}
// Run it
runBacktest()
Verification
After running the backtest, verify:
- Sufficient Trades: Minimum 30-50 trades for statistical significance
- Realistic Results: Check if returns are reasonable (not too good to be true)
- Trade Distribution: Trades should be spread across the date range
- No Errors: Check for execution errors or warnings
// Verify backtest quality
function verifyBacktest(results) {
const checks = {
sufficientTrades: results.totalTrades >= 30,
realisticWinRate: results.winRate >= 30 && results.winRate <= 80,
positiveProfitFactor: results.profitFactor > 1.0,
acceptableDrawdown: results.maxDrawdown < 30
}
console.log('Backtest Quality Checks:', checks)
if (Object.values(checks).every(check => check)) {
console.log('✓ Backtest passed all quality checks')
} else {
console.log('⚠ Backtest has quality issues - review results carefully')
}
}
Troubleshooting
Problem: No Trades Generated
Possible Causes:
- Entry conditions too strict
- Symbol had no data for the period
- Trading hours don't match market hours
- Algorithm status not set correctly
Solutions:
- Review entry conditions - simplify if needed
- Check symbol format and data availability
- Verify trading hours configuration
- Ensure algorithm is in "stopped" or "active" status
Problem: Backtest Takes Too Long
Possible Causes:
- Too many symbols
- Very short timeframe (1m, 5m)
- Long date range
- Complex indicator calculations
Solutions:
- Reduce number of symbols
- Use longer timeframe for initial tests
- Shorten date range
- Simplify indicator calculations
Problem: Unrealistic Results
Possible Causes:
- Look-ahead bias in indicators
- No slippage configured
- Insufficient data quality
- Overfitted parameters
Solutions:
- Review indicator calculations
- Add realistic slippage (0.1% minimum)
- Use quality data sources
- Test on out-of-sample data
Best Practices
- Start Small: Test single symbol first, then expand
- Use Realistic Parameters: Match live trading conditions
- Include Slippage: Always add 0.1% minimum slippage
- Test Multiple Periods: Validate across different market conditions
- Check Trade Count: Aim for 50+ trades for significance
- Review Trade Log: Examine individual trades for anomalies
- Compare Timeframes: Test on multiple timeframes
- Document Results: Keep records of all backtest configurations