-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathBBRSIHyperStrategy.py
184 lines (156 loc) · 7.63 KB
/
BBRSIHyperStrategy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# --- Do not remove these libs ----------------------------------------------------------------------------------------
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import talib.abstract as ta
import logging
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter, CategoricalParameter
from typing import Dict, List
from skopt.space import Dimension, Real, Integer
# ---------------------------------------------------------------------------------------------------------------------
# --- logger for parameter merging output, only remove if you remove it further down too! -----------------------------
logger = logging.getLogger(__name__)
# ---------------------------------------------------------------------------------------------------------------------
class BBRSIHyperStrategy(IStrategy):
"""
enhanced auto hyperoptable version based on the classic Bollinger Bands & RSI
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! as of today (14.04.2021) you need the freqtrade/develop version to be able !!!
!!! to run hyperopt/backtest with this new strategy format !!!
!!! !!!
!!! please check https://github.com/freqtrade/freqtrade/pull/4596 for further !!!
!!! information about the new auto-hyperoptable strategies! !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
"""
# user hyperopt for best minimal roi and stoploss!
minimal_roi = {
"0": 0.01
}
stoploss = -0.05
# best timeframes currently in backtest are 15m and 1h
timeframe = '1h'
startup_candle_count = 0
use_sell_signal = True
sell_profit_only = False
ignore_roi_if_buy_signal = False
# --- default buy/sell parameters can be ingested through config.json ---------------------------------------------
buy_params = {
'buy_rsi_enabled': True,
'buy_rsi_value': 30,
'buy_bb_trigger': 'bb_lowerband1'
}
sell_params = {
'sell_rsi_value': 80,
'sell_bb_trigger': 'bb_upperband1'
}
# --- hyperopt parameters > can be selectively turned on/off via optimize=True/False ------------------------------
buy_rsi_enabled = CategoricalParameter([True, False], default=True, space='buy', optimize=True, load=True)
buy_rsi_value = IntParameter(5, 30, default=30, space='buy', optimize=True, load=True)
buy_bb_trigger = CategoricalParameter(
[
'bb_lowerband1',
'bb_lowerband2',
'bb_lowerband3',
'bb_lowerband4'
],
default='bb_lowerband1', space='buy', optimize=True, load=True)
sell_rsi_value = IntParameter(40, 90, default=75, space='sell', optimize=True, load=True)
sell_bb_trigger = CategoricalParameter(
[
'bb_lowerband1',
'bb_middleband1',
'bb_upperband1'
],
default='bb_upperband1', space='sell', optimize=True, load=True)
use_sell_signal = True
sell_profit_only = True
ignore_roi_if_buy_signal = False
def __init__(self, config: dict) -> None:
super().__init__(config)
try:
from mergedeep import merge
except ImportError as error:
# Output expected ImportErrors.
logger.info("could not import mergedeep, please check if pip is installed: %s", error)
logger.info("therefor we are not able to merge parameters from config")
else:
logger.info('mergedeep found, so attempting to find strategy parameters in config file')
if self.config.get('strategy_parameters', {}).get(self.__class__.__name__, False):
cfg_strategy_parameters = self.config.get('strategy_parameters', {}).get(self.__class__.__name__, False)
logger.info('strategy_parameters from config: %s', repr(cfg_strategy_parameters))
if cfg_strategy_parameters.get('buy_params', {}):
logger.info('merging buy_params from config: %s', cfg_strategy_parameters.get('buy_params'))
merge(self.buy_params, cfg_strategy_parameters.get('buy_params'))
if cfg_strategy_parameters.get('sell_params', {}):
logger.info('merging sell_params from config: %s', cfg_strategy_parameters.get('sell_params'))
merge(self.sell_params, cfg_strategy_parameters.get('sell_params'))
else:
logger.info('no strategy_parameters found in config')
logger.info('final buy_params: %s', repr(self.buy_params))
logger.info('final sell_params: %s', repr(self.sell_params))
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# RSI
dataframe['rsi'] = ta.RSI(dataframe)
# Bollinger bands
bollinger1 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=1)
dataframe['bb_lowerband1'] = bollinger1['lower']
dataframe['bb_middleband1'] = bollinger1['mid']
dataframe['bb_upperband1'] = bollinger1['upper']
bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lowerband2'] = bollinger2['lower']
dataframe['bb_middleband2'] = bollinger2['mid']
dataframe['bb_upperband2'] = bollinger2['upper']
bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3)
dataframe['bb_lowerband3'] = bollinger3['lower']
dataframe['bb_middleband3'] = bollinger3['mid']
dataframe['bb_upperband3'] = bollinger3['upper']
bollinger4 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=4)
dataframe['bb_lowerband4'] = bollinger4['lower']
dataframe['bb_middleband4'] = bollinger4['mid']
dataframe['bb_upperband4'] = bollinger4['upper']
return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(
( # rsi enabled
(self.buy_rsi_enabled.value == True) &
(dataframe['rsi'] > self.buy_rsi_value.value)
) | # rsi disabled
(self.buy_rsi_enabled.value == False)
) &
(dataframe["close"] < dataframe[self.buy_bb_trigger.value])
),
'buy'
] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['rsi'] > self.sell_rsi_value.value) &
(dataframe["close"] > dataframe[self.sell_bb_trigger.value])
),
'sell'
] = 1
return dataframe
# nested hyperopt class
class HyperOpt:
# custom stop loss range
@staticmethod
def stoploss_space() -> List[Dimension]:
return [
Real(-0.5, -0.02, name='stoploss'),
]
@staticmethod
def roi_space() -> List[Dimension]:
"""
Values to search for each ROI steps
"""
return [
Integer(10, 120, name='roi_t1'),
Integer(10, 60, name='roi_t2'),
Integer(10, 40, name='roi_t3'),
Real(0.01, 0.04, name='roi_p1'),
Real(0.01, 0.07, name='roi_p2'),
Real(0.01, 0.20, name='roi_p3'),
]