Skip to main content

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.

The Backtests API is the computational core of the Hedge Fund platform. A backtest ties a trading strategy to a specific engine (vectorbt or Backtrader), an execution configuration (capital, commission, slippage, signal logic), and a date range. Once created, a backtest can be triggered synchronously for immediate results or dispatched to the Celery worker pool for non-blocking execution. After a run completes, the API surfaces structured performance, risk, and trading metrics, downloadable equity curves and trade lists, side-by-side multi-run comparison, and full grid-search parameter sweeps — all against a single persistent database record that advances through pending → running → completed (or failed).

CRUD

Create a Backtest


POST /api/v1/backtests Creates a new backtest configuration record in pending status. The record is not executed until you call /execute. Returns the persisted BacktestRead object with a generated UUID you use in every subsequent call.

Request Body

strategy_id
uuid
required
UUID of the strategy this backtest is attached to. The strategy must already exist.
engine
string
default:"vectorbt"
Execution engine. One of "vectorbt" or "backtrader". Use GET /engines/available to confirm which engines are registered on this deployment.
initial_capital
float
default:"100000.0"
Starting portfolio value in base currency units (e.g. USD).
commission
float
default:"0.0005"
Per-trade commission as a fraction of notional (e.g. 0.0005 = 5 bps).
slippage
float
default:"0.0005"
Per-trade slippage as a fraction of price, applied symmetrically on entry and exit.
config
BacktestRunConfig
required
Full execution configuration. All fields below live inside this object.

Response — BacktestRead

id
uuid
Unique identifier for this backtest record.
strategy_id
uuid
Strategy this backtest belongs to.
engine
string
Engine selected for this run ("vectorbt" or "backtrader").
status
string
Lifecycle status. One of "pending", "running", "completed", "failed".
initial_capital
float
Starting capital as persisted.
commission
float
Per-trade commission fraction.
slippage
float
Per-trade slippage fraction.
config
dict
The BacktestRunConfig stored as JSONB.
metrics
dict
Empty at creation time; populated after a successful execution.
trades_uri
string | null
Storage URI for the trades parquet artifact. null until completed.
equity_curve_uri
string | null
Storage URI for the equity-curve parquet artifact. null until completed.
created_at
datetime
ISO-8601 creation timestamp.
updated_at
datetime
ISO-8601 last-update timestamp.
curl -X POST https://api.example.com/api/v1/backtests \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": "a1b2c3d4-0000-0000-0000-000000000001",
    "engine": "vectorbt",
    "initial_capital": 100000.0,
    "commission": 0.0005,
    "slippage": 0.0005,
    "config": {
      "symbol": "AAPL",
      "timeframe": "1d",
      "start_date": "2020-01-01T00:00:00",
      "end_date": "2024-01-01T00:00:00",
      "signal_plugin_key": "crossover_signal",
      "signal_plugin_params": {"fast_period": 10, "slow_period": 50},
      "bars_per_year": 252,
      "risk_free_rate": 0.04,
      "size_type": "percent"
    }
  }'

List Backtests

GET /api/v1/backtests Returns a paginated list of backtest records. Optionally filter to a single strategy.

Query Parameters

strategy_id
uuid
When provided, only backtests belonging to this strategy are returned.
skip
int
default:"0"
Number of records to skip (offset-based pagination).
limit
int
default:"100"
Maximum records to return.
Responselist[BacktestRead] (same schema as the create response).
# All backtests for a strategy
curl "https://api.example.com/api/v1/backtests?strategy_id=a1b2c3d4-0000-0000-0000-000000000001&limit=20"

Get a Backtest

GET /api/v1/backtests/{backtest_id} Retrieves a single backtest by ID. When status is "completed", the response includes the structured_metrics block with typed sub-objects for performance, risk, and trading statistics (see Structured Metrics below).

Path Parameters

backtest_id
uuid
required
UUID of the backtest to retrieve.
ResponseBacktestResultResponse (superset of BacktestRead, adds structured_metrics).

Update a Backtest

PATCH /api/v1/backtests/{backtest_id} Partially updates a backtest record. Intended primarily for administrative corrections; normal lifecycle transitions happen automatically during execution.

Path Parameters

backtest_id
uuid
required
UUID of the backtest to update.

Request Body

status
string
Override the status string (e.g. to reset a stuck "running" record back to "pending").
metrics
dict
Replace the stored flat metrics dict.
trades_uri
string
Update the trades artifact storage URI.
equity_curve_uri
string
Update the equity-curve artifact storage URI.
ResponseBacktestRead.

Delete a Backtest

DELETE /api/v1/backtests/{backtest_id} Permanently deletes the backtest record. Artifact files stored at trades_uri and equity_curve_uri are not automatically removed from object storage; clean those up separately if needed.

Path Parameters

backtest_id
uuid
required
UUID of the backtest to delete.
Response204 No Content.

Execution

Execute a Backtest

POST /api/v1/backtests/{backtest_id}/execute Triggers the full backtest pipeline against the configuration stored in the record. Supports both synchronous and asynchronous modes via the async_mode flag.
Returns 409 Conflict if the backtest is already in "running" status. Check GET /api/v1/backtests/{backtest_id} first if you are unsure.

Path Parameters

backtest_id
uuid
required
UUID of the backtest to execute.

Request Body

async_mode
bool
default:"false"
When false (default), the request blocks until the backtest completes and returns the full BacktestResultResponse including structured_metrics. When true, the run is dispatched to Celery and the endpoint immediately returns a task_id and "PENDING" status. Poll GET /api/v1/tasks/{task_id} for the result.

Sync Response — BacktestResultResponse

id
uuid
Backtest UUID.
strategy_id
uuid
Parent strategy UUID.
engine
string
Engine used ("vectorbt" or "backtrader").
status
string
"completed" on success, "failed" if the engine raised an error.
metrics
dict
Flat metrics dict with prefixed keys (e.g. perf_sharpe_ratio, risk_max_drawdown).
structured_metrics
BacktestMetricsSummary | null
Typed breakdown of the flat metrics dict. Only present when status == "completed". See Structured Metrics.
equity_curve_uri
string
Storage URI of the equity-curve artifact.
trades_uri
string
Storage URI of the trades artifact.
created_at
datetime
Creation timestamp.
updated_at
datetime
Completion timestamp.

Async Response

{
  "task_id": "8f14e45f-ceea-467a-a866-4bf53c4540b2",
  "status": "PENDING"
}
# Synchronous run — blocks until complete
curl -X POST https://api.example.com/api/v1/backtests/f47ac10b-58cc-4372-a567-0e02b2c3d479/execute \
  -H "Content-Type: application/json" \
  -d '{"async_mode": false}'

# Asynchronous — returns task_id immediately
curl -X POST https://api.example.com/api/v1/backtests/f47ac10b-58cc-4372-a567-0e02b2c3d479/execute \
  -H "Content-Type: application/json" \
  -d '{"async_mode": true}'

Execute Async (dedicated endpoint)

POST /api/v1/backtests/{backtest_id}/execute/async Convenience endpoint that always dispatches execution to the Celery worker pool — equivalent to calling /execute with async_mode: true. Returns 409 if the backtest is already running.

Path Parameters

backtest_id
uuid
required
UUID of the backtest to execute asynchronously.
Response
{
  "task_id": "3e4d5f6a-0000-0000-0000-000000000099",
  "status": "PENDING"
}
Poll GET /api/v1/tasks/{task_id} to check worker progress. When the task succeeds, retrieve the full result from GET /api/v1/backtests/{backtest_id}.

List Available Engines

GET /api/v1/backtests/engines/available Returns the list of backtest engines currently registered in the engine registry on this deployment. Response
{
  "engines": ["vectorbt", "backtrader"]
}

Results

All four result endpoints below require the backtest to be in "completed" status and to have non-null artifact URIs. They return 404 if the backtest ID does not exist and 409 if the backtest is not yet completed or the result artifacts are missing.
Result endpoints return 409 Conflict when called on a backtest that has not yet completed. Ensure status == "completed" (via GET /api/v1/backtests/{backtest_id}) before requesting artifacts.

Get Equity Curve (JSON)

GET /api/v1/backtests/{backtest_id}/equity-curve Returns the full equity curve as a JSON array of {date, equity} objects — one record per bar.
backtest_id
uuid
required
UUID of a completed backtest.
Response
[
  {"date": "2020-01-02", "equity": 100000.0},
  {"date": "2020-01-03", "equity": 100412.5},
  {"date": "2020-01-06", "equity": 101093.8}
]

Download Equity Curve (Parquet)

GET /api/v1/backtests/{backtest_id}/equity-curve/parquet Streams the equity curve as an Apache Parquet file with a date index and an equity column. The response has Content-Disposition: attachment; filename=equity_{backtest_id}.parquet.
backtest_id
uuid
required
UUID of a completed backtest.
curl -O "https://api.example.com/api/v1/backtests/f47ac10b-58cc-4372-a567-0e02b2c3d479/equity-curve/parquet"

Get Trade List (JSON)

GET /api/v1/backtests/{backtest_id}/trades Returns the complete list of closed trades as a JSON array. Each object contains at minimum pnl, return_pct, and side columns as recorded by the engine adapter.
backtest_id
uuid
required
UUID of a completed backtest.
Response
[
  {"entry_date": "2020-01-02", "exit_date": "2020-01-10", "side": "long", "pnl": 412.5, "return_pct": 0.00413},
  {"entry_date": "2020-02-03", "exit_date": "2020-02-14", "side": "long", "pnl": -218.0, "return_pct": -0.00218}
]

Download Trade List (Parquet)

GET /api/v1/backtests/{backtest_id}/trades/parquet Streams the trade list as a Parquet file (no index). The response has Content-Disposition: attachment; filename=trades_{backtest_id}.parquet.
backtest_id
uuid
required
UUID of a completed backtest.
curl -O "https://api.example.com/api/v1/backtests/f47ac10b-58cc-4372-a567-0e02b2c3d479/trades/parquet"

Structured Metrics

When GET /api/v1/backtests/{backtest_id} or a synchronous /execute returns a completed backtest, the structured_metrics field is populated. This is a typed decomposition of the flat metrics JSONB column into three namespaced sub-objects, computed by the engine-agnostic compute_metrics function so the numbers are identical regardless of which engine ran the backtest.
total_return
float
Cumulative return over the full backtest period as a decimal fraction. 0.25 = 25% total return.
bars_in_market
int
Number of bars where the strategy held a non-zero position. Refined by engine adapters if a position series is available.
performance
PerformanceMetricsSchema
Annualised risk-adjusted performance metrics.
risk
RiskMetricsSchema
Drawdown and tail-risk metrics.
trading
TradingMetricsSchema
Trade-level execution statistics.
The flat metrics dict stores the same values with prefixed keys for direct database querying:
Flat keyStructured path
total_returnstructured_metrics.total_return
bars_in_marketstructured_metrics.bars_in_market
perf_cagrstructured_metrics.performance.cagr
perf_sharpe_ratiostructured_metrics.performance.sharpe_ratio
perf_sortino_ratiostructured_metrics.performance.sortino_ratio
perf_calmar_ratiostructured_metrics.performance.calmar_ratio
risk_max_drawdownstructured_metrics.risk.max_drawdown
risk_max_drawdown_durationstructured_metrics.risk.max_drawdown_duration
risk_var_95structured_metrics.risk.var_95
risk_cvar_95structured_metrics.risk.cvar_95
risk_var_99structured_metrics.risk.var_99
risk_cvar_99structured_metrics.risk.cvar_99
risk_volatility_annualisedstructured_metrics.risk.volatility_annualised
trade_total_tradesstructured_metrics.trading.total_trades
trade_win_ratestructured_metrics.trading.win_rate
trade_profit_factorstructured_metrics.trading.profit_factor
trade_avg_winstructured_metrics.trading.avg_win
trade_avg_lossstructured_metrics.trading.avg_loss
trade_expectancystructured_metrics.trading.expectancy
trade_turnover_annualisedstructured_metrics.trading.turnover_annualised

Comparison

Compare Multiple Backtests

POST /api/v1/backtests/compare Side-by-side metric comparison of between 2 and 10 backtest runs. For every metric key found across any of the supplied runs, the response includes each run’s value and identifies the best-performing run based on whether higher or lower is better for that metric.
All requested backtest IDs must exist; the endpoint returns 404 if any are missing. Backtests do not need to be completed — the raw metrics dict is compared regardless of status, though absent metrics simply show null.

Request Body

backtest_ids
list[uuid]
required
Between 2 and 10 backtest UUIDs to compare. Order does not affect results.

Response — BacktestCompareResponse

runs
list[BacktestCompareRow]
One entry per requested backtest.
metric_diff
dict[string, MetricDiff]
Keyed by flat metric name (e.g. "perf_sharpe_ratio"). Each value is a MetricDiff object.
Higher-is-better metrics (higher_is_better: true): perf_cagr, perf_sharpe_ratio, perf_sortino_ratio, perf_calmar_ratio, total_return, trade_win_rate, trade_profit_factor, trade_expectancy, bars_in_market Lower-is-better metrics (higher_is_better: false): risk_max_drawdown, risk_max_drawdown_duration, risk_var_95, risk_cvar_95, risk_var_99, risk_cvar_99, risk_volatility_annualised
curl -X POST https://api.example.com/api/v1/backtests/compare \
  -H "Content-Type: application/json" \
  -d '{
    "backtest_ids": [
      "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "9b74c980-0000-0000-0000-000000000002",
      "1a2b3c4d-0000-0000-0000-000000000003"
    ]
  }'
{
  "runs": [
    {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "engine": "vectorbt",
      "status": "completed",
      "metrics": {"perf_sharpe_ratio": 1.42, "risk_max_drawdown": 0.18}
    },
    {
      "id": "9b74c980-0000-0000-0000-000000000002",
      "engine": "backtrader",
      "status": "completed",
      "metrics": {"perf_sharpe_ratio": 0.97, "risk_max_drawdown": 0.12}
    }
  ],
  "metric_diff": {
    "perf_sharpe_ratio": {
      "values": {
        "f47ac10b-58cc-4372-a567-0e02b2c3d479": 1.42,
        "9b74c980-0000-0000-0000-000000000002": 0.97
      },
      "best_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "higher_is_better": true
    },
    "risk_max_drawdown": {
      "values": {
        "f47ac10b-58cc-4372-a567-0e02b2c3d479": 0.18,
        "9b74c980-0000-0000-0000-000000000002": 0.12
      },
      "best_id": "9b74c980-0000-0000-0000-000000000002",
      "higher_is_better": false
    }
  }
}

Parameter Sweep

POST /api/v1/backtests/sweep Submits a grid of backtest configurations to the Celery worker pool for parallel execution. Each entry in param_grid is merged (shallow) over base_config to produce one complete BacktestRunConfig, so only the fields you want to vary need to appear in each grid entry. The engine ranks all completed runs by rank_metric and returns the leaderboard when the task finishes.
The sweep endpoint always dispatches asynchronously. Poll GET /api/v1/tasks/{task_id} to retrieve progress and the ranked leaderboard once all runs complete.
param_grid is capped at 50 entries. Requests with more than 50 override dicts will be rejected with 422 Unprocessable Entity.

Request Body

strategy_id
string
required
UUID string of the strategy to run the sweep against.
engine
string
default:"vectorbt"
Engine to use for all runs in the grid. All entries share the same engine.
base_config
dict
required
A complete BacktestRunConfig-compatible dict. Every key not overridden by a param_grid entry will use this value.
param_grid
list[dict]
required
List of 1–50 override dicts. Each dict is merged over base_config to produce one run’s configuration. Keys that appear in an entry replace the corresponding base_config key; all other base_config keys are inherited unchanged.
rank_metric
string
default:"perf_sharpe_ratio"
Flat metric key used to rank completed runs in the leaderboard (e.g. "perf_sharpe_ratio", "perf_calmar_ratio", "total_return").

Response

task_id
string
Celery task UUID. Use with GET /api/v1/tasks/{task_id} to poll for the ranked leaderboard.
status
string
Always "PENDING" immediately after dispatch.
n_configs
int
Number of backtest configurations dispatched (equals len(param_grid)).
# Sweep over three commission levels — all other settings are inherited from base_config
curl -X POST https://api.example.com/api/v1/backtests/sweep \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": "a1b2c3d4-0000-0000-0000-000000000001",
    "engine": "vectorbt",
    "base_config": {
      "symbol": "AAPL",
      "timeframe": "1d",
      "start_date": "2020-01-01T00:00:00",
      "end_date": "2024-01-01T00:00:00",
      "signal_plugin_key": "crossover_signal",
      "signal_plugin_params": {"fast_period": 10, "slow_period": 50},
      "bars_per_year": 252,
      "risk_free_rate": 0.04,
      "size_type": "percent"
    },
    "param_grid": [
      {"commission": 0.0001},
      {"commission": 0.0005},
      {"commission": 0.001}
    ],
    "rank_metric": "perf_sharpe_ratio"
  }'
{
  "task_id": "d2e3f4a5-0000-0000-0000-000000000077",
  "status": "PENDING",
  "n_configs": 3
}
Once the task completes, GET /api/v1/tasks/{task_id} returns the full ranked leaderboard — a list of {config, metrics} pairs ordered by rank_metric descending. The first entry is the best-performing configuration from the sweep.

Build docs developers (and LLMs) love