Backtesting is the process of replaying a strategy’s signal logic against historical price data to estimate how it would have performed. The Hedge Fund Backend’s Backtest Engine resolves all of a strategy’s referenced artifacts — features, model predictions, signal logic — feeds them to vectorbt, Backtrader, or Lean, and persists the resulting equity curve, trade list, and a comprehensive suite of performance metrics. A completed backtest is a prerequisite for validation and strategy promotion.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/najmulhossainnj/Hedge-fund-backend/llms.txt
Use this file to discover all available pages before exploring further.
BacktestPipeline
When you execute a backtest, the pipeline runs the following resolution steps before any simulation begins:engine field accepts "vectorbt", "backtrader", or "lean":
Backtest Engines
vectorbt
Fast vectorized simulation. Operates on NumPy arrays in a single pass — backtests over years of daily data complete in milliseconds. Supports
discrete (BUY/SELL/HOLD) and numeric (±1) signal modes. Preferred engine for parameter sweeps and AutoML comparisons where speed matters.Backtrader
Event-driven simulation. Processes bars one at a time, firing order execution, fill, and commission events. More realistic for strategies that require order management, position sizing logic, or custom broker models. A custom
BacktraderStrategy class is built dynamically from the signal series.Lean
QuantConnect Lean engine. Production-grade, multi-asset simulation with institutional-quality fill modelling, margin, and corporate-action handling. Use
"engine": "lean" in the execution request to target this adapter.compute_metrics() function after their run completes, ensuring that metrics definitions are identical regardless of which engine was used.
The
size_type field in BacktestRunConfig controls position sizing:"percent"— allocates a fixed percentage of portfolio equity per signal"shares"— allocates a fixed share count"signal_weight"— uses the raw numeric prediction magnitude as the position weight (numeric output mode only)
BacktestResult Fields
After execution, theBacktest record exposes:
| Field | Type | Description |
|---|---|---|
status | string | pending → running → completed | failed |
metrics | object | Flat dict of all computed metrics (see below) |
equity_curve_uri | string | S3 URI to a Parquet file with columns (timestamp, equity) |
trades_uri | string | S3 URI to a Parquet file with columns (entry, exit, pnl, return_pct, side) |
initial_capital | float | Starting capital in base currency |
commission | float | Per-trade commission as a fraction of trade value |
slippage | float | Per-trade slippage as a fraction of trade value |
Metrics Reference
Thecompute_metrics() function (in app/engines/backtest_engine/metrics.py) stores 20 values flat in the Backtest.metrics JSONB column. Two top-level keys (total_return, bars_in_market) are unprefixed; the remaining 18 carry perf_, risk_, or trade_ prefixes:
Top-Level Keys (unprefixed)
| Metric | Key | Description |
|---|---|---|
| Total Return | total_return | (final_equity / initial_capital) - 1 |
| Bars in Market | bars_in_market | Number of bars where a non-zero position was held |
Performance Metrics
| Metric | Key | Description |
|---|---|---|
| CAGR | perf_cagr | Compound Annual Growth Rate: (final/initial)^(1/n_years) - 1 |
| Sharpe Ratio | perf_sharpe_ratio | Annualised excess return / annualised volatility |
| Sortino Ratio | perf_sortino_ratio | Annualised excess return / downside deviation |
| Calmar Ratio | perf_calmar_ratio | CAGR / Max Drawdown |
Risk Metrics
| Metric | Key | Description |
|---|---|---|
| Max Drawdown | risk_max_drawdown | Largest peak-to-trough decline as a positive fraction |
| Max DD Duration | risk_max_drawdown_duration | Longest time (in bars) spent below previous high |
| VaR 95% | risk_var_95 | 1-bar 95% Value at Risk (5th percentile of returns) |
| CVaR 95% | risk_cvar_95 | Expected Shortfall at 95% — mean return below VaR 95% |
| VaR 99% | risk_var_99 | 1-bar 99% Value at Risk (1st percentile of returns) |
| CVaR 99% | risk_cvar_99 | Expected Shortfall at 99% |
| Annualised Vol | risk_volatility_annualised | std(daily_returns) × √bars_per_year |
Trading Metrics
| Metric | Key | Description |
|---|---|---|
| Total Trades | trade_total_trades | Number of closed round-trip trades |
| Win Rate | trade_win_rate | Fraction of trades with positive PnL |
| Profit Factor | trade_profit_factor | Gross profit / gross loss |
| Avg Win | trade_avg_win | Mean PnL of winning trades |
| Avg Loss | trade_avg_loss | Mean PnL of losing trades |
| Expectancy | trade_expectancy | win_rate × avg_win + (1 - win_rate) × avg_loss |
| Annualised Turnover | trade_turnover_annualised | Fraction of portfolio rotated per year |
Parameter Sweep
To find the optimal configuration across many parameter combinations, use the sweep endpoint:Backtest Comparison
Compare up to 10 backtest runs side-by-side to highlight which configuration wins on each metric:metric_diff object contains, for each metric, the value from every run and the ID of the winning run:
Async Execution
For multi-year daily backtests or any Backtrader run (which is inherently event-driven and slower), passasync_mode: true to POST /api/backtests/{id}/execute. The endpoint returns a Celery task_id immediately. Poll GET /api/backtests/{id} to check status.