# source: https://raw.githubusercontent.com/Jarrodsz/freqtrade-test/492736cee485b116cac95431dc3906a71c4fa678/ProfitAvalon.py
from typing import Dict, List
from freqtrade.strategy import IStrategy
import talib.abstract as ta
from pandas import DataFrame
import pandas as pd
from freqtrade.strategy import IntParameter
import talib.abstract
from technical.indicators import ichimoku
import numpy as np


def calc_supertrend(dataframe, period, multiplier):
    #print("calc_supertrend")
    close = dataframe['close']
    supertrend = [np.nan] * len(close)
    supertrend[0] = ((dataframe['high'][0] + dataframe['low'][0]) / 2) + (multiplier * talib.ATR(dataframe['high'], dataframe['low'], close, timeperiod=period)[0])
    for i in range(1, len(close)):
        atr = talib.ATR(dataframe['high'], dataframe['low'], close, timeperiod=period)[i]
        supertrend[i] = max(((dataframe['high'][i] + dataframe['low'][i]) / 2) + (multiplier * atr),
                            ((dataframe['high'][i] + dataframe['low'][i]) / 2) - (multiplier * atr),
                            supertrend[i - 1] if close[i] > supertrend[i - 1] else np.nan)
    return pd.Series(supertrend).fillna(0)  # Replace nan values with 0


class github_Jarrodsz_freqtrade_test__ProfitAvalon__20230405_180015(IStrategy):
    """
       author@: Jordan Lance
       idea:
       This is a trend-following strategy that aims to identify oversold conditions in the market using a combination of technical indicators.
       The strategy looks for buying opportunities when the 20-period EMA is above the Ichimoku cloud,
       the RSI is below 30, the SuperTrend is bullish, the WilliamsR is oversold, and the StochRSI is oversold.
       The buy signals are accompanied by a trailing stop-loss to minimize potential losses.

    """

    INTERFACE_VERSION: int = 3

    minimal_roi = {
        "0": 0.5
    }

    stoploss = -0.08

    timeframe = '1h'

    buy_range_long = IntParameter(5, 30, default=10)
    buy_range_short = IntParameter(3, 10, default=5)

    buy_params = {
        'ema_period': 15,
        'ichimoku_length': 15,
        'rsi_period': 10,
        'stochrsi_period': 10,
        'super_trend_period': 5,
        'super_trend_multiplier': 2.0,
        'williamsr_period': 10,
        'takeprofit': 0.10,
        'trailing_stop': True,
        'trailing_stop_positive': 0.03,
        'trailing_stop_positive_offset': 0.05,
        'trailing_only_offset_is_reached': True,
    }

    plot_config = {
        'main': {
            'height': 10,
            'add_subplot': True,
            'subplots': {
                'StochRSI': {
                    'rsi': {'color': 'blue'},
                    'stochrsi': {'color': 'red'},
                },
                'SuperTrend': {
                    'super_trend': {'color': 'green'},
                    'close': {'color': 'blue'},
                },
            },
        },
        'signals': {
            'height': 5,
            'add_subplot': True,
            'subplots': {
                'default': {
                    'buy_marker': 'green',
                    'sell_marker': 'red',
                    'marker_size': 10,
                },
            },
        },
    }

    def informative_pairs(self) -> List[str]:
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        # Add EMA indicator
        ema_periods = range(self.buy_range_short.value, self.buy_range_long.value + 1)
        ema_columns = [f'ema{val}' for val in ema_periods]
        for col, val in zip(ema_columns, ema_periods):
            dataframe[col] = ta.EMA(dataframe, timeperiod=val)

        # Long-term EMAs for market trend
        dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20)
        dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)

        # Add Ichimoku indicator
        ichi = ichimoku(dataframe)
        dataframe['tenkan'] = ichi['tenkan_sen']
        dataframe['kijun'] = ichi['kijun_sen']
        dataframe['senkou_a'] = ichi['senkou_span_a']
        dataframe['senkou_b'] = ichi['senkou_span_b']
        dataframe['cloud_green'] = ichi['cloud_green']
        dataframe['cloud_red'] = ichi['cloud_red']

        # Add RSI indicator
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.buy_params['rsi_period'])

        # Add StochRSI indicator
        stoch_k, stoch_d = ta.STOCH(dataframe['high'], dataframe['low'], dataframe['close'])
        dataframe['stochrsi_k'] = stoch_k
        dataframe['stochrsi_d'] = stoch_d

        # STOCH RSI
        stoch_rsi = ta.STOCHRSI(dataframe)
        dataframe['fastd_rsi'] = stoch_rsi['fastd']
        dataframe['fastk_rsi'] = stoch_rsi['fastk']

        # Add Supertrend with custom method?
        supertrend_period = self.buy_params['super_trend_period']
        supertrend_multiplier = self.buy_params['super_trend_multiplier']
        dataframe['supertrend'] = calc_supertrend(dataframe, supertrend_period, supertrend_multiplier)

        # Add WilliamsR indicator
        dataframe['williams_r'] = ta.WILLR(dataframe, timeperiod=self.buy_params['williamsr_period'])

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        condition1 = dataframe['ema_20'] > dataframe['senkou_a'] and dataframe['ema_20'] > dataframe['senkou_b']
        condition2 = dataframe['fastd_rsi'] < 30
        condition3 = dataframe['super_trend'] == True
        condition4 = dataframe['williams_r'] < -80
        condition5 = dataframe['stochrsi_k'] < 0.2

        # If all conditions are True, set 'buy' column to 1, otherwise set it to 0
        dataframe.loc[dataframe.index[-1], 'buy'] = (condition1 & condition2 & condition3 & condition4 & condition5).astype(int)

        return dataframe


    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        # If we have an open position and any of the following conditions are True,
        # we should close the position
        dataframe.loc[dataframe['close'] <= (1 + self.stoploss) * dataframe['buy_price'], 'sell'] = 1 if self.stoploss else 0
        dataframe.loc[dataframe['close'] >= (1 + self.takeprofit) * dataframe['buy_price'], 'sell'] = 1 if self.takeprofit else 0


        # If we have an open position and trailing stop-loss is enabled,
        # we should dynamically adjust our stop-loss
        stop_loss = self.buy_price * (1 - self.trailing_stop_positive)
        dataframe.loc[dataframe['close'] <= stop_loss * (1 + self.trailing_stop_positive_offset), 'stoploss'] = stop_loss * (1 + self.trailing_stop_positive_offset)
        self.trailing_only_offset_is_reached = (dataframe['close'] <= stop_loss * (1 + self.trailing_stop_positive_offset)).any()

        return dataframe
