# source: https://raw.githubusercontent.com/andongniu/okx-btc-trading-system/87abd1bdb603ee44fd52976a4bc639487abdc5b8/user_data/strategies/OptimizedStrategy.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these libs ---
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional, Union

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

# --------------------------------
# Add your lib to import here
import ta as ta_lib
from freqtrade.persistence import Trade


class Github_andongniu_okx_btc_trading_system__OptimizedStrategy__20260227_025219(IStrategy):
    """
    优化的交易策略 - 结合多个技术指标
    1. RSI超买超卖
    2. 移动平均线交叉
    3. MACD信号
    4. 布林带突破
    5. 成交量确认
    """
    INTERFACE_VERSION = 3

    timeframe = '5m'

    can_short: bool = False

    # 优化的止盈参数
    minimal_roi = {
        "0": 0.15,      # 立即止盈15%
        "15": 0.10,     # 15分钟后止盈10%
        "30": 0.05,     # 30分钟后止盈5%
        "60": 0.02,     # 60分钟后止盈2%
        "120": 0        # 120分钟后平仓
    }

    # 止损设置
    stoploss = -0.08  # 8%止损

    # 追踪止损
    trailing_stop = True
    trailing_stop_positive = 0.05
    trailing_stop_positive_offset = 0.08
    trailing_only_offset_is_reached = True

    process_only_new_candles = True

    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    startup_candle_count: int = 50  # 需要更多数据计算指标

    order_types = {
        'entry': 'limit',
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    order_time_in_force = {
        'entry': 'GTC',
        'exit': 'GTC'
    }

    # 策略参数
    rsi_buy = IntParameter(25, 35, default=30, space="buy")
    rsi_sell = IntParameter(65, 75, default=70, space="sell")
    macd_fast = IntParameter(10, 15, default=12, space="buy")
    macd_slow = IntParameter(20, 26, default=26, space="buy")
    macd_signal = IntParameter(7, 10, default=9, space="buy")
    bb_period = IntParameter(18, 22, default=20, space="buy")
    bb_std = DecimalParameter(1.8, 2.2, default=2.0, space="buy")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # RSI指标
        dataframe['rsi'] = ta_lib.momentum.rsi(dataframe['close'], window=14)
        
        # 移动平均线
        dataframe['sma_fast'] = dataframe['close'].rolling(window=20).mean()
        dataframe['sma_slow'] = dataframe['close'].rolling(window=50).mean()
        dataframe['ema_fast'] = dataframe['close'].ewm(span=12).mean()
        dataframe['ema_slow'] = dataframe['close'].ewm(span=26).mean()
        
        # MACD指标
        macd = ta_lib.trend.macd(dataframe['close'], window_slow=26, window_fast=12, window_sign=9)
        dataframe['macd'] = macd
        dataframe['macd_signal'] = ta_lib.trend.macd_signal(dataframe['close'], window_slow=26, window_fast=12, window_sign=9)
        dataframe['macd_diff'] = ta_lib.trend.macd_diff(dataframe['close'], window_slow=26, window_fast=12, window_sign=9)
        
        # 布林带
        bb_period = self.bb_period.value
        bb_std = self.bb_std.value
        dataframe['bb_upper'] = ta_lib.volatility.bollinger_hband(dataframe['close'], window=bb_period, window_dev=bb_std)
        dataframe['bb_middle'] = dataframe['close'].rolling(window=bb_period).mean()
        dataframe['bb_lower'] = ta_lib.volatility.bollinger_lband(dataframe['close'], window=bb_period, window_dev=bb_std)
        dataframe['bb_width'] = (dataframe['bb_upper'] - dataframe['bb_lower']) / dataframe['bb_middle']
        
        # 成交量指标
        dataframe['volume_sma'] = dataframe['volume'].rolling(window=20).mean()
        dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_sma']
        
        # ATR指标（波动率）
        dataframe['atr'] = ta_lib.volatility.average_true_range(dataframe['high'], dataframe['low'], dataframe['close'], window=14)
        
        # 价格位置指标
        dataframe['price_position'] = (dataframe['close'] - dataframe['bb_lower']) / (dataframe['bb_upper'] - dataframe['bb_lower'])
        
        # 趋势强度指标
        dataframe['trend_strength'] = abs(dataframe['sma_fast'] - dataframe['sma_slow']) / dataframe['atr']
        
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        多条件买入信号：
        1. RSI超卖
        2. 价格在布林带下轨附近
        3. MACD金叉或即将金叉
        4. 成交量放大确认
        5. 短期均线上穿长期均线
        """
        dataframe.loc[
            (
                # RSI条件
                (dataframe['rsi'] < self.rsi_buy.value) &
                
                # 价格位置条件（在布林带下轨附近）
                (dataframe['price_position'] < 0.2) &
                
                # MACD条件（金叉或即将金叉）
                ((dataframe['macd'] > dataframe['macd_signal']) | 
                 ((dataframe['macd'] < dataframe['macd_signal']) & 
                  (dataframe['macd'].shift(1) > dataframe['macd_signal'].shift(1)))) &
                
                # 成交量确认
                (dataframe['volume_ratio'] > 1.2) &
                
                # 趋势条件（短期均线上穿长期均线）
                (dataframe['sma_fast'] > dataframe['sma_slow']) &
                
                # 波动率过滤（避免高波动期）
                (dataframe['atr'] / dataframe['close'] < 0.02) &
                
                # 趋势强度过滤
                (dataframe['trend_strength'] > 0.5) &
                
                # 确保有成交量
                (dataframe['volume'] > 0)
            ),
            'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        多条件卖出信号：
        1. RSI超买
        2. 价格在布林带上轨附近
        3. MACD死叉或即将死叉
        4. 成交量萎缩
        5. 短期均线下穿长期均线
        """
        dataframe.loc[
            (
                # RSI条件
                (dataframe['rsi'] > self.rsi_sell.value) &
                
                # 价格位置条件（在布林带上轨附近）
                (dataframe['price_position'] > 0.8) &
                
                # MACD条件（死叉或即将死叉）
                ((dataframe['macd'] < dataframe['macd_signal']) | 
                 ((dataframe['macd'] > dataframe['macd_signal']) & 
                  (dataframe['macd'].shift(1) < dataframe['macd_signal'].shift(1)))) &
                
                # 成交量确认
                (dataframe['volume_ratio'] < 0.8) &
                
                # 趋势条件（短期均线下穿长期均线）
                (dataframe['sma_fast'] < dataframe['sma_slow']) &
                
                # 确保有成交量
                (dataframe['volume'] > 0)
            ),
            'exit_long'] = 1

        return dataframe

    def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
                           proposed_stake: float, min_stake: Optional[float], max_stake: float,
                           leverage: float, entry_tag: Optional[str], side: str,
                           **kwargs) -> float:
        """
        自定义仓位管理：根据ATR调整仓位大小
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        
        if len(dataframe) > 0:
            current_atr = dataframe['atr'].iloc[-1]
            current_price = dataframe['close'].iloc[-1]
            
            # 根据波动率调整仓位：波动率越高，仓位越小
            atr_ratio = current_atr / current_price
            
            if atr_ratio < 0.01:
                # 低波动，正常仓位
                stake_multiplier = 1.0
            elif atr_ratio < 0.02:
                # 中等波动，减少仓位
                stake_multiplier = 0.7
            else:
                # 高波动，大幅减少仓位
                stake_multiplier = 0.4
            
            adjusted_stake = proposed_stake * stake_multiplier
            
            # 确保在最小和最大限制内
            if min_stake is not None:
                adjusted_stake = max(adjusted_stake, min_stake)
            adjusted_stake = min(adjusted_stake, max_stake)
            
            return adjusted_stake
        
        return proposed_stake