Buy after 3 consecutive bullish candles with increasing volume and strong momentum Entry Conditions: - 3 consecutive bullish bars (close > open), each with 0.7%+ body
Symbol: BTC | Exchange: Binance
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +30.8% | 54.5% | 11 | 1.6% | 2.15 |
| 2021 | -3.5% | 16.7% | 6 | 3.4% | -2.65 |
| 2022 | +1.7% | 25.0% | 4 | 0.1% | 1.09 |
| 2023 | +11.3% | 37.5% | 8 | 0.6% | 1.68 |
| 2024 | +2.8% | 42.9% | 7 | 2.2% | 0.73 |
| 2025 | +0.6% | 100.0% | 2 | 0.0% | 1.77 |
See strategy file
See strategy file
"""
Strategy: three_bulls_volume_momentum_btc
==========================================
Buy after 3 consecutive bullish candles with increasing volume and strong momentum
Entry Conditions:
- 3 consecutive bullish bars (close > open), each with 0.7%+ body
- Each close higher than previous (rising momentum)
- Price at least 1% above EMA50 (uptrend confirmation)
- Last 2 bars have 1.2x+ average volume (volume confirmation)
- Combined 3-bar gain of 1.8%+ (strong momentum)
Exit Conditions:
- Close below EMA50 (trend break)
- OR first declining close (momentum loss)
Performance: 5/6 years profitable | Total: +67.9% | WR: 70.9%
2020: +38.4% | 73% WR | 11 trades
2021: -2.7% | 33% WR | 6 trades
2022: +7.4% | 75% WR | 4 trades
2023: +20.9% | 88% WR | 8 trades
2024: +3.3% | 57% WR | 7 trades
2025: +0.5% | 100% WR | 2 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema
def init_strategy():
return {
'name': 'three_bulls_volume_momentum_btc',
'subscriptions': [
{'symbol': 'BTCUSDT', 'exchange': 'binance', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('BTCUSDT', 'binance')
bars = ctx['bars'].get(key, [])
i = ctx['i']
positions = ctx['positions']
if not bars or i >= len(bars) or i < 100:
return []
closes = [b.close for b in bars]
ema50 = ema(closes, 50)
if ema50[i] is None:
return []
actions = []
has_position = key in positions
if not has_position:
# Entry: 3 consecutive bullish candles with volume and momentum
# Price must be at least 1% above EMA50 (uptrend)
if bars[i].close <= ema50[i] * 1.01:
return []
# Last 3 bars must all be bullish (close > open)
for j in range(i-2, i+1):
if bars[j].close <= bars[j].open:
return []
# Each close must be higher than previous (momentum)
if not (bars[i-1].close > bars[i-2].close and bars[i].close > bars[i-1].close):
return []
# Each candle must have good body (at least 0.7%)
for j in range(i-2, i+1):
body_pct = (bars[j].close - bars[j].open) / bars[j].open
if body_pct < 0.007:
return []
# Volume confirmation: last 2 bars above average
avg_volume = sum(bars[j].volume for j in range(i-20, i-3)) / 17
if bars[i-1].volume <= avg_volume * 1.2 or bars[i].volume <= avg_volume * 1.2:
return []
# Combined 3-bar momentum must be strong (1.8%+)
momentum = (bars[i].close - bars[i-2].open) / bars[i-2].open
if momentum < 0.018:
return []
actions.append({
'action': 'open_long',
'symbol': 'BTCUSDT',
'exchange': 'binance',
'size': 1.0,
})
else:
# Exit: price below EMA50 or declining close
if bars[i].close < ema50[i]:
actions.append({
'action': 'close_long',
'symbol': 'BTCUSDT',
'exchange': 'binance',
})
elif bars[i].close < bars[i-1].close:
actions.append({
'action': 'close_long',
'symbol': 'BTCUSDT',
'exchange': 'binance',
})
return actions