Auto-discovered strategy
Symbol: ETH | Exchange: Binance | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | -3.3% | 51.4% | 74 | 20.4% | -0.15 |
| 2021 | -13.7% | 49.2% | 61 | 28.2% | -0.54 |
| 2022 | -6.5% | 51.9% | 27 | 14.9% | -0.44 |
| 2023 | +6.9% | 46.4% | 56 | 8.6% | 0.51 |
| 2024 | +21.4% | 57.4% | 47 | 9.1% | 1.52 |
| 2025 | +16.6% | 62.5% | 40 | 13.7% | 1.10 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | -11.3% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
Not yet reviewed. Run: ./review_strategy.sh eth_dow_momentum
"""
ETH Day-of-Week Momentum Strategy
=================================
Exploits observed day-of-week momentum patterns in ETHUSDT on Binance.
Key Observations:
- Wednesday 16:00 UTC shows strong momentum continuation in uptrends
- Sunday 16:00 UTC shows positive returns as week kickoff
- Both patterns stronger when EMA50 > EMA200 (bull market regime)
Strategy Logic:
- ENTRY: Sunday or Wednesday at 16:00 UTC when in uptrend (EMA50 > EMA200)
- EXIT: After 3 bars (12 hours) OR if trend flips (EMA50 < EMA200)
- RISK: 5% stop loss, 5% take profit
Rationale:
- Mid-week and week-start show consistent momentum in bull markets
- Short holding period reduces exposure to weekend gaps
- Trend filter stays flat during bear markets
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema
def init_strategy():
return {
'name': 'eth_dow_momentum',
'role': 'momentum', # Can lose bounded amount in bear markets
'warmup': 200, # Need EMA200
'subscriptions': [
{'symbol': 'ETHUSDT', 'exchange': 'binance', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('ETHUSDT', 'binance')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
state = ctx['state']
# Calculate EMAs
closes = [b.close for b in bars[:i+1]]
ema50_val = ema(closes, 50)[-1] if len(closes) >= 50 else None
ema200_val = ema(closes, 200)[-1] if len(closes) >= 200 else None
actions = []
current_bar = bars[i]
dow = current_bar.timestamp.weekday() # 0=Monday, 6=Sunday
hour = current_bar.timestamp.hour
# Track entry bar for exit timing
if 'entry_bar' not in state:
state['entry_bar'] = None
has_position = key in positions
if not has_position:
# ENTRY CONDITIONS:
# 1. Uptrend: EMA50 > EMA200
# 2. Day-of-week: Sunday or Wednesday at 16:00 UTC
is_uptrend = (ema50_val is not None and
ema200_val is not None and
ema50_val > ema200_val)
is_entry_time = (dow == 6 and hour == 16) or (dow == 2 and hour == 16)
if is_uptrend and is_entry_time:
actions.append({
'action': 'open_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
'size': 1.0,
'stop_loss_pct': 5, # 5% stop loss
'take_profit_pct': 5, # 5% take profit (caps gains for robustness)
})
state['entry_bar'] = i
else:
# EXIT CONDITIONS:
# 1. Held for 3 bars (~12 hours)
# 2. Trend flips (EMA50 < EMA200)
bars_held = i - state['entry_bar'] if state['entry_bar'] else 0
trend_flip = (ema50_val is not None and
ema200_val is not None and
ema50_val < ema200_val)
should_exit = bars_held >= 3 or trend_flip
if should_exit:
actions.append({
'action': 'close_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
})
state['entry_bar'] = None
return actions
# For testing
if __name__ == '__main__':
from strategy import backtest_strategy
results, profitable, _ = backtest_strategy(init_strategy, process_time_step)