Files
mt-data-mcp/docs/BARRIER_FUNCTIONS.md
T

35 KiB
Raw Blame History

Barrier Functions - Comprehensive Guide

Overview

Related:

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%):

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

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:

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:

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 a Gaussian HMM to log-returns (Baum-Welch)
  2. Use its transition matrix and filtered final state distribution
  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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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

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

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:

{
  "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:

# 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:

# 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:

# 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_same_bar (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:

# 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:

# 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

{
  "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

{
  "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:

# 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:

# 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:

# 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:

# 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
# 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:

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:

# 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

# 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:

# 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:

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:

mtdata-cli forecast_barrier_prob \
  EURUSD --timeframe H1 --horizon 12 \
  --method auto --tp-pct 0.5 --sl-pct 0.3

Find optimal:

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:

mtdata-cli forecast_barrier_prob \
  EURUSD --timeframe H1 --horizon 12 \
  --method closed_form --direction long --barrier 1.1000

Further Reading


Last updated: 2026-01-01