← Back to list

trend_fade_hedge VALIDATED PASS

Auto-discovered strategy

Symbol: BTC | Exchange: Bitfinex | Role: hedge

6/6
Profitable Years
+415.4%
Total Return
71.4%
Avg Win Rate
4.09
Avg Sharpe

Year-by-Year Results

Click a year to view chart

Year Return Win Rate Trades Max DD Sharpe
2020 +34.1% 78.0% 41 4.0% 2.63
2021 +114.4% 70.2% 57 5.3% 5.23
2022 +85.7% 75.4% 65 2.0% 4.97
2023 +45.1% 64.5% 62 1.8% 3.17
2024 +59.9% 73.8% 42 2.0% 4.05
2025 +76.2% 66.7% 63 1.6% 4.51

Performance Chart

Loading chart...

Walk-Forward Validation PASS

1/1 Windows Profitable
+39.9% OOS Return
0.00 Median Sharpe
0.000 Score
Window Train Period Val Period Val Return Val Test Period Test Return Status
WF-1 2024-01→2025-06 2025-07→2025-12 +39.9% OK 2026-01→ongoing +0.0% PASS

AI Review Score: 85/100

complexity
## Strategy Quality Assessment: trend_fade_hedge ### Strengths **Robust Parameter Selection** - Uses standard indicator periods (10, 20, 50, 100, 14) - excellent adherence to anti-overfitting rules - No magic numbers or curve-fitted values - All parameters are industry-standard technical analysis values **Relative Indicators Only** - Uses EMAs, RSI, and ATR - all relative measures - No absolute price levels or specific support/resistance zones - Properly designed for unknown future market conditions **Execution Realism** - Trades on next bar (no same-candle execution) - Includes stop loss (4%) and take profit (6%) levels - Time-based exit prevents indefinite holding - Reasonable slippage assumptions for 4h timeframe **Year-Over-Year Consistency** - Returns distributed across all years in train period (34-114%) - No single "lucky year" driving performance - Works across different market regimes (bull/bear/sideways) - Consistent win rates (64-78%) across years **Statistical Significance** - 330+ trades across train period - 69 trades in validation period - Well above minimum threshold for statistical validity **Role Compliance (Hedge)** - Max DD ~5% << 50% threshold - Validation return 39.91% > 0% requirement - Sharpe 3.05 > 0.3 minimum - Trades: 69 >> 2 minimum - **Fully meets hedge role requirements** **No Concentration Risk** - 69 validation trades suggests no reliance on few large winners - Consistent win rates indicate distributed PnL ### Areas of Concern **Entry Condition Complexity (6 conditions)** - Death cross active - EMA rejection (with 2 sub-conditions) - RSI weak zone check - RSI declining check - EMA50 flat/down check - Red bar confirmation This is at the upper limit of acceptable complexity. While each condition is logically sound, having 6 simultaneous requirements can: - Make the strategy fragile to parameter changes - Reduce future trade frequency if any condition becomes less reliable - Potentially overfit to specific market transitions **EMA50 Flatness Check** - Uses `ema_50[i] <= ema_50[i-5] * 1.005` (0.5% tolerance over 5 bars) - The 1.005 multiplier (0.5%) is not a standard value - Should use rounder thresholds: 1.00 (perfectly flat), 1.01 (1%), or 1.02 (2%) - The 5-bar lookback is acceptable but the percentage threshold adds specificity **EMA Rejection Logic** - Uses `highs[i] > ema_20[i] * 0.99` (1% tolerance) - While reasonable, the 0.99 multiplier is slightly fitted - Consider simplifying to `highs[i] >= ema_20[i]` for cleaner logic ### Risk Assessment **Overfitting Risk: LOW-MODERATE** - Uses standard parameters throughout - Minor concern with the 0.99 and 1.005 multipliers - 6 entry conditions increases curve-fit risk **Lookahead Bias: NONE** - All indicators calculated on full arrays correctly - No future data referenced **Execution Issues: NONE** - Proper next-bar execution - Realistic stops and targets **Regime Dependence: LOW** - Strong performance across multiple years - Works in different market conditions ### Recommendations 1. **Simplify EMA rejection logic**: Remove the 0.99 multiplier, use direct comparison `highs[i] >= ema_20[i]` 2. **Round the EMA50 flatness threshold**: Change 1.005 to 1.01 or remove percentage check entirely, just compare `ema_50[i] <= ema_50[i-5]` 3. **Consider reducing entry conditions**: The strategy might be just as effective with 4-5 conditions instead of 6. Test removing the weakest contributor (likely the red bar confirmation or RSI declining check). 4. **Monitor future trade frequency**: With 6 conditions, there's risk of too few trades in different market regimes ### Overall Assessment This is a **well-designed hedge strategy** with strong fundamentals. The consistency across years, proper use of relative indicators, and statistical significance are all excellent. The main concern is modest complexity (6 entry conditions) and use of slightly fitted percentage thresholds (0.99, 1.005) rather than round values. The strategy passes all hedge role requirements with comfortable margins and shows no signs of concentration risk or lucky-year dependence. With minor simplifications to remove the non-standard multipliers, this would score in the 90+ range. **Verdict: APPROVED** - Minor refinements recommended but fundamentally sound.
Reviewed: 2026-01-14T06:21:06.078565

Source Code

"""
Trend Fade Hedge Strategy
=========================

A hedge strategy that shorts when uptrends show signs of exhaustion
and start breaking down. Captures early trend failure by detecting
EMA rejections after short-term death crosses.

Role: hedge
Exchange: bitfinex
Symbol: tBTCUSD

Differentiation from existing volatility_spike_hedge:
- Different entry trigger: EMA rejection vs volatility spike
- Catches trend exhaustion earlier (death cross + rejection)
- Works in transition zones, not just established bear trends
- More frequent trades with smaller individual profits

Entry Conditions (all must be met):
1. EMA10 < EMA20 (short-term death cross active)
2. Price rejected from EMA20 or EMA50 (failed recovery attempt)
3. RSI in weak zone (35-50) and declining
4. EMA50 is flat or declining (momentum fading)
5. Current bar is red (bearish confirmation)

Exit Conditions (any triggers exit):
1. EMA10 crosses above EMA20 (golden cross)
2. RSI recovery above 50
3. Price closes above EMA20
4. Time stop: 15 bars

Train Performance (2024-01-01 to 2025-06-30):
- 2024: +59.9% | 42 trades | 74% WR
- 2025 (H1): +32.2% | 27 trades | 70% WR
- Total: +92.1%
- Max Drawdown: ~2%

Validation Performance (2025-07-01 to 2025-12-31):
- Return: +39.9%
- Sharpe: 3.05
- Status: PASSED
"""

import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema, rsi, atr


def init_strategy():
    return {
        'name': 'trend_fade_hedge',
        'role': 'hedge',
        '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']

    # Extract full price data arrays
    closes = [b.close for b in bars]
    highs = [b.high for b in bars]
    lows = [b.low for b in bars]
    opens = [b.open for b in bars]

    # Calculate indicators on full data
    ema_10 = ema(closes, 10)
    ema_20 = ema(closes, 20)
    ema_50 = ema(closes, 50)
    ema_100 = ema(closes, 100)
    rsi_vals = rsi(closes, 14)
    atr_vals = atr(highs, lows, closes, 14)

    # Check indicator availability at current index
    if ema_10[i] is None or ema_20[i] is None:
        return []
    if ema_50[i] is None or ema_100[i] is None:
        return []
    if rsi_vals[i] is None or atr_vals[i] is None:
        return []
    if i < 10:
        return []

    actions = []

    if key not in positions:
        # === ENTRY CONDITIONS ===

        # 1. Short-term death cross active: EMA10 < EMA20
        death_cross_active = ema_10[i] < ema_20[i]

        # 2. Price rejected from EMA20 or EMA50
        # (High touched EMA but close below)
        rejected_ema20 = highs[i] > ema_20[i] * 0.99 and closes[i] < ema_20[i]
        rejected_ema50 = highs[i] > ema_50[i] * 0.99 and closes[i] < ema_50[i]
        rejection = rejected_ema20 or rejected_ema50

        # 3. RSI in weak zone (35-50) and declining
        rsi_weak = 35 < rsi_vals[i] < 50
        rsi_declining = rsi_vals[i] < rsi_vals[i-1] if i > 0 else False

        # 4. EMA50 is flat or declining (momentum fading)
        ema50_flat_down = ema_50[i] <= ema_50[i-5] * 1.005 if i >= 5 else False

        # 5. Red bar (bearish confirmation)
        red_bar = closes[i] < opens[i]

        # All conditions must be met
        if death_cross_active and rejection and rsi_weak and rsi_declining and ema50_flat_down and red_bar:
            actions.append({
                'action': 'open_short',
                'symbol': 'tBTCUSD',
                'exchange': 'bitfinex',
                'size': 1.0,
                'stop_loss_pct': 4,
                'take_profit_pct': 6,
            })
    else:
        pos = positions[key]
        if pos.side != 'short':
            return []

        bars_held = i - pos.entry_bar

        # === EXIT CONDITIONS ===

        # 1. Golden cross: EMA10 crosses above EMA20
        golden_cross = (
            ema_10[i] > ema_20[i] and
            i > 0 and ema_10[i-1] <= ema_20[i-1]
        )

        # 2. RSI recovery above 50
        rsi_recovery = rsi_vals[i] > 50

        # 3. Time stop - 15 bars
        time_exit = bars_held >= 15

        # 4. Price closes above EMA20 (trend recovery)
        above_ema20 = closes[i] > ema_20[i]

        if golden_cross or rsi_recovery or time_exit or above_ema20:
            actions.append({
                'action': 'close_short',
                'symbol': 'tBTCUSD',
                'exchange': 'bitfinex',
            })

    return actions


# Testing
if __name__ == '__main__':
    from strategy import backtest_strategy, validate_new_strategy

    print("="*60)
    print("TRAIN PERIOD BACKTEST")
    print("="*60)
    results, profitable, _ = backtest_strategy(init_strategy, process_time_step)

    print("\n" + "="*60)
    print("VALIDATION ON UNSEEN DATA")
    print("="*60)
    validate_new_strategy(init_strategy, process_time_step)