Skip to content
Finance
Skill

/regime-detection

Market regime identification using volatility clustering, trend detection, and statistical methods for adaptive trading

From plugin
trading-skills
26767 skills
Install
$ npx -y skills add agiprolabs/claude-trading-skills --skill regime-detection --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/regime-detection

Context preview

The summary Claude sees to decide when to auto-load this skill.

Market regime identification using volatility clustering, trend detection, and statistical methods for adaptive trading

SKILL.md

regime-detection.SKILL.md
name: regime-detection
description: Market regime identification using volatility clustering, trend detection, and statistical methods for adaptive trading

Regime Detection

Identify the current market regime so you can pick the right strategy, size positions correctly, and avoid deploying trend-following logic in a ranging market (or vice versa).

Why Regime Detection Matters

Every strategy has a "home regime." A momentum strategy prints money in a clean uptrend but bleeds in a choppy range. A mean-reversion grid thrives in low-volatility consolidation but gets steamrolled by a trending breakout. Regime detection tells you **which playbook to use right now**.

Key benefits:

  • **Strategy selection**: Route signals to the right strategy for the current environment
  • **Position sizing**: Reduce exposure in hostile regimes, increase in favorable ones
  • **Stop adaptation**: Wider stops in high-vol regimes, tighter in low-vol trends
  • **Drawdown control**: Sit out "danger zone" regimes (high vol + no trend)

Core Regime Dimensions

Two orthogonal axes define the four-quadrant regime model:

| | Low Volatility | High Volatility | |---|---|---| | **Trending** | Q1: Clean trend — best for trend following | Q2: Volatile trend — momentum with caution | | **Ranging** | Q3: Quiet range — mean-reversion paradise | Q4: Choppy chaos — reduce or sit out |

A third dimension — **mean-reversion tendency** (Hurst exponent) — refines Q3 by telling you how reliably price reverts.

Simple Approaches (No ML Required)

1. ATR Volatility Percentile

Rank the current ATR against its own recent history to get a 0–100 percentile score.

import pandas as pd
import numpy as np

def atr_percentile(
    high: pd.Series, low: pd.Series, close: pd.Series,
    atr_period: int = 14, lookback: int = 100
) -> pd.Series:
    """ATR percentile rank over a rolling window."""
    tr = pd.concat([
        high - low,
        (high - close.shift(1)).abs(),
        (low - close.shift(1)).abs()
    ], axis=1).max(axis=1)
    atr = tr.rolling(atr_period).mean()
    return atr.rolling(lookback).apply(
        lambda x: pd.Series(x).rank(pct=True).iloc[-1], raw=False
    )
  • **< 25th percentile** → Low volatility regime
  • **25th–75th** → Normal volatility
  • **> 75th percentile** → High volatility regime

2. ADX Trend Strength

ADX above 25 signals a trending market; below 20 signals a range.

def compute_adx(
    high: pd.Series, low: pd.Series, close: pd.Series,
    period: int = 14
) -> pd.Series:
    """Average Directional Index."""
    plus_dm = high.diff().clip(lower=0)
    minus_dm = (-low.diff()).clip(lower=0)
    # Zero out when the other is larger
    plus_dm[plus_dm < minus_dm] = 0
    minus_dm[minus_dm < plus_dm] = 0

    tr = pd.concat([
        high - low,
        (high - close.shift(1)).abs(),
        (low - close.shift(1)).abs()
    ], axis=1).max(axis=1)

    atr = tr.ewm(span=period, adjust=False).mean()
    plus_di = 100 * plus_dm.ewm(span=period, adjust=False).mean() / atr
    minus_di = 100 * minus_dm.ewm(span=period, adjust=False).mean() / atr
    dx = 100 * (plus_di - minus_di).abs() / (plus_di + minus_di)
    return dx.ewm(span=period, adjust=False).mean()

3. EMA Slope + Price Position

def trend_direction(close: pd.Series, period: int = 20) -> pd.Series:
    """Returns +1 (uptrend), -1 (downtrend), 0 (neutral)."""
    ema = close.ewm(span=period, adjust=False).mean()
    slope = ema.diff(5)  # 5-bar slope
    above = (close > ema).astype(int)
    direction = pd.Series(0, index=close.index)
    direction[(slope > 0) & (above == 1)] = 1
    direction[(slope < 0) & (above == 0)] = -1
    return direction

4. Bollinger Band Width Percentile

BB width (upper - lower) / middle as a volatility proxy. A "squeeze" (low percentile) often precedes a breakout.

def bb_width_percentile(
    close: pd.Series, period: int = 20,
    std_dev: float = 2.0, lookback: int = 100
) -> pd.Series:
    """Bollinger Band width percentile."""
    sma = close.rolling(period).mean()
    std = close.rolling(period).std()
    width = (2 * std_dev * std) / sma
    return width.rolling(lookback).apply(
        lambda x: pd.Series(x).rank(pct=True).iloc[-1], raw=False
    )

Statistical Approaches

Rolling Hurst Exponent

The Hurst exponent H classifies time series behavior:

  • **H < 0.4** → Mean-reverting (anti-persistent)
  • **0.4 ≤ H ≤ 0.6** → Random walk (no exploitable structure)
  • **H > 0.6** → Trending (persistent)

Computed via the Rescaled Range (R/S) method. See `references/methodology.md` for the full derivation.

def hurst_exponent(series: pd.Series, max_lag: int = 50) -> float:
    """Estimate Hurst exponent using R/S method."""
    lags = range(2, max_lag)
    rs_values = []
    for lag in lags:
        chunks = [series.iloc[i:i+lag] for i in range(0, len(series) - lag, lag)]
        rs_list = []
        for chunk in chunks:
            if len(chunk) < lag:
                continue
            mean_val = chunk.mean()
            devs = chunk - mean_val
            cumdev = devs.cumsum()
            r = cumdev.max() - cumdev.min()
            s = chunk.std(ddof=1)
            if s > 0:
                rs_list.append(r / s)
        if rs_list:
            rs_values.append(np.mean(rs_list))
        else:
            rs_values.append(np.nan)
    valid = [(l, r) for l, r in zip(lags, rs_values) if not np.isnan(r)]
    if len(valid) < 5:
        return 0.5
    log_lags = np.log([v[0] for v in valid])
    log_rs = np.log([v[1] for v in valid])
    coeffs = np.polyfit(log_lags, log_rs, 1)
    return coeffs[0]

Change-Point Detection (CUSUM)

Detects abrupt shifts in mean or variance of a return series.

def cusum_test(
    returns: pd.Series, threshold: float = 2.0
) -> list[int]:
    """CUSUM change-point detection on returns.

    Returns indices where regime changes are detected.
    """
    mean_r = returns.me
Read more
Ships withtrading-skills

A comprehensive collection of 67 ready-to-use trading, DeFi, and quantitative finance Agent Skills. Works with Claude Code, Cursor, Codex, Gemini CLI, and 30+ other tools.

Get the whole plugin
Stats
312
Stars
62
Forks
Maintained
Maintenance
Python
Language
MIT
License
1mo ago
Last commit
5mo ago
Created

Repo: agiprolabs/claude-trading-skills