Skip to main content
Skip to main content
Version: Next 🚧

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:

  1. Sufficient Trades: Minimum 30-50 trades for statistical significance
  2. Realistic Results: Check if returns are reasonable (not too good to be true)
  3. Trade Distribution: Trades should be spread across the date range
  4. 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:

  1. Review entry conditions - simplify if needed
  2. Check symbol format and data availability
  3. Verify trading hours configuration
  4. 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:

  1. Reduce number of symbols
  2. Use longer timeframe for initial tests
  3. Shorten date range
  4. Simplify indicator calculations

Problem: Unrealistic Results

Possible Causes:

  • Look-ahead bias in indicators
  • No slippage configured
  • Insufficient data quality
  • Overfitted parameters

Solutions:

  1. Review indicator calculations
  2. Add realistic slippage (0.1% minimum)
  3. Use quality data sources
  4. Test on out-of-sample data

Best Practices

  1. Start Small: Test single symbol first, then expand
  2. Use Realistic Parameters: Match live trading conditions
  3. Include Slippage: Always add 0.1% minimum slippage
  4. Test Multiple Periods: Validate across different market conditions
  5. Check Trade Count: Aim for 50+ trades for significance
  6. Review Trade Log: Examine individual trades for anomalies
  7. Compare Timeframes: Test on multiple timeframes
  8. Document Results: Keep records of all backtest configurations