# source: https://raw.githubusercontent.com/jaredrsommer/freqtradestrategies/63cd46ea087ed8ed01f7d54d8cfcf1dbed166b04/OmaGann.py
from freqtrade.strategy import IStrategy
from freqtrade.strategy import IntParameter, DecimalParameter
from pandas import DataFrame
import numpy as np
import pandas_ta as ta

'''
      ______   __          __              __    __   ______   __    __        __     __    __             ______            
 /      \ /  |       _/  |            /  |  /  | /      \ /  \  /  |      /  |   /  |  /  |           /      \           
/$$$$$$  |$$ |____  / $$ |    _______ $$ | /$$/ /$$$$$$  |$$  \ $$ |     _$$ |_  $$ |  $$ |  _______ /$$$$$$  |  _______ 
$$ |  $$/ $$      \ $$$$ |   /       |$$ |/$$/  $$ ___$$ |$$$  \$$ |    / $$   | $$ |__$$ | /       |$$$  \$$ | /       |
$$ |      $$$$$$$  |  $$ |  /$$$$$$$/ $$  $$<     /   $$< $$$$  $$ |    $$$$$$/  $$    $$ |/$$$$$$$/ $$$$  $$ |/$$$$$$$/ 
$$ |   __ $$ |  $$ |  $$ |  $$ |      $$$$$  \   _$$$$$  |$$ $$ $$ |      $$ | __$$$$$$$$ |$$ |      $$ $$ $$ |$$      \ 
$$ \__/  |$$ |  $$ | _$$ |_ $$ \_____ $$ |$$  \ /  \__$$ |$$ |$$$$ |      $$ |/  |     $$ |$$ \_____ $$ \$$$$ | $$$$$$  |
$$    $$/ $$ |  $$ |/ $$   |$$       |$$ | $$  |$$    $$/ $$ | $$$ |______$$  $$/      $$ |$$       |$$   $$$/ /     $$/ 
 $$$$$$/  $$/   $$/ $$$$$$/  $$$$$$$/ $$/   $$/  $$$$$$/  $$/   $$//      |$$$$/       $$/  $$$$$$$/  $$$$$$/  $$$$$$$/  
                                                                   $$$$$$/                                               
                                                                                                                         
'''     

class Github_jaredrsommer_freqtradestrategies__OmaGann__20260509_225308(IStrategy):
    # Hyperopt parameters
    len_param = IntParameter(5, 20, default=10, space="buy")
    const_param = DecimalParameter(1.5, 5, default=2.5, space="buy")
    clsper_param = IntParameter(1, 5, default=1, space="buy")

    timeframe = '30m'
    minimal_roi = {"0": 0.1}
    stoploss = -0.1

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Calculate OMA with adaptive logic
        def oma_series(src_series, length, const, adaptive=True):
            series = src_series.copy()
            e1 = series.ewm(alpha=1/length, adjust=adaptive).mean()
            e2 = e1.ewm(alpha=1/length, adjust=adaptive).mean()
            v1 = 1.5*e1 - 0.5*e2
            
            e3 = v1.ewm(alpha=1/length, adjust=adaptive).mean()
            e4 = e3.ewm(alpha=1/length, adjust=adaptive).mean()
            v2 = 1.5*e3 - 0.5*e4
            
            e5 = v2.ewm(alpha=1/length, adjust=adaptive).mean()
            e6 = e5.ewm(alpha=1/length, adjust=adaptive).mean()
            return 1.5*e5 - 0.5*e6

        # Get hyperopt values
        len_val = int(self.len_param.value)
        const_val = float(self.const_param.value)
        clsper_val = int(self.clsper_param.value)

        # Calculate OMA values
        dataframe['high_ma'] = oma_series(dataframe['high'], len_val, const_val)
        dataframe['low_ma'] = oma_series(dataframe['low'], len_val, const_val)
        dataframe['close_ma'] = oma_series(dataframe['close'], clsper_val, const_val)

        # Calculate Gann HiLo Activator
        jfghla = []
        for i in range(len(dataframe)):
            if i == 0:
                jfghla.append(np.nan)
                continue
                
            close_ma = dataframe['close_ma'].iloc[i]
            prev_high_ma = dataframe['high_ma'].iloc[i-1]
            prev_low_ma = dataframe['low_ma'].iloc[i-1]
            
            if close_ma > prev_high_ma:
                jfghla.append(dataframe['low_ma'].iloc[i])
            elif close_ma < prev_low_ma:
                jfghla.append(dataframe['high_ma'].iloc[i])
            else:
                jfghla.append(jfghla[-1] if len(jfghla) > 0 else np.nan)
        
        dataframe['jfghla'] = jfghla
        dataframe['trend'] = np.where(dataframe['close_ma'] > dataframe['jfghla'], 1, 
                                    np.where(dataframe['close_ma'] < dataframe['jfghla'], -1, 0))
        
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Long entry when trend turns positive
        dataframe.loc[
            (dataframe['trend'] == 1) &
            (dataframe['trend'].shift(1) <= 0),
            'enter_long'] = 1

        # Short entry when trend turns negative
        dataframe.loc[
            (dataframe['trend'] == -1) &
            (dataframe['trend'].shift(1) >= 0),
            'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exit long when trend turns negative
        dataframe.loc[
            (dataframe['trend'] == -1) &
            (dataframe['trend'].shift(1) >= 0),
            'exit_long'] = 1

        # Exit short when trend turns positive
        dataframe.loc[
            (dataframe['trend'] == 1) &
            (dataframe['trend'].shift(1) <= 0),
            'exit_short'] = 1

        return dataframe