Tutorial

Strategy Development,
Backtesting & Optimization

A step-by-step guide to building quantitative investment strategies with AlphaForge — from writing strategy JSON to running backtests, Bayesian optimization, and walk-forward validation. We use CL=F (WTI crude oil futures) with an HMM + Bollinger Bands + RSI strategy as the working example.

What is AlphaForge?

AlphaForge is a quantitative strategy development CLI that runs fast simulations via vectorbt, optimizes parameters with Optuna Bayesian optimization, and validates robustness with walk-forward testing to prevent overfitting. Strategies are defined entirely in JSON, making them easy to develop with AI coding agents like Claude.

ComponentRole
forgeCore simulation and optimization engine
data/Workspace holding strategy JSON, historical data, and backtest results
strikeWebhook server that receives TradingView alerts and forwards to broker APIs

Installation & Setup

  1. Install alpha-forge

    The installer downloads the latest binary (macOS / Linux shown). See the installation guide for Windows or manual placement. Then sign in with your Whop account (OAuth 2.0 PKCE) — the browser opens automatically.

    # Install the latest binary (macOS / Linux)
    curl -sSL https://alforge-labs.github.io/install.sh | bash
    
    # Sign in via Whop OAuth
    forge system auth login
  2. Initialize a strategy workspace

    Creates forge.yaml plus the data/, output/, docs/, .claude/, and .agents/ directories. Setting FORGE_CONFIG lets subsequent commands pick up this forge.yaml automatically.

    mkdir my-strategies && cd my-strategies
    forge system init
    # → forge.yaml, data/, output/, docs/, .claude/, .agents/ are created
    
    # Make the new forge.yaml the default for later commands (add to ~/.zshrc to make it permanent)
    export FORGE_CONFIG=$(pwd)/forge.yaml
  3. Fetch historical data

    Downloads from Yahoo Finance and caches under data/historical/. To grab several symbols at once, list them in a watchlist file (one symbol per line).

    # Download 5 years of CL=F (WTI crude oil futures)
    forge data fetch CL=F --period 5y
    
    # Batch download via a watchlist file (one symbol per line)
    printf "SPY\nQQQ\n" > watchlist.txt
    forge data fetch --watchlist watchlist.txt --period 5y

Writing a Strategy JSON

Every AlphaForge strategy is defined in a JSON file. Below is an example HMM + Bollinger Bands + RSI strategy for CL=F. Save it as cl_hmm_bb_rsi_v1.json in your working directory; the next step registers it via forge strategy save.

{
  "strategy_id": "cl_hmm_bb_rsi_v1",
  "name": "CL HMM + BB + RSI v1",
  "version": "1.0.0",
  "description": "HMM regime × Bollinger Bands × RSI composite strategy for CL=F",
  "target_symbols": ["CL=F"],
  "asset_type": "commodity",
  "timeframe": "1d",
  "parameters": {
    "bb_length": 20,
    "bb_std": 2.0,
    "rsi_length": 14,
    "rsi_entry": 40,
    "rsi_exit": 60
  },
  "indicators": [
    { "id": "bb_lower", "type": "BBANDS", "params": { "length": 20, "std": 2.0, "line": "lower" } },
    { "id": "bb_upper", "type": "BBANDS", "params": { "length": 20, "std": 2.0, "line": "upper" } },
    { "id": "rsi",      "type": "RSI",    "params": { "length": 14 } },
    { "id": "hmm_state","type": "HMM",    "params": { "n_states": 2, "features": ["returns","volatility"] } }
  ],
  "entry_conditions": {
    "long": {
      "logic": "AND",
      "conditions": [
        { "left": "close",     "op": "crosses_above", "right": "bb_lower" },
        { "left": "rsi",       "op": "<",             "right": "rsi_entry" },
        { "left": "hmm_state", "op": "==",            "right": 1 }
      ]
    }
  },
  "exit_conditions": {
    "long": {
      "logic": "OR",
      "conditions": [
        { "left": "close", "op": "crosses_above", "right": "bb_upper" },
        { "left": "rsi",   "op": ">",             "right": "rsi_exit" }
      ]
    }
  },
  "risk_management": {
    "leverage": 5.0,
    "position_sizing_method": "risk_based",
    "risk_per_trade_pct": 1.5,
    "max_positions": 1
  },
  "optimizer_config": {
    "param_ranges": {
      "bb_length":  { "min": 10, "max": 40, "step": 5 },
      "bb_std":     { "min": 1.5, "max": 3.0, "step": 0.5 },
      "rsi_length": { "min": 10, "max": 20, "step": 2 },
      "rsi_entry":  { "min": 30, "max": 50, "step": 5 },
      "rsi_exit":   { "min": 55, "max": 75, "step": 5 }
    },
    "constraints": { "min_trades": 10 },
    "metric": "sharpe_ratio"
  }
}
Note on HMM states: The hmm_state value of 1 typically corresponds to the bullish regime, but this can vary per dataset. Run forge backtest run <SYMBOL> --strategy <id> --regime to inspect the per-regime statistics and verify state meanings.

Register the JSON locally with forge strategy save. Once registered, you can reference it via --strategy <strategy_id> and see it in forge strategy list.

forge strategy save cl_hmm_bb_rsi_v1.json
forge strategy list   # verify the strategy is registered

Running a Backtest

  1. Run a basic backtest
    forge backtest run CL=F \
      --strategy cl_hmm_bb_rsi_v1 \
      --start 2019-01-01 \
      --end 2024-12-31
  2. Get JSON output (for scripting)
    forge backtest run CL=F \
      --strategy cl_hmm_bb_rsi_v1 \
      --json | jq '.summary'

    Example output:

    {
      "symbol": "CL=F",
      "strategy": "cl_hmm_bb_rsi_v1",
      "period": "2019-01-01 to 2024-12-31",
      "total_return": 0.892,
      "cagr": 0.136,
      "sharpe_ratio": 1.07,
      "max_drawdown": -0.183,
      "total_trades": 24,
      "win_rate": 0.583
    }

Bayesian Optimization

Unlike grid search, Optuna's Bayesian optimization learns from previous trials to explore the parameter space efficiently, finding better solutions in fewer iterations.

  1. Run optimization (200 trials)
    forge optimize run CL=F \
      --strategy cl_hmm_bb_rsi_v1 \
      --trials 200 \
      --metric sharpe_ratio \
      --save
  2. View the optimization history
    forge optimize history \
      --strategy cl_hmm_bb_rsi_v1
  3. Apply the best parameters

    The result file is printed by optimize run --save and lives under data/results/.

    forge optimize apply \
      data/results/optimize_cl_hmm_bb_rsi_v1_<timestamp>.json \
      --to-strategy cl_hmm_bb_rsi_v1
Overfitting risk: Optimization maximizes in-sample performance. Always validate with walk-forward testing before trusting the results.

Walk-Forward Validation

Walk-forward testing splits the time series into training and validation windows, repeatedly optimizing on training data and measuring performance on unseen validation data. This is the gold standard for detecting overfitting in quantitative strategies.

  1. Run walk-forward test
    forge optimize walk-forward CL=F \
      --strategy cl_hmm_bb_rsi_v1_optimized \
      --windows 5 \
      --metric sharpe_ratio
  2. View the fold-by-fold report (JSON)
    forge optimize walk-forward CL=F \
      --strategy cl_hmm_bb_rsi_v1_optimized \
      --windows 5 --json | jq '.windows'
WF Efficiency: The ratio of out-of-sample Sharpe to in-sample Sharpe. Values above 80% indicate the strategy generalizes well to unseen data.

Reading Performance Metrics

MetricDescriptionTarget
CAGR Compound Annual Growth Rate. Annualized average return. 10%+
Sharpe Ratio Risk-adjusted return (return / volatility). Higher is more efficient. 1.0+
Max Drawdown Maximum peak-to-trough decline. Smaller absolute value = lower risk. < -20%
Win Rate Percentage of profitable trades. Evaluate alongside Sharpe. 50%+
WF Efficiency Out-of-sample vs in-sample Sharpe ratio. Measures overfitting. 80%+

FAQ

  • What do HMM state numbers mean?

    HMM state numbers (0, 1, ...) can change between training runs. Run forge backtest run <SYMBOL> --strategy <strategy_id> --regime to view the mean return and volatility for each state and identify which is the bullish regime.

  • How do I connect to TradingView?

    Run forge pine generate --strategy <strategy_id> to generate TradingView Pine Script v6 code. Set up a Webhook alert in TradingView pointing to alpha-strike for automated order execution.

  • How many optimization trials do I need?

    100–200 trials is sufficient for strategies with 3–5 parameters. For more parameters or higher precision, use 500–1000 trials.

    forge optimize run CL=F --strategy cl_hmm_bb_rsi_v1 --trials 500 --metric sharpe_ratio --save