# source: https://raw.githubusercontent.com/cycle-luca/reqtrade-strategies/e589f2c35dfda347f2ea94637ecda003bfdeda45/macd.py
#!/usr/bin/env python
# coding=utf-8
'''
Author: Luca Shaw
LastEditors: Luca Shaw
email: xiaosuyang@cndatacom.com
Date: 2023-03-20 12:12:26
LastEditTime: 2023-03-20 13:28:06
Description: Modify here please
FilePath: \reqtrade-strategies\macd.py
'''
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional, Union
from freqtrade.strategy import (
    BooleanParameter,
    CategoricalParameter,
    DecimalParameter,
    IntParameter,
    IStrategy,
    merge_informative_pair,
)
import talib.abstract as ta
import pandas_ta as pta
from technical import qtpylib

class github_cycle_luca_reqtrade_strategies__macd__20230320_074120(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = '5m'
    can_short = True
    startup_candle_count = 50
    buy_pow = DecimalParameter(0, 4, decimals=3, default=3.849, space="buy")
    sell_pow = DecimalParameter(0, 4, decimals=3, default=3.798, space="sell")
    fast_period = IntParameter(1, 50, default=13, space="fast")
    slow_period = IntParameter(1, 100, default=34, space="slow")
    atr_period = IntParameter(1, 50, default=14, space="atr")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        macd = ta.github_cycle_luca_reqtrade_strategies__macd__20230320_074120(
            dataframe,
            self.fast_period.value,
            self.slow_period.value,
            9,
        )
        dataframe["macd"] = macd["macd"]
        dataframe["macd_signal"] = macd["macdsignal"]
        dataframe["macd_hist"] = macd["macdhist"]
        dataframe["atr"] = ta.ATR(dataframe, self.atr_period.value)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        k_low = (dataframe["low"] < dataframe["low"].shift(1))
        macd_bull_div = (
            (dataframe["macd_hist"] < 0)
            & (dataframe["macd_hist"].shift(1) < dataframe["macd_hist"])
        )
        macd_peak = (
            (dataframe["macd_hist"] > 0)
            & (dataframe["macd_hist"].shift(1) > dataframe["macd_hist"])
        )
        key_candle = (
            (dataframe["macd_hist"].shift(1) < 0)
            & (dataframe["macd_hist"] >= 0)
        )
        conditions = (
            k_low.rolling(window=3).sum() == 3
            & macd_bull_div.rolling(window=3).sum() == 3
            & macd_peak.rolling(window=3).sum() == 3
            & key_candle.rolling(window=3).sum() > 0
        )
        dataframe.loc[conditions, "enter_long"] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        macd = ta.github_cycle_luca_reqtrade_strategies__macd__20230320_074120(
            dataframe["close"],
            fastperiod=13,
            slowperiod=34,
        )
        dataframe["macd"] = macd["macd"]
        dataframe["macd_signal"] = macd["macd_signal"]
        dataframe["macd_hist"] = macd["macd_hist"]

        atr_stop_loss = qtpylib.atr_stop_loss(
            dataframe,
            atr_multiplier=3,
            length=21,
        )

        exit_long_conditions = (
            (dataframe['low'].rolling(3).min() == dataframe['low']) &
            (dataframe['macd_hist'].rolling(2).apply(lambda x: x[0] > x[1] and x[1] < 0 and x[0] < 0)) &
            (dataframe['macd_hist'].shift(1) > 0) &
            (dataframe['macd_hist'] < 0)
        )
        dataframe.loc[exit_long_conditions, 'exit_long'] = 1
        dataframe['stop_loss'] = dataframe['macd_hist'].rolling(2).apply(
            lambda x: max(dataframe['low'].iloc[x.index[0]:x.index[1]+1]) - atr_stop_loss['atr_stoploss'].iloc[x.index[1]]
            if x[0] > x[1] and x[1] < 0 and x[0] < 0 else np.nan,
            raw=True
        )

        # Exit Short
        exit_short_conditions = (
            (dataframe['high'].rolling(3).max() == dataframe['high']) &
            (dataframe['macd_hist'].rolling(2).apply(lambda x: x[0] < x[1] and x[1] > 0 and x[0] > 0)) &
            (dataframe['macd_hist'].shift(1) < 0) &
            (dataframe['macd_hist'] > 0)
        )
        dataframe.loc[exit_short_conditions, 'exit_short'] = 1
        dataframe['stop_loss'] = dataframe['macd_hist'].rolling(2).apply(
            lambda x: min(dataframe['high'].iloc[x.index[0]:x.index[1]+1]) + atr_stop_loss['atr_stoploss'].iloc[x.index[1]]
            if x[0] < x[1] and x[1] > 0 and x[0] > 0 else np.nan,
            raw=True
        )

        return dataframe
