# Barrier Functions - Comprehensive Guide

## Overview

**Related:**
- [GLOSSARY.md](GLOSSARY.md) — TP/SL, pips, and spread
- [SAMPLE-TRADE.md](SAMPLE-TRADE.md) — Practical workflow example
- [CLI.md](CLI.md) — CLI usage and output formats
- [forecast/UNCERTAINTY.md](forecast/UNCERTAINTY.md) — Confidence and interval concepts

Barrier functions are essential tools for risk management in trading. They help answer the critical question: *"What's the probability that my take-profit will be hit before my stop-loss within a given time horizon?"*

This document provides a deep dive into the barrier analytics available in mtdata, covering the underlying algorithms, when to use each method, and real-world trading scenarios.

---

## Quick Start (Simple Usage First)

### 1) Probability for one TP/SL pair

Percent barriers are expressed in percent (e.g., `--tp-pct 0.40` means **0.40%**, not 40%):
```bash
mtdata-cli forecast_barrier_prob EURUSD --timeframe H1 --horizon 12 \
  --method mc_gbm --direction long --tp-pct 0.40 --sl-pct 0.60 --json
```

Look for `prob_tp_first`, `prob_sl_first`, `prob_no_hit`, and `edge` in the output.

**Defaults**: `--method hmm_mc`, `--horizon 12`, `--direction long`.

### 2) Search for “good” TP/SL levels

```bash
mtdata-cli forecast_barrier_optimize EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct --grid-style volatility --objective edge --json
```

---

## Core Concepts

### What is a Barrier?

A barrier is a price level that, when touched, triggers an event:
- **Take-Profit (TP)**: Profit-taking level
- **Stop-Loss (SL)**: Risk-limiting level

### The Barrier Problem

Given:
- Current price: `S₀`
- TP level: `B_tp`
- SL level: `B_sl`
- Time horizon: `T` (number of bars)
- Trade direction: long/short

We want to compute:
- `P(TP first)`: Probability TP is hit before SL
- `P(SL first)`: Probability SL is hit before TP
- `P(no hit)`: Probability neither is hit by time T
- `E[time to hit]`: Expected time until resolution

---

## Available Methods & Algorithms

### 1. Monte Carlo GBM (`mc_gbm`)

**Algorithm**: Geometric Brownian Motion simulation

**Mathematical Model**:
```
S_t = S₀ * exp((μ - 0.5σ²)t + σW_t)
```
where:
- `μ` = drift (mean log-return)
- `σ` = volatility (std of log-returns)
- `W_t` = Wiener process (Brownian motion)

**How it works**:
1. Calibrate μ and σ from historical log-returns
2. Generate N random paths using the formula above (with antithetic variance reduction by default for more stable estimates)
3. Count paths that hit TP first vs SL first

**Strengths**:
- Fast and stable
- Minimal assumptions
- Works with limited history

**Weaknesses**:
- Assumes constant volatility
- Ignores fat tails
- No regime awareness

**When to use**:
- Short horizons (< 20 bars)
- Stable market conditions
- Quick screening of many TP/SL combinations
- Baseline for comparison

**Real-life example**:
> **Scenario**: EURUSD scalp on 5-minute chart, horizon = 12 bars (1 hour)
>
> **Why GBM**: Short timeframe, relatively stable intraday volatility, need fast results for live trading
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob EURUSD --timeframe M5 --horizon 12 \
>   --method mc_gbm --tp-pct 0.2 --sl-pct 0.15
> ```

---

### 2. Brownian Bridge GBM (`mc_gbm_bb`)

**Algorithm**: GBM with Brownian Bridge correction

**Mathematical Model**:
The Brownian Bridge is a Brownian motion conditioned to return to a specific value at time T. For barrier hitting, it provides more accurate probabilities for short horizons by accounting for the path between endpoints.

**Key insight**: If we know the price at time T (from simulation), the probability of hitting a barrier between t and t+Δt is:
```
P(hit | S_t, S_T) = exp(-2 * (B - S_t)(B - S_T) / (σ²Δt))
```

**How it works**:
1. Generate GBM paths as normal
2. Apply bridge correction between each time step
3. Detect hits that occur "between" discrete simulation points

**Strengths**:
- More accurate for short horizons
- Captures intra-barrier hits
- Better resolution for tight TP/SL

**Weaknesses**:
- Slightly slower than plain GBM
- Requires more history for stable σ

**When to use**:
- Very short horizons (< 10 bars)
- Tight TP/SL (near current price)
- Scalping strategies
- When precision matters more than speed

**Real-life example**:
> **Scenario**: Crypto scalping on 1-minute BTC chart, TP = 0.1%, SL = 0.08%, horizon = 6 bars
>
> **Why Bridge**: Tiny barriers, very short horizon - need to capture hits that occur between 1-minute marks
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob BTCUSD --timeframe M1 --horizon 6 \
>   --method mc_gbm_bb --tp-pct 0.1 --sl-pct 0.08
> ```

---

### 3. HMM Monte Carlo (`hmm_mc`)

**Algorithm**: Hidden Markov Model with regime-switching

**Mathematical Model**:
```
State s_t ∈ {1, 2, ..., K} (hidden)
Return r_t ~ N(μ_{s_t}, σ_{s_t})
Transition: P(s_t = j | s_{t-1} = i) = A_{ij}
```

**How it works**:
1. Fit Gaussian mixture to log-returns (EM algorithm)
2. Estimate transition matrix from soft assignments
3. Simulate state paths via Markov chain
4. Sample returns conditional on current state
5. Build price paths

**Strengths**:
- Captures volatility regimes (low/high vol)
- Adapts to changing market conditions
- More realistic than constant-volatility models
- Handles trending vs ranging markets

**Weaknesses**:
- Requires more history (200+ bars)
- Computationally intensive
- Needs careful initialization

**When to use**:
- Medium to long horizons (10-100 bars)
- Clearly regime-switching markets
- Swing/position trading
- When volatility clustering is evident

**Real-life example**:
> **Scenario**: GBPUSD swing trade on 4H chart, horizon = 48 bars (8 days)
>
> **Why HMM**: Markets show clear regimes - trending days vs consolidation periods
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob GBPUSD --timeframe H4 --horizon 48 \
>   --method hmm_mc --tp-pct 1.5 --sl-pct 1.0 \
>   --params "n_states=2 n_sims=5000"
> ```

---

### 4. GARCH Monte Carlo (`garch`)

**Algorithm**: Generalized Autoregressive Conditional Heteroskedasticity

**Mathematical Model**:
```
r_t = μ + ε_t
ε_t = σ_t * z_t, z_t ~ N(0,1)
σ_t² = ω + α * ε_{t-1}² + β * σ_{t-1}²
```

**How it works**:
1. Fit GARCH(1,1) to scaled returns
2. Forecast volatility path conditional on history
3. Simulate returns using time-varying σ_t
4. Build price paths

**Strengths**:
- Explicit volatility modeling
- Captures volatility clustering
- Widely studied and validated
- Good for risk forecasting

**Weaknesses**:
- Requires `arch` package
- Needs substantial history (100+ bars)
- Assumes normal innovations
- Sensitive to parameter initialization

**When to use**:
- Volatility clustering is strong (high autocorrelation in squared returns)
- Risk management focus
- Options pricing or volatility trading
- When you need volatility forecasts, not just prices

**Real-life example**:
> **Scenario**: SPY options hedge on daily chart, horizon = 20 days
>
> **Why GARCH**: Volatility clustering is well-documented in equity indices; need accurate vol for options
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob SPY --timeframe D1 --horizon 20 \
>   --method garch --tp-pct 3.0 --sl-pct 2.0 \
>   --params "p=1 q=1"
> ```

---

### 5. Bootstrap (`bootstrap`)

**Algorithm**: Circular block bootstrap

**How it works**:
1. Compute historical returns
2. Sample contiguous blocks of returns (size = `block_size`)
3. Concatenate blocks to create synthetic paths
4. No parametric assumptions

**Strengths**:
- Non-parametric (no distribution assumptions)
- Preserves autocorrelation structure
- Captures fat tails and skew
- Works with any return distribution

**Weaknesses**:
- Limited to historical patterns
- Cannot extrapolate beyond observed volatility
- Requires long history for good coverage

**When to use**:
- Non-normal returns with complex patterns
- When you suspect model misspecification
- Validation of parametric models
- Markets with structural breaks

**Real-life example**:
> **Scenario**: Emerging market FX (e.g., USDTRY), horizon = 24 bars
>
> **Why Bootstrap**: Returns have fat tails, skew, and jumps that parametric models miss
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob USDTRY --timeframe H1 --horizon 24 \
>   --method bootstrap --tp-pct 2.0 --sl-pct 1.5 \
>   --params "block_size=5"
> ```

---

### 6. Heston Model (`heston`)

**Algorithm**: Stochastic volatility (Heston 1993)

**Mathematical Model**:
```
dS_t = μS_t dt + √v_t S_t dW_t^1
dv_t = κ(θ - v_t) dt + ξ√v_t dW_t^2
dW_t^1 dW_t^2 = ρ dt
```

**Parameters**:
- `κ`: mean reversion speed
- `θ`: long-term variance
- `ξ`: volatility of volatility
- `ρ`: correlation between price and vol
- `v₀`: initial variance

**Strengths**:
- Captures leverage effects (ρ)
- Stochastic volatility
- Closed-form option pricing available
- More realistic than GBM

**Weaknesses**:
- Complex parameter estimation
- Requires many assumptions
- Computationally expensive
- Hard to calibrate

**When to use**:
- Equity options trading
- When leverage effect is important
- Long-dated derivatives
- Academic/research contexts

**Real-life example**:
> **Scenario**: AAPL options strategy, horizon = 60 days
>
> **Why Heston**: Need stochastic vol + leverage effect for accurate option pricing
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob AAPL --timeframe D1 --horizon 60 \
>   --method heston --tp-pct 10.0 --sl-pct 5.0 \
>   --params "kappa=2.0 theta=0.04 xi=0.3 rho=-0.5"
> ```

---

### 7. Jump Diffusion (`jump_diffusion`)

**Algorithm**: Merton jump-diffusion

**Mathematical Model**:
```
dS_t = (μ - λk)S_t dt + σS_t dW_t + S_t dJ_t
J_t: compound Poisson process with log-normal jumps
```

**Parameters**:
- `jump_lambda`: jump intensity (frequency)
- `jump_mu`: mean jump size
- `jump_sigma`: jump size volatility
- `jump_threshold`: outlier threshold for calibration

**Strengths**:
- Captures sudden price jumps
- Models tail events
- Better for crisis periods
- Accounts for news events

**Weaknesses**:
- Difficult to calibrate reliably
- Many parameters
- Overfits easily
- Requires long history

**When to use**:
- Earnings announcements
- Major news events
- Cryptocurrency markets
- Crisis periods

**Real-life example**:
> **Scenario**: Trading around FOMC announcement, horizon = 4 hours
>
> **Why Jump Diffusion**: Expecting discrete price jumps from news, not continuous movement
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob EURUSD --timeframe M15 --horizon 16 \
>   --method jump_diffusion --tp-pct 0.5 --sl-pct 0.3 \
>   --params "jump_lambda=0.5 jump_mu=0.001 jump_sigma=0.002"
> ```

---

### 8. Automatic Selection (`auto`)

**Algorithm**: Heuristic method selector based on data characteristics

**Decision Tree**:
```
Note: `garch` requires the `arch` package; auto falls back to `heston` if it is not available.
1. Insufficient history (< 10 bars or < 30 returns)?
   → mc_gbm_bb if horizon ≤ 12, else mc_gbm

2. Crypto or short timeframe (≤ 15 min)?
   → If heavy tails (kurtosis > 2, jump_ratio > 4): jump_diffusion
   → Otherwise continue

3. Heavy tails (kurtosis > 3.5, jump_ratio > 5)?
   → jump_diffusion

4. Volatility regime change (vol_ratio > 1.6 or < 0.65)?
   → hmm_mc (if enough history)

5. Strong volatility clustering (vol_corr > 0.3, r2 size ≥ 150)?
   → garch (if available) or heston

6. Moderate volatility clustering (vol_corr > 0.15)?
   → heston

7. Non-normal but no clear patterns (skew > 0.7, not jumpy)?
   → bootstrap

8. Short horizon and mild tails?
   → mc_gbm_bb

9. Default:
   → mc_gbm
```

**Strengths**:
- No need to manually select method
- Adapts to data characteristics
- Prevents obvious mistakes

**Weaknesses**:
- Black box (but reports reason)
- May not be optimal for all cases
- Still needs sufficient history

**When to use**:
- Initial exploration
- Production automation
- When unsure about market characteristics
- Multi-asset screening

**Real-life example**:
> **Scenario**: Screening 20 currency pairs for trading opportunities
>
> **Why Auto**: Don't want to manually analyze each pair's characteristics
>
> **Command**:
> ```bash
> mtdata-cli forecast_barrier_prob EURUSD --timeframe H1 --horizon 12 \
>   --method auto --tp-pct 0.5 --sl-pct 0.3
>
> # Returns: method_used: "hmm_mc", auto_reason: "auto: regime shift (volatility change)"
> ```

---

## Optimization: Finding Optimal TP/SL

### Grid Search (`forecast_barrier_optimize`)

Searches combinations of TP/SL to maximize an objective function.

**Search Profiles**: Control the compute budget with `--search-profile`:

| Profile | n_sims | n_trials | Grid density | Refine |
|---------|--------|----------|-------------|--------|
| `fast` | 1,200 | 24 | 4 × 4 | off |
| `medium` (default) | 4,000 | 63 | 7 × 9 | off |
| `long` | 10,000 | 600 | 41 × 51 | on |

Use `--fast-defaults true` as a shortcut for the `fast` profile. Explicit `--n-sims`, `--tp-steps`, etc. override the profile values.

**Grid Styles**:

#### 1. Fixed Grid (`grid_style=fixed`)
```
TP: [tp_min, tp_max] with tp_steps points
SL: [sl_min, sl_max] with sl_steps points
Total combinations: tp_steps × sl_steps
```

**Use case**: General purpose, known reasonable ranges

**Example**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct \
  --tp-min 0.25 --tp-max 1.5 --tp-steps 7 \
  --sl-min 0.25 --sl-max 2.5 --sl-steps 9
```

---

#### 2. Volatility Grid (`grid_style=volatility`)
Scales TP/SL based on recent volatility

**Algorithm**:
```
vol_per_bar = std(returns[-vol_window:])
vol_horizon = vol_per_bar * sqrt(horizon)
vol_pct = vol_horizon * 100

tp_start = max(vol_floor_pct, vol_pct * vol_min_mult)
tp_end = max(tp_start * 1.1, vol_pct * vol_max_mult)
sl_start = max(vol_floor_pct, vol_pct * vol_min_mult * 0.8)
sl_end = sl_start * vol_sl_multiplier
```

**Use case**: Adapts to current market volatility

Use `vol_sl_multiplier` to control the volatility-grid stop-loss multiplier.

**Example**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct --grid-style volatility \
  --params "vol_window=250 vol_min_mult=0.5 vol_max_mult=4.0 vol_sl_multiplier=1.8"
```

---

#### 3. Ratio Grid (`grid_style=ratio`)
Fixes risk/reward ratio

**Algorithm**:
```
For each SL in [sl_min, sl_max]:
  For each ratio in [ratio_min, ratio_max]:
    TP = SL * ratio
```

**Use case**: When you want specific risk/reward profiles

**Example**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct --grid-style ratio \
  --ratio_min 1.5 --ratio_max 3.0 --ratio_steps 5 \
  --sl-min 0.3 --sl-max 1.0 --sl-steps 5
```

---

#### 4. Preset Grid (`grid_style=preset`)
Pre-configured ranges for trading styles

**Presets**:
- `scalp`: TP 0.08-0.60%, SL 0.20-1.20%
- `intraday`: TP 0.25-1.50%, SL 0.25-2.50%
- `swing`: TP 0.60-3.50%, SL 0.50-4.50%
- `position`: TP 1.00-8.00%, SL 0.75-6.00%

**Use case**: Quick setup for standard trading styles

Note:
- Presets are stored in percentage terms.
- In `mode=ticks`, the optimizer converts those preset percentages to tick-size distances using the current reference price.
- That means named presets in tick mode are not portable across different price levels.

**Example**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct --grid-style preset \
  --preset swing
```

---

### Objectives

Choose what to optimize. Each objective answers a different trading question:

#### Quick Reference Table

| Objective | Formula | Best For |
|-----------|---------|----------|
| `edge` | `P(win) - P(loss)` | General purpose, consistent win rate |
| `prob_tp_first` | `P(win)` | Maximize win rate only |
| `prob_resolve` | `1 - P(no hit)` | Ensure trades complete |
| `kelly` | `P(tp_first) - P(sl_first)/net_RR` | Position sizing |
| `kelly_cond` | Kelly on resolved trades only | Position sizing (ignoring timeouts) |
| `ev` | `P(tp_first)*net_TP - P(sl_first)*net_SL` | Maximize profit per trade |
| `ev_cond` | EV on resolved trades only | Profit per trade (ignoring timeouts) |
| `ev_per_bar` | `EV / mean_time_in_trade_all_paths` | Fast trades, capital turnover |
| `profit_factor` | `(P(tp_first)*net_TP) / (P(sl_first)*net_SL)` | Risk/reward ratio focus |
| `min_loss_prob` | Minimize `P(loss)` | Capital preservation |
| `utility` | `P(tp_first)*log(1+TP) + P(sl_first)*log(1-SL)` | Risk-averse trading |

#### Detailed Descriptions

**`edge`** — *"How often do I win vs lose?"*
- Measures raw probability advantage
- Edge = 0.20 means you win 20% more often than you lose
- **Use when:** You want consistent winners, regardless of payoff size
- **Limitation:** Ignores how much you win/lose

**`ev` (Expected Value)** — *"What's my average profit per trade?"*
- Accounts for both probability AND payoff size
- When spread, slippage, or commission inputs are supplied, EV is net of those costs
- EV = 0.15% means you expect to gain 0.15% per trade on average
- **Use when:** Payoff asymmetry matters (e.g., small wins, big losses)
- **Limitation:** Doesn't account for trade duration

**`ev_per_bar`** — *"What's my profit per unit of time?"*
- Normalizes EV by how long trades take
- Uses unconditional time-in-trade, so unresolved paths count at full horizon
- Favors fast trades over slow ones with same total EV
- **Use when:** Capital turnover matters (reinvesting profits)
- **Limitation:** May favor trades with higher transaction costs

**`kelly`** — *"How much should I bet?"*
- Optimal fraction of capital for maximum long-term growth
- Uses net reward/risk when trading costs are supplied
- Kelly = 0.25 means bet 25% of capital (but use fractional Kelly in practice)
- **Use when:** Position sizing decisions
- **Limitation:** Full Kelly leads to large drawdowns; use 0.25× Kelly

**`prob_resolve`** — *"Will my trade actually close?"*
- Probability that TP or SL is hit within the horizon
- High value means trades complete; low value means many expire
- **Use when:** You need trades to close (e.g., day trading)
- **Limitation:** High resolve doesn't mean profitable

**`profit_factor`** — *"What's my gains-to-losses ratio?"*
- Profit factor > 1 means profitable; > 2 is very good
- Uses net wins/net losses when trading costs are supplied
- Common metric in backtesting reports
- **Use when:** Comparing strategies by risk/reward
- **Limitation:** Doesn't account for trade frequency

**`min_loss_prob`** — *"How do I avoid losses?"*
- Minimizes probability of stop-loss being hit
- **Use when:** Capital preservation is priority
- **Limitation:** May result in tiny TP or trades that never resolve

**`utility`** — *"What's my risk-adjusted outcome?"*
- Logarithmic utility penalizes large losses more than it rewards equivalent gains
- Naturally avoids bets that could wipe you out
- **Use when:** Risk-averse trading, avoiding ruin
- **Limitation:** More theoretical than practical

Notes:
- `_cond` variants (e.g., `ev_cond`, `kelly_cond`) calculate metrics only on trades that resolved (hit TP or SL), ignoring timeouts, and remain cost-adjusted when trading costs are supplied.
- `ev_per_bar` uses unconditional time-in-trade (`t_hit_resolve_mean_all`), counting unresolved paths at horizon expiry.
- `t_hit_tp_median` and `t_hit_sl_median` are conditional medians for paths that hit that barrier; `t_hit_tp_median_cond` and `t_hit_sl_median_cond` are aliases.

---

### Two-Stage Refinement

**Problem**: Coarse grid may miss optimal values

**Solution**:
1. Run coarse grid search
2. Zoom around best result
3. Run fine grid in zoomed region

**Parameters**:
- `refine=true`: Enable refinement
- `refine_radius=0.3`: Search within ±30% of best
- `refine_steps=5`: Points per dimension in refinement

**Example**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct \
  --tp-min 0.25 --tp-max 1.5 --tp-steps 5 \
  --sl-min 0.25 --sl-max 2.5 --sl-steps 5 \
  --refine true --refine_radius 0.35 --refine_steps 7
```

---

### Constraints

Filter candidates before ranking:

| Constraint | Description | Example |
|------------|-------------|---------|
| `min_prob_win` | Minimum tie-adjusted TP-first probability | `0.5` (50%) |
| `max_prob_no_hit` | Maximum no-hit probability | `0.2` (20%) |
| `max_median_time` | Maximum resolution time (bars) | `10` |

**Example**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct \
  --tp-min 0.5 --tp-max 2.0 --tp-steps 5 \
  --sl-min 0.5 --sl-max 2.0 --sl-steps 5 \
  --min_prob_win 0.55 --max_prob_no_hit 0.15 --max_median_time 8
```

---

### Statistical Robustness

`forecast_barrier_optimize` can attach extra diagnostics for Monte Carlo quality. This is useful when you want to check whether the selected TP/SL pair is stable enough to trust for research or discretionary trading review.

Enable it with `statistical_robustness=true` in `params` or with the Python keyword arguments.

**What it currently adds:**
- Minimum simulation guidance based on the requested CI width
- Convergence diagnostics for the Monte Carlo success estimate
- Cross-seed stability checks for the selected barrier pair
- Optional bootstrap uncertainty for `prob_win`, `prob_loss`, `ev`, `edge`, `kelly`, and related metrics
- Optional power analysis
- Optional local sensitivity analysis around the selected `tp` and `sl`

**Important:** These checks do not make a trade valid by themselves. They are quality controls on the simulation and on the optimizer output.

#### Python Example

```python
from mtdata.forecast.barriers_optimization import forecast_barrier_optimize

result = forecast_barrier_optimize(
    symbol="EURUSD",
    timeframe="H1",
    horizon=12,
    method="hmm_mc",
    mode="pct",
    grid_style="volatility",
    objective="ev",
    statistical_robustness=True,
    target_ci_width=0.05,
    n_seeds_stability=3,
    enable_bootstrap=True,
    n_bootstrap=500,
    enable_power_analysis=True,
    enable_sensitivity_analysis=True,
    sensitivity_params=["tp", "sl"],
    params={"n_sims": 5000, "seed": 42},
)
```

#### CLI Example

```bash
mtdata-cli forecast_barrier_optimize EURUSD \
  --timeframe H1 \
  --horizon 12 \
  --method hmm_mc \
  --mode pct \
  --grid-style volatility \
  --objective ev \
  --params "statistical_robustness=true,target_ci_width=0.05,n_seeds_stability=3,enable_bootstrap=true,n_bootstrap=500,enable_power_analysis=true,n_sims=5000,seed=42" \
  --json
```

Use Python when you want to pass `sensitivity_params` explicitly.

#### Parameters

| Parameter | Default | Meaning |
|-----------|---------|---------|
| `statistical_robustness` | `False` | Enables the extra diagnostics block |
| `target_ci_width` | `0.05` | Requested width used for minimum-simulation guidance |
| `n_seeds_stability` | `3` | Number of seed re-runs requested for the selected barrier pair |
| `enable_convergence_check` | `True` | Adds `convergence_diagnostic` |
| `enable_bootstrap` | `False` | Adds `bootstrap_uncertainty` |
| `n_bootstrap` | `200` | Number of bootstrap resamples |
| `enable_power_analysis` | `False` | Adds `power_analysis` |
| `power_effect_size` | `0.05` | Effect size assumed in the power calculation |
| `enable_sensitivity_analysis` | `False` | Adds local `tp`/`sl` sensitivity checks |
| `sensitivity_params` | `["tp", "sl"]` | Parameters varied in the sensitivity pass |

#### Output Shape

When enabled, the result can include:

```json
{
  "min_sims_recommended": 1537,
  "statistical_robustness": {
    "minimum_simulations": {
      "recommended": 1537,
      "used": 5000,
      "target_ci_width": 0.05,
      "confidence": 0.95
    },
    "convergence_diagnostic": {
      "converged": true,
      "current_estimate": 0.55,
      "window_mean": 0.548,
      "window_std": 0.008,
      "max_change": 0.006
    },
    "cross_seed_stability": {
      "stable": true,
      "n_seeds": 3,
      "seeds_attempted": 3,
      "seeds_succeeded": 3,
      "metrics": {
        "prob_win": {
          "mean": 0.55,
          "std": 0.02,
          "cv": 0.036
        }
      }
    },
    "bootstrap_uncertainty": {
      "prob_win": {
        "mean": 0.55,
        "std": 0.018,
        "ci_low": 0.51,
        "ci_high": 0.59
      }
    },
    "power_analysis": {
      "power": 0.92,
      "min_n_for_80_power": 3200
    },
    "sensitivity_analysis": {
      "tp": {
        "success": true,
        "values_tested": 5
      }
    }
  }
}
```

Only the sections you enable are returned. `cross_seed_stability` may also report an error if fewer than two seed re-runs succeed.

#### Practical Use

- For a quick research pass, start with `target_ci_width=0.10`, `n_seeds_stability=2`, and leave bootstrap off.
- For a fuller review, use `target_ci_width=0.05`, `n_seeds_stability=3`, and turn on bootstrap.
- Treat failed convergence or unstable cross-seed metrics as a reason to increase `n_sims` or simplify the setup before trusting the optimizer output.
- Sensitivity analysis is most useful after you already have a candidate worth inspecting; it is not a replacement for the main grid search.

---

## Real-Life Trading Scenarios

### Scenario 1: Scalping EURUSD

**Context**: 5-minute chart, quick trades, tight spreads

**Requirements**:
- Fast execution
- High win rate
- Short holding time

**Method Selection**:
```bash
# Use auto or mc_gbm_bb for precision
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe M5 --horizon 6 \
  --method mc_gbm_bb --mode pct --grid-style preset \
  --preset scalp \
  --objective kelly_cond \
  --refine true --refine_radius 0.25
```

**Interpretation**:
- Look for `kelly_cond > 0` (positive edge after costs)
- `prob_resolve > 0.7` (most trades close out)
- `t_hit_resolve_median < 4` (fast resolution)

---

### Scenario 2: Swing Trading Gold

**Context**: 4H chart, multi-day holds, volatility spikes

**Requirements**:
- Handle regime changes
- Account for volatility clustering
- Wider stops

**Method Selection**:
```bash
# HMM captures regimes, volatility grid adapts to current vol
mtdata-cli forecast_barrier_optimize \
  XAUUSD --timeframe H4 --horizon 60 \
  --method hmm_mc --mode pct --grid-style volatility \
  --params "vol_window=300 vol_min_mult=0.8 vol_max_mult=3.0" \
  --objective edge --min_prob_win 0.5
```

**Interpretation**:
- Look for `edge > 0.1` (10% advantage)
- Check `prob_no_hit` (avoid if too high)
- Verify `time_to_tp_seconds.median` aligns with swing timeframe

---

### Scenario 3: Post-Earnings Options

**Context**: AAPL daily chart, jump risk from earnings

**Requirements**:
- Model jumps
- Short horizon (1-5 days)
- High volatility expected

**Method Selection**:
```bash
# Jump diffusion captures earnings moves
mtdata-cli forecast_barrier_optimize \
  AAPL --timeframe D1 --horizon 5 \
  --method jump_diffusion --mode pct \
  --tp-min 3.0 --tp-max 10.0 --tp-steps 5 \
  --sl-min 2.0 --sl-max 6.0 --sl-steps 5 \
  --params "jump_lambda=0.3" \
  --objective ev
```

**Interpretation**:
- Focus on `ev` (expected value)
- Check `prob_tie` (should be low)
- Verify jump parameters via `model_summary`

---

### Scenario 4: Range-Bound Market

**Context**: EURUSD in tight range, mean reversion

**Requirements**:
- High probability of no hit
- Small barriers
- Quick resolution if hit

**Method Selection**:
```bash
# Bootstrap preserves range characteristics
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method bootstrap --mode pct \
  --tp-min 0.2 --tp-max 0.6 --tp-steps 5 \
  --sl-min 0.2 --sl-max 0.6 --sl-steps 5 \
  --objective prob_resolve \
  --max_prob_no_hit 0.3
```

**Interpretation**:
- High `prob_resolve` (trades close out)
- Low `prob_no_hit`
- Balanced `prob_win` and `prob_loss`

---

### Scenario 5: Multi-Asset Screening

**Context**: Finding best setups across 20 pairs

**Requirements**:
- Automated selection
- Consistent comparison
- Fast processing

**Method Selection**:
```bash
# Auto method adapts to each pair
for pair in EURUSD GBPUSD USDJPY AUDUSD NZDUSD USDCAD USDCHF; do
  mtdata-cli forecast_barrier_optimize \
    $pair --timeframe H1 --horizon 12 \
    --method auto --mode pct --grid-style volatility \
    --objective edge --top_k 1
done
```

**Interpretation**:
- Rank pairs by `edge` from `best` output
- Check `auto_reason` to understand method choice
- Filter by `prob_resolve > 0.6`

---

## Output Interpretation

### Single Barrier Query

```json
{
  "success": true,
  "method": "hmm_mc",
  "prob_tp_first": 0.62,
  "prob_sl_first": 0.28,
  "prob_no_hit": 0.10,
  "edge": 0.34,
  "time_to_tp_bars": {"mean": 6.2, "median": 5.0},
  "time_to_sl_bars": {"mean": 4.8, "median": 4.0}
}
```

**Interpretation**:
- `prob_tp_first = 0.62`: 62% chance TP hits first
- `prob_sl_first = 0.28`: 28% chance SL hits first
- `prob_no_hit = 0.10`: 10% chance neither hits
- `edge = 0.34`: 34% advantage (TP prob - SL prob)
- **Decision**: Good trade if edge > 0 and you have edge after costs

---

### Optimization Output

```json
{
  "best": {
    "tp": 0.85,
    "sl": 0.62,
    "rr": 1.37,
    "prob_win": 0.58,
    "prob_loss": 0.32,
    "prob_no_hit": 0.10,
    "prob_resolve": 0.90,
    "edge": 0.26,
    "kelly": 0.34,
    "kelly_cond": 0.47,
    "ev": 0.22,
    "ev_cond": 0.32,
    "ev_per_bar": 0.03,
    "profit_factor": 2.45,
    "utility": 0.18,
    "t_hit_resolve_mean": 6.8,
    "t_hit_resolve_median": 6.0
  },
  "auto_reason": "auto: regime shift (volatility change)"
}
```

**Interpretation**:
- **TP/SL**: 0.85% / 0.62% (RR = 1.37)
- **Win prob**: 58% (conditional on resolution: 58/(58+32) = 64%)
- **Edge**: 26% raw (TP prob − SL prob)
- **Resolve prob**: 90% of paths hit TP/SL within the horizon
- **Kelly**: 34% (raw), 47% conditional on resolution
- **EV**: 0.22% per trade; **EV per bar**: 0.03% based on unconditional time in trade
- **Profit factor**: 2.45 (wins/losses ratio)
- **Utility**: 0.18 (risk‑averse log utility)
- **Resolve time**: mean 6.8 bars, median 6 bars
- **Method used**: HMM (detected regime shift)

**Decision**: This is a good setup - positive edge, reasonable RR, fast resolution.

---

## Common Pitfalls & Solutions

### Pitfall 1: Insufficient History

**Problem**: Method fails or gives unreliable results

**Solution**:
```bash
# Check history length first
mtdata-cli data_fetch_candles EURUSD --timeframe H1 --limit 500

# If insufficient, use mc_gbm (or mc_gbm_bb for short horizons)
mtdata-cli forecast_barrier_prob EURUSD --timeframe H1 --horizon 10 \
  --method mc_gbm --tp-pct 0.2 --sl-pct 0.15
```

---

### Pitfall 2: Overfitting to Recent Volatility

**Problem**: Optimizer picks TP/SL that won't generalize

**Solution**:
```bash
# Use longer vol_window for stable estimates
--params "vol_window=500"

# Or bootstrap (non-parametric)
--method bootstrap

# Validate with rolling backtest
```

---

### Pitfall 3: Ignoring No-Hit Probability

**Problem**: High edge but many trades never close

**Solution**:
```bash
# Add constraint
--max_prob_no_hit 0.2

# Or optimize for resolve probability
--objective prob_resolve
```

---

### Pitfall 4: Wrong Method for Market Regime

**Problem**: Using GBM in highly regime-switching market

**Solution**:
```bash
# Use auto to select appropriate method
--method auto

# Or manually check for regimes
mtdata-cli regime_detect EURUSD --timeframe H1 --method hmm --params "n_states=3"
```

---

### Pitfall 5: Not Accounting for Slippage/Spread

**Problem**: Paper trading results don't match reality

**Solution**:
- Reduce TP by spread/2
- Increase SL by spread/2
- Or use `tp_ticks`/`sl_ticks` which account for tick size

```bash
# Example: 20/15 tick-size barriers on EURUSD
mtdata-cli forecast_barrier_prob \
  EURUSD --timeframe M5 --horizon 12 \
  --method hmm_mc --tp-ticks 20 --sl-ticks 15  # RR = 1.33 after spread
```

---

## Advanced Tips

### 1. Multi-Horizon Analysis

Run multiple horizons to understand time dynamics:

```bash
for H in 6 12 24 48; do
  echo "Horizon $H bars:"
  mtdata-cli forecast_barrier_prob \
    EURUSD --timeframe H1 --horizon $H \
    --method hmm_mc --tp-pct 0.5 --sl-pct 0.3 \
    --json | jq '{horizon: .horizon, edge: .edge, prob_resolve: (.prob_tp_first + .prob_sl_first)}'
done
```

---

### 2. Regime-Conditional Analysis

Detect regimes first, then optimize per regime:

```bash
# Detect current regime
mtdata-cli regime_detect EURUSD --timeframe H1 --method hmm --params "n_states=2"

# If high-vol regime, use wider barriers
# If low-vol regime, use tighter barriers
```

---

### 3. Denoising for Cleaner Signals

```bash
# Apply denoising before simulation
mtdata-cli forecast_barrier_optimize EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct --grid-style preset --preset swing \
  --denoise lowpass_fft --denoise-params "cutoff_ratio=0.1"
```

---

### 4. Parameter Sensitivity

Test stability of results:

```bash
# Vary n_sims
for N in 1000 2000 5000 10000; do
  mtdata-cli forecast_barrier_prob EURUSD --timeframe H1 --horizon 12 \
    --method hmm_mc --tp-pct 0.5 --sl-pct 0.3 --params "n_sims=$N" \
    --json | jq '.prob_tp_first'
done
```

---

### 5. Cross-Validation

Compare methods on same data:

```bash
for METHOD in mc_gbm hmm_mc bootstrap; do
  echo "Method: $METHOD"
  mtdata-cli forecast_barrier_prob EURUSD --timeframe H1 --horizon 12 \
    --method $METHOD --tp-pct 0.5 --sl-pct 0.3 \
    --json | jq '{method: .method, edge: .edge, prob_resolve: (.prob_tp_first + .prob_sl_first)}'
done
```

---

## Performance Considerations

### Speed vs Accuracy Trade-off

| Method | Speed | Accuracy | History Needed |
|--------|-------|----------|----------------|
| mc_gbm | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | Minimal |
| mc_gbm_bb | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Minimal |
| hmm_mc | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 200+ bars |
| garch | ⭐⭐ | ⭐⭐⭐⭐ | 100+ bars |
| bootstrap | ⭐⭐⭐ | ⭐⭐⭐⭐ | 400+ bars |
| heston | ⭐ | ⭐⭐⭐⭐ | 200+ bars |
| jump_diffusion | ⭐ | ⭐⭐⭐⭐ | 300+ bars |

### Optimization Speed

- **Fixed grid**: `O(S × T × S)` where S=sl_steps, T=tp_steps
- **Volatility grid**: Similar, but adaptive ranges
- **Refinement**: Adds ~2× computation
- **n_sims**: Linear scaling (2× sims = 2× time)

**Tips for speed**:
1. Start with `mc_gbm` for screening
2. Use `detail="compact"` to limit grid output
3. Set `top_k` to limit evaluations
4. Reduce `n_sims` for initial runs (1000), increase for final (5000+)

---

## Summary Decision Tree

```
Start with: --method auto --horizon [your_horizon]

If horizon < 10:
  → Consider mc_gbm_bb for precision

If horizon > 50:
  → Consider hmm_mc or garch for regimes

If crypto/jumpy:
  → Consider jump_diffusion

If non-normal/fat tails:
  → Consider bootstrap

If optimizing:
  → Use grid-style volatility for adaptive ranges
  → Use refine=true for precision
  → Set constraints (min_prob_win, max_prob_no_hit)

Validate:
  → Check prob_no_hit < 0.2
  → Check edge > 0
  → Check median time fits your style
  → Run cross-validation across methods
```

---

## Quick Reference

### Most Common Commands

**Quick check**:
```bash
mtdata-cli forecast_barrier_prob \
  EURUSD --timeframe H1 --horizon 12 \
  --method auto --tp-pct 0.5 --sl-pct 0.3
```

**Find optimal**:
```bash
mtdata-cli forecast_barrier_optimize \
  EURUSD --timeframe H1 --horizon 12 \
  --method hmm_mc --mode pct --grid-style volatility \
  --refine true --objective edge
```

**Closed-form check**:
```bash
mtdata-cli forecast_barrier_prob \
  EURUSD --timeframe H1 --horizon 12 \
  --method closed_form --direction long --barrier 1.1000
```

---

## Further Reading

- [FORECAST.md](FORECAST.md) - General forecasting documentation
- [SAMPLE-TRADE.md](SAMPLE-TRADE.md) - Example trading workflows
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - Troubleshooting

---

*Last updated: 2026-01-01*
