# source: https://raw.githubusercontent.com/hextropian/hextropian-freqtrade-bots/4d27ed056fcdcb026cde32e4591fd54d76656b55/user_data/strategies/TheForceMod_5.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement

import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame, Series

from freqtrade.strategy import IStrategy

import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


class github_hextropian_hextropian_freqtrade_bots__TheForceMod_5__20220913_053352(IStrategy):
    """
    Originally based in the ideas of TheForce, particularly using crosses on EMA5 close and open as triggers
    along with Stochastic fast.
    https://github.com/StephaneTurquay/freqtrade-strategies-crypto-trading-bot

    This version adds tweaks the use of the MACD for entries and exits.
    ----
    Mods made by @hextropian (Twitter), a.k.a. as DrWho?#8511 (Discord)
    Use at your own risk - no warranties of success whatsoever.
    """
    INTERFACE_VERSION = 3

    minimal_roi = {
        # These parameters below were generated via 1000X hyperoptimization for a selected portfolio of
        # 48 tokens/coins, fitted from 8/1/22 to 9/12/22
        # 891/1000:    393 trades. 368/0/25 Wins/Draws/Losses. Avg profit   
        # 0.33%. Median profit   
        # 0.01%. Total profit 2390.28582140 USDT (  11.12%). 
        # Avg duration 1 day, 0:35:00 min. Objective: -12.78700
        "0": 0.264,
        "102": 0.068,
        "270": 0.021,
        "536": 0
    }

    stoploss = -0.166

    # Trailing stoploss (hyperopted)
    trailing_stop = True
    trailing_stop_positive = 0.246
    trailing_stop_positive_offset = 0.309
    trailing_only_offset_is_reached = True

    # Optimal timeframe for the strategy.
    timeframe = '15m'

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

    # These values can be overridden in the "ask_strategy" section in the config.
    use_exit_signal = False
    # exit_profit_only = True is dangerous. You need to keep a close eye in case of a strong
    # downtrend and control your exits manually. Only recommended for testing.
    exit_profit_only = False
    ignore_roi_if_entry_signal = True

    # Number of candles the strategy requires before producing valid signals
    startup_candle_count: int = 30

    custom_info = {}
    
    plot_config = {
        # Main plot indicators (Moving averages, ...)
        'main_plot': {
            'ema5c': {'color': 'green'},
            'ema5o': {'color': 'yellow'},
            'mavm': {'color': 'white'},
        },
        'subplots': {
            # Subplots - each dict defines one additional plot
            "MACD": {
                'macd': {'color': 'blue'},
                'macdsignal': {'color': 'orange'},
            }
        }
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) :
        """
        Indicators we need for the selected timeframe (15m)
        """
        
        # Momentum Indicators
        # ------------------------------------

        # Stochastic Fast
        stoch_fast = ta.STOCHF(dataframe,5,3,3)
        dataframe['fastd'] = stoch_fast['fastd']
        dataframe['fastk'] = stoch_fast['fastk']

        # MACD
        macd = ta.MACD(dataframe,12,26,1)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']

        # EMA - Exponential Moving Average for open and close

        dataframe['ema5c'] = ta.EMA(dataframe['close'], timeperiod=5)
        dataframe['ema5o'] = ta.EMA(dataframe['open'], timeperiod=5)

        # MAVW indicator
        dataframe['mavw'] = MAVW(dataframe)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) :
        """
        Entry (buy) rules
        """
        dataframe.loc[
            (
                (dataframe['low'] >= dataframe['mavw'])
                &
                (dataframe['ema5c'] >= dataframe['ema5o'])
                &
                (dataframe['fastk'] >= dataframe['fastd'])
                &
                (
                    (dataframe['fastk'] >= 20) & (dataframe['fastk'] <= 80)
                    &
                    (dataframe['fastd'] >= 20) & (dataframe['fastd'] <= 80)
                )
                &
                (
                    (dataframe['macdhist'] >= dataframe['macdhist'].shift(1))
                    |
                    (
                        (dataframe['macd'] > dataframe['macd'].shift(1))
                        &
                        (dataframe['macdsignal'] > dataframe['macdsignal'].shift(1))
                    )
                )
                &
                (
                    (dataframe['close'] > dataframe['close'].shift(1))
                )
            ),
            'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) :
        """
        Exit (sell) rules
        """
        dataframe.loc[
            (
                (
                    (
                        (dataframe['fastk'] < dataframe['fastd'])
                        &
                        (dataframe['fastk'] < 80)
                        &
                        (
                            (dataframe['macd'] < dataframe['macd'].shift(1))
                            &
                            (dataframe['macdsignal'] < dataframe['macdsignal'].shift(1))
                            &
                            (dataframe['macdhist'] < dataframe['macdhist'].shift(1))
                        )
                        &
                        (
                            (dataframe['ema5c'] < dataframe['ema5o'])
                        )
                        &
                        (
                            (dataframe['close'] < dataframe['open'])
                        )
                        &
                        (
                            (dataframe['close'] < dataframe['ema5c'])
                        )
                    )
                )
            ),
            'exit_long'] = 1
        return dataframe

# MavilimW indicator
def MAVW(dataframe, fmal=3, smal=5):
    """
    Python implementation of the MavilimW indicator by KivancOzbilgic
    https://www.tradingview.com/v/IAssyObN/
    """
    tmal = fmal + smal
    Fmal = smal + tmal
    Ftmal = tmal + Fmal
    Smal = Fmal + Ftmal
    M1 = ta.WMA(dataframe['close'], timeperiod=fmal)
    M2 = ta.WMA(M1, timeperiod=smal)
    M3 = ta.WMA(M2, timeperiod=tmal)
    M4 = ta.WMA(M3, timeperiod=Fmal)
    M5 = ta.WMA(M4, timeperiod=Ftmal)
    return Series(ta.WMA(M5, timeperiod=Smal))
