Auto-discovered strategy
Symbol: BTC | Exchange: Bitfinex | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +21.3% | 42.9% | 35 | 14.7% | 0.78 |
| 2021 | +4.2% | 38.2% | 34 | 27.7% | 0.15 |
| 2022 | -18.7% | 21.4% | 14 | 18.0% | -1.35 |
| 2023 | +10.0% | 47.8% | 23 | 9.2% | 0.67 |
| 2024 | +32.1% | 54.2% | 24 | 7.6% | 1.60 |
| 2025 | +22.0% | 61.5% | 13 | 4.3% | 1.86 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | +0.9% | OK | 2026-01→ongoing | +0.0% | PASS |
Not yet reviewed. Run: ./review_strategy.sh fvg_support_bounce
"""
Strategy: FVG Support Bounce
============================
Trades bullish Fair Value Gap (FVG) retests in uptrends.
A Fair Value Gap forms when price moves rapidly, leaving a gap between
bar[i-2].high and bar[i].low. This creates an "inefficiency zone" that
price tends to revisit and use as support. When price retests this zone
and bounces, it confirms buyer strength at that level.
Entry Conditions:
- EMA50 > EMA200 (uptrend regime filter)
- Bullish FVG exists in recent bars (3-15 bars ago)
- FVG gap size is 1-5% (significant but not extreme)
- Current bar's low touches the FVG zone (retest)
- Current bar is bullish (close > open)
- Current bar closes above the FVG (reclaim)
- Strong close in upper 50% of bar range
Exit Conditions:
- Take profit at 5%+ gain
- Trail exit when close < EMA50
- Time exit after 30 bars (~5 days on 4h)
- Regime exit when EMA50 < EMA200
- 5% stop loss
Role: momentum (trend-following with support bounce entries)
Train Performance (2024-01-01 to 2025-06-30):
2024: +32.1% | 24 trades | 54% WR | Sharpe 1.60 | MaxDD 7.6%
2025: +19.8% | 7 trades | 71% WR | Sharpe 2.17 | MaxDD 2.6%
Total: +51.9%
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema
def init_strategy():
return {
'name': 'fvg_support_bounce',
'role': 'momentum',
'warmup': 200,
'subscriptions': [
{'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('tBTCUSD', 'bitfinex')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
state = ctx['state']
actions = []
# Calculate EMAs for regime filter
closes = [bars[j].close for j in range(i+1)]
ema50_vals = ema(closes, 50)
ema200_vals = ema(closes, 200)
if ema50_vals[i] is None or ema200_vals[i] is None:
return []
# REGIME FILTER: Only trade when EMA50 > EMA200 (uptrend)
in_uptrend = ema50_vals[i] > ema200_vals[i]
curr_bar = bars[i]
if key not in positions:
if not in_uptrend:
return []
# ENTRY: Find bullish FVG that's being retested and reclaimed
for lookback in range(3, 15):
if i - lookback < 2:
continue
fvg_bar1 = bars[i - lookback - 2]
fvg_bar3 = bars[i - lookback]
# Bullish FVG: bar1.high < bar3.low (price gapped up)
if fvg_bar1.high >= fvg_bar3.low:
continue
gap_bottom = fvg_bar1.high
gap_top = fvg_bar3.low
gap_pct = (gap_top - gap_bottom) / gap_bottom * 100
# Gap must be 1-5% (significant but not extreme)
if not (1 <= gap_pct <= 5):
continue
# Current bar's low must touch the FVG zone (retest)
if not (gap_bottom <= curr_bar.low <= gap_top * 1.02):
continue
# Current bar must be bullish
if curr_bar.close <= curr_bar.open:
continue
# Must close above the FVG (reclaim)
if curr_bar.close < gap_top:
continue
# Strong close: in upper 50% of range
bar_range = curr_bar.high - curr_bar.low
if bar_range > 0:
close_pos = (curr_bar.close - curr_bar.low) / bar_range
if close_pos < 0.5:
continue
state['entry_bar'] = i
state['entry_price'] = curr_bar.close
state['fvg_bottom'] = gap_bottom
actions.append({
'action': 'open_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 5, # 5% hard stop
})
break
else:
# Exit logic
entry_bar = state.get('entry_bar', 0)
entry_price = state.get('entry_price', curr_bar.close)
bars_held = i - entry_bar
should_exit = False
# Take profit at 5%+ gain
if curr_bar.close >= entry_price * 1.05:
should_exit = True
# Trail exit: close below EMA50
if curr_bar.close < ema50_vals[i]:
should_exit = True
# Time exit: max 30 bars (~5 days)
if bars_held >= 30:
should_exit = True
# Regime exit: trend reversal
if ema50_vals[i] < ema200_vals[i]:
should_exit = True
if should_exit:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
return actions