def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ qtpylib. crossed_below(dataframe['tenkan_sen'], dataframe['kijun_sen']) | qtpylib.crossed_below(dataframe['close'], dataframe['kijun_sen'] ), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe['rsi'].rolling(8).max() > 93) & (dataframe['macd'] > 0) & (qtpylib.crossed_below(dataframe['macd'], dataframe['macdsignal'])) ), 'sell'] = 1 return dataframe
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: EMA = "EMA" + str(params['length']) pmax = "pm_" + str(params['length']) + "_" + str( params['multiplier']) + "_" + str( params['length']) + "_" + str(params['MAtype']) dataframe.loc[(( qtpylib.crossed_below(dataframe[EMA], dataframe[pmax]))), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[( # fast ema crosses below slow ema (qtpylib.crossed_below(dataframe['ema9'], dataframe['ema21'])) | (dataframe['low'] < dataframe['ema200'] ) # OR price is below trend ema ), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ dataframe.loc[( qtpylib.crossed_below(dataframe['macd'], dataframe['macdsignal']) & (dataframe['cci'] >= 100.0)), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators. Should be a copy of same method from strategy. Must align to populate_indicators in this file. Only used when --spaces does not include sell space. """ dataframe.loc[(( qtpylib.crossed_below(dataframe['close'], dataframe['middle']))), 'sell'] = 1 return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] dataframe['bb_width'] = ( (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_middleband']) dataframe['bb_bottom_cross'] = qtpylib.crossed_below( dataframe['close'], dataframe['bb_lowerband']).astype('int') dataframe['rsi'] = ta.RSI(dataframe, timeperiod=10) dataframe['plus_di'] = ta.PLUS_DI(dataframe) dataframe['minus_di'] = ta.MINUS_DI(dataframe) dataframe['cci'] = ta.CCI(dataframe, 30) dataframe['mfi'] = ta.MFI(dataframe, timeperiod=14) dataframe['cmf'] = chaikin_mf(dataframe) dataframe['rmi'] = RMI(dataframe, length=8, mom=4) stoch = ta.STOCHRSI(dataframe, 15, 20, 2, 2) dataframe['srsi_fk'] = stoch['fastk'] dataframe['srsi_fd'] = stoch['fastd'] dataframe['fastEMA'] = ta.EMA(dataframe['volume'], timeperiod=12) dataframe['slowEMA'] = ta.EMA(dataframe['volume'], timeperiod=26) dataframe['pvo'] = ((dataframe['fastEMA'] - dataframe['slowEMA']) / dataframe['slowEMA']) * 100 dataframe['is_dip'] = ((dataframe['rmi'] < 20) & (dataframe['cci'] <= -150) & (dataframe['srsi_fk'] < 20) # Maybe comment mfi and cmf to make more trades & (dataframe['mfi'] < 25) & (dataframe['cmf'] <= -0.1)).astype('int') dataframe['is_break'] = ( (dataframe['bb_width'] > 0.025) & (dataframe['bb_bottom_cross'].rolling(10).sum() > 1) & (dataframe['close'] < 0.99 * dataframe['bb_lowerband']) ).astype('int') dataframe['buy_signal'] = ((dataframe['is_dip'] > 0) & (dataframe['is_break'] > 0)).astype('int') return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ # (dataframe['Ichimoku_Score']<0)| (qtpylib.crossed_below( ta.SMA(dataframe['Ichimoku_Score'], self.sell_fast_timeperiod. value), ta.SMA(dataframe['Ichimoku_Score'], self.sell_slow_timeperiod. value))), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair :return: DataFrame with buy column """ dataframe.loc[( (qtpylib.crossed_below(dataframe['ema5'], dataframe['ema50'])) & (dataframe["close"] < (dataframe["high"] * 0.99))), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] conditions.append( qtpylib.crossed_below( dataframe[self.sell_fast_key.value].shift( self.sell_horizontal_push.value), dataframe[self.sell_slow_key.value] * self.sell_vertical_push.value)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # print(dataframe['slowk']/dataframe['wt1']) dataframe.loc[( (qtpylib.crossed_below(dataframe['wt1'], dataframe['wt2'])) & (dataframe['wt1'].between(self.sell_min0.value, self.sell_max0. value)) & (dataframe['slowk'].between(self.sell_min1.value, self.sell_max1. value)) & (dataframe['def'].between(self.sell_min.value, self.sell_max.value) )), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] # RSI Sell Hyperopt if self.rsi_sell_enabled.value: conditions.append( qtpylib.crossed_below(dataframe['rsi'], self.rsi_sell.value)) dataframe.loc[((qtpylib.crossed_above(dataframe['rsi'], 70)) & (dataframe['tema'] > dataframe['bb_middleband']) & (dataframe['tema'] < dataframe['tema'].shift(1)) & (dataframe['volume'] > 0)), 'sell'] = 1 return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[((dataframe['rsi'] < self.buy_rsi.value) & (dataframe['fastd'] < 35) & (dataframe['adx'] > 30) & (dataframe['plus_di'] > self.buy_plusdi.value)) | ((dataframe['adx'] > 65) & (dataframe['plus_di'] > self.buy_plusdi.value)), 'enter_long'] = 1 dataframe.loc[( qtpylib.crossed_below(dataframe['rsi'], self.sell_rsi.value)), 'enter_short'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: params = self.sell_params trade_data = self.custom_trade_info[metadata['pair']] conditions = [] if trade_data['active_trade']: loss_cutoff = self.linear_growth(-0.03, 0, 0, 300, trade_data['open_minutes']) conditions.append((trade_data['current_profit'] < loss_cutoff) & (trade_data['current_profit'] > self.stoploss) & (dataframe['rmi-dn-trend'] == 1) & (dataframe['volume'].gt(0))) if trade_data['peak_profit'] > 0: conditions.append( qtpylib.crossed_below(dataframe['rmi-slow'], 50)) else: conditions.append( qtpylib.crossed_below(dataframe['rmi-slow'], 10)) if trade_data['other_trades']: if trade_data['free_slots'] > 0: hold_pct = (trade_data['free_slots'] / 100) * -1 conditions.append( trade_data['avg_other_profit'] >= hold_pct) else: conditions.append(trade_data['biggest_loser'] == True) else: conditions.append(dataframe['volume'].lt(0)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators, populates the buy signal for the given dataframe :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair :return: DataFrame with buy column """ dataframe.loc[(( qtpylib.crossed_below(dataframe['close'], dataframe['lower'])) # & # (dataframe["close"].iloc[-1] < dataframe['lower']) ), 'buy'] = 1 return dataframe
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] rmi_drop = dataframe['rmi-max'] - (dataframe['rmi-max'] * params['sell-rmi-drop']) conditions.append((dataframe['rmi-dn-trend'] == 1) & ( qtpylib.crossed_below(dataframe['rmi-slow'], rmi_drop)) & (dataframe['volume'].gt(0))) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 # dataframe['sell'] = 0 return dataframe
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: """ Sell strategy Hyperopt will build and use. """ conditions = [] # GUARDS AND TRENDS for i in range(DNA_SIZE): OPR = params[f'sell-oper-{i}'] IND = params[f'sell-indicator-{i}'] CRS = params[f'sell-cross-{i}'] INT = params[f'sell-int-{i}'] REAL = params[f'sell-real-{i}'] DFIND = dataframe[IND] DFCRS = dataframe[CRS] if OPR == ">": conditions.append(DFIND > DFCRS) elif OPR == "=": conditions.append(np.isclose(DFIND, DFCRS)) elif OPR == "<": conditions.append(DFIND < DFCRS) elif OPR == "CA": conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) elif OPR == "CB": conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) elif OPR == ">I": conditions.append(DFIND > INT) elif OPR == "=I": conditions.append(DFIND == INT) elif OPR == "<I": conditions.append(DFIND < INT) elif OPR == ">R": conditions.append(DFIND > REAL) elif OPR == "=R": conditions.append(np.isclose(DFIND, REAL)) elif OPR == "<R": conditions.append(DFIND < REAL) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: """ Sell strategy Hyperopt will build and use. """ conditions = [] # TRIGGERS if 'sell-trigger' in params: if params['sell-trigger'] == 'sell-middle': conditions.append( qtpylib.crossed_below(dataframe['close'], dataframe['middle'])) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = list() # /5: Cuz We have 5 Group of variables inside buy_param for i in range(int(len(self.buy_params)/5)): OPR = self.buy_params[f'buy-oper-{i}'] IND = self.buy_params[f'buy-indicator-{i}'] CRS = self.buy_params[f'buy-cross-{i}'] INT = self.buy_params[f'buy-int-{i}'] REAL = self.buy_params[f'buy-real-{i}'] DFIND = dataframe[IND] DFCRS = dataframe[CRS] if OPR == ">": conditions.append(DFIND > DFCRS) elif OPR == "=": conditions.append(np.isclose(DFIND, DFCRS)) elif OPR == "<": conditions.append(DFIND < DFCRS) elif OPR == "CA": conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) elif OPR == "CB": conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) elif OPR == ">I": conditions.append(DFIND > INT) elif OPR == "=I": conditions.append(DFIND == INT) elif OPR == "<I": conditions.append(DFIND < INT) elif OPR == ">R": conditions.append(DFIND > REAL) elif OPR == "=R": conditions.append(np.isclose(DFIND, REAL)) elif OPR == "<R": conditions.append(DFIND < REAL) print(conditions) dataframe.loc[ reduce(lambda x, y: x & y, conditions), 'buy'] = 1 return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = list() for i in range(self.Buy_DNA_Size): OPR = self.buy_params[f'buy-oper-{i}'] IND = self.buy_params[f'buy-indicator-{i}'] CRS = self.buy_params[f'buy-cross-{i}'] INT = self.buy_params[f'buy-int-{i}'] REAL = self.buy_params[f'buy-real-{i}'] DFIND = dataframe[IND] DFCRS = dataframe[CRS] if OPR == ">": conditions.append(DFIND > DFCRS) elif OPR == "=": conditions.append(np.isclose(DFIND, DFCRS)) elif OPR == "<": conditions.append(DFIND < DFCRS) elif OPR == "CA": conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) elif OPR == "CB": conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) elif OPR == ">I": conditions.append(DFIND > INT) elif OPR == "=I": conditions.append(DFIND == INT) elif OPR == "<I": conditions.append(DFIND < INT) elif OPR == ">R": conditions.append(DFIND > REAL) elif OPR == "=R": conditions.append(np.isclose(DFIND, REAL)) elif OPR == "<R": conditions.append(DFIND < REAL) if self.Buy_DNA_Size > 0: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: params = self.get_pair_params(metadata['pair'], 'sell') trade_data = self.custom_trade_info[metadata['pair']] conditions = [] # If we are in an active trade (which is the only way a sell can occur...) # This is needed to block backtest/hyperopt from hitting the profit stuff and erroring out. if trade_data['active_trade']: # Decay a loss cutoff point where we allow a sell to occur idea is this allows # a trade to go into the negative a little bit before we react to sell. loss_cutoff = cta.linear_growth(-0.03, 0, 0, 240, trade_data['open_minutes']) conditions.append((trade_data['current_profit'] < loss_cutoff)) # Examine the state of our other trades and free_slots to inform the decision if trade_data['other_trades']: if trade_data['free_slots'] > 0: # If the average of all our other trades is below a certain threshold based # on free slots available, hold and wait for market recovery. hold_pct = (1 / trade_data['free_slots']) * -0.04 conditions.append( trade_data['avg_other_profit'] >= hold_pct) else: # If we are out of free slots disregard the above and allow the biggest loser to sell. conditions.append(trade_data['biggest_loser'] == True) # Primary sell trigger rmi_drop = dataframe['rmi-max'] - (dataframe['rmi-max'] * params['sell-rmi-drop']) conditions.append((dataframe['rmi-dn-trend'] == 1) & ( qtpylib.crossed_below(dataframe['rmi-slow'], rmi_drop)) & (dataframe['volume'].gt(0))) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] # Guards if params.get('sell-rsi-enabled'): conditions.append( (qtpylib.crossed_below(dataframe['rsi'], params['sell-rsi-limit']) | qtpylib.crossed_below(dataframe['rsi'].shift(1), params['sell-rsi-limit']) | qtpylib.crossed_below(dataframe['rsi'].shift(2), params['sell-rsi-limit'])) & (dataframe['rsi'].lt(params['sell-rsi-limit']))) if params.get('sell-cci-enabled'): conditions.append( (qtpylib.crossed_below(dataframe['cci'], params['sell-cci-limit']) | qtpylib.crossed_below(dataframe['cci'].shift(1), params['sell-cci-limit']) | qtpylib.crossed_below(dataframe['cci'].shift(2), params['sell-cci-limit'])) & (dataframe['cci'].lt(params['sell-cci-limit']))) # Triggers if params.get('sell-kama-trigger') == 'cross': conditions.append( qtpylib.crossed_below(dataframe['kama-short'], dataframe['kama-long'])) if params.get('sell-kama-trigger') == 'slope': conditions.append( dataframe['kama-long'] < dataframe['kama-long'].shift(1)) # Check that the candle had volume conditions.append(dataframe['volume'] > 0) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: params = self.sell_params trade_data = self.custom_trade_info[metadata['pair']] conditions = [] # In this strategy all sells for profit happen according to ROI # This sell signal is designed as a "dynamic stoploss" # if we are in an active trade for this pair if trade_data['active_trade']: # if we are at a loss, consider what the trend looks and preempt the stoploss conditions.append( (trade_data['current_profit'] < 0) & (trade_data['current_profit'] > self.stoploss) & (dataframe['rmi-dn-trend'] == 1) & (qtpylib.crossed_below(dataframe['rmi-fast'], 50)) & (dataframe['volume'].gt(0))) # if there are other open trades in addition to this one, consider the average profit # across them all (not including this one), don't sell if entire market is down big and wait for recovery if trade_data['other_trades']: if trade_data['free_slots'] == 0: conditions.append(trade_data['avg_other_profit'] >= -0.03) else: conditions.append(trade_data['avg_other_profit'] >= -0.01) # the bot comes through this loop even when there isn't an open trade to sell # so we pass an impossible condiiton here because we don't want a sell signal # clogging up the charts and not having one leads the bot to crash else: conditions.append(dataframe['volume'].lt(0)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: # Detect if current trend going Downwards / Sideways / Upwards, strategy will respond accordingly dataframe.loc[(dataframe['adx'] > 20) & (dataframe['plus_di'] < dataframe['minus_di']), 'trend'] = 'downwards' dataframe.loc[dataframe['adx'] < 20, 'trend'] = 'sideways' dataframe.loc[(dataframe['adx'] > 20) & (dataframe['plus_di'] > dataframe['minus_di']), 'trend'] = 'upwards' # If a Weighted Sell Signal goes off => Bearish Indication, Set to true (=1) and multiply by weight # percentage # Weighted Sell Signal: ADX above 25 & +DI below -DI (The trend has strength while moving down) dataframe.loc[(dataframe['trend'] == 'downwards') & (dataframe['adx'] > 25), 'total_sell_signal_strength'] += 1 * params[ 'downwards_trend_adx_strong_down_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & (dataframe['adx'] > 25), 'total_sell_signal_strength'] += 1 * params[ 'sideways_trend_adx_strong_down_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & (dataframe['adx'] > 25), 'total_sell_signal_strength'] += 1 * params[ 'upwards_trend_adx_strong_down_sell_weight'] # Weighted Sell Signal: RSI crosses below 70 (Over-bought / high-price and dropping indication) dataframe.loc[(dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['rsi'], 70), 'total_sell_signal_strength'] += 1 * params[ 'downwards_trend_rsi_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['rsi'], 70), 'total_sell_signal_strength'] += 1 * params[ 'sideways_trend_rsi_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['rsi'], 70), 'total_sell_signal_strength'] += 1 * params[ 'upwards_trend_rsi_sell_weight'] # Weighted Sell Signal: MACD below Signal dataframe.loc[(dataframe['trend'] == 'downwards') & (dataframe['macd'] < dataframe['macdsignal']), 'total_sell_signal_strength'] += 1 * params[ 'downwards_trend_macd_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & (dataframe['macd'] < dataframe['macdsignal']), 'total_sell_signal_strength'] += 1 * params[ 'sideways_trend_macd_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & (dataframe['macd'] < dataframe['macdsignal']), 'total_sell_signal_strength'] += 1 * params[ 'upwards_trend_macd_sell_weight'] # Weighted Sell Signal: SMA short term Death Cross (Short term SMA crosses below Medium term SMA) dataframe.loc[(dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['sma9'], dataframe[ 'sma50']), 'total_sell_signal_strength'] += \ 1 * params['downwards_trend_sma_short_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['sma9'], dataframe[ 'sma50']), 'total_sell_signal_strength'] += \ 1 * params['sideways_trend_sma_short_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['sma9'], dataframe[ 'sma50']), 'total_sell_signal_strength'] += \ 1 * params['upwards_trend_sma_short_death_cross_sell_weight'] # Weighted Sell Signal: EMA short term Death Cross (Short term EMA crosses below Medium term EMA) dataframe.loc[(dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['ema9'], dataframe[ 'ema50']), 'total_sell_signal_strength'] += \ 1 * params['downwards_trend_ema_short_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['ema9'], dataframe[ 'ema50']), 'total_sell_signal_strength'] += \ 1 * params['sideways_trend_ema_short_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['ema9'], dataframe[ 'ema50']), 'total_sell_signal_strength'] += \ 1 * params['upwards_trend_ema_short_death_cross_sell_weight'] # Weighted Sell Signal: SMA long term Death Cross (Medium term SMA crosses below Long term SMA) dataframe.loc[(dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['sma50'], dataframe[ 'sma200']), 'total_sell_signal_strength'] += \ 1 * params['downwards_trend_sma_long_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['sma50'], dataframe[ 'sma200']), 'total_sell_signal_strength'] += \ 1 * params['sideways_trend_sma_long_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['sma50'], dataframe[ 'sma200']), 'total_sell_signal_strength'] += \ 1 * params['upwards_trend_sma_long_death_cross_sell_weight'] # Weighted Sell Signal: EMA long term Death Cross (Medium term EMA crosses below Long term EMA) dataframe.loc[(dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['ema50'], dataframe[ 'ema200']), 'total_sell_signal_strength'] += \ 1 * params['downwards_trend_ema_long_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['ema50'], dataframe[ 'ema200']), 'total_sell_signal_strength'] += \ 1 * params['sideways_trend_ema_long_death_cross_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['ema50'], dataframe[ 'ema200']), 'total_sell_signal_strength'] += \ 1 * params['upwards_trend_ema_long_death_cross_sell_weight'] # Weighted Sell Signal: Re-Entering Upper Bollinger Band after upward breakout # (Candle closes below Upper Bollinger Band) dataframe.loc[(dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['close'], dataframe[ 'bb_upperband']), 'total_sell_signal_strength'] += \ 1 * params['downwards_trend_bollinger_bands_sell_weight'] dataframe.loc[(dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['close'], dataframe[ 'bb_upperband']), 'total_sell_signal_strength'] += \ 1 * params['sideways_trend_bollinger_bands_sell_weight'] dataframe.loc[(dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['close'], dataframe[ 'bb_upperband']), 'total_sell_signal_strength'] += \ 1 * params['upwards_trend_bollinger_bands_sell_weight'] # Weighted Sell Signal: VWAP crosses below current price dataframe.loc[ (dataframe['trend'] == 'downwards') & qtpylib.crossed_below(dataframe['vwap'], dataframe['close']), 'total_sell_signal_strength'] += 1 * params[ 'downwards_trend_vwap_cross_sell_weight'] dataframe.loc[ (dataframe['trend'] == 'sideways') & qtpylib.crossed_below(dataframe['vwap'], dataframe['close']), 'total_sell_signal_strength'] += 1 * params[ 'sideways_trend_vwap_cross_sell_weight'] dataframe.loc[ (dataframe['trend'] == 'upwards') & qtpylib.crossed_below(dataframe['vwap'], dataframe['close']), 'total_sell_signal_strength'] += 1 * params[ 'upwards_trend_vwap_cross_sell_weight'] # Check if sell signal should be sent depending on the current trend dataframe.loc[(dataframe['trend'] == 'downwards') & ( dataframe['total_sell_signal_strength'] >= params['_downwards_trend_total_sell_signal_needed']), 'sell'] = 1 dataframe.loc[(dataframe['trend'] == 'sideways') & (dataframe['total_sell_signal_strength'] >= params['_sideways_trend_total_sell_signal_needed']), 'sell'] = 1 dataframe.loc[(dataframe['trend'] == 'upwards') & (dataframe['total_sell_signal_strength'] >= params['_upwards_trend_total_sell_signal_needed']), 'sell'] = 1 # Override Sell Signal: When configured sell signals can be completely turned off for each kind of trend if not params['.trade_sells_when_downwards']: dataframe.loc[dataframe['trend'] == 'downwards', 'sell'] = 0 if not params['.trade_sells_when_sideways']: dataframe.loc[dataframe['trend'] == 'sideways', 'sell'] = 0 if not params['.trade_sells_when_upwards']: dataframe.loc[dataframe['trend'] == 'upwards', 'sell'] = 0 return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[(( qtpylib.crossed_below(dataframe['ema20'], dataframe['ema60']))), 'sell'] = 1 return dataframe
'sma_short_golden_cross': lambda df: (qtpylib.crossed_above(df['sma9'], df['sma50'])), # Weighted Buy Signal: TEMA 'tema': lambda df: (df['tema'] <= df['bb_middleband']) & (df['tema'] > df['tema'].shift(1)) } # Define the Weighted Sell Signals to be used by MGM sell_signals = { # Weighted Sell Signal: MACD below Signal 'macd': lambda df: (df['macd'] < df['macdsignal']), # Weighted Sell Signal: MFI crosses below 80 (Over-bought / high-price and dropping indication) 'mfi': lambda df: (qtpylib.crossed_below(df['mfi'], 80)), # Weighted Sell Signal: Rolling VWAP crosses below current price 'rolling_vwap_cross': lambda df: (qtpylib.crossed_below(df['rolling_vwap'], df['close'])), # Weighted Sell Signal: Price crosses below Parabolic SAR 'sar_cross': lambda df: (qtpylib.crossed_below(df['sar'], df['close'])), # Weighted Sell Signal: Stochastic Slow above 80 (Over-bought, indication of starting to move down) 'stoch': lambda df: (df['slowk'] > 80), # Weighted Sell Signal: SMA long term Death Cross (Medium term SMA crosses below Long term SMA) 'sma_long_death_cross': lambda df: (qtpylib.crossed_below(df['sma50'], df['sma200'])), # Weighted Sell Signal: SMA short term Death Cross (Short term SMA crosses below Medium term SMA) 'sma_short_death_cross': lambda df: (qtpylib.crossed_below(df['sma9'], df['sma50'])),
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: params = self.get_pair_params(metadata['pair'], 'sell') trade_data = self.custom_trade_info[metadata['pair']] conditions = [] """ Previous Schism sell implementation has been *partially* replaced by custom_stoploss. Doing it there makes it able to be backtested more realistically but some of the functionality such as the ability to use other trades or the # of slots in our decision need to remain here. The current sell is meant to be a pre-stoploss bailout but most sells at a loss should happen due to the stoploss in live/dry. ** Only part of this signal functions in backtest/hyperopt. Can only be optimized in live/dry. ** Results in backtest/hyperopts will sell far more readily than in live due to the profit guards. """ # If we are in an active trade (which is the only way a sell can occur...) # This is needed to block backtest/hyperopt from hitting the profit stuff and erroring out. if trade_data['active_trade']: # Decay a loss cutoff point where we allow a sell to occur idea is this allows # a trade to go into the negative a little bit before we react to sell. loss_cutoff = self.linear_growth(-0.03, 0, 0, 240, trade_data['open_minutes']) conditions.append((trade_data['current_profit'] < loss_cutoff)) # Primary sell trigger # TODO: Experiment with replacing or augmenting this with PMAX rmi_drop = dataframe['rmi-max'] - (dataframe['rmi-max'] * 0.50) conditions.append( (dataframe['rmi-dn-trend'] == 1) & (qtpylib.crossed_below(dataframe['rmi-slow'], rmi_drop)) & (dataframe['volume'].gt(0)) ) # Examine the state of our other trades and free_slots to inform the decision if trade_data['other_trades']: if trade_data['free_slots'] > 0: # If the average of all our other trades is below a certain threshold based # on free slots available, hold and wait for market recovery. max_market_down = -0.04 hold_pct = (1/trade_data['free_slots']) * max_market_down conditions.append(trade_data['avg_other_profit'] >= hold_pct) else: # If we are out of free slots disregard the above and allow the biggest loser to sell. conditions.append(trade_data['biggest_loser'] == True) else: # This is an impossible condition but needs to be here for some reason? conditions.append(dataframe['volume'].lt(0)) """ rmi_drop = dataframe['rmi-max'] - (dataframe['rmi-max'] * params['sell-rmi-drop']) conditions.append( (dataframe['rmi-dn-trend'] == 1) & (qtpylib.crossed_below(dataframe['rmi-slow'], rmi_drop)) & (dataframe['volume'].gt(0)) ) """ if conditions: dataframe.loc[ reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
def condition_generator(dataframe, operator, indicator, crossed_indicator, real_num): condition = (dataframe['volume'] > 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] < 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 == "/<R": condition = (dataframe[indicator].div(dataframe[crossed_indicator]) < real_num) elif operator == "UT": condition = (dataframe[indicator] > 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