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

# Backtest

# Backtest API

The Backtest API powers the Sequency rule-driven backtester, enabling R\&D engineers to stress-test intraday signal strategies against historical market data, optimize parameters, and analyze edge quality. This group includes two versions: the original `/v1` (fixed-request, blocking) and the modern `/v2` (async, Redis-driven, out-of-process workers).

**Base path:** `/api/graph/v1/backtest`

**Auth:** Public routes require a Supabase JWT (user) OR an `X-Internal-Secret` header (service principal). Strict auth is enforced in production (anon → 401).

***

## Core Backtest Run (v1)

### POST /api/graph/v1/backtest

**Start a backtest run**

Launches a historical backtest of intraday signal strategies. The request registers a pending run and spawns a background task to execute it (no longer blocks the HTTP call). Poll `GET /{run_id}` for results.

**Parameters:** None (all config in request body)

**Request body:**

```json theme={null}
{
  "symbols": ["NVDA", "AAPL"],
  "start_date": "2024-01-01",
  "end_date": "2024-12-31",
  "signal_types": ["vwap_touch", "ib_breakout"],
  "stop_atr_mult": 1.5,
  "t1_atr_mult": 2.0,
  "t2_atr_mult": 3.0,
  "t3_atr_mult": 4.0,
  "time_stop_et": "15:45",
  "position_size": 100,
  "slippage_per_share": 0.01,
  "commission_per_share": 0.001,
  "gate_thresholds": null
}
```

**Response 200:**

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "symbols": ["NVDA", "AAPL"],
  "start_date": "2024-01-01",
  "end_date": "2024-12-31",
  "signal_types": ["vwap_touch", "ib_breakout"],
  "stop_atr_mult": 1.5,
  "t1_atr_mult": 2.0,
  "t2_atr_mult": 3.0,
  "t3_atr_mult": 4.0,
  "time_stop_et": "15:45",
  "created_at": "2024-01-15T10:30:00Z",
  "position_size": 100,
  "slippage_per_share": 0.01,
  "commission_per_share": 0.001
}
```

**Constraints:**

* Max 50 symbols per run
* Max 365-day date range
* Max 3 concurrent pending/running backtests per user (returns 429 if exceeded)
* `end_date` must be after `start_date`

***

### GET /api/graph/v1/backtest/{run_id}

**Get backtest run status**

Poll the status and full results of a backtest run. Returns the same shape as the response above, plus computed metrics once the run completes.

**Parameters:**

* `run_id` (path, required): UUID of the backtest run

**Response 200:**

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "symbols": ["NVDA"],
  "start_date": "2024-01-01",
  "end_date": "2024-12-31",
  "signal_types": ["vwap_touch"],
  "stop_atr_mult": 1.5,
  "t1_atr_mult": 2.0,
  "t2_atr_mult": 3.0,
  "t3_atr_mult": 4.0,
  "time_stop_et": "15:45",
  "total_trades": 42,
  "win_count": 28,
  "loss_count": 14,
  "win_rate": 0.667,
  "avg_rr_ratio": 1.85,
  "total_pnl": 12450.50,
  "max_drawdown": -0.08,
  "profit_factor": 2.15,
  "sharpe_ratio": 1.42,
  "by_signal_type": [
    {
      "signal_type": "vwap_touch",
      "total_trades": 42,
      "win_count": 28,
      "loss_count": 14,
      "win_rate": 0.667,
      "avg_pnl_r": 0.85,
      "expectancy_per_r": 1.15,
      "total_pnl": 12450.50
    }
  ],
  "by_symbol": [
    {
      "symbol": "NVDA",
      "total_trades": 42,
      "win_count": 28,
      "loss_count": 14,
      "win_rate": 0.667,
      "total_pnl": 12450.50,
      "max_drawdown": -0.08
    }
  ],
  "equity_curve": [
    {"trade_num": 1, "cumulative_pnl": 245.25, "cumulative_r": 0.5},
    {"trade_num": 2, "cumulative_pnl": 980.75, "cumulative_r": 2.0}
  ],
  "validation_gate": {
    "passed": true,
    "criteria": [
      {
        "name": "Sample Size",
        "description": "Minimum 30 trades for statistical significance",
        "threshold": "≥ 30",
        "actual": "42",
        "passed": true
      },
      {
        "name": "Profit Factor",
        "description": "Total profits must exceed total losses",
        "threshold": "≥ 1.00",
        "actual": "2.15",
        "passed": true
      }
    ]
  },
  "progress_pct": 100,
  "started_at": "2024-01-15T10:31:00Z",
  "completed_at": "2024-01-15T10:45:00Z",
  "created_at": "2024-01-15T10:30:00Z",
  "position_size": 100,
  "slippage_per_share": 0.01,
  "commission_per_share": 0.001
}
```

**Status lifecycle:** `pending` → `running` → `completed` | `failed` | `cancelled`

***

### GET /api/graph/v1/backtest/{run_id}/trades

**Get backtest trades (paginated)**

Retrieve individual trades from a completed backtest run with optional filtering by symbol, signal type, or direction.

**Parameters:**

* `run_id` (path, required): UUID of the backtest run
* `page` (query, optional): Page number (default 1, min 1)
* `page_size` (query, optional): Trades per page (default 50, max 200)
* `symbol` (query, optional): Filter by symbol (e.g., "NVDA")
* `signal_type` (query, optional): Filter by signal type
* `direction` (query, optional): Filter by direction ("long" | "short")

**Response 200:**

```json theme={null}
{
  "trades": [
    {
      "entry_time": "2024-01-15T09:45:00Z",
      "symbol": "NVDA",
      "signal_type": "vwap_touch",
      "direction": "long",
      "trigger_price": 845.50,
      "entry_price": 846.00,
      "exit_price": 855.25,
      "stop_price": 840.00,
      "t1_price": 851.00,
      "t2_price": 856.00,
      "t3_price": 861.00,
      "atr_at_entry": 3.50,
      "exit_reason": "t1_hit",
      "pnl": 370.25,
      "pnl_r": 2.57,
      "round_trip_cost": 8.50,
      "hold_minutes": 45,
      "exit_time": "2024-01-15T10:30:00Z"
    }
  ],
  "total": 42,
  "page": 1,
  "page_size": 50
}
```

***

### GET /api/graph/v1/backtest/{run_id}/trades/export

**Export backtest trades**

Export all trades from a run as CSV or JSON.

**Parameters:**

* `run_id` (path, required): UUID of the backtest run
* `format` (query, optional): `"csv"` or `"json"` (default "csv")

**Response 200:** File download (CSV or JSON array)

***

### POST /api/graph/v1/backtest/{run_id}/cancel

**Cancel a backtest run**

Cancel a running or pending backtest. Returns 409 if the run is already completed or failed.

**Parameters:**

* `run_id` (path, required): UUID of the backtest run

**Response 200:**

```json theme={null}
{
  "status": "cancelled",
  "run_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

***

### POST /api/graph/v1/backtest/{run_id}/analyze

**AI analysis of backtest results**

Run LLM analysis on a completed backtest to assess edge quality, signal insights, and risk factors.

**Parameters:**

* `run_id` (path, required): UUID of the backtest run

**Response 200:**

```json theme={null}
{
  "summary": "The strategy shows solid statistical edge with a 2.15 profit factor across 42 trades...",
  "signal_insights": [
    {
      "signal_type": "vwap_touch",
      "assessment": "Strong signal quality with 66.7% win rate",
      "reasoning": "VWAP reverts reliably in low-volatility regimes",
      "suggestion": "Consider increasing position size on VWAP touches in the first 30 minutes"
    }
  ],
  "risk_assessment": "Drawdown remains within 8% on a $100k account; consider adding regime filters for volatile market days",
  "parameter_suggestions": [
    "Increase stop_atr_mult from 1.5 to 2.0 for higher reward-to-risk",
    "Add time_stop filter for post-3pm trades (lower volume)"
  ],
  "edge_quality": "Medium-High",
  "edge_confidence": 0.78,
  "analyzed_at": "2024-01-15T10:46:00Z",
  "tokens_used": 2450
}
```

***

## History & Optimization (v1)

### GET /api/graph/v1/backtest/history

**List backtest history**

Retrieve the user's past backtest runs (most recent first).

**Parameters:**

* `limit` (query, optional): Max results (default 50, max 100)

**Response 200:** Array of `BacktestRunResponse` objects (see `GET /{run_id}` for structure)

***

### POST /api/graph/v1/backtest/optimize

**Start parameter optimization**

Run a grid search over stop/target ATR multiplier combinations to find optimal parameters.

**Request body:**

```json theme={null}
{
  "symbols": ["NVDA"],
  "start_date": "2024-01-01",
  "end_date": "2024-12-31",
  "signal_types": ["vwap_touch"],
  "stop_atr_range": [1.0, 1.5, 2.0],
  "target_atr_range": [2.0, 2.5, 3.0],
  "top_n": 5
}
```

**Response 200:**

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "results": null,
  "progress_pct": 0,
  "error_message": null
}
```

Poll the `id` returned by calling `GET /api/graph/v1/backtest/{run_id}` to retrieve results as they complete.

***

### GET /api/graph/v1/backtest/field-availability

**Per-field coverage for rule-driven backtester**

Reports which scoring/indicator/regime fields are populated in `backtest_universe` for a given date range, so the Visual Canvas can render honest "available from" badges and block rules that depend on fields with insufficient coverage.

**Parameters:**

* `from` (query, required): YYYY-MM-DD (inclusive)
* `to` (query, required): YYYY-MM-DD (inclusive)
* `symbols` (query, optional): Comma-separated filter. Omit for universe-wide coverage (fastest). Provide the same symbols you intend to backtest for accuracy.

**Response 200:**

```json theme={null}
{
  "from": "2024-01-01",
  "to": "2024-12-31",
  "symbols": ["NVDA"],
  "fields": {
    "rsi_14": {
      "status": "available",
      "coverage_pct": 99.5,
      "category": "indicator",
      "available_from": "2022-01-01"
    },
    "regime_grid": {
      "status": "available",
      "coverage_pct": 100.0,
      "category": "regime",
      "available_from": "2020-01-01"
    },
    "vp_poc": {
      "status": "partial",
      "coverage_pct": 45.0,
      "category": "level",
      "available_from": "2024-06-01"
    },
    "vp_poc_options": {
      "status": "forward_only",
      "coverage_pct": 0.0,
      "category": "level",
      "available_from": null
    }
  }
}
```

Status values:

* `available`: ≥90% coverage; rules can run with confidence
* `partial`: ≥10% coverage; rules run but results exclude uncovered bars
* `missing`: \<10% coverage; rules are effectively inoperable
* `forward_only`: field only exists in live `score_history`, never in historical `backtest_universe`

***

## Modern Async Backtest (v2)

The `/v2` endpoints use ClickHouse-backed async execution with out-of-process workers, supporting advanced features like walk-forward analysis, Monte Carlo simulation, regime fitness, and detailed equity-curve metrics.

### POST /api/graph/v1/backtest/v2/run

**Start async backtest run (v2)**

Launches a modern async backtest with advanced parameters. Returns immediately with status `pending`; poll `GET /run/{run_id}` for progress.

**Request body:**

```json theme={null}
{
  "symbols": ["NVDA", "AAPL"],
  "signal_types": ["vwap_touch", "ib_breakout"],
  "quality_tiers": ["EXCELLENT", "GOOD"],
  "regime_filter": ["BULL_HIGH_VOL", "NEUTRAL_LOW_VOL"],
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "stop_atr": 1.5,
  "target_atr": 2.5,
  "time_stop": "15:45",
  "slippage_model": "realistic",
  "fee_model": "commission_per_share",
  "initial_capital": 100000.0,
  "max_positions": 5,
  "sizing_method": "score_weighted",
  "strategy_rules": null,
  "universe_symbols": null,
  "benchmark_symbol": "SPY",
  "bar_timeframe": "1min",
  "timeframe": "intraday",
  "train_test_split": 0.8,
  "walk_forward": true,
  "monte_carlo_n": 10000,
  "random_seed": 42,
  "regime_strategy": null
}
```

**Response 200:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "progress_pct": 0
}
```

**Constraints:**

* Max 3 concurrent runs per user (returns 429)
* Max 365-day range
* `sizing_method`: `equal_weight`, `score_weighted`, `risk_parity`, or `kelly`
* Max 50 symbols
* `mse_signal` conditions not yet supported (use indicator/price-action/pattern/volume instead)

***

### GET /api/graph/v1/backtest/v2/run/{run_id}

**Get run status (v2)**

Poll the status and progress of a v2 backtest run.

**Parameters:**

* `run_id` (path, required): Run UUID

**Response 200:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "running",
  "progress_pct": 45,
  "total_trades": 0,
  "phase": "analyzing_trades",
  "total_signals": 250,
  "symbols_processed": 2,
  "symbols_total": 5,
  "current_symbol": "AAPL",
  "request_config": {
    "date_from": "2024-01-01",
    "date_to": "2024-12-31",
    "stop_atr": 1.5
  }
}
```

***

### GET /api/graph/v1/backtest/v2/run/{run_id}/results

**Get full backtest results (v2)**

Retrieve complete results including trades, portfolio metrics, equity curve, Monte Carlo analysis, and validation gate.

**Parameters:**

* `run_id` (path, required): Run UUID

**Response 200:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "total_trades": 42,
  "metrics": {
    "win_rate": 0.667,
    "profit_factor": 2.15,
    "sharpe_ratio": 1.42,
    "sortino_ratio": 1.65,
    "max_drawdown_pct": -8.0,
    "expectancy_pct": 2.85,
    "avg_winner_pct": 1.45,
    "avg_loser_pct": -0.85
  },
  "benchmark_metrics": {
    "beta": 1.15,
    "correlation": 0.78,
    "alpha": 0.025,
    "excess_return_pct": 18.5
  },
  "benchmark_alpha": {
    "alpha_pct": 2.5,
    "tracking_error": 5.2,
    "information_ratio": 0.48
  },
  "detailed_metrics": {
    "by_signal_type": [
      {
        "signal_type": "vwap_touch",
        "trades": 28,
        "win_rate": 0.75,
        "profit_factor": 2.4,
        "expectancy_pct": 3.2
      }
    ],
    "by_regime": [
      {
        "regime": "BULL_HIGH_VOL",
        "trades": 15,
        "win_rate": 0.8,
        "profit_factor": 2.8
      }
    ],
    "by_quality_tier": [
      {
        "tier": "EXCELLENT",
        "trades": 30,
        "win_rate": 0.7,
        "profit_factor": 2.3
      }
    ],
    "by_symbol": [
      {
        "symbol": "NVDA",
        "trades": 22,
        "win_rate": 0.68,
        "profit_factor": 2.1
      }
    ]
  },
  "monte_carlo": {
    "final_equity_ci_low": 108500.0,
    "final_equity_ci_high": 116200.0,
    "ruin_probability_pct": 0.1,
    "worst_case_drawdown_pct": -18.5,
    "best_case_final_equity": 125000.0
  },
  "equity_curve_metrics": {
    "cagr_pct": 12.5,
    "total_return_pct": 18.2,
    "sharpe_ratio": 1.42,
    "sortino_ratio": 1.65,
    "max_drawdown_pct": -8.0,
    "calmar_ratio": 1.56,
    "n_days": 252,
    "densified": true,
    "n_sessions": 250
  },
  "breadth": {
    "n_symbols": 5,
    "n_trades": 42,
    "net_pnl_dollars": 18200.0,
    "top1_pnl_share_pct": 35.0,
    "top3_pnl_share_pct": 65.0,
    "net_pnl_ex_top3_dollars": 6370.0,
    "pct_symbols_profitable": 80.0,
    "herfindahl": 0.28,
    "is_single_name_artifact": false
  },
  "validation_gate": {
    "passed": true,
    "criteria": [
      {
        "name": "Sample Size",
        "threshold": "≥ 30",
        "actual": "42",
        "passed": true
      },
      {
        "name": "Profit Factor",
        "threshold": "≥ 1.00",
        "actual": "2.15",
        "passed": true
      },
      {
        "name": "Sharpe Ratio",
        "threshold": "≥ 0.50",
        "actual": "1.42",
        "passed": true
      },
      {
        "name": "Max Drawdown",
        "threshold": "≤ 25%",
        "actual": "8.0%",
        "passed": true
      },
      {
        "name": "Win Rate",
        "threshold": "≥ 35%",
        "actual": "66.7%",
        "passed": true
      }
    ]
  },
  "trades": [
    {
      "symbol": "NVDA",
      "direction": "long",
      "signal_type": "vwap_touch",
      "quality_tier": "EXCELLENT",
      "entry_timestamp": "2024-01-15T09:45:00Z",
      "entry_price": 846.00,
      "exit_timestamp": "2024-01-15T10:30:00Z",
      "exit_price": 855.25,
      "exit_reason": "t1_hit",
      "holding_period_minutes": 45,
      "pnl_pct": 1.09,
      "pnl_r_multiple": 2.57,
      "pnl_dollars": 370.25,
      "sizing_multiplier": 1.0,
      "conviction_at_entry": 85,
      "regime_dominant": "BULL_HIGH_VOL",
      "slippage_model": "realistic",
      "entry_slippage_bps": 2.5,
      "exit_slippage_bps": 2.5,
      "total_slippage_bps": 5.0,
      "entry_atr": 3.50,
      "stop_price": 840.00,
      "target_price": 851.00,
      "stop_atr_multiplier": 1.5,
      "target_atr_multiplier": 2.5,
      "signal_details": {
        "vwap_deviation_pct": -0.8,
        "volume_profile_tier": "HIGH_VOLUME_NODE"
      },
      "mfe_30min": 1.5,
      "mae_30min": -0.3,
      "mfe_eod": 2.1,
      "mae_eod": -0.5
    }
  ],
  "equity_curve": [
    {
      "timestamp": "2024-01-15T10:30:00Z",
      "equity": 100370.25,
      "drawdown": 0.0,
      "position_count": 1
    }
  ],
  "walk_forward_by_regime": {
    "BULL_HIGH_VOL": {
      "train_sharpe": 1.8,
      "test_sharpe": 1.2,
      "train_profit_factor": 2.8,
      "test_profit_factor": 1.9
    }
  },
  "decision_summary": {
    "entry_triggered": 250,
    "entry_filtered": 200,
    "position_opened": 42,
    "exited_t1": 25,
    "exited_stop": 5,
    "exited_time_stop": 12
  },
  "diagnostics": {
    "condition_funnel": [
      {
        "condition": "signal_triggered",
        "count": 250,
        "pct": 100.0
      },
      {
        "condition": "confluence_score",
        "count": 180,
        "pct": 72.0
      },
      {
        "condition": "regime_filter",
        "count": 42,
        "pct": 16.8
      }
    ]
  },
  "execution_assumptions": {
    "timeframe": "intraday",
    "slippage_model": "realistic",
    "slippage_entry_pct": 0.025,
    "slippage_exit_pct": 0.025,
    "commission_per_trade": 2.0
  },
  "data_quality": {
    "split_adjustments_applied": 3,
    "trade_count": 42,
    "coverage": {
      "symbol_coverage_pct": 98.5,
      "bar_completeness_pct": 99.2
    }
  },
  "request_config": {
    "date_from": "2024-01-01",
    "date_to": "2024-12-31",
    "symbols": ["NVDA", "AAPL"],
    "signal_types": ["vwap_touch", "ib_breakout"],
    "stop_atr": 1.5,
    "target_atr": 2.5
  }
}
```

Returns 202 with progress info while the run is still in progress. When a backtest produces fewer than 5 trades, includes a `diagnostics` field showing the condition funnel.

***

### GET /api/graph/v1/backtest/v2/run/{run_id}/results/by-symbol

**Get per-symbol attribution (v2)**

Breakdown of metrics by symbol.

**Parameters:**

* `run_id` (path, required): Run UUID

**Response 200:** Array of per-symbol metrics (trades, win\_rate, profit\_factor, sharpe, max\_drawdown)

***

### GET /api/graph/v1/backtest/v2/run/{run_id}/results/regime-fitness

**Get regime fitness breakdown (v2)**

Performance across different market regimes (2×3 grid: BULL/NEUTRAL/BEAR × LOW\_VOL/HIGH\_VOL).

**Parameters:**

* `run_id` (path, required): Run UUID

**Response 200:** Metrics grouped by regime

***

### GET /api/graph/v1/backtest/v2/run/{run_id}/trades/{trade_index}

**Get single trade detail (v2)**

Retrieve enriched data for a specific trade, including stop/target levels for chart visualization.

**Parameters:**

* `run_id` (path, required): Run UUID
* `trade_index` (path, required): Trade index (0-based)

**Response 200:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "trade_index": 0,
  "symbol": "NVDA",
  "direction": "long",
  "signal_type": "vwap_touch",
  "quality_tier": "EXCELLENT",
  "entry_timestamp": "2024-01-15T09:45:00Z",
  "entry_price": 846.00,
  "exit_timestamp": "2024-01-15T10:30:00Z",
  "exit_price": 855.25,
  "exit_reason": "t1_hit",
  "holding_period_minutes": 45,
  "pnl_pct": 1.09,
  "pnl_r_multiple": 2.57,
  "pnl_dollars": 370.25,
  "sizing_multiplier": 1.0,
  "conviction_at_entry": 85,
  "regime_dominant": "BULL_HIGH_VOL",
  "slippage_model": "realistic",
  "entry_slippage_bps": 2.5,
  "exit_slippage_bps": 2.5,
  "total_slippage_bps": 5.0,
  "entry_atr": 3.50,
  "stop_price": 840.00,
  "target_price": 851.00,
  "stop_atr_multiplier": 1.5,
  "target_atr_multiplier": 2.5,
  "signal_details": {
    "vwap_deviation_pct": -0.8,
    "volume_profile_tier": "HIGH_VOLUME_NODE"
  }
}
```

***

### POST /api/graph/v1/backtest/v2/run/{run_id}/cancel

**Cancel backtest run (v2)**

**Parameters:**

* `run_id` (path, required): Run UUID

**Response 200:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "cancelled"
}
```

***

## Annotations (v2)

### PUT /api/graph/v1/backtest/v2/run/{run_id}/trades/{trade_id}/annotate

**Annotate a trade**

Add tags and notes to a trade for later reference.

**Parameters:**

* `run_id` (path, required): Run UUID
* `trade_id` (path, required): Trade UUID

**Request body:**

```json theme={null}
{
  "tags": ["winner", "low_volume"],
  "note": "Perfect entry at VWAP, exited at first target"
}
```

**Response 200:** Annotation created

***

### DELETE /api/graph/v1/backtest/v2/run/{run_id}/trades/{trade_id}/annotate

**Delete annotation**

Remove annotations from a trade.

**Parameters:**

* `run_id` (path, required): Run UUID
* `trade_id` (path, required): Trade UUID

**Response 200:** Annotation deleted

***

### GET /api/graph/v1/backtest/v2/run/{run_id}/annotations

**Get run annotations**

List all annotations for trades in a backtest run.

**Parameters:**

* `run_id` (path, required): Run UUID

**Response 200:** Array of annotations

***

### GET /api/graph/v1/backtest/v2/annotations

**Search annotations**

Search annotations across all backtest runs by tag.

**Parameters:**

* `tag` (query, optional): Filter by tag
* `limit` (query, optional): Max results

**Response 200:** Array of annotations

***

## History & Groups (v2)

### GET /api/graph/v1/backtest/v2/runs

**List runs (v2)**

Paginated list of the user's backtest runs.

**Parameters:**

* `limit` (query, optional): Max results (default 50)
* `offset` (query, optional): Pagination offset

**Response 200:** Array of run summaries

***

### GET /api/graph/v1/backtest/v2/history

**Backtest history with filters**

Paginated history with optional signal type filter.

**Parameters:**

* `signal_type` (query, optional): Filter by signal type
* `limit` (query, optional): Max results
* `offset` (query, optional): Pagination offset

**Response 200:** Array of run objects

***

### POST /api/graph/v1/backtest/v2/groups

**Create symbol group**

Create a named group of symbols for reuse across backtests.

**Request body:**

```json theme={null}
{
  "group_name": "Tech Mega Caps",
  "symbols": ["NVDA", "AAPL", "MSFT", "GOOGL"]
}
```

**Response 200:** Group created

***

### GET /api/graph/v1/backtest/v2/groups

**List groups**

Retrieve all symbol groups for the user.

**Response 200:** Array of groups

***

### PUT /api/graph/v1/backtest/v2/groups/{group_id}

**Update group**

Modify a symbol group's name or member list.

**Parameters:**

* `group_id` (path, required): Group UUID

**Request body:** Same as POST /groups

**Response 200:** Group updated

***

### DELETE /api/graph/v1/backtest/v2/groups/{group_id}

**Delete group**

Remove a symbol group.

**Parameters:**

* `group_id` (path, required): Group UUID

**Response 200:** Group deleted

***

## Parameter Optimization (v2)

### POST /api/graph/v1/backtest/v2/optimize

**Optimize parameters (v2)**

Run walk-forward parameter optimization to find best stop/target ATR combinations.

**Request body:**

```json theme={null}
{
  "materialize_run_id": "550e8400-e29b-41d4-a716-446655440000",
  "signal_types": ["vwap_touch"],
  "quality_tiers": ["EXCELLENT", "GOOD"],
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "objective": "sharpe",
  "walk_forward": true,
  "n_folds": 5
}
```

**Response 200:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "results": null,
  "progress_pct": 0
}
```

***

### POST /api/graph/v1/backtest/v2/sweep

**Parameter sensitivity sweep (async)**

Run a parameter sweep and retrieve results asynchronously.

**Request body:**

```json theme={null}
{
  "base_request": {
    "symbols": ["NVDA"],
    "date_from": "2024-01-01",
    "date_to": "2024-12-31"
  },
  "param_ranges": [
    {"stop_atr": [1.0, 1.5, 2.0]},
    {"target_atr": [2.0, 2.5, 3.0]}
  ],
  "target_metric": "sharpe"
}
```

**Response 200:**

```json theme={null}
{
  "sweep_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "progress_pct": 0
}
```

***

### GET /api/graph/v1/backtest/v2/sweep/{sweep_id}/status

**Sweep progress**

Poll the status of an async parameter sweep.

**Parameters:**

* `sweep_id` (path, required): Sweep UUID

**Response 200:**

```json theme={null}
{
  "sweep_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "running",
  "progress_pct": 35,
  "total_combinations": 9,
  "completed": 3
}
```

***

### GET /api/graph/v1/backtest/v2/sweep/{sweep_id}/results

**Sweep results matrix**

Retrieve the results matrix after a sweep completes.

**Parameters:**

* `sweep_id` (path, required): Sweep UUID

**Response 200:** Parameter combinations with metrics (Sharpe, profit\_factor, win\_rate, etc.)

***

## Comparison & Analysis (v2)

| Endpoint                                          | Purpose                                        |
| ------------------------------------------------- | ---------------------------------------------- |
| `POST /api/graph/v1/backtest/v2/compare`          | Compare 2-5 backtest runs side-by-side         |
| `POST /api/graph/v1/backtest/v2/compare/detailed` | Compare with trade deltas and overlap analysis |
| `GET /api/graph/v1/backtest/v2/progression`       | Tier progression dashboard                     |
| `GET /api/graph/v1/backtest/v2/coverage`          | Backtest data coverage summary                 |
| `GET /api/graph/v1/backtest/v2/universe/status`   | Universe status and field availability         |

***

## Strategies & Forward Testing (v2)

| Endpoint                                                                     | Purpose                                        |
| ---------------------------------------------------------------------------- | ---------------------------------------------- |
| `POST /api/graph/v1/backtest/v2/strategies/versions`                         | Save strategy version                          |
| `GET /api/graph/v1/backtest/v2/strategies/{strategy_name}/versions`          | List strategy versions                         |
| `GET /api/graph/v1/backtest/v2/strategies/versions/{version_id}`             | Get single version                             |
| `GET /api/graph/v1/backtest/v2/strategies/versions/{v1}/diff/{v2}`           | Diff two versions                              |
| `GET /api/graph/v1/backtest/v2/strategies/versions/{v1}/signal-overlap/{v2}` | Signal overlap analysis                        |
| `POST /api/graph/v1/backtest/v2/strategy-test`                               | Simplified retail backtest (see Schemas below) |
| `POST /api/graph/v1/backtest/v2/forward-test`                                | Start paper trading session                    |
| `GET /api/graph/v1/backtest/v2/forward-test/{session_id}`                    | Session status                                 |
| `POST /api/graph/v1/backtest/v2/forward-test/{session_id}/stop`              | Stop session                                   |
| `GET /api/graph/v1/backtest/v2/forward-test/{session_id}/fills`              | Session fills                                  |
| `GET /api/graph/v1/backtest/v2/forward-tests`                                | List user's sessions                           |

***

## Options Backtesting

### POST /api/graph/v1/backtest/v2/options/run

**Options backtest (single-leg)**

Backtest options strategies with delta targeting, DTE ranges, and contract selection logic.

**Request body:**

```json theme={null}
{
  "symbols": ["NVDA"],
  "signal_types": ["vwap_touch"],
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "target_delta": 0.30,
  "delta_tolerance": 0.05,
  "dte_min": 7,
  "dte_max": 45,
  "min_open_interest": 100,
  "max_spread_pct": 1.0,
  "max_quote_age_seconds": 60,
  "premium_stop_pct": -20.0,
  "premium_target_pct": 50.0,
  "contracts": 1,
  "base_capital_per_trade": 10000.0,
  "commission_per_contract": 0.65
}
```

**Response 200:** Backtest results (same structure as equity backtest, with options-specific fields like delta, theta, vega decay)

***

## Regime & Coverage

### GET /api/graph/v1/backtest/v2/regime/calendar

**Get regime calendar**

Retrieve the 2×3 regime grid labels for a date range.

**Parameters:**

* `date_from` (query, required): YYYY-MM-DD
* `date_to` (query, required): YYYY-MM-DD

**Response 200:**

```json theme={null}
{
  "regime_calendar": [
    {
      "date": "2024-01-15",
      "regime": "BULL_HIGH_VOL",
      "vix_close": 18.5,
      "spy_close": 481.25
    }
  ]
}
```

***

### POST /api/graph/v1/backtest/v2/regime/backfill

**Trigger regime backfill**

Manually trigger a backfill of the 2×3 regime grid for a date range (normally automatic).

**Parameters:**

* `date_from` (query, optional): YYYY-MM-DD
* `date_to` (query, optional): YYYY-MM-DD

**Response 200:** Backfill initiated

***

### GET /api/graph/v1/backtest/v2/coverage

**Get backtest coverage**

Return available data coverage (earliest/latest dates, symbol count) for the date picker.

**Response 200:**

```json theme={null}
{
  "earliest": "2020-01-01",
  "latest": "2024-12-29",
  "symbol_count": 3450
}
```

***

## Key Schemas

### BacktestRequest

Request to launch a v1 backtest run.

```json theme={null}
{
  "symbols": [string],
  "start_date": "YYYY-MM-DD",
  "end_date": "YYYY-MM-DD",
  "signal_types": ["vwap_touch", "ib_breakout", "ib_retest", "or_hold", "level_confluence", "trend_continuation"],
  "stop_atr_mult": number,
  "t1_atr_mult": number,
  "t2_atr_mult": number,
  "t3_atr_mult": number,
  "time_stop_et": "HH:MM",
  "position_size": integer,
  "slippage_per_share": number,
  "commission_per_share": number,
  "gate_thresholds": object | null
}
```

### BacktestRunRequest

Request to launch a v2 backtest run (see above for full structure).

### BacktestTradeResponse

Individual trade from a backtest result.

```json theme={null}
{
  "entry_time": "ISO 8601 timestamp",
  "symbol": "NVDA",
  "signal_type": "vwap_touch",
  "direction": "long" | "short",
  "trigger_price": number,
  "entry_price": number,
  "exit_price": number | null,
  "stop_price": number,
  "t1_price": number | null,
  "t2_price": number | null,
  "t3_price": number | null,
  "atr_at_entry": number,
  "exit_reason": "t1_hit" | "t2_hit" | "t3_hit" | "stop_hit" | "time_stop" | "eod",
  "pnl": number,
  "pnl_r": number,
  "round_trip_cost": number,
  "hold_minutes": integer | null,
  "exit_time": "ISO 8601 timestamp" | null
}
```

### SignalType

Intraday signal types available for backtesting.

```
enum: "vwap_touch" | "ib_breakout" | "ib_retest" | "or_hold" | "level_confluence" | "trend_continuation"
```

### BacktestStatus

Run lifecycle status.

```
enum: "pending" | "running" | "completed" | "failed" | "cancelled"
```

### EquityCurvePoint

Single point on the equity curve (cumulative P\&L by trade count and R-multiple).

```json theme={null}
{
  "trade_num": integer,
  "cumulative_pnl": number,
  "cumulative_r": number,
  "timestamp": "ISO 8601 timestamp" | null
}
```

### ValidationGateResult

Aggregate validation gate (P3 Phase 3: sample size, profit factor, Sharpe, max drawdown, win rate).

```json theme={null}
{
  "passed": boolean,
  "criteria": [
    {
      "name": "Sample Size",
      "description": "Minimum 30 trades for statistical significance",
      "threshold": "≥ 30",
      "actual": "42",
      "passed": boolean
    }
  ]
}
```

### TradeDetailResponse

Enriched single-trade response with stop/target levels and detailed signal metadata.

```json theme={null}
{
  "run_id": "UUID",
  "trade_index": integer,
  "symbol": "NVDA",
  "direction": "long" | "short",
  "signal_type": "vwap_touch",
  "quality_tier": "EXCELLENT" | "GOOD" | "MARGINAL" | "POOR",
  "entry_timestamp": "ISO 8601",
  "entry_price": number,
  "exit_timestamp": "ISO 8601",
  "exit_price": number,
  "exit_reason": "t1_hit" | "stop_hit" | "time_stop",
  "holding_period_minutes": integer,
  "pnl_pct": number,
  "pnl_r_multiple": number,
  "pnl_dollars": number,
  "sizing_multiplier": number,
  "conviction_at_entry": number (0–100),
  "regime_dominant": "BULL_HIGH_VOL" | "BULL_LOW_VOL" | "NEUTRAL_HIGH_VOL" | "NEUTRAL_LOW_VOL" | "BEAR_HIGH_VOL" | "BEAR_LOW_VOL",
  "slippage_model": "realistic" | "pessimistic",
  "entry_slippage_bps": number,
  "exit_slippage_bps": number,
  "total_slippage_bps": number,
  "entry_atr": number,
  "stop_price": number | null,
  "target_price": number | null,
  "stop_atr_multiplier": number,
  "target_atr_multiplier": number,
  "signal_details": object
}
```

### StrategyTestRequest

Simplified retail backtest request.

```json theme={null}
{
  "signal_types": [string],
  "quality_tiers": ["EXCELLENT", "GOOD"],
  "date_from": "YYYY-MM-DD",
  "date_to": "YYYY-MM-DD",
  "stop_atr": number,
  "target_atr": number
}
```

### PromoteFromBacktestRequest

Promote a strategy (post-backtest) to a Trade Manager card.

```json theme={null}
{
  "symbol": "NVDA",
  "mode": "autonomous" | "supervised" | "monitor" | "manual",
  "paper_live_mode": "paper" | "live",
  "sizing_type": "fixed_pct" | "kelly",
  "sizing_value": number
}
```
