# source: https://raw.githubusercontent.com/tradingstrategy-ai/gmx-ccxt-freqtrade/cdcba720b80c0fdcdfe7ab4a90ad61121f9ee9d3/user_data/strategies/pingpong.py
"""A strategy to test all trading pairs on an exchange."""

import logging
from datetime import datetime, timedelta
from freqtrade.strategy import IStrategy
from pandas import DataFrame

from freqtrade.persistence import Trade
from freqtrade.enums import RunMode

logger = logging.getLogger(__name__)


class Github_tradingstrategy_ai_gmx_ccxt_freqtrade__pingpong__20251210_191501(IStrategy):
    buy_params = {}
    sell_params = {}

    # 1. Strategy interface version
    INTERFACE_VERSION: int = 3

    # 2. Timeframe and minimal startup candles
    timeframe = "1m"
    startup_candle_count = 0

    # 3. ROI table and stoploss
    minimal_roi = {"1": -1}
    stoploss = -0.99

    # 4. Trailing stop (fixed here, but could also be hyperopt'ed)
    trailing_stop = False
    trailing_stop_positive = 0.02  # trail once +2%
    trailing_stop_positive_offset = 0.02  # start trailing after +2%
    trailing_only_offset_is_reached = False

    # 5. Plot configuration
    plot_config = {
        "main_plot": {
        },
        "subplots": {
        }
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Calculate all necessary indicators."""
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Buy on every candle."""
        dataframe.loc[:, "enter_long"] = 1
        dataframe.loc[:, "buy"] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """No exit signals in dataframe - all exits handled by custom_exit."""
        dataframe.loc[:, "exit_long"] = 0
        dataframe.loc[:, "sell"] = 0
        return dataframe

    def confirm_trade_entry(
        self,
        pair: str,
        order_type: str,
        amount: float,
        rate: float,
        side: str,
        **kwargs,
    ) -> bool:
        if self.dp.runmode.value in ('backtest', 'plot'):
            return True
            
        existing = Trade.get_trades([Trade.is_open.is_(True), Trade.pair == pair]).first()
        if existing:
            logger.info(f"⛔ Skipping entry for {pair}: open trade exists (id={existing.id}).")
            return False

        current_time = datetime.now()
        logger.info(f"🎯 ENTRY SIGNAL: {pair} | Price: {rate:.4f} | Time: {current_time}")
        return True

    def custom_exit(self, pair: str, trade: 'Trade', current_time: datetime,
                    current_rate: float, current_profit: float, **kwargs) -> str | bool | None:
        """
        Custom exit logic to sell exactly 1 minute after entry.
        This function is called for every open trade at every bot loop iteration.
        """
        time_diff = current_time - trade.open_date_utc
        time_diff_seconds = time_diff.total_seconds()
        
        profit_pct = current_profit * 100
        price_change = current_rate - trade.open_rate
        price_change_pct = (price_change / trade.open_rate) * 100

        if time_diff >= timedelta(minutes=1):
            logger.info(
                f"🚪 EXIT SIGNAL: {pair} | "
                f"Entry: {trade.open_rate:.4f} @ {trade.open_date_utc.strftime('%H:%M:%S')} | "
                f"Exit: {current_rate:.4f} @ {current_time.strftime('%H:%M:%S')} | "
                f"Duration: {int(time_diff_seconds)}s | "
                f"Price Change: {price_change:+.4f} ({price_change_pct:+.2f}%) | "
                f"Final P&L: {profit_pct:+.2f}%"
            )
            return "one_minute_exit"
        
        # Continue holding the position
        return None

    def lock_pair(self, pair: str, until: datetime, reason: str | None = None, side: str = "*") -> None:
        """Override to disable auto lock completely."""
        pass

    def bot_loop_start(self, current_time: datetime, **kwargs) -> None:
        """
        Log bot loop start with open positions summary
        """
        current_mode = self.config['runmode']
        is_trading_mode = current_mode in (RunMode.LIVE, RunMode.DRY_RUN)

        if is_trading_mode:
            open_trades = Trade.get_open_trades()
            logger.info(f"🔄 BOT LOOP START: {current_time} | Open Trades: {len(open_trades)}")
          