Volatility Compression Acceleration Breakout - ETHUSDT A momentum breakout strategy that identifies volatility compression followed by explosive moves. Core Concept:
Symbol: ETH | Exchange: Binance
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +52.4% | 52.8% | 36 | 5.5% | 2.13 |
| 2021 | +20.1% | 60.0% | 30 | 8.2% | 1.12 |
| 2022 | +11.6% | 55.6% | 27 | 18.6% | 0.62 |
| 2023 | +8.6% | 50.0% | 22 | 6.1% | 0.63 |
| 2024 | -0.7% | 33.3% | 27 | 9.5% | -0.05 |
| 2025 | +27.5% | 40.0% | 25 | 10.6% | 0.98 |
See strategy file
See strategy file
"""
Strategy: vol_compress_accel
============================
Volatility Compression Acceleration Breakout - ETHUSDT
A momentum breakout strategy that identifies volatility compression followed by explosive moves.
Core Concept:
- Detects periods of low volatility (ATR compression in bottom 35%)
- Waits for acceleration breakout with volume confirmation
- Combines price acceleration, velocity, and volume percentiles
Entry Conditions:
1. ATR was compressed (< 35th percentile) within last 12 bars
2. Price acceleration > 1.5% (momentum of momentum)
3. Velocity > 3% (7-bar rate of change)
4. Volume above 70th percentile (past 60 bars)
5. Breaking above 25-bar high (within 1%)
Exit Conditions:
- Maximum hold: 18 bars (72 hours / 3 days on 4h timeframe)
- Velocity turns negative (< -0.5%)
- Acceleration reverses strongly (< -2.0%)
Performance: 5/6 years profitable | Total: +46.8%
2020: +28.2% | 70% WR | 27 trades
2021: +14.6% | 67% WR | 27 trades
2022: +4.2% | 52% WR | 27 trades
2023: -10.9% | 44% WR | 27 trades
2024: +0.6% | 37% WR | 27 trades
2025: +10.1% | 41% WR | 27 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
def init_strategy():
return {
'name': 'vol_compress_accel',
'subscriptions': [
{'symbol': 'ETHUSDT', 'exchange': 'binance', 'timeframe': '4h'},
],
'parameters': {'hold_bars': 18}
}
def process_time_step(ctx):
key = ('ETHUSDT', 'binance')
bars = ctx['bars'].get(key, [])
i = ctx['i']
positions = ctx['positions']
if not bars or i >= len(bars) or i < 65:
return []
closes = [b.close for b in bars]
highs = [b.high for b in bars]
lows = [b.low for b in bars]
volumes = [b.volume for b in bars]
# Calculate ATR using EMA smoothing
atr_vals = [0.0] * len(bars)
for j in range(1, i + 1):
tr = max(
highs[j] - lows[j],
abs(highs[j] - closes[j-1]),
abs(lows[j] - closes[j-1])
)
if j < 14:
atr_vals[j] = tr
else:
atr_vals[j] = (atr_vals[j-1] * 13 + tr) / 14
# Calculate velocity: 7-bar rate of change (%)
velocity = [0.0] * len(bars)
for j in range(7, i + 1):
velocity[j] = (closes[j] - closes[j-7]) / closes[j-7] * 100
# Calculate acceleration: change in velocity over 4 bars
acceleration = [0.0] * len(bars)
for j in range(11, i + 1):
acceleration[j] = velocity[j] - velocity[j-4]
# ATR as % of price (normalized volatility)
atr_pct = [0.0] * len(bars)
for j in range(i + 1):
if closes[j] > 0:
atr_pct[j] = (atr_vals[j] / closes[j]) * 100
# ATR percentile: where current ATR ranks in last 60 bars
atr_percentile = [0.0] * len(bars)
for j in range(60, i + 1):
window = atr_pct[j-60:j]
atr_percentile[j] = sum(1 for x in window if x < atr_pct[j]) / len(window) * 100
# Volume 70th percentile over 60 bars
vol_percentile_70 = [0.0] * len(bars)
for j in range(60, i + 1):
vol_window = sorted(volumes[j-60:j])
vol_percentile_70[j] = vol_window[int(len(vol_window) * 0.7)]
# 25-bar high for breakout detection
high_25 = [0.0] * len(bars)
for j in range(25, i + 1):
high_25[j] = max(highs[j-25:j])
actions = []
has_position = key in positions
if not has_position:
# Entry: volatility compression + acceleration breakout
# 1. ATR was compressed (< 35th percentile) within last 12 bars
compression_found = False
for lookback in range(1, 13):
if i - lookback >= 60 and atr_percentile[i - lookback] < 35:
compression_found = True
break
if not compression_found:
return []
# 2. Price acceleration > 1.5%
if acceleration[i] < 1.5:
return []
# 3. Positive velocity > 3%
if velocity[i] < 3.0:
return []
# 4. Volume above 70th percentile
if volumes[i] < vol_percentile_70[i]:
return []
# 5. Breaking above recent highs (within 1%)
if closes[i] < high_25[i] * 0.99:
return []
actions.append({
'action': 'open_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
'size': 1.0,
})
else:
# Exit conditions
pos = positions[key]
bars_held = i - pos.entry_bar
# 1. Max holding period: 18 bars
if bars_held >= 18:
actions.append({
'action': 'close_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
})
# 2. Velocity turns negative (momentum reversal)
elif velocity[i] < -0.5:
actions.append({
'action': 'close_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
})
# 3. Acceleration reverses strongly
elif acceleration[i] < -2.0:
actions.append({
'action': 'close_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
})
return actions