# source: https://raw.githubusercontent.com/shaojintian/crypto_backtesting/75ba72665f1a6afaa985e9e0e853330d6d2bd848/freq_trade/user_data/strategies/reversal_strategy.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these imports ---
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Optional, Union

from freqtrade.strategy import (
    IStrategy,
    Trade,
    Order,
    PairLocks,
    informative,  # @informative decorator
    # Hyperopt Parameters
    BooleanParameter,
    CategoricalParameter,
    DecimalParameter,
    IntParameter,
    RealParameter,
    # timeframe helpers
    timeframe_to_minutes,
    timeframe_to_next_date,
    timeframe_to_prev_date,
    # Strategy helper functions
    merge_informative_pair,
    stoploss_from_absolute,
    stoploss_from_open,
)

# --------------------------------
# Add your lib to import here
import talib.abstract as ta
from technical import qtpylib

class Github_shaojintian_crypto_backtesting__reversal_strategy__20250211_105003(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = "3m"
    
    # 参数优化范围
    bb_length = IntParameter(10, 50, default=20, space='buy')
    bb_std = DecimalParameter(1.5, 3.0, default=2.0, space='buy')
    rsi_length = IntParameter(10, 30, default=14, space='buy')
    vol_mult = DecimalParameter(1.5, 5.0, default=2.0, space='buy')
    sigma_multiplier = DecimalParameter(4.0, 8.0, default=6.0, space='buy')
    vol_window = IntParameter(20, 100, default=50, space='buy')
    
    # 止损设置
    stoploss = -0.01
    
    # ROI设置
    minimal_roi = {
        "0": 0.02,
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # 计算布林带
        bollinger = qtpylib.bollinger_bands(
            dataframe['close'], 
            window=self.bb_length.value,
            stds=self.bb_std.value
        )
        dataframe['bb_upperband'] = bollinger['upper']
        dataframe['bb_middleband'] = bollinger['mid']
        dataframe['bb_lowerband'] = bollinger['lower']


         # Calculate volatility
        dataframe['std'] = dataframe['close'].rolling(window=self.vol_window.value).std()
        dataframe['upper_risk'] = dataframe['close'].rolling(window=self.vol_window.value).mean() + \
                                 self.sigma_multiplier.value * dataframe['std']
        dataframe['lower_risk'] = dataframe['close'].rolling(window=self.vol_window.value).mean() - \
                                 self.sigma_multiplier.value * dataframe['std']
        
        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.rsi_length.value)
        
        # 成交量均值
        dataframe['volume_mean'] = dataframe['volume'].rolling(window=20).mean()
        dataframe['volume_std'] = dataframe['volume'].rolling(window=20).std()
        
        return dataframe
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                # 价格低于下轨
                (dataframe['close'] < dataframe['bb_lowerband']) &
                # RSI超卖
                (dataframe['rsi'] < 30) &
                # 放量
                (dataframe['volume'] > dataframe['volume_mean'] * self.vol_mult.value) &

                # 价格在风险区间内
                (dataframe['close'] > dataframe['lower_risk']) 
            ),
            'enter_long'
        ] = 1
        
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                # 价格回归均值
                (dataframe['close'] > dataframe['bb_middleband']) |
                # RSI超买
                (dataframe['rsi'] > 70)
            ),
            'exit_long'
        ] = 1
        
        return dataframe