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

Get Backtest Results

Retrieve detailed results and performance metrics for a completed backtest.

Endpoint

GET /api/backtests/:id

Authentication

Requires authentication via Bearer token.

Authorization: Bearer <access_token>

Request

Path Parameters

ParameterTypeRequiredDescription
idstringYesBacktest ID

Response

Success (200 OK)

{
"id": "507f1f77bcf86cd799439013",
"algorithmId": "507f1f77bcf86cd799439011",
"userId": "507f191e810c19729de860ea",
"status": "completed",
"progress": 100,

"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-01-31T23:59:59Z",
"initialBalance": 100000,
"finalBalance": 115000,
"symbols": ["NSE:RELIANCE", "NSE:TCS"],

"results": {
"totalTrades": 45,
"winningTrades": 28,
"losingTrades": 17,
"totalProfit": 18000,
"totalLoss": 3000,
"netProfit": 15000,
"winRate": 62.22,
"profitFactor": 6.0,
"sharpeRatio": 1.8,
"maxDrawdown": 5.2,
"maxDrawdownPercent": 5.2,
"averageWin": 642.86,
"averageLoss": 176.47,
"largestWin": 2500,
"largestLoss": 500,
"averageTradeDuration": 180,
"expectancy": 333.33,
"returnOnInvestment": 15.0
},

"equityCurve": [
{ "date": "2024-01-01", "balance": 100000 },
{ "date": "2024-01-02", "balance": 101500 },
{ "date": "2024-01-03", "balance": 103000 },
"..."
],

"trades": [
{
"symbol": "NSE:RELIANCE",
"entryTime": "2024-01-02T10:15:00Z",
"entryPrice": 2500,
"exitTime": "2024-01-02T14:30:00Z",
"exitPrice": 2550,
"quantity": 10,
"side": "long",
"profit": 500,
"profitPercent": 2.0,
"exitReason": "take_profit"
},
"..."
],

"createdAt": "2024-01-15T11:00:00Z",
"completedAt": "2024-01-15T11:05:00Z"
}

Running Backtest

If backtest is still running:

{
"id": "507f1f77bcf86cd799439013",
"status": "running",
"progress": 45,
"message": "Processing historical data..."
}

Failed Backtest

If backtest failed:

{
"id": "507f1f77bcf86cd799439013",
"status": "failed",
"error": "Insufficient historical data for NSE:RELIANCE",
"createdAt": "2024-01-15T11:00:00Z",
"failedAt": "2024-01-15T11:02:00Z"
}

Errors

StatusCodeMessage
401UNAUTHORIZEDAuthentication required
403FORBIDDENAccess denied (not your backtest)
404NOT_FOUNDBacktest not found

Examples

Get Backtest Results

cURL:

curl -X GET https://api.x3algo.com/api/backtests/507f1f77bcf86cd799439013 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

JavaScript:

const backtestId = '507f1f77bcf86cd799439013'

const response = await fetch(
`https://api.x3algo.com/api/backtests/${backtestId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
)

const backtest = await response.json()

if (backtest.status === 'completed') {
console.log('Win Rate:', backtest.results.winRate + '%')
console.log('Profit Factor:', backtest.results.profitFactor)
console.log('Net Profit:', backtest.results.netProfit)
} else {
console.log('Status:', backtest.status)
console.log('Progress:', backtest.progress + '%')
}

Python:

backtest_id = '507f1f77bcf86cd799439013'

response = requests.get(
f'https://api.x3algo.com/api/backtests/{backtest_id}',
headers={'Authorization': f'Bearer {access_token}'}
)

backtest = response.json()

if backtest['status'] == 'completed':
results = backtest['results']
print(f"Win Rate: {results['winRate']}%")
print(f"Profit Factor: {results['profitFactor']}")
print(f"Net Profit: {results['netProfit']}")

Analyze Equity Curve

JavaScript:

const backtest = await getBacktestResults(backtestId)

// Calculate drawdown periods
const equityCurve = backtest.equityCurve
let peak = equityCurve[0].balance
let maxDrawdown = 0

for (const point of equityCurve) {
if (point.balance > peak) {
peak = point.balance
}

const drawdown = ((peak - point.balance) / peak) * 100
if (drawdown > maxDrawdown) {
maxDrawdown = drawdown
}
}

console.log('Max Drawdown:', maxDrawdown.toFixed(2) + '%')

Analyze Trade Distribution

JavaScript:

const backtest = await getBacktestResults(backtestId)

// Group trades by exit reason
const tradesByReason = backtest.trades.reduce((acc, trade) => {
acc[trade.exitReason] = (acc[trade.exitReason] || 0) + 1
return acc
}, {})

console.log('Trades by Exit Reason:', tradesByReason)

// Calculate average profit by symbol
const profitBySymbol = backtest.trades.reduce((acc, trade) => {
if (!acc[trade.symbol]) {
acc[trade.symbol] = { total: 0, count: 0 }
}
acc[trade.symbol].total += trade.profit
acc[trade.symbol].count++
return acc
}, {})

for (const [symbol, data] of Object.entries(profitBySymbol)) {
const avgProfit = data.total / data.count
console.log(`${symbol}: ${avgProfit.toFixed(2)} avg profit`)
}

Performance Metrics Explained

MetricDescriptionGood Value
Win RatePercentage of winning trades> 50%
Profit FactorTotal profit / Total loss> 1.5
Sharpe RatioRisk-adjusted returns> 1.0
Max DrawdownLargest peak-to-trough decline< 20%
ExpectancyAverage profit per trade> 0
ROIReturn on investment> 10% annually

Trade Fields

FieldDescription
symbolTrading symbol
entryTimeEntry timestamp
entryPriceEntry price
exitTimeExit timestamp
exitPriceExit price
quantityPosition size
sidelong or short
profitProfit/loss amount
profitPercentProfit/loss percentage
exitReasonWhy position closed: take_profit, stop_loss, trailing_stop, opposite_signal, time_exit

Notes

  • Results are cached for 30 days
  • Equity curve shows daily balance
  • All trades include entry/exit details
  • Slippage is included in calculations
  • Commission/fees are applied if configured