> ## Documentation Index
> Fetch the complete documentation index at: https://quantcontext.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# backtest_strategy

> Test a trading strategy historically using a rebalance-loop engine

**When to use:** The user wants to test a trading strategy historically. Any query about "backtest", "test this strategy", "what would have happened if", "historical performance", or "how does this strategy do over time" should use this tool.

**What it returns:** Performance metrics (CAGR, Sharpe, max drawdown, Calmar, win rate, turnover), a sampled equity curve, and a trade summary. Also includes the full equity curve for use with `factor_analysis`.

## Parameters

<ParamField query="stages" type="list[object]" required>
  Pipeline stages defining the strategy. See [Pipeline Stage Schema](#pipeline-stage-schema) below.
</ParamField>

<ParamField query="universe" type="string" default="sp500">
  Stock universe: `sp500`, `russell2000`, or `nasdaq100`
</ParamField>

<ParamField query="rebalance" type="string" default="monthly">
  Rebalance frequency: `daily`, `weekly`, `monthly`, or `quarterly`
</ParamField>

<ParamField query="sizing" type="string" default="equal_weight">
  Position sizing method: `equal_weight` or `inverse_volatility`
</ParamField>

<ParamField query="start_date" type="string" default="2023-01-01">
  Backtest start date in `YYYY-MM-DD` format.
</ParamField>

<ParamField query="end_date" type="string" default="2025-12-31">
  Backtest end date in `YYYY-MM-DD` format.
</ParamField>

<ParamField query="max_position_size" type="float | null" default="null">
  Maximum weight per position (0–1). E.g. `0.1` caps each position at 10% of portfolio.
</ParamField>

<ParamField query="stop_loss" type="float | null" default="null">
  Per-position stop loss (0–1). E.g. `0.15` sells a position if it falls 15% from entry.
</ParamField>

<ParamField query="max_drawdown" type="float | null" default="null">
  Portfolio circuit breaker (0–1). E.g. `0.2` moves the portfolio to cash if it drawdowns 20% from peak.
</ParamField>

## Pipeline Stage Schema

Each stage is an object:

```json theme={null}
{
  "order": 1,
  "type": "screen",
  "skill": "fundamental_screen",
  "config": { "pe_lt": 15 }
}
```

| Field    | Type    | Description                                                                         |
| -------- | ------- | ----------------------------------------------------------------------------------- |
| `order`  | integer | Execution order, ascending                                                          |
| `type`   | string  | `"screen"`, `"analyze"`, or `"signal"`                                              |
| `skill`  | string  | Any screen type from `screen_stocks` (e.g. `fundamental_screen`, `momentum_screen`) |
| `config` | object  | Same config object as `screen_stocks`                                               |

### Multi-stage example

Filter value stocks, then rank survivors by momentum:

```json theme={null}
[
  {
    "order": 1,
    "type": "screen",
    "skill": "fundamental_screen",
    "config": { "pe_lt": 15, "roe_gt": 12 }
  },
  {
    "order": 2,
    "type": "signal",
    "skill": "momentum_screen",
    "config": { "lookback_days": 200, "top_pct": 0.3 }
  }
]
```

<Tip>
  The pipeline is sequential:stage 2 receives the filtered output of stage 1 as its input universe. This lets you compose screens (filter → rank → select).
</Tip>

## Example Response

```json theme={null}
{
  "strategy": {
    "universe": "sp500",
    "rebalance": "monthly",
    "sizing": "equal_weight",
    "stages": [{ "order": 1, "type": "screen", "skill": "value_screen", "config": { "pe_lt": 15 } }],
    "period": "2023-01-01 to 2025-12-31"
  },
  "metrics": {
    "total_return": 0.3241,
    "cagr": 0.1012,
    "sharpe": 1.24,
    "max_drawdown": -0.1483,
    "calmar": 0.68,
    "win_rate": 0.5312,
    "turnover": 2.41,
    "total_trades": 384
  },
  "equity_curve": [
    { "date": "2023-01-03", "value": 100000.0 },
    { "date": "2023-06-30", "value": 108234.5 },
    { "date": "2025-12-31", "value": 132410.0 }
  ],
  "equity_curve_points": 756,
  "trades": {
    "total_trades": 384,
    "buys": 204,
    "sells": 180,
    "recent_trades": [
      { "date": "2025-12-01", "ticker": "VTRS", "action": "BUY", "shares": 142.5, "price": 70.18 }
    ]
  },
  "full_equity_curve": ["...full array, pass to factor_analysis..."]
}
```

## What to do next

<CardGroup cols={3}>
  <Card title="Decompose returns" icon="magnifying-glass-chart" href="/docs/tools/factor-analysis">
    Pass `full_equity_curve` to `factor_analysis` to understand whether returns come from alpha or factor exposure.
  </Card>

  <Card title="Compare strategies" icon="code-compare">
    Run the same backtest with different screen types, rebalance frequencies, or universes side by side.
  </Card>

  <Card title="Add risk controls" icon="shield">
    Set `stop_loss`, `max_position_size`, or `max_drawdown` to see how risk management affects the equity curve.
  </Card>
</CardGroup>
