freqtrade / freqtrade-strategies

Free trading strategies for Freqtrade bot
GNU General Public License v3.0
3.44k stars 1.13k forks source link

The Quantitative Qualitative Estimation (QQE) Strategy request. #260

Open JiSeopHyun opened 2 years ago

JiSeopHyun commented 2 years ago

For requestion a new strategy. Please use the template below.
Any strategy request that does not follow the template will be closed.

Step 1: What indicators are required?

I found an explanation that corresponds to QQE.

The Quantitative Qualitative Estimation (QQE) indicator is derived from Wilder’s famous Relative Strength Index (RSI). In essence, the QQE is a heavily smoothed RSI.

This is the original content. https://tradingtact.com/qqe-indicator/

And I also found some meaningful pseudo-code for this.

https://stackoverflow.com/questions/57164253/pinescript-to-python-getting-the-truth-value-of-a-series-is-ambiguous

Please list all the indicators required for the buy and sell strategy.

"(Volume Adjusted Moving Average) VAMA" , "Smoothed RSI" , "Slow Trailing"

Step 2: Explain the Buy Strategy

Please explain in details the indicators you need to run the buy strategy, then explain in detail what is the trigger to buy.

entry trend "Smoothed RSI" below "Slow Trailing" --> enter Short (Any Time) "Slow Trailing" below "Smoothed RSI" --> enter Long (Any Time) When VAMA is increased more than usual (hypetopt) is the best entry point

Step 1: Explain the Sell Strategy

exit trend "Smoothed RSI" crossed above "Slow Trailing" --> exit Short "Slow Trailing" crossed above "Smoothed RSI" --> exit Long When VAMA is increased more than usual (hypetopt)

Please explain in details the indicators you need to run the sell strategy, then explain in detail what is the trigger to sell.

Source

What come from this strategy? Cite your source:

This is my latest Fsupertrend that I have corrected.

--- Do not remove these libs ---

import numpy as np # noqa import pandas as pd # noqa from pandas import DataFrame # noqa from datetime import datetime # noqa from typing import Optional, Union # noqa

from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, IStrategy, IntParameter)

from numpy.lib import math import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib import logging from functools import reduce

class FSupertrendStrategy(IStrategy):

INTERFACE_VERSION: int = 3
# Buy hyperspace params:
buy_params = {
    "buy_m1": 4,
    "buy_m2": 7,
    "buy_m3": 1,
    "buy_p1": 8,
    "buy_p2": 9,
    "buy_p3": 8,
}

# Sell hyperspace params:
sell_params = {
    "sell_m1": 1,
    "sell_m2": 3,
    "sell_m3": 6,
    "sell_p1": 16,
    "sell_p2": 18,
    "sell_p3": 18,
}

# ROI table:
minimal_roi = {"0": 0.1, "30": 0.75, "60": 0.05, "120": 0.025}
# minimal_roi = {"0": 1}

# Stoploss:
stoploss = -0.265

# Can this strategy go short?
# can_short: bool = False
can_short: bool = True

# Trailing stop:
trailing_stop = True
trailing_stop_positive = 0.03 # old value 0.05
trailing_stop_positive_offset = 0.1
trailing_only_offset_is_reached = False # trailing_stop_positive_offset in use True

timeframe = "1h"

startup_candle_count = 25

buy_m1 = IntParameter(1, 7, default=1)
buy_m2 = IntParameter(1, 7, default=3)
buy_m3 = IntParameter(1, 7, default=4)
buy_p1 = IntParameter(7, 21, default=14)
buy_p2 = IntParameter(7, 21, default=10)
buy_p3 = IntParameter(7, 21, default=10)

sell_m1 = IntParameter(1, 7, default=1)
sell_m2 = IntParameter(1, 7, default=3)
sell_m3 = IntParameter(1, 7, default=4)
sell_p1 = IntParameter(7, 21, default=14)
sell_p2 = IntParameter(7, 21, default=10)
sell_p3 = IntParameter(7, 21, default=10)
ADD
# timeframe_select = CategoricalParameter(["5m", "15m","30m" , "1h" ], default="1h", space="buy")
# if timeframe_select.value == "5m" :
#     timeframe = "5m"
# if timeframe_select.value == "15m" :
#     timeframe = "15m"
# if timeframe_select.value == "30m" :
#     timeframe = "30m"
# if timeframe_select.value == "1h" :
#     timeframe = "1h"

# EnterL_bollinger_enabled = CategoricalParameter([True, False], default=False, space="buy")
# EnterL_trigger_bollinger = CategoricalParameter(["bb_middleband", "bb_lowerband"], default="bb_lowerband", space="buy")

# EnterS_bollinger_enabled = CategoricalParameter([True, False], default=False, space="sell")
# EnterS_trigger_bollinger = CategoricalParameter(["bb_upperband", "bb_middleband"], default="bb_upperband", space="sell")

# ExitL_bollinger_enabled = CategoricalParameter([True, False], default=False, space="buy")
# ExitL_trigger_bollinger = CategoricalParameter(["bb_middleband", "bb_lowerband"], default="bb_lowerband", space="buy")

# ExitS_bollinger_enabled = CategoricalParameter([True, False], default=False, space="sell")
# ExitS_trigger_bollinger = CategoricalParameter(["bb_upperband", "bb_middleband"], default="bb_upperband", space="sell")
def version(self) -> str:
    return "1.2"

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    # # Bollinger bands
    # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=17, stds=2)
    # dataframe['bb_lowerband'] = bollinger['lower']
    # dataframe['bb_middleband'] = bollinger['mid']
    # dataframe['bb_upperband'] = bollinger['upper']

    # dataframe['cci_one'] = ta.CCI(dataframe, timeperiod=17)

    frames = [dataframe]
    for multiplier in self.buy_m1.range:
        for period in self.buy_p1.range:
            frames.append(DataFrame({
                f'supertrend_1_buy_{multiplier}_{period}' : self.supertrend ( dataframe, multiplier, period )['STX']
            }))

    for multiplier in self.buy_m2.range:
        for period in self.buy_p2.range:
            frames.append(DataFrame({
                f'supertrend_2_buy_{multiplier}_{period}' : self.supertrend ( dataframe, multiplier, period )['STX']
            }))

    for multiplier in self.buy_m3.range:
        for period in self.buy_p3.range:
            frames.append(DataFrame({
                f'supertrend_3_buy_{multiplier}_{period}' : self.supertrend ( dataframe, multiplier, period )['STX']
            }))                

    for multiplier in self.sell_m1.range:
        for period in self.sell_p1.range:
            frames.append(DataFrame({
                f'supertrend_1_sell_{multiplier}_{period}' : self.supertrend ( dataframe, multiplier, period )['STX']
            }))                

    for multiplier in self.sell_m2.range:
        for period in self.sell_p2.range:
            frames.append(DataFrame({
                f'supertrend_2_sell_{multiplier}_{period}' : self.supertrend ( dataframe, multiplier, period )['STX']
            }))                 

    for multiplier in self.sell_m3.range:
        for period in self.sell_p3.range:
            frames.append(DataFrame({
                f'supertrend_3_sell_{multiplier}_{period}' : self.supertrend ( dataframe, multiplier, period )['STX']
            }))                  

    # Append columns to existing dataframe
    merged_frame = pd.concat(frames, axis=1)

    return merged_frame

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

    conditions = []

    conditions.append ( dataframe[f'supertrend_1_buy_{self.buy_m1.value}_{self.buy_p1.value}'] == "up" )

    conditions.append ( dataframe[f'supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}'] == "up" )

    conditions.append ( dataframe[f'supertrend_3_buy_{self.buy_m3.value}_{self.buy_p3.value}'] == "up" )

    conditions.append ( dataframe['volume'] > 0 )

    # if self.EnterL_bollinger_enabled.value:

    #     if self.EnterL_trigger_bollinger.value == "bb_middleband" :

    #         conditions.append ( dataframe['low'] < dataframe['bb_middleband'] )

    #     if self.EnterL_trigger_bollinger.value == "bb_lowerband" :

    #         conditions.append ( dataframe['low'] < dataframe['bb_lowerband'] )

    if conditions:

        dataframe.loc[

            reduce(lambda x, y: x & y, conditions), ['enter_long','enter_tag']

        ] = ( 1 , 'FSupertrendStrategy_InL' )

    conditions = []

    conditions.append ( dataframe[f'supertrend_1_sell_{self.sell_m1.value}_{self.sell_p1.value}'] == "down" )

    conditions.append ( dataframe[f'supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}'] == "down" )

    conditions.append ( dataframe[f'supertrend_3_sell_{self.sell_m3.value}_{self.sell_p3.value}'] == "down" )

    conditions.append ( dataframe['volume'] > 0 )

    # if self.EnterS_bollinger_enabled.value:

    #     if self.EnterS_trigger_bollinger.value == "bb_upperband" :

    #         conditions.append ( dataframe['high'] > dataframe['bb_upperband'] )

    #     if self.EnterS_trigger_bollinger.value == "bb_middleband" :

    #         conditions.append ( dataframe['high'] > dataframe['bb_middleband'] )

    if conditions:

        dataframe.loc[

            reduce(lambda x, y: x & y, conditions), ['enter_short','enter_tag']

        ] = ( 1 , 'FSupertrendStrategy_InS' )

    return dataframe

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

    conditions = []

    conditions.append ( dataframe[ f'supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}'] == "down" )

    conditions.append ( dataframe['volume'] > 0 )

    # if self.ExitL_bollinger_enabled.value:

    #     if self.ExitL_trigger_bollinger.value == "bb_upperband" :

    #         conditions.append ( dataframe['high'] > dataframe['bb_upperband'] )

    #     if self.ExitL_trigger_bollinger.value == "bb_middleband" :

    #         conditions.append ( dataframe['high'] > dataframe['bb_middleband'] )

    if conditions:

        dataframe.loc[

            reduce(lambda x, y: x & y, conditions), ['exit_long','exit_tag']

        ] = ( 1 , 'FSupertrendStrategy_OutL' )

    conditions = []

    conditions.append (  dataframe[f'supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}'] == "up" )

    conditions.append ( dataframe['volume'] > 0 )

    # if self.ExitS_bollinger_enabled.value:

    #     if self.ExitS_trigger_bollinger.value == "bb_upperband" :

    #         conditions.append ( dataframe['high'] > dataframe['bb_upperband'] )

    #     if self.ExitS_trigger_bollinger.value == "bb_middleband" :

    #         conditions.append ( dataframe['high'] > dataframe['bb_middleband'] )

    if conditions:

        dataframe.loc[

            reduce(lambda x, y: x & y, conditions), ['exit_short','exit_tag']

        ] = ( 1 , 'FSupertrendStrategy_OutS' )

    return dataframe

"""
    Supertrend Indicator; adapted for freqtrade
    from: https://github.com/freqtrade/freqtrade-strategies/issues/30
"""

def supertrend(self, dataframe: DataFrame, multiplier, period):
    df = dataframe.copy()

    df["TR"] = ta.TRANGE(df)
    df["ATR"] = ta.SMA(df["TR"], period)

    st = "ST_" + str(period) + "_" + str(multiplier)
    stx = "STX_" + str(period) + "_" + str(multiplier)

    # Compute basic upper and lower bands
    df["basic_ub"] = (df["high"] + df["low"]) / 2 + multiplier * df["ATR"]
    df["basic_lb"] = (df["high"] + df["low"]) / 2 - multiplier * df["ATR"]

    # Compute final upper and lower bands
    df["final_ub"] = 0.00
    df["final_lb"] = 0.00
    for i in range(period, len(df)):
        df["final_ub"].iat[i] = (
            df["basic_ub"].iat[i]
            if df["basic_ub"].iat[i] < df["final_ub"].iat[i - 1]
            or df["close"].iat[i - 1] > df["final_ub"].iat[i - 1]
            else df["final_ub"].iat[i - 1]
        )
        df["final_lb"].iat[i] = (
            df["basic_lb"].iat[i]
            if df["basic_lb"].iat[i] > df["final_lb"].iat[i - 1]
            or df["close"].iat[i - 1] < df["final_lb"].iat[i - 1]
            else df["final_lb"].iat[i - 1]
        )

    # Set the Supertrend value
    df[st] = 0.00
    for i in range(period, len(df)):
        df[st].iat[i] = (
            df["final_ub"].iat[i]
            if df[st].iat[i - 1] == df["final_ub"].iat[i - 1]
            and df["close"].iat[i] <= df["final_ub"].iat[i]
            else df["final_lb"].iat[i]
            if df[st].iat[i - 1] == df["final_ub"].iat[i - 1]
            and df["close"].iat[i] > df["final_ub"].iat[i]
            else df["final_lb"].iat[i]
            if df[st].iat[i - 1] == df["final_lb"].iat[i - 1]
            and df["close"].iat[i] >= df["final_lb"].iat[i]
            else df["final_ub"].iat[i]
            if df[st].iat[i - 1] == df["final_lb"].iat[i - 1]
            and df["close"].iat[i] < df["final_lb"].iat[i]
            else 0.00
        )
    # Mark the trend direction up/down
    df[stx] = np.where(
        (df[st] > 0.00), np.where((df["close"] < df[st]), "down", "up"), np.NaN
    )

    # Remove basic and final bands from the columns
    df.drop(["basic_ub", "basic_lb", "final_ub", "final_lb"], inplace=True, axis=1)

    df.fillna(0, inplace=True)

    return DataFrame(index=df.index, data={"ST": df[st], "STX": df[stx]})

def leverage(self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str, **kwargs) -> float:
    # """
    # Customize leverage for each new trade. This method is only called in futures mode.

    # :param pair: Pair that's currently analyzed
    # :param current_time: datetime object, containing the current datetime
    # :param current_rate: Rate, calculated based on pricing settings in exit_pricing.
    # :param proposed_leverage: A leverage proposed by the bot.
    # :param max_leverage: Max leverage allowed on this pair
    # :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
    # :param side: 'long' or 'short' - indicating the direction of the proposed trade
    # :return: A leverage amount, which is between 1.0 and max_leverage.
    # """

    return 4.0

########################### Original source: Juan Carlos Soriano ###########################

References

https://www.freqtrade.io/en/stable/strategy-advanced/#performance-warning https://www.freqtrade.io/en/stable/strategy-advanced/ https://www.freqtrade.io/en/stable/strategy-callbacks/#leverage-callback

I use the "Fsupertrend" strategy to backtest the practice and optimization. It brought a profit, but there were many cases where you could buy at the highs and sell at the lows and lose money. I came across QQE while searching for power to compensate for this. Thank you to everyone involved in the Freqtrade projector for their hard work. And it is a projector that helps several programmers and ordinary investors. I'm using a transformer.

xmatthias commented 2 years ago

I think this request is combining 2 things, which should really be separate as they're not really related. It's one point to request a strategy (based on a new or existing indicator) - however the FSupertrend stuff is not related to this new strategy/indicator. While it could be added to it - the request doesn't include this - and i think it produces different signals than supertrend, anyway.

If you've made improvements to a strategy you'd like to contribute, i'd apreciate a Pull request - which is adding the changes directly to the repository.