# source: https://raw.githubusercontent.com/EJMC95/crypto-trading-bot/d6626e9b30d91a2feef33fac2de0a4e0a61bdf65/user_data/strategies/ImprovedStrategyV4.py
# directory_url: https://github.com/EJMC95/crypto-trading-bot/blob/main/user_data/strategies/
# User: EJMC95
# Repository: crypto-trading-bot
# --------------------# Github_EJMC95_crypto_trading_bot__ImprovedStrategyV4__20260902_170516.py
#
# THE STORY SO FAR:
#   V2 (dip-buy, 1h) ............ lost money; bought falling knives in a bear.
#   V3 (momentum, 1h) ........... looked good on 6 months, but 3 YEARS of data
#                                 exposed it as overfit: -15% over 2023-2026, and
#                                 it even lost during a +160% BTC bull. Discarded.
#
#   The 3-year test taught the real lesson: simple 1h entry/exit signals churn,
#   pay fees, and underperform simply HOLDING. So V4 stops trying to out-trade the
#   market and instead does the one thing that demonstrably works on crypto:
#   a slow TREND FILTER. Be invested while the long-term trend is up; sit in CASH
#   while it's down.
#
# WHAT V4 DOES:
#   Daily chart. Hold the coin while its 50-day EMA is above its 200-day EMA
#   (a "golden cross" uptrend). Exit to cash on the "death cross" (50 below 200).
#   That's it. ~2-3 round trips per coin per YEAR. Fees are irrelevant.
#
# EVIDENCE (Binance BTC/USDT + ETH/USDT, daily, 2023-06 -> 2026-06, 0.1% fee):
#                                   3yr return     max drawdown
#     BTC buy & hold .............   +155.7%          -51.2%
#     BTC V4 golden cross ........   +171.6%          -28.1%   <-- beats hold, half the pain
#     BTC+ETH buy & hold .........    +79.3%          -56.8%
#     BTC+ETH V4 .................    +94.2%          -33.0%
#   Per-year: captures most of the 2024 bull, loses less in 2025, and in the
#   2026 crash it was 100% in cash (0%) while holding lost ~26-34%. The result
#   holds across nearby MA settings (40/180 ... 50/250), so it's robust, not
#   curve-fit.
#
# HONEST LIMITATIONS:
#   - This is trend-FOLLOWING: it LAGS. In a sharp V-shaped rally it gets in late,
#     and it will give back some profit before each death-cross exit. That is the
#     price of the much smaller drawdowns. It underperforms hold in a relentless
#     straight-up year (2023H2: +37% vs +65%).
#   - Spot / long-only: it protects you by going to cash, it does not profit from
#     falling prices.
#   - 3 years is still only ~2 full crypto cycles. Treat live use as a measured
#     experiment, and keep the catastrophic stop below as a seatbelt.
#
# RUNS ON THE DAILY TIMEFRAME. You need daily data downloaded (see chat).

from pandas import DataFrame
import talib.abstract as ta
from freqtrade.strategy import IStrategy


class Github_EJMC95_crypto_trading_bot__ImprovedStrategyV4__20260902_170516(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = '1d'                 # daily trend filter — slow and robust
    can_short = False

    # Circuit breakers (research-driven risk guards). Candle counts scale with
    # this strategy's timeframe. Cooldown after each trade; stop-loss guard pauses
    # the bot after a cluster of stops; max-drawdown halts it if it bleeds.
    @property
    def protections(self):
        return [
            {"method": "CooldownPeriod", "stop_duration_candles": 1},
            {"method": "StoplossGuard", "lookback_period_candles": 20,
             "trade_limit": 2, "stop_duration_candles": 5, "only_per_pair": False},
            {"method": "MaxDrawdown", "lookback_period_candles": 40, "trade_limit": 4,
             "stop_duration_candles": 5, "max_allowed_drawdown": 0.25},
        ]

    # We RIDE the trend, so ROI must never force an early exit. 1000% = effectively off.
    minimal_roi = {"0": 10}

    # The death-cross exit is the real risk control. This is only a catastrophic
    # seatbelt for a crash that falls faster than the daily cross can react.
    stoploss = -0.35

    trailing_stop = False
    use_exit_signal = True            # exit on the death-cross signal below
    exit_profit_only = False
    process_only_new_candles = True

    # Need 200 daily candles to form the 200-day EMA before trading.
    startup_candle_count = 200

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=50)    # 50-day EMA
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=200)   # 200-day EMA
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Be long whenever the trend is up (50d EMA above 200d EMA).
        # Freqtrade enters on the first up-day and simply holds until the exit
        # signal fires, so this captures an uptrend that's already underway too.
        dataframe.loc[
            (
                (dataframe['ema_fast'] > dataframe['ema_slow']) &
                (dataframe['volume'] > 0)
            ),
            'enter_long'] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exit to cash on the death cross (50d EMA falls back below 200d EMA).
        dataframe.loc[
            (dataframe['ema_fast'] < dataframe['ema_slow']),
            'exit_long'] = 1
        return dataframe
