# Zeus Strategy: First Generation of GodStra Strategy with maximum # AVG/MID profit in USDT # Author: @Mablue (Masoud Azizi) # github: https://github.com/mablue/ # IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) # freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus # --- Do not remove these libs --- from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter from freqtrade.strategy.interface import IStrategy from pandas import DataFrame # -------------------------------- # Add your lib to import here import ta from functools import reduce import numpy as np import talib.abstract as talib from freqtrade.strategy.strategy_helper import merge_informative_pair import freqtrade.vendor.qtpylib.indicators as qtpylib class Zeus_4(IStrategy): # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 # "max_open_trades": 10, # "stake_currency": "BTC", # "stake_amount": 0.01, # "tradable_balance_ratio": 0.99, # "timeframe": "4h", # "dry_run_wallet": 0.1, # Buy hyperspace params: buy_b_params = { "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", "= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ & (days < self.sell_b_too_old_day.value * 2)\ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "too_old_0.01" if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ & (days < self.sell_b_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "too_old_0.02" if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "too_old_0.03" if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): return "quick_lost" if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ & ((current_time - trade.open_date_utc).seconds >= 3600): return "no_change" if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): return "quick_gain_param" if self.profit_b_sma5.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma5'] > last_candle['sma5']) \ | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'sma5' if self.profit_b_sma10.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma10'] > last_candle['sma10']) \ | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'sma10' if self.profit_b_sma20.value: if (current_profit > 0.005) \ & (previous_last_candle['sma10'] > last_candle['sma10']) \ & ((current_time - trade.open_date_utc).seconds >= 3600) \ & ((previous_last_candle['sma20'] > last_candle['sma20']) & ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'sma20' if self.profit_b_over_rsi.value: if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi_2' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi_max' if self.profit_b_short_loss.value: if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'short_lost' else: if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ & (days < self.sell_h_too_old_day.value * 2)\ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "too_old_0.01" if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ & (days < self.sell_h_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "too_old_0.02" if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "too_old_0.03" if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): return "quick_lost" if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ & ((current_time - trade.open_date_utc).seconds >= 3600): return "no_change" if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): return "quick_gain_param" if self.profit_h_sma5.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma5'] > last_candle['sma5']) \ | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'sma5' if self.profit_h_sma10.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma10'] > last_candle['sma10']) \ | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'sma10' if self.profit_h_sma20.value: if (current_profit > 0.005) \ & (previous_last_candle['sma10'] > last_candle['sma10']) \ & ((current_time - trade.open_date_utc).seconds >= 3600) \ & ((previous_last_candle['sma20'] > last_candle['sma20']) & ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'sma20' if self.profit_h_over_rsi.value: if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi_2' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi_max' if self.profit_h_short_loss.value: if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'short_lost' def informative_pairs(self): # get access to all pairs available in whitelist. pairs = self.dp.current_whitelist() informative_pairs = [(pair, '1d') for pair in pairs] return informative_pairs def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Add all ta features dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( dataframe['high'], dataframe['low'], window1=9, window2=26, visual=False, fillna=False ) KST = ta.trend.KSTIndicator( close=dataframe['close'], roc1=10, roc2=15, roc3=20, roc4=30, window1=10, window2=10, window3=10, window4=15, nsig=9, fillna=False ) dataframe['trend_kst_diff'] = KST.kst_diff() dataframe['pct_change'] = dataframe['close'].pct_change(5); dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) dataframe['rsi'] = talib.RSI(dataframe) dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] dataframe["percent5"] = dataframe["percent"].rolling(5).sum() dataframe["percent3"] = dataframe["percent"].rolling(3).sum() dataframe["percent10"] = dataframe["percent"].rolling(10).sum() dataframe["percent20"] = dataframe["percent"].rolling(20).sum() dataframe["percent50"] = dataframe["percent"].rolling(50).sum() dataframe["volume10"] = dataframe["volume"].rolling(10).mean() # Bollinger Bands bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] dataframe["bb_percent"] = ( (dataframe["close"] - dataframe["bb_lowerband"]) / (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) ) dataframe["bb_width"] = ( (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] ) dataframe['sar'] = talib.SAR(dataframe) # Normalization tib = dataframe['trend_ichimoku_base'] dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) tkd = dataframe['trend_kst_diff'] dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") informative["rsi"] = talib.RSI(informative) informative["max3"] = talib.MAX(informative['close'], timeperiod=3) informative["min3"] = talib.MIN(informative['close'], timeperiod=3) informative['pct_change_1'] = informative['close'].pct_change(1) informative['pct_change_3'] = informative['close'].pct_change(3) informative['pct_change_5'] = informative['close'].pct_change(5) informative['sma3'] = talib.SMA(informative, timeperiod=3) informative['sma5'] = talib.SMA(informative, timeperiod=5) informative['sma10'] = talib.SMA(informative, timeperiod=10) informative['sar'] = talib.SAR(informative) bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) informative['bb_lowerband'] = bollinger['lower'] informative['bb_middleband'] = bollinger['mid'] informative['bb_upperband'] = bollinger['upper'] informative["bb_percent"] = ( (informative["close"] - informative["bb_lowerband"]) / (informative["bb_upperband"] - informative["bb_lowerband"]) ) informative["bb_width"] = ( (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] ) dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] IND = 'trend_ichimoku_base' REAL = self.buy_h_real.value OPR = self.buy_h_cat.value DFIND = dataframe[IND] # print(DFIND.mean()) if OPR == ">R": conditions.append(DFIND > REAL) elif OPR == "=R": conditions.append(np.isclose(DFIND, REAL)) elif OPR == " 0) & (dataframe['pct_change_3_1d'] > 0) & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) & (dataframe['close'] <= dataframe['sma5_1d']) & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) , ['buy', 'buy_tag']] = (1, 'buy_h') conditions = [] IND = 'trend_ichimoku_base' REAL = self.buy_b_real.value OPR = self.buy_b_cat.value DFIND = dataframe[IND] # print(DFIND.mean()) if OPR == ">R": conditions.append(DFIND > REAL) elif OPR == "=R": conditions.append(np.isclose(DFIND, REAL)) elif OPR == " 0) & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) & (dataframe['close'] <= dataframe['sma5_1d']) & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) , ['buy', 'buy_tag']] = (1, 'buy_b') return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # conditions = [] # IND = 'trend_kst_diff' # REAL = self.sell_h_real.value # OPR = self.sell_h_cat.value # DFIND = dataframe[IND] # # print(DFIND.mean()) # # if OPR == ">R": # conditions.append(DFIND > REAL) # elif OPR == "=R": # conditions.append(np.isclose(DFIND, REAL)) # elif OPR == "