From 86bd9e2dcf14dae180d2cc730f41574162904c9c Mon Sep 17 00:00:00 2001 From: OtenMoten <32872932+OtenMoten@users.noreply.github.com> Date: Mon, 15 Mar 2021 12:42:01 +0100 Subject: [PATCH 1/4] Create HO-Strategy005.py --- user_data/hyperopts/HO-Strategy005.py | 171 ++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 user_data/hyperopts/HO-Strategy005.py diff --git a/user_data/hyperopts/HO-Strategy005.py b/user_data/hyperopts/HO-Strategy005.py new file mode 100644 index 0000000..a43ec44 --- /dev/null +++ b/user_data/hyperopts/HO-Strategy005.py @@ -0,0 +1,171 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement + +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +from pandas import DataFrame +from typing import Dict, Any, Callable, List +from functools import reduce +from skopt.space import Categorical, Dimension, Integer, Real +from freqtrade.optimize.hyperopt_interface import IHyperOpt + +__author__ = "Kevin Ossenbrueck" +__github__ = "github.com/OtenMoten" +__linkedin__ = "linkedin.com/in/kevin-ossenbrueck/?locale=en_US" +__twitter__ = "twitter.com/ossenbrueck" +__instagram__ = "instagram.com/kevin_ossenbrueck" +__facebook__ = "facebook.com/kevin.ossenbrueck" +__creator__ = ["github.com/xmatthias", "github.com/mishaker"] +__credits__ = ["MontrealTradingGroup", "Udemy", "Mohsen Hassan", "Ilyass Tabiai"] +__version__ = "3.0" +__copyright__ = "GNU GPL" +__status__ = "Live" + +""" +I was inspired by: https://github.com/freqtrade/freqtrade-strategies/blob/master/user_data/strategies/Strategy005.py +Therefore, I wrote this hyperopt to make it more better. Thank you xmatthias and mishaker! +""" + +# Rolling volume range +volumeAvgValueMin = 50 +volumeAvgValueMax = 300 + +# RSI range +rsiValueMin = 1 +rsiValueMax = 100 + +# STOCH FAST range +fastdValueMin = 1 +fastdValueMax = 100 + +# MINUS DI range +minusdiValueMin = 1 +minusdiValueMax = 100 + +fishRsiNormaValueMin = 1 +fishRsiNormaValueMax = 100 + +class HODobby(IHyperOpt): + + """ + If you trade on Binance then the API endopoint is "api.binance.com". + It's based in Tokyo. You can get a VPS in Tokyo on Vultr with 2ms latency. + I feel free to share my referral link (you get a bonus too): + > https://www.vultr.com/?ref=8806640 + """ + + ############### THIS STRATEGY IS DESIGNED FOR 5m TIMEFRAME ############### + + @staticmethod + def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + # tadoc.org/indicator/MACD.htm + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + + # MINUS DI + # tadoc.org/indicator/MINUS_DI.htm + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # RSI + # tadoc.org/indicator/RSI.htm + # tradingview.com/scripts/fishertransform/ + # goo.gl/2JGGoy + dataframe['rsi'] = ta.RSI(dataframe) + rsi = 0.1 * (dataframe['rsi'] - 50) + dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) # Inverse Fisher transform on RSI, values [-1.0, 1.0] + dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) # Inverse Fisher transform on RSI normalized, value [0.0, 100.0] + + # STOCH FAST + # tadoc.org/indicator/STOCHF.htm + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # SAR + dataframe['sar'] = ta.SAR(dataframe) + + # SMA + dataframe['sma'] = ta.SMA(dataframe, timeperiod=50) + + return dataframe + + @staticmethod + def buy_strategy_generator(params: Dict[str, Any]) -> Callable: + + def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = [] + + # TRIGGER and GUARD + if 'buy-trigger' in params: + + conditions.append(dataframe['close'] > 0.00000200) + conditions.append(dataframe['volume'] > dataframe['volume'].rolling(params['volumeAVG-buy-value']).mean()) + conditions.append(dataframe['close'] < dataframe['sma']) + conditions.append(dataframe['rsi'] > params['rsi-buy-value']) + conditions.append(dataframe['fastd'] > dataframe['fastk']) + conditions.append(dataframe['fastd'] > params['fastd-buy-value']) + conditions.append(dataframe['fisher_rsi_norma'] < params['fishRsiNorma-buy-value']) + + if conditions: + dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1 + + return dataframe + + return populate_buy_trend + + @staticmethod + def indicator_space() -> List[Dimension]: + + buyTriggerList = ["True"] + + return [ + Integer(volumeAvgValueMin, volumeAvgValueMax, name='volumeAVG-buy-value'), + Integer(rsiValueMin, rsiValueMax, name='rsi-buy-value'), + Integer(fastdValueMin, fastdValueMax, name='fastd-buy-value'), + Integer(fishRsiNormaValueMin, fishRsiNormaValueMax, name='fishRsiNorma-buy-value'), + Categorical(buyTriggerList, name='buy-trigger') + ] + + @staticmethod + def sell_strategy_generator(params: Dict[str, Any]) -> Callable: + + def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: + + # TRIGGERS and GUARDS + # Solving a mistery: Which sell trigger is better? + # The winner of both will be displayed in the output of the hyperopt. + + conditions = [] + + if 'sell-trigger' in params: + if params['sell-trigger'] == 'rsi-macd-minusdi': + conditions.append(qtpylib.crossed_above(dataframe['rsi'], params['rsi-sell-value'])) + conditions.append(dataframe['macd'] < 0) + conditions.append(dataframe['minus_di'] > params['minusdi-sell-value']) + + if 'sell-trigger' in params: + if params['sell-trigger'] == 'sar-fisherRsi': + conditions.append(dataframe['sar'] > dataframe['close']) + conditions.append(dataframe['fisher_rsi'] > params['fishRsiNorma-sell-value']) + + if conditions: + dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 + + return dataframe + + return populate_sell_trend + + @staticmethod + def sell_indicator_space() -> List[Dimension]: + + sellTriggerList = ["rsi-macd-minusdi", "sar-fisherRsi"] + + return [ + Integer(rsiValueMin, rsiValueMax, name='rsi-sell-value'), + Integer(minusdiValueMin, minusdiValueMax, name='minusdi-sell-value'), + Integer(fishRsiNormaValueMin, fishRsiNormaValueMax, name='fishRsiNorma-sell-value'), + Categorical(sellTriggerList, name='sell-trigger') + ] From 58981b31669012e3842dc94f616cd50d079bc271 Mon Sep 17 00:00:00 2001 From: OtenMoten <32872932+OtenMoten@users.noreply.github.com> Date: Sun, 28 Mar 2021 15:22:21 +0200 Subject: [PATCH 2/4] Added second indicator (RSI) --- user_data/strategies/Swing-High-To-Sky.py | 66 +++++++++++------------ 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/user_data/strategies/Swing-High-To-Sky.py b/user_data/strategies/Swing-High-To-Sky.py index ea83bf9..eb25400 100644 --- a/user_data/strategies/Swing-High-To-Sky.py +++ b/user_data/strategies/Swing-High-To-Sky.py @@ -1,13 +1,11 @@ -# --- Do not remove these libs --- from freqtrade.strategy.interface import IStrategy from typing import Dict, List from functools import reduce from pandas import DataFrame -# -------------------------------- import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib -import numpy # noqa +import numpy __author__ = "Kevin Ossenbrück" __copyright__ = "Free For Use" @@ -18,60 +16,56 @@ __maintainer__ = "Kevin Ossenbrück" __email__ = "kevin.ossenbrueck@pm.de" __status__ = "Live" -class_name = 'SwingHighToSky' +# CCI timerperiods and values +cciBuyTP = 72 +cciBuyVal = -175 +cciSellTP = 66 +cciSellVal = -106 + +# RSI timeperiods and values +rsiBuyTP = 36 +rsiBuyVal = 90 +rsiSellTP = 45 +rsiSellVal = 88 + class SwingHighToSky(IStrategy): - # Disable ROI - # Could be replaced with new ROI from hyperopt. - minimal_roi = { - "0": 100 - } - - stoploss = -0.30 - - ### Do extra hyperopt for trailing seperat. Use "--spaces default" and then "--spaces trailing". - ### See here for more information: https://www.freqtrade.io/en/latest/hyperopt - trailing_stop = True - trailing_stop_positive = 0.08 - trailing_stop_positive_offset = 0.10 - trailing_only_offset_is_reached = True - - ticker_interval = '30m' - + ticker_interval = '15m' + + stoploss = -0.34338 + + minimal_roi = {"0": 0.27058, "33": 0.0853, "64": 0.04093, "244": 0} + def informative_pairs(self): return [] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - - macd = ta.MACD(dataframe) - dataframe['macd'] = macd['macd'] - dataframe['macdsignal'] = macd['macdsignal'] - - ### Add timeperiod from hyperopt (replace xx with value): - ### "xx" must be replaced even before the first hyperopt is run, - ### else "xx" would be a syntax error because it must be a Integer value. - dataframe['cci-buy'] = ta.CCI(dataframe, timeperiod=xx) - dataframe['cci-sell'] = ta.CCI(dataframe, timeperiod=xx) + + dataframe['cci-'+str(cciBuyTP)] = ta.CCI(dataframe, timeperiod=cciBuyTP) + dataframe['cci-'+str(cciSellTP)] = ta.CCI(dataframe, timeperiod=cciSellTP) + dataframe['rsi-'+str(rsiBuyTP)] = ta.RSI(dataframe, timeperiod=rsiBuyTP) + dataframe['rsi-'+str(rsiSellTP)] = ta.RSI(dataframe, timeperiod=rsiSellTP) + return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( - (dataframe['macd'] > dataframe['macdsignal']) & - (dataframe['cci-buy'] <= -100.0) # Replace with value from hyperopt. + (dataframe['cci-'+str(cciBuyTP)] < cciBuyVal) & + (dataframe['rsi-'+str(rsiBuyTP)] < rsiBuyVal) ), 'buy'] = 1 - + return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( - (dataframe['macd'] < dataframe['macdsignal']) & - (dataframe['cci-sell'] >= 200.0) # Replace with value from hyperopt. + (dataframe['cci-'+str(cciSellTP)] > cciSellVal) & + (dataframe['rsi-'+str(rsiSellTP)] > rsiSellVal) ), 'sell'] = 1 From 67fd683de39ca2be6218f33c07578157d321c052 Mon Sep 17 00:00:00 2001 From: OtenMoten <32872932+OtenMoten@users.noreply.github.com> Date: Sun, 28 Mar 2021 15:22:51 +0200 Subject: [PATCH 3/4] Added second indicator (RSI) --- user_data/hyperopts/HO-SwingHighToSky.py | 89 +++++++++++++++++------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/user_data/hyperopts/HO-SwingHighToSky.py b/user_data/hyperopts/HO-SwingHighToSky.py index 3807ac9..b2a54bb 100644 --- a/user_data/hyperopts/HO-SwingHighToSky.py +++ b/user_data/hyperopts/HO-SwingHighToSky.py @@ -20,26 +20,32 @@ __email__ = "kevin.ossenbrueck@pm.de" __status__ = "Live" cciTimeMin = 10 -cciTimeMax = 100 -cciValueMin = -400 -cciValueMax = 400 +cciTimeMax = 80 +cciValueMin = -200 +cciValueMax = 200 cciTimeRange = range(cciTimeMin, cciTimeMax) -class_name = 'HOSwingHighToSky' +rsiTimeMin = 10 +rsiTimeMax = 80 +rsiValueMin = 10 +rsiValueMax = 90 +rsiTimeRange = range(rsiTimeMin, rsiTimeMax) + class HOSwingHighToSky(IHyperOpt): @staticmethod def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame: - - macd = ta.MACD(dataframe) - dataframe['macd'] = macd['macd'] - dataframe['macdsignal'] = macd['macdsignal'] for cciTime in cciTimeRange: cciName = "cci-" + str(cciTime) dataframe[cciName] = ta.CCI(dataframe, timeperiod = cciTime) + for rsiTime in rsiTimeRange: + + rsiName = "rsi-" + str(rsiTime) + dataframe[rsiName] = ta.RSI(dataframe, timeperiod = rsiTime) + return dataframe @staticmethod @@ -50,15 +56,24 @@ class HOSwingHighToSky(IHyperOpt): conditions = [] # TRIGGERS & GUARDS - if 'trigger' in params: + if 'cci-buy-trigger' in params: for cciTime in cciTimeRange: cciName = "cci-" + str(cciTime) - if params['trigger'] == cciName: - conditions.append(dataframe[cciName] < params["buy-cci-value"]) - conditions.append(dataframe['macd'] > dataframe['macdsignal']) + if params['cci-buy-trigger'] == cciName: + conditions.append(dataframe[cciName] < params["cci-buy-value"]) + conditions.append(dataframe['volume'] > 0) + + if 'rsi-buy-trigger' in params: + + for rsiTime in rsiTimeRange: + + rsiName = "rsi-" + str(rsiTime) + + if params['rsi-buy-trigger'] == rsiName: + conditions.append(dataframe[rsiName] < params["rsi-buy-value"]) conditions.append(dataframe['volume'] > 0) if conditions: @@ -71,16 +86,24 @@ class HOSwingHighToSky(IHyperOpt): @staticmethod def indicator_space() -> List[Dimension]: - buyTriggerList = [] + cciBuyTriggerList = [] + rsiBuyTriggerList = [] for cciTime in cciTimeRange: cciName = "cci-" + str(cciTime) - buyTriggerList.append(cciName) + cciBuyTriggerList.append(cciName) + + for rsiTime in rsiTimeRange: + + rsiName = "rsi-" + str(rsiTime) + rsiBuyTriggerList.append(rsiName) return [ - Integer(cciValueMin, cciValueMax, name='buy-cci-value'), - Categorical(buyTriggerList, name='trigger') + Integer(cciValueMin, cciValueMax, name='cci-buy-value'), + Integer(rsiValueMin, rsiValueMax, name='rsi-buy-value'), + Categorical(cciBuyTriggerList, name='cci-buy-trigger'), + Categorical(rsiBuyTriggerList, name='rsi-buy-trigger') ] @staticmethod @@ -91,15 +114,23 @@ class HOSwingHighToSky(IHyperOpt): conditions = [] # TRIGGERS & GUARDS - if 'sell-trigger' in params: + if 'cci-sell-trigger' in params: for cciTime in cciTimeRange: cciName = "cci-" + str(cciTime) - if params['sell-trigger'] == cciName: - conditions.append(dataframe[cciName] > params["sell-cci-value"]) - conditions.append(dataframe['macd'] < dataframe['macdsignal']) + if params['cci-sell-trigger'] == cciName: + conditions.append(dataframe[cciName] > params["cci-sell-value"]) + + if 'rsi-sell-trigger' in params: + + for rsiTime in rsiTimeRange: + + rsiName = "rsi-" + str(rsiTime) + + if params['rsi-sell-trigger'] == rsiName: + conditions.append(dataframe[rsiName] > params["rsi-sell-value"]) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 @@ -111,14 +142,22 @@ class HOSwingHighToSky(IHyperOpt): @staticmethod def sell_indicator_space() -> List[Dimension]: - sellTriggerList = [] + cciSellTriggerList = [] + rsiSellTriggerList = [] for cciTime in cciTimeRange: cciName = "cci-" + str(cciTime) - sellTriggerList.append(cciName) + cciSellTriggerList.append(cciName) + + for rsiTime in rsiTimeRange: + + rsiName = "rsi-" + str(rsiTime) + rsiSellTriggerList.append(rsiName) return [ - Integer(cciValueMin, cciValueMax, name='sell-cci-value'), - Categorical(sellTriggerList, name='sell-trigger') - ] \ No newline at end of file + Integer(cciValueMin, cciValueMax, name='cci-sell-value'), + Integer(rsiValueMin, rsiValueMax, name='rsi-sell-value'), + Categorical(cciSellTriggerList, name='cci-sell-trigger'), + Categorical(rsiSellTriggerList, name='rsi-sell-trigger') + ] From 95aade53d1a28a66f5c47dcd2e2cd61e29cc35ff Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 29 Mar 2021 06:59:35 +0200 Subject: [PATCH 4/4] Remove referral code --- user_data/hyperopts/HO-Strategy005.py | 47 +++++++++++++-------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/user_data/hyperopts/HO-Strategy005.py b/user_data/hyperopts/HO-Strategy005.py index a43ec44..cd5bcf6 100644 --- a/user_data/hyperopts/HO-Strategy005.py +++ b/user_data/hyperopts/HO-Strategy005.py @@ -45,20 +45,17 @@ minusdiValueMax = 100 fishRsiNormaValueMin = 1 fishRsiNormaValueMax = 100 -class HODobby(IHyperOpt): +class HODobby(IHyperOpt): """ - If you trade on Binance then the API endopoint is "api.binance.com". - It's based in Tokyo. You can get a VPS in Tokyo on Vultr with 2ms latency. - I feel free to share my referral link (you get a bonus too): - > https://www.vultr.com/?ref=8806640 + Hyperopt file for Strategy005 """ - + ############### THIS STRATEGY IS DESIGNED FOR 5m TIMEFRAME ############### - + @staticmethod def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame: - + # MACD # tadoc.org/indicator/MACD.htm macd = ta.MACD(dataframe) @@ -83,24 +80,24 @@ class HODobby(IHyperOpt): dataframe['fastd'] = stoch_fast['fastd'] dataframe['fastk'] = stoch_fast['fastk'] - # SAR + # SAR dataframe['sar'] = ta.SAR(dataframe) # SMA dataframe['sma'] = ta.SMA(dataframe, timeperiod=50) - + return dataframe @staticmethod def buy_strategy_generator(params: Dict[str, Any]) -> Callable: - + def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: - + conditions = [] - + # TRIGGER and GUARD if 'buy-trigger' in params: - + conditions.append(dataframe['close'] > 0.00000200) conditions.append(dataframe['volume'] > dataframe['volume'].rolling(params['volumeAVG-buy-value']).mean()) conditions.append(dataframe['close'] < dataframe['sma']) @@ -108,7 +105,7 @@ class HODobby(IHyperOpt): conditions.append(dataframe['fastd'] > dataframe['fastk']) conditions.append(dataframe['fastd'] > params['fastd-buy-value']) conditions.append(dataframe['fisher_rsi_norma'] < params['fishRsiNorma-buy-value']) - + if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1 @@ -118,9 +115,9 @@ class HODobby(IHyperOpt): @staticmethod def indicator_space() -> List[Dimension]: - + buyTriggerList = ["True"] - + return [ Integer(volumeAvgValueMin, volumeAvgValueMax, name='volumeAVG-buy-value'), Integer(rsiValueMin, rsiValueMax, name='rsi-buy-value'), @@ -133,24 +130,24 @@ class HODobby(IHyperOpt): def sell_strategy_generator(params: Dict[str, Any]) -> Callable: def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: - + # TRIGGERS and GUARDS - # Solving a mistery: Which sell trigger is better? + # Solving a mistery: Which sell trigger is better? # The winner of both will be displayed in the output of the hyperopt. - + conditions = [] - + if 'sell-trigger' in params: if params['sell-trigger'] == 'rsi-macd-minusdi': conditions.append(qtpylib.crossed_above(dataframe['rsi'], params['rsi-sell-value'])) conditions.append(dataframe['macd'] < 0) conditions.append(dataframe['minus_di'] > params['minusdi-sell-value']) - + if 'sell-trigger' in params: if params['sell-trigger'] == 'sar-fisherRsi': conditions.append(dataframe['sar'] > dataframe['close']) conditions.append(dataframe['fisher_rsi'] > params['fishRsiNorma-sell-value']) - + if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 @@ -160,9 +157,9 @@ class HODobby(IHyperOpt): @staticmethod def sell_indicator_space() -> List[Dimension]: - + sellTriggerList = ["rsi-macd-minusdi", "sar-fisherRsi"] - + return [ Integer(rsiValueMin, rsiValueMax, name='rsi-sell-value'), Integer(minusdiValueMin, minusdiValueMax, name='minusdi-sell-value'),