# source: https://raw.githubusercontent.com/tellyoung/money_game/8a1eeba562c35611d7e78a8cd184c0dba5d9284a/Trading/user_data/strategies/IntradayMomentum.py
from functools import reduce
from pandas import DataFrame
from freqtrade.strategy import IStrategy

import talib.abstract as ta

from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, 
                                IStrategy, IntParameter)

class Github_tellyoung_money_game__IntradayMomentum__20250419_044326(IStrategy):
    INTERFACE_VERSION: int = 3
    can_short = True

    timeframe = "5m"

    # ROI table (hyperoptable)
    minimal_roi = {
        "0": 0.05,  # Default values, will be overridden by hyperopt
        "30": 0.03,
        "60": 0.01
    }

    # Stoploss (hyperoptable)
    stoploss = -0.01  # Default value, will be overridden by hyperopt

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.05
    trailing_stop_positive_offset = 0.1
    trailing_only_offset_is_reached = False


    # Hyperoptable parameters
    band_mult_UB = DecimalParameter(0.3, 5., default=0.8, space="buy", optimize=True)
    band_mult_LB = DecimalParameter(0.3, 5., default=0.8, space="buy", optimize=True)
    sell_threshold = DecimalParameter(0.95, 1.05, default=1.0, space="sell", optimize=True)


    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
            Populate indicators required for the strategy.
        """
        # Calculate VWAP
        hlc = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
        dataframe['vwap'] = (hlc * dataframe['volume']).cumsum() / dataframe['volume'].cumsum()

        # Calculate rolling mean and sigma
        dataframe['move_open'] = (dataframe['close'] / dataframe['open'] - 1).abs()
        dataframe['move_open_rolling_mean'] = dataframe['move_open'].rolling(window=14, min_periods=13).mean()
        dataframe['sigma_open'] = dataframe['move_open_rolling_mean'].shift(1)

        return dataframe


    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
            Populate entry signals based on the strategy logic.
        """
        dataframe['enter_long'] = 0
        dataframe['enter_short'] = 0

        # Calculate upper and lower bands
        dataframe['UB'] = dataframe['open'] * (1 + self.band_mult_UB.value * dataframe['sigma_open'])
        dataframe['LB'] = dataframe['open'] * (1 - self.band_mult_LB.value * dataframe['sigma_open'])

        # Long entry signal: Price > UB and Price > VWAP
        dataframe.loc[
            (dataframe['close'] > dataframe['UB']) & (dataframe['close'] > dataframe['vwap']),
            'enter_long'
        ] = 1

        # Short entry signal: Price < LB and Price < VWAP
        dataframe.loc[
            (dataframe['close'] < dataframe['LB']) & (dataframe['close'] < dataframe['vwap']),
            'enter_short'
        ] = 1

        # print(dataframe[['close', 'UB', 'LB', 'vwap', "enter_long", "enter_short"]].tail(100))
        # print(dataframe.loc[dataframe['enter_long'] == 1, ['date', 'close', 'UB', 'LB', 'vwap', "enter_long", "enter_short"]]).tail(100))
        # print(dataframe.loc[dataframe['enter_short'] == 1, ['date', 'close', 'UB', 'LB', 'vwap', "enter_long", "enter_short"]]).tail(100))

        return dataframe


    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Populate exit signals.
        """
        dataframe['exit_long'] = 0
        dataframe['exit_short'] = 0

        # dataframe.loc[
        #     (dataframe['close'] < dataframe['LB']) & (dataframe['close'] < dataframe['vwap']),
        #     'exit_long'
        # ] = 1

        # dataframe.loc[
        #     (dataframe['close'] > dataframe['UB']) & (dataframe['close'] > dataframe['vwap']),
        #     'exit_short'
        # ] = 1

        # Exit long when price drops below VWAP
        # dataframe.loc[
        #     (dataframe['close'] < dataframe['vwap']),
        #     'exit_long'
        # ] = 1

        # # Exit short when price rises above VWAP
        # dataframe.loc[
        #     (dataframe['close'] > dataframe['vwap']),
        #     'exit_short'
        # ] = 1

        # Exit long when price drops below VWAP * sell_threshold
        dataframe.loc[
            (dataframe['close'] < dataframe['vwap'] * self.sell_threshold.value),
            'exit_long'
        ] = 1

        # Exit short when price rises above VWAP * sell_threshold
        dataframe.loc[
            (dataframe['close'] > dataframe['vwap'] * self.sell_threshold.value),
            'exit_short'
        ] = 1
        return dataframe




