Install
$ agentstack add skill-mahmoud20138-tradecraft-capitulation-mean-reversion ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Lance Breitstein's Capitulation Mean Reversion Framework
> Source: Lance Breitstein — verified $100M+ trader, Trillium Capital's #1 trader (2020 & 2021), > all-time firm PNL record holder, adviser to SMB Capital, featured in Jack Schwager's upcoming > Market Wizards: The Next Generation. Chart Fanatics interview (March 2026).
Core Philosophy
Markets are extremely efficient. The starting price is usually the RIGHT price. The strategy focuses on identifying moments when price has moved FAR from equilibrium and stacking variables to create massive positive expected value for the reversion trade.
Expected Value Formula:
EV = (Win Rate x Reward) - (Loss Rate x Risk)
The entire system is about shifting EVERY component of this equation in your favor simultaneously.
The 7-Variable Checklist
At any given moment, Lance is constantly weighing ALL factors dynamically. Each variable is scored on a mental 0-10 scale.
Variable 1: Size of Move
- S&P down 1 penny? Not interesting. S&P down $100? Very interesting.
- The LARGER the move from equilibrium, the more appealing for mean reversion.
- Measure in % terms AND absolute terms relative to normal ranges.
Variable 2: Speed / Rate of Change (THE MOST IMPORTANT)
- A 5% move over a year = not interesting.
- A 5% move in 1 minute = extremely interesting.
- Slope analysis grades:
| Slope | Description | Tradeable? | |----------|-------------------------|-----------------------------------------------| | -0.5 | Slow, steady decline | NO — grinding, not capitulating | | -1 | Moderate acceleration | Getting interesting | | -3 | Sharp selloff | Good setup territory | | -10 | Asymptotic waterfall | BEST setups — "we love this" |
- The ideal pattern: Boring/stable -> steady decline -> acceleration -> WATERFALL (asymptotic).
- Rate of change CRESCENDO is the key visual signature.
Variable 3: News Presence
- No news = best. The move is purely technical/sentiment-driven, equilibrium hasn't changed.
- Fundamental news that changes fair value SHIFTS the equilibrium — less appealing for reversion.
- Old/stale news driving fresh panic = still acceptable (news already priced in prior move).
Variable 4: Number of Days/Bars in a Row
- Efficient market theory says each day is independent 50/50. Lance says this is absolutely not true.
- S&P down 3% for 8 days straight? The probability of bouncing on day 9 is FAR above 50%.
- More consecutive directional bars = higher probability of reversal.
- This is a fractal — applies on 2-min bars, hourly, daily, weekly.
Variable 5: Forced Buying/Selling
- Forced liquidations (margin calls, redemptions, loss of borrow).
- When hedge funds MUST sell billions regardless of price, the clearing mechanism creates
extreme dislocation from fair value.
- COVID crash was a textbook example of forced selling creating capitulation opportunities.
Variable 6: Sentiment
- Euphoria = "nothing can ever go wrong" = short opportunity.
- Despair = "nothing will ever go right again" = long opportunity.
- Truth is always somewhere in the middle.
- Sentiment EXTREMES are what create the best mean reversion setups.
Variable 7: Diversification / Market Cap / "Boringness"
- The more boring and stable = the better the mean reversion trade.
- Ranking (safest to riskiest for mean reversion):
- Government bonds (quantifiable par value, near-zero default risk)
- S&P 500 / diversified indices
- Large-cap blue chips (Bank of America, Apple)
- Mid-caps with analyst coverage
- Small/micro-caps (least safe, but can produce biggest moves)
- Crypto/Bitcoin (no cash flows, but increasingly institutionalized)
- Sub-factors within this variable:
- How quantitative/calculable is fair value? (Bonds > stocks > crypto)
- How many "eyes" are on it? (More attention = faster mean reversion)
- How stable historically? (Low ATR relative to current move = better)
- What are normal average trading ranges? (Current bars should be MULTIPLES of normal)
Bonus Variable: Long vs Short (Structural Asymmetry)
- Longs have a $0 floor = maximum loss is capped.
- Shorts have unlimited risk = no upper bound.
- This structural difference means long-side capitulation trades are inherently safer.
- Short-side waterfall plays require SMALLER size to compensate for tail risk.
The Mental Rubric / Scoring System
Lance runs a mental tally across all variables, each scored 0-10:
Example: Rate of Change = 9
Daily Chart = 9
Intraday Setup = 6
Boringness = 2
────────────────────
TOTAL = 26
Grade Thresholds
| Score | Grade | Action | |--------|----------|-----------------------------------------------------| | 35-40+ | A++ / A+ | Max conviction, aggressive sizing, exponential bet | | 26-34 | A / B+ | Strong trade, meaningful size | | 20-25 | B / C+ | Acceptable, moderate-to-small size | | 15-19 | C | Marginal, very small size if taken at all | | $60.
- Daily: Volume so extreme prior bars' volume is invisible on chart.
- Intraday: 7 consecutive green bars, massive distance from MA ($26 MA vs $60 price).
- Entry: Short the break of prior bar lows.
- Result: ~$20/share gain, ~3:1 R:R, ~70%+ win rate.
- Risk factor: Short side = uncapped risk. Used smaller size despite A++ grade.
- Lesson: Best trade of 2020 for many. One of the most extreme examples of the framework.
Example 4: UAMY (Oct 2025) — Grade: B+ / A-
- Setup: Rare earth stock, historically boring (20-30 cents). Doubled in 1-2 weeks on trade war.
- Daily bars expanding: $1 range -> $3 -> $4 -> $5 range bars.
- Cleanly held prior bar lows: 8-9 consecutive bars up.
- Entry: Short break of prior bar lows at ~$15.50.
- Deductions: Short side, low market cap, less liquid.
- Result: ~$3/share gain. Trailing prior bar highs.
Example 5: Bitcoin (Nov 2025) — Grade: A (Swing Long)
- Setup: 3 legs down, 30%+ decline over weeks. Stable -> panicked 5% in 4 minutes at 2:30am.
- Daily: Highest volume flush, most extended below Bollinger. Normal bar range $1-2K, this bar $8K.
- Entry: Had blind bids in (front-side, small size). Added on trend break above MA.
- Intra-bar bounce: Nearly 100% retracement on the flush candle.
- Swing management: Still holding core, trailing prior bar lows.
- Deduction: Bitcoin not quantifiable (no cash flows), but institutionalized.
Scanning / Finding Setups
Daily Chart Filters
Scan for:
1. Price BELOW lower Bollinger Band (20, 2.0)
2. Price ABOVE upper Bollinger Band (20, 2.0)
3. Consecutive UP days >= 4 (for short setups)
4. Consecutive DOWN days >= 4 (for long setups)
5. Volume > 3x 20-day average volume
6. Distance from 20MA > 2x ATR(14)
7. ATR expansion: today's range > 3x ATR(14)
Intraday Filters
Scan for:
1. Holding prior bar highs (declining, clean waterfall)
2. Holding prior bar lows (rising, clean melt-up)
3. Volume capitulation spike (> 5x average bar volume)
4. Distance from intraday VWAP or Bollinger midline
5. Multiple ATR moves from open
Mindset
- Never pre-commit to specific tickers. Trade whatever offers the BEST opportunity.
- Move to where the extreme setups are — different stocks/products each day.
- Pocket aces (A++ setups) are rare. Most days are B/C setups or no-trades.
Python Implementation
import pandas as pd
import numpy as np
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class CapitulationScore:
"""Multi-variable rubric for scoring capitulation setups."""
size_of_move: float = 0 # 0-10
rate_of_change: float = 0 # 0-10 (THE most important)
news_absence: float = 0 # 0-10 (10 = no news)
consecutive_bars: float = 0 # 0-10
forced_flow: float = 0 # 0-10
sentiment_extreme: float = 0 # 0-10
boringness: float = 0 # 0-10
daily_chart: float = 0 # 0-10
intraday_setup: float = 0 # 0-10
volume_capitulation: float = 0 # 0-10
distance_from_ma: float = 0 # 0-10
num_legs: float = 0 # 0-10
long_vs_short: float = 0 # 0-10 (10 = long with $0 floor, lower for shorts)
@property
def total_score(self) -> float:
return sum([
self.size_of_move, self.rate_of_change, self.news_absence,
self.consecutive_bars, self.forced_flow, self.sentiment_extreme,
self.boringness, self.daily_chart, self.intraday_setup,
self.volume_capitulation, self.distance_from_ma, self.num_legs,
self.long_vs_short
])
@property
def max_possible(self) -> float:
return 130.0 # 13 variables x 10
@property
def normalized_score(self) -> float:
"""Normalized to 0-100 scale."""
return round((self.total_score / self.max_possible) * 100, 1)
@property
def grade(self) -> str:
s = self.normalized_score
if s >= 80: return "A++"
if s >= 70: return "A+"
if s >= 60: return "A"
if s >= 50: return "B+"
if s >= 40: return "B"
if s >= 30: return "C+"
if s >= 25: return "C"
return "NO TRADE"
@property
def action(self) -> str:
g = self.grade
if g in ("A++", "A+"): return "MAX SIZE — exponential bet sizing"
if g in ("A", "B+"): return "Meaningful size — strong conviction"
if g in ("B", "C+"): return "Small size — acceptable but marginal"
if g == "C": return "Very small or skip"
return "DO NOT TRADE"
@property
def estimated_win_rate(self) -> str:
s = self.normalized_score
if s >= 70: return "75-90%"
if s >= 55: return "65-75%"
if s >= 40: return "55-65%"
if s >= 25: return "45-55%"
return " str:
s = self.normalized_score
if s >= 70: return "80-100% to MA"
if s >= 55: return "50-80%"
if s >= 40: return "30-50%"
return " dict:
"""
Analyze price action for capitulation/waterfall pattern.
df must have columns: open, high, low, close, volume
"""
close = df["close"]
high = df["high"]
low = df["low"]
volume = df["volume"]
# Bollinger Bands
ma = close.rolling(bb_period).mean()
std = close.rolling(bb_period).std()
upper_bb = ma + bb_std * std
lower_bb = ma - bb_std * std
# ATR for range measurement
tr = pd.concat([
high - low,
(high - close.shift(1)).abs(),
(low - close.shift(1)).abs()
], axis=1).max(axis=1)
atr = tr.rolling(14).mean()
current = df.iloc[-1]
prev = df.iloc[-2] if len(df) > 1 else current
# --- Score each variable ---
score = CapitulationScore()
# 1. Size of move: how far from MA in ATR multiples
dist_from_ma = abs(current["close"] - ma.iloc[-1])
atr_multiples = dist_from_ma / atr.iloc[-1] if atr.iloc[-1] > 0 else 0
score.distance_from_ma = min(10, atr_multiples * 2)
score.size_of_move = min(10, atr_multiples * 2.5)
# 2. Rate of change / slope analysis
if len(df) >= 5:
recent_bars = df.tail(5)
bar_ranges = (recent_bars["high"] - recent_bars["low"]).values
range_acceleration = bar_ranges[-1] / (np.mean(bar_ranges[:-1]) + 1e-10)
score.rate_of_change = min(10, range_acceleration * 2)
# 3. Consecutive bars in same direction
direction = "down" if current["close"] df.iloc[i]["open"]:
consecutive += 1
else:
break
score.consecutive_bars = min(10, consecutive * 1.5)
# 4. Volume capitulation
avg_vol = volume.rolling(20).mean().iloc[-1]
vol_ratio = current["volume"] / avg_vol if avg_vol > 0 else 1
score.volume_capitulation = min(10, vol_ratio * 2)
# 5. Bollinger Band breach
below_lower = current["close"] upper_bb.iloc[-1]
# 6. Prior bar highs/lows pattern (clean waterfall check)
holding_prior_bar = True
if direction == "down":
for i in range(len(df) - 1, max(0, len(df) - 6), -1):
if i > 0 and df.iloc[i]["high"] > df.iloc[i-1]["high"]:
holding_prior_bar = False
break
else:
for i in range(len(df) - 1, max(0, len(df) - 6), -1):
if i > 0 and df.iloc[i]["low"] 2.0 and
consecutive >= 3 and
atr_multiples > 1.5
)
# Entry levels
if direction == "down" and is_capitulating:
entry_level = prev["high"] # Break of prior bar high
stop_level = df.tail(10)["low"].min() # Low of move
target_level = ma.iloc[-1] # 20MA equilibrium
elif direction == "up" and is_capitulating:
entry_level = prev["low"] # Break of prior bar low
stop_level = df.tail(10)["high"].max() # High of move
target_level = ma.iloc[-1]
else:
entry_level = stop_level = target_level = None
risk = abs(entry_level - stop_level) if entry_level and stop_level else 0
reward = abs(target_level - entry_level) if entry_level and target_level else 0
rr_ratio = round(reward / risk, 2) if risk > 0 else 0
return {
"is_capitulating": is_capitulating,
"direction": "LONG (buy the panic)" if direction == "down" else "SHORT (sell the euphoria)",
"score": score,
"grade": score.grade,
"normalized_score": score.normalized_score,
"action": score.action,
"estimated_win_rate": score.estimated_win_rate,
"expected_retracement": score.expected_retracement,
"entry": round(entry_level, 5) if entry_level else None,
"stop": round(stop_level, 5) if stop_level else None,
"target_ma": round(target_level, 5) if target_level else None,
"risk_reward": rr_ratio,
"bb_lower": round(lower_bb.iloc[-1], 5),
"bb_upper": round(upper_bb.iloc[-1], 5),
"ma_20": round(ma.iloc[-1], 5),
"atr_multiples_from_ma": round(atr_multiples, 2),
"volume_ratio": round(vol_ratio, 2),
"consecutive_bars": consecutive,
"holding_prior_bar_pattern": holding_prior_bar,
"slope_assessment": (
"WATERFALL (asymptotic)" if score.rate_of_change >= 8 else
"Sharp selloff" if score.rate_of_change >= 5 else
"Moderate acceleration" if score.rate_of_change >= 3 else
"Slow/steady (AVOID)"
),
}
@staticmethod
def trail_prior_bar(df: pd.DataFrame, direction: str = "long") -> dict:
"""
Calculate trailing stop using prior bar lows (long) or prior bar highs (short).
"""
current = df.iloc[-1]
prev = df.iloc[-2] if len(df) > 1 else current
if direction == "long":
trail_stop = prev["low"]
status = "HOLD" if current["close"] > trail_stop else "STOPPED OUT"
else:
trail_stop = prev["high"]
status = "HOLD" if current["close"] list:
"""
Scan multiple symbols for capitulation setups.
symbols_data: dict of {symbol: DataFrame}
Returns sorted list of candidates by score.
"""
candidates = []
detector = CapitulationDetector()
for sy
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [mahmoud20138](https://github.com/mahmoud20138)
- **Source:** [mahmoud20138/Tradecraft](https://github.com/mahmoud20138/Tradecraft)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.