# source: https://raw.githubusercontent.com/crow2673/Echo-core/4b50513160935782341b850b2ff36cd0e63ba632/backtests/strategies/EchoL1StrategyV6.py
"""
Github_crow2673_Echo_core__EchoL1StrategyV6__20260503_192400 — Long AND short. Profits in any market direction.

V4/V5 problem: long-only strategy loses in bear/sideways markets.
An AI should profit regardless of direction.

V6 adds short selling:
  Long:  RSI recovery from oversold + MACD turning up   + near MA50 + volume
  Short: RSI reversal from overbought + MACD turning down + near MA50 + volume

Exit: 5% TP | 2% SL (tighter — crypto moves fast both ways)
No trailing stop — let signals run to target.

Expected: long signals fire in dips, short signals fire at tops.
Net result: profits in bull, bear, AND sideways markets.
"""
from freqtrade.strategy import IStrategy, informative
from pandas import DataFrame
import talib.abstract as ta
import pandas as pd


class Github_crow2673_Echo_core__EchoL1StrategyV6__20260503_192400(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = "1h"

    minimal_roi = {"0": 0.05}
    stoploss = -0.02
    trailing_stop = False
    can_short = True

    @informative("1d")
    def populate_indicators_1d(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ma50"] = dataframe["close"].rolling(50).mean()
        dataframe["near_or_above_ma50"] = (
            dataframe["close"] > dataframe["ma50"] * 0.92
        ).astype(int)
        dataframe["near_or_below_ma50"] = (
            dataframe["close"] < dataframe["ma50"] * 1.08
        ).astype(int)
        return dataframe

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["rsi"] = ta.RSI(dataframe["close"], timeperiod=14)
        dataframe["vol_ma20"] = dataframe["volume"].rolling(20).mean()

        _macd, _signal, _hist = ta.MACD(dataframe["close"], fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe["macd_hist"] = pd.Series(_hist, index=dataframe.index)
        dataframe["macd_hist_prev"] = dataframe["macd_hist"].shift(1)

        dataframe["rsi_prev"] = dataframe["rsi"].shift(1)

        # Long conditions
        dataframe["rsi_was_oversold"] = (dataframe["rsi_prev"] < 40).astype(int)
        dataframe["rsi_recovering"] = (
            (dataframe["rsi_was_oversold"] == 1) &
            (dataframe["rsi"] > dataframe["rsi_prev"])
        ).astype(int)
        dataframe["macd_turning_up"] = (
            dataframe["macd_hist"] > dataframe["macd_hist_prev"]
        ).astype(int)

        # Short conditions (mirror)
        dataframe["rsi_was_overbought"] = (dataframe["rsi_prev"] > 60).astype(int)
        dataframe["rsi_reversing"] = (
            (dataframe["rsi_was_overbought"] == 1) &
            (dataframe["rsi"] < dataframe["rsi_prev"])
        ).astype(int)
        dataframe["macd_turning_down"] = (
            dataframe["macd_hist"] < dataframe["macd_hist_prev"]
        ).astype(int)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Long entry
        dataframe.loc[
            (dataframe["near_or_above_ma50_1d"] == 1) &
            (dataframe["rsi_recovering"] == 1) &
            (dataframe["rsi"] < 45) &
            (dataframe["macd_turning_up"] == 1) &
            (dataframe["volume"] > dataframe["vol_ma20"] * 1.2) &
            (dataframe["volume"] > 0),
            "enter_long",
        ] = 1

        # Short entry (mirror logic)
        dataframe.loc[
            (dataframe["near_or_below_ma50_1d"] == 1) &
            (dataframe["rsi_reversing"] == 1) &
            (dataframe["rsi"] > 55) &
            (dataframe["macd_turning_down"] == 1) &
            (dataframe["volume"] > dataframe["vol_ma20"] * 1.2) &
            (dataframe["volume"] > 0),
            "enter_short",
        ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[:, "exit_long"] = 0
        dataframe.loc[:, "exit_short"] = 0
        return dataframe
