# source: https://raw.githubusercontent.com/cohen-zhang/learn_wave_trade/8d376fcf7f16321d9808dc383fea87b66c4e2c89/strategies/freqtrade/WaveSupportStrategy.py
"""
Freqtrade strategy template — wave support bounce with 10% stop loss.

Aligns with docs/investment/principles.md:
- BTC spot only
- strict stoploss at -10%
- enter near annotated support, reclaim SMA20

Setup:
  1. Install freqtrade: https://www.freqtrade.io/en/stable/
  2. Copy this file to <freqtrade_dir>/user_data/strategies/
  3. Dry-run: freqtrade trade --strategy Github_cohen_zhang_learn_wave_trade__WaveSupportStrategy__20260707_023445 --dry-run

Docs: strategies/freqtrade/README.md
"""

from datetime import datetime
from typing import Optional

import talib.abstract as ta
from pandas import DataFrame

from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter


class Github_cohen_zhang_learn_wave_trade__WaveSupportStrategy__20260707_023445(IStrategy):
    INTERFACE_VERSION = 3

    # 投资原则: 严格 10% 止损
    stoploss = -0.10
    trailing_stop = False

    timeframe = "1d"
    startup_candle_count = 50

    # Annotated support from docs/wave-theory/analysis/btc-2026-03.md
    support_level = DecimalParameter(60000, 75000, default=67979, decimals=0, space="buy")
    support_tolerance = DecimalParameter(0.01, 0.05, default=0.02, decimals=2, space="buy")
    rsi_max = IntParameter(40, 70, default=55, space="buy")

    minimal_roi = {
        "0": 0.15,
        "7": 0.08,
        "30": 0.04,
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["sma_20"] = ta.SMA(dataframe, timeperiod=20)
        dataframe["sma_50"] = ta.SMA(dataframe, timeperiod=50)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        support = float(self.support_level.value)
        tol = float(self.support_tolerance.value)
        near_support = dataframe["low"] <= support * (1 + tol)
        reclaim = dataframe["close"] > dataframe["sma_20"]
        not_overbought = dataframe["rsi"] < self.rsi_max.value

        dataframe.loc[
            near_support & reclaim & not_overbought,
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exit when price loses SMA50 in weak RSI environment (trend failure)
        dataframe.loc[
            (dataframe["close"] < dataframe["sma_50"])
            & (dataframe["rsi"] < 45),
            "exit_long",
        ] = 1
        return dataframe

    def custom_stoploss(
        self,
        pair: str,
        trade,
        current_time: datetime,
        current_rate: float,
        current_profit: float,
        after_fill: bool,
        **kwargs,
    ) -> Optional[float]:
        # Hard cap: never widen beyond -10%
        return self.stoploss
