# source: https://raw.githubusercontent.com/Filimonov-Eremeyka/freqtrade/edf4ff8f6dc4d6617f318dd5ebaa0c3427654b1f/user_data/strategies/PolusStrategy.py
# user_data/strategies/Github_Filimonov_Eremeyka_freqtrade__PolusStrategy__20250905_154014.py
import numpy as np
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy.interface import IStrategy

# Убедитесь, что путь к индикатору правильный
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))

from indicators.polus_x import PolusX


class Github_Filimonov_Eremeyka_freqtrade__PolusStrategy__20250905_154014(IStrategy):
    """
    Стратегия на основе индикатора PolusX
    """
    
    # Базовые настройки стратегии
    INTERFACE_VERSION = 3
    
    # Настройки временного интервала
    timeframe = '5m'
    process_only_new_candles = True
    startup_candle_count = 200

    # Настройки ROI и стоп-лосса
    minimal_roi = {
        "60": 0.01,
        "30": 0.02, 
        "0": 0.04
    }
    stoploss = -0.10
    trailing_stop = False
    
    # Настройки сигналов выхода
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    # Конфигурация графика
    plot_config = {
        'main_plot': {
            'polus_high1': {'color': 'green'},
            'polus_min1':  {'color': 'red'},
            'polus_max2':  {'color': 'aqua'},
            'polus_min2':  {'color': 'magenta'},
            'polus_max3':  {'color': 'steelblue'},
            'polus_min3':  {'color': 'orangered'},
            'polus_cl':    {'color': 'gold'},
        }
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Добавляет индикаторы PolusX к dataframe
        """
        if dataframe.empty:
            return dataframe

        # Проверяем наличие необходимых колонок
        required_columns = ['open', 'high', 'low', 'close', 'volume']
        for col in required_columns:
            if col not in dataframe.columns:
                print(f"Warning: Missing column {col}")
                return dataframe

        try:
            # Создаём экземпляр индикатора
            polus = PolusX(use_tick_volume=False, show_lines=True, ind1=True, ind2=True, ind3=True)

            # Вычисляем индикаторы
            high1, min1 = polus._calc_ind1(dataframe)
            max2, min2 = polus._calc_ind2(dataframe)  
            max3, min3, cl = polus._calc_ind3(dataframe)

            # Добавляем индикаторы в dataframe
            dataframe['polus_high1'] = high1
            dataframe['polus_min1']  = min1
            dataframe['polus_max2']  = max2
            dataframe['polus_min2']  = min2
            dataframe['polus_max3']  = max3
            dataframe['polus_min3']  = min3
            dataframe['polus_cl']    = cl

            # Добавляем сдвинутые значения для сравнения
            dataframe['close_prev'] = dataframe['close'].shift(1)
            dataframe['ph1_prev']   = dataframe['polus_high1'].shift(1)
            dataframe['pm1_prev']   = dataframe['polus_min1'].shift(1)
            
            # Заполняем NaN значения для корректной работы
            for col in ['polus_high1', 'polus_min1', 'polus_max2', 'polus_min2', 
                       'polus_max3', 'polus_min3', 'polus_cl']:
                dataframe[col] = dataframe[col].fillna(method='ffill')
            
        except Exception as e:
            print(f"Error in populate_indicators: {e}")
            # В случае ошибки возвращаем dataframe с NaN значениями
            for col in ['polus_high1', 'polus_min1', 'polus_max2', 'polus_min2',
                       'polus_max3', 'polus_min3', 'polus_cl', 'close_prev', 
                       'ph1_prev', 'pm1_prev']:
                dataframe[col] = np.nan

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Определяет сигналы на вход в позицию
        """
        # Инициализируем колонку входа
        dataframe.loc[:, 'enter_long'] = False
        
        # Проверяем наличие необходимых колонок
        required_cols = ['close', 'polus_high1', 'close_prev', 'ph1_prev']
        if not all(col in dataframe.columns for col in required_cols):
            return dataframe
            
        try:
            # Условие входа: цена закрытия пересекает вверх polus_high1
            cond = (
                (dataframe['close'] > dataframe['polus_high1']) & 
                (dataframe['close_prev'] <= dataframe['ph1_prev']) &
                (dataframe['volume'] > 0) &  # Убеждаемся что есть объём
                (~dataframe['polus_high1'].isna()) &  # Индикатор не NaN
                (~dataframe['ph1_prev'].isna())  # Предыдущее значение не NaN
            )
            
            dataframe.loc[cond, 'enter_long'] = True
            dataframe.loc[cond, 'enter_tag'] = 'cross_ph1_up'
            
        except Exception as e:
            print(f"Error in populate_entry_trend: {e}")
            
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Определяет сигналы на выход из позиции
        Выход когда close пересекает ВНИЗ polus_min1 (пробой «нижнего» уровня).
        """
        # Инициализируем колонку выхода
        dataframe.loc[:, 'exit_long'] = False

        # Проверяем наличие необходимых колонок
        required_cols = ['close', 'polus_min1', 'close_prev', 'pm1_prev']
        if not all(col in dataframe.columns for col in required_cols):
            return dataframe

        try:
            # Условие выхода: цена закрытия пересекает вниз polus_min1
            cond_cross_down = (
                (dataframe['close'] < dataframe['polus_min1']) &
                (dataframe['close_prev'] >= dataframe['pm1_prev']) &
                (dataframe['volume'] > 0) &  # Убеждаемся что есть объём
                (~dataframe['polus_min1'].isna()) &  # Индикатор не NaN
                (~dataframe['pm1_prev'].isna())  # Предыдущее значение не NaN
            )

            dataframe.loc[cond_cross_down, 'exit_long'] = True
            dataframe.loc[cond_cross_down, 'exit_tag'] = 'cross_pm1_down'
            
        except Exception as e:
            print(f"Error in populate_exit_trend: {e}")

        return dataframe