Breakout strategy engine
Skill mahmoud20138/Tradecraft/plugins/tradecraft/skills/breakout-strategy-engine
102 Claude Code skills across 7 categories -- trading strategies, Azure, VSCode extensions, AI prompts, and custom automation skills
npx -y skills add mahmoud20138/Tradecraft --skill breakout-strategy-engineAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Pre-built breakout strategy templates — volatility squeeze detection, range breakout, momentum breakout with confirmation filters. Use this skill whenever the user asks about "breakout strategy", "Bollinger squeeze", "range breakout", "momentum breakout", "volatility expansion", "ATR breakout", "Donchian breakout", "breakout confirmation", "false breakout filter", "squeeze momentum", "compression breakout", or any breakout-based trade setup. Works with market-regime-classifier, mt5-chart-browser, and risk-and-portfolio.
SKILL.md
11.5 KB, as published. Nobody here has run it
Breakout Strategy Engine
Pre-Built Breakout Strategies with Confirmation Filters
import pandas as pd
import numpy as np
from dataclasses import dataclass
from typing import Optional
@dataclass
class BreakoutSignal:
symbol: str
direction: str # "long" or "short"
entry: float
stop_loss: float
target: float
strategy: str
confirmation: list[str]
strength: float # 0-1
class BreakoutEngine:
# ═══════════════════════════════════════
# 1. BOLLINGER SQUEEZE BREAKOUT
# ═══════════════════════════════════════
@staticmethod
def bollinger_squeeze(df: pd.DataFrame, bb_period: int = 20, kc_period: int = 20,
kc_mult: float = 1.5) -> dict:
"""Bollinger inside Keltner Channel = squeeze. Breakout when squeeze releases."""
close = df["close"]
bb_mid = close.rolling(bb_period).mean()
bb_std = close.rolling(bb_period).std()
bb_upper = bb_mid + 2 * bb_std
bb_lower = bb_mid - 2 * bb_std
atr = ((df["high"] - df["low"]).rolling(kc_period).mean())
kc_upper = bb_mid + kc_mult * atr
kc_lower = bb_mid - kc_mult * atr
squeeze_on = (bb_lower > kc_lower) & (bb_upper < kc_upper)
squeeze_off = ~squeeze_on
# Squeeze just released
squeeze_fire = squeeze_off & squeeze_on.shift(1)
# Direction from momentum
momentum = close - close.rolling(bb_period).mean()
direction = np.where(momentum > 0, "long", "short")
df_out = df.copy()
df_out["squeeze_on"] = squeeze_on
df_out["squeeze_fire"] = squeeze_fire
df_out["direction"] = direction
df_out["bb_width"] = (bb_upper - bb_lower) / bb_mid * 100
current = df_out.iloc[-1]
return {
"strategy": "bollinger_squeeze",
"squeeze_active": bool(current["squeeze_on"]),
"squeeze_firing": bool(current["squeeze_fire"]),
"direction": current["direction"],
"bb_width": round(current["bb_width"], 3),
"bars_in_squeeze": int(squeeze_on.iloc[-20:].sum()),
"signal": "BREAKOUT FIRING" if current["squeeze_fire"] else
"SQUEEZE BUILDING" if current["squeeze_on"] else "NO SQUEEZE",
}
# ═══════════════════════════════════════
# 2. RANGE BREAKOUT (Donchian)
# ═══════════════════════════════════════
@staticmethod
def donchian_breakout(df: pd.DataFrame, period: int = 20, atr_mult: float = 1.5) -> dict:
"""Break above/below N-period high/low with ATR confirmation."""
high_n = df["high"].rolling(period).max().shift(1)
low_n = df["low"].rolling(period).min().shift(1)
atr_val = ((df["high"] - df["low"]).rolling(14).mean())
close = df["close"]
long_break = close > high_n
short_break = close < low_n
# Volume confirmation
vol_confirm = df["volume"] > df["volume"].rolling(20).mean() * 1.5
current = df.iloc[-1]
return {
"strategy": "donchian_breakout",
"upper_channel": round(high_n.iloc[-1], 5),
"lower_channel": round(low_n.iloc[-1], 5),
"current_price": round(current["close"], 5),
"long_breakout": bool(long_break.iloc[-1]),
"short_breakout": bool(short_break.iloc[-1]),
"volume_confirmed": bool(vol_confirm.iloc[-1]),
"atr": round(atr_val.iloc[-1], 5),
"stop_long": round(high_n.iloc[-1] - atr_mult * atr_val.iloc[-1], 5),
"stop_short": round(low_n.iloc[-1] + atr_mult * atr_val.iloc[-1], 5),
}
# ═══════════════════════════════════════
# 3. MOMENTUM BREAKOUT
# ═══════════════════════════════════════
@staticmethod
def momentum_breakout(df: pd.DataFrame) -> dict:
"""Multi-filter momentum breakout: ADX + volume + close above/below structure."""
close = df["close"]
atr = (df["high"] - df["low"]).rolling(14).mean()
# ADX proxy
plus_dm = df["high"].diff().clip(lower=0).rolling(14).mean()
minus_dm = (-df["low"].diff()).clip(lower=0).rolling(14).mean()
dx = abs(plus_dm - minus_dm) / (plus_dm + minus_dm + 1e-10) * 100
adx = dx.rolling(14).mean()
# Momentum
mom_10 = close.pct_change(10)
vol_ratio = df["volume"] / df["volume"].rolling(20).mean()
# Structure break
high_20 = df["high"].rolling(20).max()
low_20 = df["low"].rolling(20).min()
current = df.iloc[-1]
filters = []
if adx.iloc[-1] > 25: filters.append("ADX>25 (trending)")
if vol_ratio.iloc[-1] > 1.5: filters.append("Volume 1.5x avg")
if current["close"] > high_20.iloc[-2]: filters.append("New 20-bar high")
if current["close"] < low_20.iloc[-2]: filters.append("New 20-bar low")
if abs(mom_10.iloc[-1]) > 0.01: filters.append("Strong 10-bar momentum")
direction = "long" if mom_10.iloc[-1] > 0 else "short"
return {
"strategy": "momentum_breakout",
"direction": direction,
"adx": round(adx.iloc[-1], 1),
"momentum_10": round(mom_10.iloc[-1] * 100, 2),
"volume_ratio": round(vol_ratio.iloc[-1], 2),
"confirmations": filters,
"n_confirmations": len(filters),
"signal_quality": "A+" if len(filters) >= 4 else "A" if len(filters) >= 3 else "B" if len(filters) >= 2 else "C",
"atr_stop": round(atr.iloc[-1] * 2, 5),
}
# ═══════════════════════════════════════
# FALSE BREAKOUT FILTER
# ═══════════════════════════════════════
@staticmethod
def false_breakout_probability(df: pd.DataFrame, lookback: int = 100) -> dict:
"""Historical false breakout rate for current pair to calibrate expectations."""
high_n = df["high"].rolling(20).max().shift(1)
low_n = df["low"].rolling(20).min().shift(1)
breakouts = (df["close"] > high_n) | (df["close"] < low_n)
# A breakout is false if price returns inside range within 5 bars
false_count = 0
total = 0
for i in range(20, len(df) - 5):
if breakouts.iloc[i]:
total += 1
future = df.iloc[i+1:i+6]
mid = (high_n.iloc[i] + low_n.iloc[i]) / 2
if (future["close"] < high_n.iloc[i]).any() and (future["close"] > low_n.iloc[i]).any():
false_count += 1
rate = false_count / max(total, 1)
return {
"false_breakout_rate": round(rate * 100, 1),
"total_breakouts": total,
"recommendation": "Wait for retest" if rate > 0.5 else "Trade breakout with confirmation",
}
@staticmethod
def scan_all(df: pd.DataFrame, symbol: str = "") -> dict:
return {
"symbol": symbol,
"squeeze": BreakoutEngine.bollinger_squeeze(df),
"donchian": BreakoutEngine.donchian_breakout(df),
"momentum": BreakoutEngine.momentum_breakout(df),
"false_breakout_rate": BreakoutEngine.false_breakout_probability(df),
}
Automated Breakout Detection with Liquidity Sweep (CodeTrading Python)
Source: "Automated Break Out Detection in Python" by CodeTrading (Nov 2025)
Why Simple Breakouts Fail
A candle closing above a recent high is NOT enough — price often reverts back (fake breakout). A stronger breakout pattern is preceded by a liquidity sweep.
The Liquidity-Confirmed Breakout Pattern
Bullish breakout with sweep:
- Identify pivot highs and pivot lows within a lookback window (e.g., 40 candles)
- Find the most recent pivot high (resistance level)
- Check if a pivot low formed AFTER that high AND is lower than all previous pivot lows in the window = liquidity sweep
- Current candle closes above the pivot high AND previous candle was below it = breakout confirmed
- Filter: only take bullish breakouts when last 15 candles are ALL above EMA (trend confirmation)
Bearish breakout with sweep: Mirror logic — pivot low → higher high sweep → breakdown below pivot low
Python Implementation Details
Pivot Detection (no look-ahead bias):
def mark_pivots(df, window=7, high_col='high', low_col='low'):
# Compare candle high to W neighbors left AND right
# Pivot high: higher than all W neighbors
# Pivot low: lower than all W neighbors
# CRITICAL: stop at current_candle - window + 1 to avoid future data
Breakout Detection Function:
def detect_breakout(candle_idx, back_candles=40, window=5):
# 1. Find pivots in [candle_idx - back_candles : candle_idx - window + 1]
# 2. Find last pivot high value
# 3. Check if close[candle_idx] > pivot_high AND close[candle_idx-1] < pivot_high
# 4. Find pivot low between last_pivot_high and breakout candle
# 5. Confirm pivot_low < min(all previous pivot lows) = SWEEP
# Return: 2 = bullish breakout, 1 = bearish breakout, 0 = no signal
Trend Filter (EMA-based):
- Check if last N candles (e.g., 15) are ALL above EMA → uptrend → only bullish breakouts
- ALL below EMA → downtrend → only bearish breakouts
- Adjustable selectivity: 10, 15, 20, 25 candles
Backtest Results (EURUSD, 20 years hourly data, 2003-2023)
Optimization surface (TP/SL ratio vs ATR multiplier):
- Best zone: TP/SL ratio 4-5x, ATR multiplier 4+
- Returns: 5-52% depending on parameters (no leverage, no commission)
- Drawdown minimized at ATR mult ~1, TP/SL ~1 (but returns limited to 5-8%)
Key Parameters
back_candles = 40 # Lookback window for pattern detection
pivot_window = 5-7 # Neighbors for pivot detection
ema_candles = 15 # Candles for trend confirmation
atr_mult = 1-5 # Stop loss = ATR * multiplier
tp_sl_ratio = 1-5 # Take profit / stop loss ratio
Usage Recommendation
- Best as an alert indicator — bot detects pattern, human manages trade
- Run simultaneously on multiple assets to multiply signal count without losing precision
- Trade management (TP/SL optimization) is asset-specific — needs tuning per instrument
See also: smart-money-trap-detector (fake breakout detection), liquidity-order-flow-mapper, chart-pattern-scanner