# source: https://raw.githubusercontent.com/DOUGLASGUEDESATRIA/OSIRIS_TRADE/fe3c09567f3798d1cad6d7a306fa4f6131d91e17/user_data/strategies/OsirisSwingV1.py
"""
OSIRIS SWING v1.0 — 1H Pullback-to-Trend Strategy
====================================================
Designed for high WR + high RR by catching pullbacks in established trends.

Logic:
  1H timeframe entry — bigger candles = bigger moves = easier 3:1 RR
  Trend: EMA(9) > EMA(21) > EMA(50) on 1H (bull)
  Entry: RSI(14) pulls back below 45 (in uptrend) then recovers above 50
  Confirmation: MACD histogram positive and growing
  ADX > 25 (trend present)

Exit: Trailing after 1R profit, no fixed TP.
  Initial SL = -1.5%
  After +1.5%: trail at 1.0%
  After +3.0%: trail at 1.5%  
  Time exit: 48h max
"""

import logging
import numpy as np
from pandas import DataFrame
from datetime import datetime

from freqtrade.strategy import IStrategy
from freqtrade.persistence import Trade
import talib.abstract as ta

logger = logging.getLogger(__name__)


class Github_DOUGLASGUEDESATRIA_OSIRIS_TRADE__OsirisSwingV1__20260329_060843(IStrategy):
    INTERFACE_VERSION = 3
    can_short = True
    timeframe = "1h"

    stoploss = -0.015  # 1.5% initial SL
    minimal_roi = {}   # No fixed TP

    trailing_stop = False
    trailing_stop_positive = 0.0
    trailing_stop_positive_offset = 0.0
    trailing_only_offset_is_reached = False

    use_custom_stoploss = True
    use_exit_signal = True

    startup_candle_count = 200
    process_only_new_candles = True

    def custom_stoploss(self, pair: str, trade: Trade,
                        current_time: datetime, current_rate: float,
                        current_profit: float, after_fill: bool,
                        **kwargs) -> float:
        # Phase 3: deep into profit, trail tightly
        if current_profit >= 0.03:
            return -0.015  # Trail at 1.5%

        # Phase 2: trail once at 1.5% profit
        if current_profit >= 0.015:
            return -0.01  # Trail at 1.0%, locking ~0.5% min

        # Phase 1: after reaching 0.8%, move near breakeven
        if current_profit >= 0.008:
            return -0.005  # ~0.3% profit locked

        # Phase 0: initial
        return -0.015

    def custom_exit(self, pair: str, trade: Trade,
                    current_time: datetime, current_rate: float,
                    current_profit: float, **kwargs):
        elapsed = (current_time - trade.open_date_utc).total_seconds()

        # Not working after 12 hours → cut
        if elapsed > 12 * 3600 and current_profit < 0.003:
            return "time_exit_12h"

        # Max hold 48h
        if elapsed > 48 * 3600:
            return "time_exit_48h"

        return None

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ema9"] = ta.EMA(dataframe, timeperiod=9)
        dataframe["ema21"] = ta.EMA(dataframe, timeperiod=21)
        dataframe["ema50"] = ta.EMA(dataframe, timeperiod=50)
        dataframe["rsi14"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["adx14"] = ta.ADX(dataframe, timeperiod=14)

        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe["macd_hist"] = macd["macdhist"]

        # Pullback detection: RSI was below 45 recently (within 3 bars)
        dataframe["rsi_below_45_recently"] = (
            (dataframe["rsi14"].shift(1) < 45) |
            (dataframe["rsi14"].shift(2) < 45) |
            (dataframe["rsi14"].shift(3) < 45)
        )
        dataframe["rsi_above_55_recently"] = (
            (dataframe["rsi14"].shift(1) > 55) |
            (dataframe["rsi14"].shift(2) > 55) |
            (dataframe["rsi14"].shift(3) > 55)
        )

        # EMA alignment
        dataframe["trend_bull"] = (
            (dataframe["ema9"] > dataframe["ema21"]) &
            (dataframe["ema21"] > dataframe["ema50"])
        )
        dataframe["trend_bear"] = (
            (dataframe["ema9"] < dataframe["ema21"]) &
            (dataframe["ema21"] < dataframe["ema50"])
        )

        # Volume
        dataframe["vol_sma20"] = ta.SMA(dataframe["volume"], timeperiod=20)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Pullback-to-trend entry:
        - Strong trend (EMA aligned + ADX>25)
        - RSI pulled back below 45 recently, now recovering above 50
        - MACD histogram aligned
        """
        # Trend filters
        adx_ok = dataframe["adx14"] > 25

        # LONG: Bull trend + RSI pullback recovery
        long_cond = (
            dataframe["trend_bull"] &
            adx_ok &
            dataframe["rsi_below_45_recently"] &
            (dataframe["rsi14"] > 50) &
            (dataframe["macd_hist"] > 0) &
            (dataframe["close"] > dataframe["ema21"]) &
            (dataframe["volume"] > 0)
        )

        # SHORT: Bear trend + RSI rally recovery
        short_cond = (
            dataframe["trend_bear"] &
            adx_ok &
            dataframe["rsi_above_55_recently"] &
            (dataframe["rsi14"] < 50) &
            (dataframe["macd_hist"] < 0) &
            (dataframe["close"] < dataframe["ema21"]) &
            (dataframe["volume"] > 0)
        )

        dataframe.loc[long_cond, "enter_long"] = 1
        dataframe.loc[short_cond, "enter_short"] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return dataframe
