# source: https://raw.githubusercontent.com/liyunfang1907-cmd/QUANT/faeddd9a8893daf86ed21fc409e72b04c3abc171/templates/dual_momentum_strategy.py
from datetime import datetime, timedelta
from typing import Dict

import numpy as np
import pandas as pd

from freqtrade.strategy import IStrategy, IntParameter


class Github_liyunfang1907_cmd_QUANT__dual_momentum_strategy__20251012_045326(IStrategy):
    """
    Simple dual momentum strategy combining long-term trend and relative strength.
    """

    timeframe = "1h"
    can_short = False

    stoploss = -0.1
    minimal_roi = {
        "0": 0.05,
        "60": 0.02,
        "120": 0.01,
        "240": 0,
    }

    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.02
    trailing_only_offset_is_reached = True

    lookback_period_days = IntParameter(5, 30, default=14)
    long_window = IntParameter(50, 200, default=100)
    short_window = IntParameter(10, 50, default=20)

    startup_candle_count = 200

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: Dict) -> pd.DataFrame:
        dataframe["ma_long"] = dataframe["close"].rolling(
            window=int(self.long_window.value)
        ).mean()
        dataframe["ma_short"] = dataframe["close"].rolling(
            window=int(self.short_window.value)
        ).mean()

        dataframe["returns"] = dataframe["close"].pct_change()
        lookback = int(self.lookback_period_days.value) * 24
        dataframe["momentum"] = dataframe["returns"].rolling(window=lookback).mean()

        dataframe["volatility"] = dataframe["returns"].rolling(window=lookback).std()
        dataframe["risk_adjusted_momentum"] = dataframe["momentum"] / (
            dataframe["volatility"] + 1e-9
        )

        dataframe["volume_mean"] = dataframe["volume"].rolling(window=lookback).mean()
        dataframe["volume_spike"] = dataframe["volume"] > (dataframe["volume_mean"] * 1.5)

        return dataframe

    def populate_buy_trend(self, dataframe: pd.DataFrame, metadata: Dict) -> pd.DataFrame:
        dataframe.loc[:, "buy"] = 0
        conditions = [
            dataframe["ma_short"] > dataframe["ma_long"],
            dataframe["risk_adjusted_momentum"] > 0,
            dataframe["volume_spike"],
            dataframe["close"] > dataframe["ma_long"] * 0.995,
        ]
        dataframe.loc[np.all(conditions, axis=0), "buy"] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: pd.DataFrame, metadata: Dict) -> pd.DataFrame:
        dataframe.loc[:, "sell"] = 0
        conditions = [
            dataframe["ma_short"] < dataframe["ma_long"],
            dataframe["risk_adjusted_momentum"] < 0,
        ]
        dataframe.loc[np.all(conditions, axis=0), "sell"] = 1
        return dataframe

    def custom_exit(self, pair: str, trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs):
        # Example exit logic: time-stop after one week regardless of profit
        max_duration = timedelta(days=7)
        if current_time - trade.open_date_utc >= max_duration:
            return "time_stop"
        return None
