Auto-discovered strategy
Symbol: ETH | Exchange: Bitfinex | Role: hedge
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +13.7% | 54.5% | 11 | 7.8% | 0.84 |
| 2021 | +8.8% | 54.5% | 11 | 7.8% | 0.54 |
| 2022 | -26.4% | 20.0% | 10 | 23.8% | -2.95 |
| 2023 | +0.0% | 0.0% | 0 | 0.0% | 0.00 |
| 2024 | +6.0% | 60.0% | 10 | 7.8% | 0.43 |
| 2025 | +14.8% | 57.1% | 7 | 4.0% | 0.97 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | +0.0% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
"""
ETH Volume Spike Capitulation Hedge
====================================
A hedge strategy that goes LONG after extreme volume spike capitulation events
in ETH. Designed to capture the bounce that typically follows panic selling.
Role: hedge
Exchange: bitfinex
Symbol: tETHUSD
Concept:
- After extreme volume spike + price drop (capitulation), bounces typically follow
- Wait for very high confidence setup: volume >3x avg + >5% drop + RSI oversold
- Take quick profits on the bounce, tight stop loss
- Regime filter: only trade when below EMA50 (not in extended bull)
Entry Conditions (all must be met):
1. Volume > 3x 20-bar average (extreme spike)
2. Bar closed down > 5% (significant panic)
3. RSI(10) < 30 (deeply oversold)
4. Price below EMA50 (not extended, in pullback)
5. Lower wick > 20% of range (rejection/capitulation)
Exit Conditions:
1. RSI > 55 (momentum recovered - take profit)
2. Two consecutive green candles (bounce confirmed)
3. Time stop: 10 bars (quick in/out)
4. Take profit: 8%
5. Stop loss: 5%
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema, rsi
def init_strategy():
return {
'name': 'eth_vol_spike_hedge',
'role': 'hedge',
'warmup': 100,
'subscriptions': [
{'symbol': 'tETHUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {
# Volume detection
'vol_lookback': 20,
'vol_threshold': 3.0, # Volume > 3x average
# Price drop threshold
'min_drop_pct': 5,
# RSI settings
'rsi_period': 10,
'rsi_oversold': 30,
'rsi_exit': 55,
# EMA regime filter
'ema_period': 50,
# Wick filter
'min_wick_ratio': 0.2,
# Exit settings
'take_profit': 8,
'stop_loss': 5,
'time_stop': 10,
}
}
def process_time_step(ctx):
key = ('tETHUSD', 'bitfinex')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
state = ctx['state']
params = ctx['parameters']
# Extract price data up to current bar
closes = [b.close for b in bars[:i+1]]
highs = [b.high for b in bars[:i+1]]
lows = [b.low for b in bars[:i+1]]
opens = [b.open for b in bars[:i+1]]
volumes = [b.volume for b in bars[:i+1]]
idx = len(closes) - 1
if idx < params['vol_lookback'] + 5:
return []
# Calculate indicators
rsi_vals = rsi(closes, params['rsi_period'])
ema_vals = ema(closes, params['ema_period'])
# Handle RSI indexing
if len(rsi_vals) == 0:
return []
rsi_idx = min(idx, len(rsi_vals) - 1)
current_rsi = rsi_vals[rsi_idx]
if current_rsi is None:
return []
# Get EMA value
current_ema = ema_vals[idx] if idx < len(ema_vals) else None
if current_ema is None:
return []
# === VOLUME SPIKE ===
vol_start = max(0, idx - params['vol_lookback'])
avg_vol = sum(volumes[vol_start:idx]) / params['vol_lookback'] if idx > vol_start else 1
vol_spike = volumes[idx] > params['vol_threshold'] * avg_vol if avg_vol > 0 else False
# === PRICE DROP ===
bar_drop_pct = (closes[idx] - opens[idx]) / opens[idx] * 100 if opens[idx] > 0 else 0
significant_drop = bar_drop_pct < -params['min_drop_pct']
# === RSI OVERSOLD ===
oversold = current_rsi < params['rsi_oversold']
# === BELOW EMA50 ===
below_ema = closes[idx] < current_ema * 1.02 # Allow small tolerance
# === LOWER WICK (capitulation) ===
bar_range = highs[idx] - lows[idx]
lower_wick = min(opens[idx], closes[idx]) - lows[idx]
wick_ratio = lower_wick / bar_range if bar_range > 0 else 0
good_wick = wick_ratio > params['min_wick_ratio']
actions = []
if key not in positions:
# Entry: all conditions must be met
if vol_spike and significant_drop and oversold and below_ema and good_wick:
state['green_count'] = 0
actions.append({
'action': 'open_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
'size': 1.0,
'take_profit_pct': params['take_profit'],
'stop_loss_pct': params['stop_loss'],
})
else:
pos = positions[key]
if pos.side != 'long':
return []
bars_held = i - pos.entry_bar
# Count green candles
if closes[idx] > opens[idx]:
state['green_count'] = state.get('green_count', 0) + 1
else:
state['green_count'] = 0
# Exit conditions
# 1. RSI recovery (primary exit)
rsi_recovered = current_rsi > params['rsi_exit']
# 2. Two consecutive green candles
green_exit = state.get('green_count', 0) >= 2
# 3. Time stop
time_exit = bars_held >= params['time_stop']
if rsi_recovered or green_exit or time_exit:
actions.append({
'action': 'close_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
return actions
# Testing
if __name__ == '__main__':
from strategy import backtest_strategy
results, profitable, _ = backtest_strategy(init_strategy, process_time_step)