Merge pull request #134 from OtenMoten/master

Create HO-Strategy005.py and update Swing-High-To-Sky hyperopt and strategy.
This commit is contained in:
Matthias
2021-03-29 07:01:32 +02:00
committed by GitHub
3 changed files with 262 additions and 61 deletions
+168
View File
@@ -0,0 +1,168 @@
# 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):
"""
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)
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')
]
+64 -25
View File
@@ -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')
]
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')
]
+30 -36
View File
@@ -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