from freqtrade.strategy import IStrategy, DecimalParameter
from pandas import DataFrame, Series

# --------------------------------

import talib.abstract as ta
import pandas as pd


# Notes: ** DON'T GO LIVE ** with this strat. Risk of big losses.
# ==============================================================
# Now it works with every pair.
# Probably it works only with "calm" market. For more volatility there are better strats.
# Remember to set "timeframe": "1m" in config.


# Chaikin Money Flow
def chaikin_mf(df, periods=20):
    close = df['close']
    low = df['low']
    high = df['high']
    volume = df['volume']
    mfv = ((close - low) - (high - close)) / (high - low)
    mfv = mfv.fillna(0.0)
    mfv *= volume
    cmf = mfv.rolling(periods).sum() / volume.rolling(periods).sum()
    return Series(cmf, name='cmf')


# Percentage Price Oscillator
def PPO(dataframe, fastperiod, slowperiod, signalperiod):
    df = dataframe.copy()
    fast = ta.SMA(df, fastperiod)
    slow = ta.SMA(df, slowperiod)
    ppo = 100 * (fast - slow) / slow
    signal = ta.SMA(ppo, signalperiod)
    df['histogram'] = ppo - signal
    return df['histogram']

    

class RabbitV2_1mTimeFrame(IStrategy):

    minimal_roi = {
        "0": 0.06
    }
    stoploss = -1.0

    timeframe = '1m'
 
    # Sell signal
    use_sell_signal = True
    sell_profit_only = False
    ignore_roi_if_buy_signal = False

    # Run "populate_indicators()" only for new candle.
    process_only_new_candles = False

    # Number of candles the strategy requires before producing valid signals
    startup_candle_count = 100


    buy_sens_ema   = DecimalParameter(0.0, 1.0,   default=0.05,  decimals=2, space='buy',  optimize=True, load=True)
    buy_sens_ppo   = DecimalParameter(-1.0, 0.0,  default=-0.10, decimals=2, space='buy',  optimize=True, load=True)
    buy_hist_gain  = DecimalParameter(-1.0, 0.0,  default=0.40, decimals=2, space='buy',   optimize=True, load=True)

    sell_sens_ema  = DecimalParameter(0.0, 1.0,   default=0.02,  decimals=2, space='sell', optimize=True, load=True)
    sell_sens_ppo  = DecimalParameter(0.0, 0.9,   default=0.20,  decimals=2, space='sell', optimize=True, load=True)
    sell_hist_gain = DecimalParameter(0.0, 1.0,   default=0.40,  decimals=2, space='sell', optimize=True, load=True)

    # Buy hyperspace params:
    buy_params = {
        "buy_hist_gain": -0.95,
        "buy_sens_ema": 0.12,
        "buy_sens_ppo": -0.11,
    }

    # Sell hyperspace params:
    sell_params = {
        "sell_hist_gain": 0.41,
        "sell_sens_ema": 0.49,
        "sell_sens_ppo": 0.42,
    }

    #buy_sens_ema = 0.03
    #sell_sens_ema = 0.02
    #buy_sens_ppo = -0.4
    #sell_sens_ppo = 0.5
    #buy_hist_gain = -0.50
    #sell_hist_gain = 0.20

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

         # EMA        
        dataframe['ema_fast'] = ta.EMA(dataframe, 15)
        dataframe['ema_slow'] = ta.EMA(dataframe, 100)

        # Chaikin Money Flow
        dataframe['cmf'] = chaikin_mf(dataframe)

        # Percentage Price Oscillator
        dataframe['ppohist'] = PPO(dataframe, 12, 26, 50)
        
        return dataframe
                

    # ============== BUY ======================

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

        dataframe.loc[
            (   (dataframe['ppohist'] < self.buy_sens_ppo.value)      
                &
                (dataframe['ppohist'] > (dataframe['ppohist'].shift(1) - dataframe['ppohist'].shift(1)*self.buy_hist_gain.value/100))                
                &
                (dataframe['ema_fast'] < dataframe['ema_slow']) 
                &
                (dataframe['ema_fast'] > (dataframe['ema_fast'].shift(1) + dataframe['ema_fast'].shift(1)*self.buy_sens_ema.value/100)) 
                &
                (dataframe['ema_fast'] > (dataframe['ema_fast'].shift(2) + dataframe['ema_fast'].shift(2)*self.buy_sens_ema.value/100)) 
                &
                (dataframe['cmf'] < -0.10) #Chaikin MF
                &                
                (dataframe['volume'] > 0)            
            ),            
            'buy'] = 1            
        return dataframe

    # ============== SELL ======================

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

        dataframe.loc[
            (
                (dataframe['ppohist'] >= self.sell_sens_ppo.value)      
                &
                (dataframe['ppohist'] < (dataframe['ppohist'].shift(1) - dataframe['ppohist'].shift(1)*self.sell_hist_gain.value/100))                
                &
                (dataframe['ema_fast'] > dataframe['ema_slow'])
                &
                (dataframe['ema_fast'] <= (dataframe['ema_fast'].shift(1) + dataframe['ema_fast'].shift(1)*self.sell_sens_ema.value/100)) 
                &                
                (dataframe['cmf'] >= 0.10) #Chaikin MF
                &                
                (dataframe['volume'] > 0)
            ),
            'sell'] = 1
        return dataframe

    plot_config = {
      'main_plot':{
            'ema_slow':{},            
            'ema_fast':{}
        },
        'subplots': {
            "PPO": {
                'ppohist':{'color':'black'},
            },
            "CMF" : {
                'cmf' : {'color':'red'}
            }
        }

    }  
