# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/MenOfSteel.py
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import talib.abstract as ta
from functools import reduce

class Github_remiotore_freqtrade__MenOfSteel__20260111_210550(IStrategy):
    INTERFACE_VERSION = 3
    can_short = False  # 숏 포지션을 사용하지 않음
    leverage_p = 1
    stoploss_p = - 0.03
    minstop = 0.003
    minimal_roi = {
        "0": 0.067,
        "8": 0.014,
        "20": 0.003,
        "30": 0
    }

    def __init__(self, config: dict) -> None:
        super().__init__(config)
        self.leverage_p = self.config.get('trade', {}).get('leverage', 1)
        self.stoploss_p = self.config.get('trade', {}).get('stoploss', -0.03) * self.leverage_p
        self.minstop = self.leverage_p * 0.003
        self.stoploss = self.stoploss_p
        self.full_leverage = float(self.config.get('trade', {}).get('leverage', 1))
        self.minimal_roi = self.generate_minimal_roi(self.full_leverage)
        #self.minimal_roi = self.leverage_roi_map.get(self.leverage_p, self.leverage_roi_map[1])
    exit_params = {
        # 0 5m / 1 15m / 2 30m / 3 1h / 4 2h / 5 4h / 6 8h
        "exit_trend_indicator": 4,
        #"exit_adx_threshold": 15   # ADX가 15 이하일 때 매도
    }
    def generate_minimal_roi(self, leverage: float):
        base_roi = {
            "0": 0.046,
            "6": 0.018,
            "15": 0.007,
            "20": 0.003,
        }

        return {k: round(v * self.leverage_p, 6) for k, v in base_roi.items()}
    # ?섏씠?쇳뙆?쇰????뺤쓽
    left = IntParameter(5, 60, default=12, space="buy")
    right = IntParameter(2, 30, default=8, space="buy")
    #maintain_candles = IntParameter(1, 10, default=9, space='buy', optimize=True)
    # 여기서 threshold 추가

    #position_amount = DecimalParameter(5, 50, decimals=1, default=10, space="stake")
    #position_amount = 10
    #minimal_roi_value = DecimalParameter(0.01, 0.2, decimals=3, default=0.052, space="sell")
    #stoploss_value = DecimalParameter(-0.99, -0.01, decimals=3, default=-0.084, space="sell")
    timeframe = '3m'

    trailing_stop = False
    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 proposed_leverage: float, max_leverage: float, entry_tag: str | None, side: str,
                 **kwargs) -> float:
        #return float(self.config.get('trade', {}).get('leverage', 1))
        #return self.leverage
        return self.full_leverage

    def f_pivothigh_confirmed(self, series: pd.Series, left: int, right: int) -> pd.Series:
        """
        - series: 고가(high)값 시리즈
        - left: 과거 몇 봉을 볼지
        - right: 미래 몇 봉이 닫힌 뒤 확정할지
        반환: pivot_highs 시리즈. 값이 찍히는 시점이 바로 '미래 right개봉이 다 닫힌 순간'인 i.
        """
        length = len(series)
        pivot_highs = [np.nan] * length

        # i가 최소 left+right 이상이어야, center = i-right ≥ left 보장
        for i in range(left + right, length):
            center = i - right

            # 과거 left개( center-left : center )
            window_left = series[center - left: center]
            # 미래 right개 ( center+1 : center+1+right )
            window_right = series[center + 1: center + 1 + right]

            center_val = series[center]

            # 과거 left 중 최고값, 미래 right 중 최고값 비교
            if (center_val >= window_left.max()) and (center_val > window_right.max()):
                # pivot 고점 확정은 “미래 right개봉까지 닫힌 시점”인 i 에 찍어준다.
                pivot_highs[i] = center_val

        return pd.Series(pivot_highs, index=series.index)

    def f_pivotlow_confirmed(self, series: pd.Series, left: int, right: int) -> pd.Series:
        """
        - series: 저가(low)값 시리즈
        - left, right 설명은 f_pivothigh_confirmed와 동일
        """
        length = len(series)
        pivot_lows = [np.nan] * length

        for i in range(left + right, length):
            center = i - right

            window_left = series[center - left: center]
            window_right = series[center + 1: center + 1 + right]
            center_val = series[center]

            # 과거 left 중 최저값, 미래 right 중 최저값 비교
            if (center_val <= window_left.min()) and (center_val < window_right.min()):
                # pivot 저점 확정은 “미래 right개봉까지 닫힌 시점”인 i 에 찍어준다.
                pivot_lows[i] = center_val

        return pd.Series(pivot_lows, index=series.index)
    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        pivotHigh = self.f_pivothigh_confirmed(dataframe['high'], self.left.value, self.right.value)
        pivotLow = self.f_pivotlow_confirmed(dataframe['low'], self.left.value, self.right.value)

        dataframe['pivotHigh'] = pivotHigh
        dataframe['pivotLow'] = pivotLow
        return dataframe

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        dataframe['buy'] = 0

        # pivotLow 이후 close가 상승 추세인지 확인
        dataframe['pivotLowValid'] = (
                (dataframe['pivotLow'].notnull()) &
                (dataframe['close'] > dataframe['close'].shift(1)) &
                (dataframe['close'].shift(1) > dataframe['close'].shift(2))
        )

        dataframe.loc[
            dataframe['pivotLowValid'],
            'buy'
        ] = 1

        return dataframe
    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:

        dataframe['sell'] = 0
        dataframe.loc[
            (dataframe['pivotHigh'].notnull()),
            'sell'
        ] = 1

        return dataframe
    #def custom_entry_amount(self, pair: str, current_time, current_rate, current_profit, **kwargs):
    #    return self.position_amount.value

    def custom_exit(self, pair: str, current_time, current_rate, current_profit, **kwargs):
        # 손절 조건
        if current_profit <= self.stoploss:
            return True  # 손절 (즉시 매도)


        return False

