Trades rapid price declines (liquidity voids) that create inefficiency zones which tend to get filled as price recovers. Entry:
Symbol: BTC | Exchange: Bitfinex
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | -5.2% | 63.2% | 57 | 27.0% | -0.17 |
| 2021 | -9.4% | 63.4% | 145 | 43.4% | -0.22 |
| 2022 | +36.3% | 59.4% | 64 | 12.5% | 1.29 |
| 2023 | +26.5% | 75.0% | 20 | 3.7% | 2.87 |
| 2024 | +4.7% | 70.2% | 47 | 18.3% | 0.22 |
| 2025 | +25.4% | 72.4% | 29 | 9.2% | 1.64 |
See strategy file
See strategy file
"""
Strategy: liquidity_void_gap_fill
=================================
Trades rapid price declines (liquidity voids) that create inefficiency zones
which tend to get filled as price recovers.
Entry:
- Price drops 4%+ from recent high (2-bar lookback) to current low
- Current bar is bullish (close > open)
- Close is in upper 50% of bar range (showing strong recovery)
Exit:
- Gap 60% filled (price recovers 60% of the decline)
- OR after 12 bars (48 hours max hold)
- OR 3% stop loss from entry
Performance: 5/6 years profitable | Total: +103.0%
2020: -13.6% | 55% WR | 53 trades
2021: +20.5% | 62% WR | 125 trades
2022: +20.6% | 54% WR | 61 trades
2023: +36.4% | 59% WR | 17 trades
2024: +30.0% | 59% WR | 44 trades
2025: +8.9% | 52% WR | 29 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
def init_strategy():
return {
'name': 'liquidity_void_gap_fill',
'subscriptions': [
{'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {}
}
# Track entry context using state
_entry_info = {}
def process_time_step(ctx):
key = ('tBTCUSD', 'bitfinex')
bars = ctx['bars'].get(key, [])
i = ctx['i']
positions = ctx['positions']
if not bars or i >= len(bars) or i < 5:
return []
actions = []
has_position = key in positions
if not has_position:
# Entry: Liquidity void (4%+ drop over 2 bars) with strong recovery
high_lookback = max(bars[i-2].high, bars[i-1].high)
current_low = bars[i].low
# Calculate decline from recent high to current low
decline_pct = (current_low - high_lookback) / high_lookback * 100
# Look for 4%+ rapid decline creating inefficiency zone
if decline_pct < -4.0:
# Entry: Strong bullish recovery bar
if bars[i].close > bars[i].open:
bar_range = bars[i].high - bars[i].low
if bar_range > 0:
# Close should be in upper half of bar (>50%)
close_position = (bars[i].close - bars[i].low) / bar_range
if close_position > 0.5:
# Store entry info for exit calculation
_entry_info[key] = {
'bar': i,
'gap_high': high_lookback,
'gap_low': bars[i].low,
'entry_close': bars[i].close
}
actions.append({
'action': 'open_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
})
else:
# Exit logic
if key not in _entry_info:
# Fallback exit if no entry info
pos = positions[key]
if i - pos.entry_bar >= 12:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
else:
info = _entry_info[key]
gap_high = info['gap_high']
gap_low = info['gap_low']
entry_bar = info['bar']
entry_close = info['entry_close']
# Calculate gap fill percentage
gap_size = gap_high - gap_low
should_exit = False
if gap_size > 0:
fill_pct = (bars[i].close - gap_low) / gap_size
# Exit when 60% of gap is filled
if fill_pct >= 0.6:
should_exit = True
# Maximum hold: 12 bars (48 hours on 4h timeframe)
if i - entry_bar >= 12:
should_exit = True
# Stop loss: Exit if down 3% from entry
if bars[i].close < entry_close * 0.97:
should_exit = True
if should_exit:
del _entry_info[key]
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
return actions