# GodStraNew Strategy # Author: @Mablue (Masoud Azizi) # github: https://github.com/mablue/ # freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew # --- Do not remove these libs --- from datetime import timedelta, datetime from freqtrade import data from freqtrade.persistence import Trade from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter from numpy.lib import math from freqtrade.strategy.interface import IStrategy from pandas import DataFrame # -------------------------------- # Add your lib to import here # TODO: talib is fast but have not more indicators import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib from functools import reduce import numpy as np from random import shuffle operators = [ "D", # Disabled gene ">", # Indicator, bigger than cross indicator "<", # Indicator, smaller than cross indicator "=", # Indicator, equal with cross indicator "C", # Indicator, crossed the cross indicator "CA", # Indicator, crossed above the cross indicator "CB", # Indicator, crossed below the cross indicator ">R", # Normalized indicator, bigger than real number "=R", # Normalized indicator, equal with real number "R", # Normalized indicator devided to cross indicator, bigger than real number "/=R", # Normalized indicator devided to cross indicator, equal with real number "/ 10) # TODO : it ill callculated in populate indicators. dataframe[indicator] = gene_calculator(dataframe, indicator) dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: dataframe[indicator_trend_sma] = gene_calculator( dataframe, indicator_trend_sma) if operator == ">": condition = ( dataframe[indicator] > dataframe[crossed_indicator] ) elif operator == "=": condition = ( np.isclose(dataframe[indicator], dataframe[crossed_indicator]) ) elif operator == "<": condition = ( dataframe[indicator] < dataframe[crossed_indicator] ) elif operator == "C": condition = ( (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | (qtpylib.crossed_above( dataframe[indicator], dataframe[crossed_indicator])) ) elif operator == "CA": condition = ( qtpylib.crossed_above( dataframe[indicator], dataframe[crossed_indicator]) ) elif operator == "CB": condition = ( qtpylib.crossed_below( dataframe[indicator], dataframe[crossed_indicator]) ) elif operator == ">R": condition = ( dataframe[indicator] > real_num ) elif operator == "=R": condition = ( np.isclose(dataframe[indicator], real_num) ) elif operator == "R": condition = ( dataframe[indicator].div(dataframe[crossed_indicator]) > real_num ) elif operator == "/=R": condition = ( np.isclose(dataframe[indicator].div( dataframe[crossed_indicator]), real_num) ) elif operator == "/ dataframe[indicator_trend_sma] ) elif operator == "DT": condition = ( dataframe[indicator] < dataframe[indicator_trend_sma] ) elif operator == "OT": condition = ( np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) ) elif operator == "CUT": condition = ( ( qtpylib.crossed_above( dataframe[indicator], dataframe[indicator_trend_sma] ) ) & ( dataframe[indicator] > dataframe[indicator_trend_sma] ) ) elif operator == "CDT": condition = ( ( qtpylib.crossed_below( dataframe[indicator], dataframe[indicator_trend_sma] ) ) & ( dataframe[indicator] < dataframe[indicator_trend_sma] ) ) elif operator == "COT": condition = ( ( ( qtpylib.crossed_below( dataframe[indicator], dataframe[indicator_trend_sma] ) ) | ( qtpylib.crossed_above( dataframe[indicator], dataframe[indicator_trend_sma] ) ) ) & ( np.isclose( dataframe[indicator], dataframe[indicator_trend_sma] ) ) ) return condition, dataframe class GodStraJD3_5_1(IStrategy): # #################### RESULTS PASTE PLACE #################### # ROI table: minimal_roi = { "0": 10, # "600": 0.12, # "1200": 0.08, # "2400": 0.06, # "3600": 0.04, # "7289": 0 } # Stoploss: stoploss = -1 # Buy hypers timeframe = '5m' # Trailing stoploss trailing_stop = False trailing_stop_positive = 0.15 trailing_stop_positive_offset = 0.20 trailing_only_offset_is_reached = True plot_config = { # Main plot indicators (Moving averages, ...) 'main_plot': { 'bb_lowerband': {'color': 'red'}, 'bb_upperband': {'color': 'green'}, 'sma100': {'color': 'blue'}, 'sma10': {'color': 'yellow'}, 'min': {'color': 'white'}, 'max': {'color': 'white'}, 'sma20': {'color': 'cyan'} }, 'subplots': { # Subplots - each dict defines one additional plot "BB": { 'bb_width': {'color': 'white'}, 'bb_min': {'color': 'red'}, }, "Ind0": { buy_crossed_indicator0: {'color': 'green'}, buy_indicator0: {'color': 'red'} }, "Ind1": { buy_indicator1: {'color': 'yellow'}, buy_crossed_indicator1: {'color': 'pink'} }, "Ind2": { buy_indicator2: {'color': 'cyan'}, buy_crossed_indicator2: {'color': 'blue'}, }, "Rsi": { 'rsi': {'color': 'pink'}, }, # "rolling": { # 'bb_rolling': {'color': '#87e470'}, # "bb_rolling_min": {'color': '#ac3e2a'} # }, "percent": { "percent": {'color': 'green'}, "percent3": {'color': 'blue'}, "percent5": {'color': 'red'} } } } # #################### END OF RESULT PLACE #################### # TODO: Its not dry code! # Buy Hyperoptable Parameters/Spaces. buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy') buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy') buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy') protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') protection_stop = IntParameter(0, 100, default=48, space='protection') protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') lookback = IntParameter(0, 200, default=48, space='protection') trade_limit = IntParameter(0, 10, default=2, space='protection') profit_no_change = BooleanParameter(default=True, space="buy") profit_sma10 = BooleanParameter(default=True, space="buy") profit_sma20 = BooleanParameter(default=True, space="buy") profit_quick_gain = BooleanParameter(default=True, space="buy") profit_quick_gain_3 = BooleanParameter(default=True, space="buy") profit_old_sma10 = BooleanParameter(default=True, space="buy") profit_very_old_sma10 = BooleanParameter(default=True, space="buy") profit_over_rsi = BooleanParameter(default=True, space="buy") profit_short_loss = BooleanParameter(default=True, space="buy") @property def protections(self): return [ { "method": "CooldownPeriod", "stop_duration_candles": 10 }, { "method": "MaxDrawdown", "lookback_period_candles": self.lookback.value, "trade_limit": self.trade_limit.value, "stop_duration_candles": self.protection_stop.value, "max_allowed_drawdown": self.protection_max_allowed_dd.value, "only_per_pair": False }, { "method": "StoplossGuard", "lookback_period_candles": 24, "trade_limit": 4, "stop_duration_candles": self.protection_stoploss_stop.value, "only_per_pair": False } ] def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, current_profit: float, **kwargs): dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() previous_last_candle = dataframe.iloc[-2].squeeze() previous_5_candle = dataframe.iloc[-5].squeeze() if self.profit_no_change.value: if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): return "no_change" #if (current_profit > 0.01) & (last_candle['rsi'] < 30): # return "small_rsi" if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): return "quick_gain_3" if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) return "quick_gain" if self.profit_sma10.value: if (current_profit > 0.01) \ & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ & ((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_sma20.value: if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ & ((current_time - trade.open_date_utc).seconds >= 3600) \ & ((previous_last_candle['sma20'] > last_candle['sma20']) & ((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_old_sma10.value: if (current_profit > 0) \ & ((current_time - trade.open_date_utc).days >= 3) \ & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'old_sma10' if self.profit_very_old_sma10.value: if (current_profit > -0.01) \ & ((current_time - trade.open_date_utc).days >= 6) \ & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'very_old_sma10' if self.profit_over_rsi.value: if (current_profit > 0) \ & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'over_rsi' if self.profit_short_loss.value: if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ & ((current_time - trade.open_date_utc).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' # if (current_profit > 0) \ # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) # return 'over_rsi_2' def informative_pairs(self): return [] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) dataframe['profit'] = 0 # RSI dataframe['rsi'] = ta.RSI(dataframe) dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) dataframe['sma100'] = ta.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() # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): # dataframe["percent_ok"] = new dataframe() # else: # dataframe["percent_ok"] = 0 dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) dataframe["volume10"] = dataframe["volume"].rolling(10).mean() dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) dataframe['max_min'] = dataframe['max'] / dataframe['min'] # 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['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) # Bollinger Bands - Weighted (EMA based instead of SMA) weighted_bollinger = qtpylib.weighted_bollinger_bands( qtpylib.typical_price(dataframe), window=20, stds=2 ) dataframe["wbb_upperband"] = weighted_bollinger["upper"] dataframe["wbb_lowerband"] = weighted_bollinger["lower"] dataframe["wbb_middleband"] = weighted_bollinger["mid"] dataframe["wbb_percent"] = ( (dataframe["close"] - dataframe["wbb_lowerband"]) / (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) ) dataframe["wbb_width"] = ( (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] ) # # EMA - Exponential Moving Average # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = list() condition, dataframe = condition_generator( dataframe, buy_operator0, buy_indicator0, buy_crossed_indicator0, self.buy_real_num0.value ) conditions.append(condition) # backup condition, dataframe = condition_generator( dataframe, buy_operator1, buy_indicator1, buy_crossed_indicator1, self.buy_real_num1.value ) conditions.append(condition) condition, dataframe = condition_generator( dataframe, buy_operator2, buy_indicator2, buy_crossed_indicator2, self.buy_real_num2.value ) conditions.append(condition) if conditions: dataframe.loc[ ( # reduce(lambda x, y: x & y, conditions) # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) # # & (dataframe['percent5'] < 0.025) # # (dataframe['percent10'] < 0.04) # ) | ( (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) & ((dataframe['percent20'].shift(5) < -0.025) | (dataframe['percent20'].shift(10) < -0.025)) & ((dataframe['percent5'] > 0.001) | (dataframe['open'] < dataframe['bb_lowerband'])) & (dataframe['sma10'].shift(1) < dataframe['sma10']) # & (dataframe['open'].shift(50) > dataframe['open']) ) #(dataframe['percent3'] > 0)) ,'buy']=1 # print(len(dataframe.keys())) return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: return dataframe