# --- Do not remove these libs --- from sqlalchemy import true from freqtrade.strategy.interface import IStrategy from pandas import DataFrame, Series import copy import logging import pathlib import rapidjson import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib import pandas as pd # noqa pd.options.mode.chained_assignment = None # default='warn' import technical.indicators as ftt from freqtrade.exchange import timeframe_to_prev_date from functools import reduce from datetime import datetime, timedelta, timezone import numpy as np from technical.util import resample_to_interval, resampled_merge from freqtrade.strategy import informative from freqtrade.strategy import stoploss_from_open from freqtrade.strategy import (BooleanParameter,timeframe_to_minutes, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter) from freqtrade.persistence import Trade from typing import Dict import numpy # noqa import math import pandas_ta as pta from typing import List from skopt.space import Dimension, Integer import time from warnings import simplefilter from technical.indicators import zema logger = logging.getLogger(__name__) simplefilter(action="ignore", category=pd.errors.PerformanceWarning) ##### SETINGS ##### # It hyperopt just one set of params for all buy and sell strategies if true. DUALFIT = False COUNT = 10 GAP = 3 ### END SETINGS ### def max_pump_detect_price_15m(dataframe, period=14, pause = 288 ): df = dataframe.copy() df['size'] = df['high'] - df['low'] cumulativeup = 0 countup = 0 cumulativedown = 0 countdown = 0 for i in range(period): cumulativeup = cumulativeup + df['volume'].shift(i) * df['size'].shift(i) * np.where(df['close'].shift(i) > df['open'].shift(i), 1, 0) cumulativedown = cumulativedown + df['volume'].shift(i) * df['size'].shift(i) * np.where(df['close'].shift(i) > df['open'].shift(i), 0, 1) flow_price = cumulativeup - cumulativedown flow_price_normalized = flow_price / (df['volume'].rolling(499).mean() * (df['high']-df['low']).rolling(499).mean()) max_flow_price = flow_price_normalized.rolling(pause).max() return max_flow_price def flow_price_15m(dataframe, period=14, pause = 288 ): df = dataframe.copy() df['size'] = df['high'] - df['low'] cumulativeup = 0 countup = 0 cumulativedown = 0 countdown = 0 for i in range(period): cumulativeup = cumulativeup + df['volume'].shift(i) * df['size'].shift(i) * np.where(df['close'].shift(i) > df['open'].shift(i), 1, 0) cumulativedown = cumulativedown + df['volume'].shift(i) * df['size'].shift(i) * np.where(df['close'].shift(i) > df['open'].shift(i), 0, 1) flow_price = cumulativeup - cumulativedown flow_price_normalized = flow_price / (df['volume'].rolling(499).mean() * (df['high']-df['low']).rolling(499).mean()) return flow_price_normalized def to_minutes(**timdelta_kwargs): return int(timedelta(**timdelta_kwargs).total_seconds() / 60) ######################################################### ####################### ichiV1_Mod ##################### ######################################################### ############################################# class ichiV1_Marius_fixed(IStrategy): class HyperOpt: @staticmethod def generate_roi_table(params: dict): """ Generate the ROI table that will be used by Hyperopt This implementation generates the default legacy Freqtrade ROI tables. Change it if you need different number of steps in the generated ROI tables or other structure of the ROI tables. Please keep it aligned with parameters in the 'roi' optimization hyperspace defined by the roi_space method. """ roi_table = {} roi_table[0] = 0.05 roi_table[params['roi_t6']] = 0.04 roi_table[params['roi_t5']] = 0.03 roi_table[params['roi_t4']] = 0.02 roi_table[params['roi_t3']] = 0.01 roi_table[params['roi_t2']] = 0.0001 roi_table[params['roi_t1']] = -10 return roi_table @staticmethod def roi_space() -> List[Dimension]: """ Values to search for each ROI steps Override it if you need some different ranges for the parameters in the 'roi' optimization hyperspace. Please keep it aligned with the implementation of the generate_roi_table method. """ return [ Integer(240, 720, name='roi_t1'), Integer(120, 240, name='roi_t2'), Integer(90, 120, name='roi_t3'), Integer(60, 90, name='roi_t4'), Integer(30, 60, name='roi_t5'), Integer(1, 30, name='roi_t6'), ] DATESTAMP = 0 SELLMA = 1 # Buy hyperspace params: buy_params = { "max_slip": 0.668, "antipump_threshold": 0.265, "antipump_threshold_2": 0.133, "buy_btc_safe_1d": -0.236, "buy_btc_safe": -213, "buy_threshold": 0.012, ## "pump_limit": 1000, "pump_pause_duration": 192, "pump_period": 14, "pump_recorver_price": 1.1, ## "buy_trend_above_senkou_level": 1, "buy_trend_bullish_level": 6, "tesla_enabled": True, # "buy_fan_magnitude_shift_value": 3, "buy_min_fan_magnitude_gain": 1.0022, # NOTE: Good value (Win% ~70%), alot of trades #"buy_min_fan_magnitude_gain": 1.008 # NOTE: Very save value (Win% ~90%), only the biggest moves 1.008, } sell_params = { "ProfitLoss1": 0.005, "ProfitLoss2": 0.021, "ProfitMargin1": 0.018, "ProfitMargin2": 0.051, "pHSL": -0.08, "sell_trend_indicator": "trend_close_2h", } # minimum conditions to match in buy buy_minimum_conditions = IntParameter( 1, 2, default=1, space="buy", optimize=False, load=True ) position_adjustment_enable = True max_dca_orders = 2 max_dca_multiplier = 1.25 dca_stake_multiplier = 1.25 def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, **kwargs) -> float: if (self.config['position_adjustment_enable'] == True) and (self.config['stake_amount'] == 'unlimited'): return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] / self.max_dca_multiplier else: return proposed_stake def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, **kwargs): if current_profit > -0.05: return None dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() previous_candle = dataframe.iloc[-2].squeeze() if last_candle['close'] < previous_candle['close']: return None filled_buys = trade.select_filled_orders('buy') count_of_buys = len(filled_buys) if 0 < count_of_buys <= self.max_dca_orders: try: stake_amount = filled_buys[0].cost # This then calculates current safety order size stake_amount = stake_amount * self.dca_stake_multiplier return stake_amount except Exception as exception: return None return None # Pump protection pump_period = IntParameter( 5, 24, default=buy_params['pump_period'], space='buy', optimize=False) pump_limit = IntParameter( 100,10000, default=buy_params['pump_limit'], space='buy', optimize=True) pump_recorver_price = DecimalParameter( 1.0, 1.3, default=buy_params['pump_recorver_price'], space='buy', optimize=True) pump_pause_duration = IntParameter( 6, 500, default=buy_params['pump_pause_duration'], space='buy', optimize=True) ################################################################## ## Slippage params is_optimize_slip = False max_slip = DecimalParameter(0.33, 0.80, default=0.33, decimals=3, optimize=is_optimize_slip , load=True) buy_btc_safe = IntParameter(-300, 50, default=buy_params['buy_btc_safe'], optimize = True) buy_btc_safe_1d = DecimalParameter(-0.5, -0.015, default=buy_params['buy_btc_safe_1d'], optimize=True) antipump_threshold = DecimalParameter(0, 0.4, default=buy_params['antipump_threshold'], space='buy', optimize=True) antipump_threshold_2 = DecimalParameter(0, 0.4, default=buy_params['antipump_threshold_2'], space='buy', optimize=True) buy_min_fan_magnitude_gain = DecimalParameter(70, 90, default=buy_params['buy_min_fan_magnitude_gain'], space='buy', optimize=False, load=True) # Multi Offset buy_threshold = DecimalParameter(0.003, 0.012, default=buy_params['buy_threshold'], optimize=True) ####################################################################### # ROI table: minimal_roi = { "0": 0.215, "40": 0.032, "87": 0.016, "201": 0 } # Stoploss: stoploss = -0.275 # value loaded from strategy # Trailing stop: trailing_stop = False #trailing_stop_positive = 0.001 #trailing_stop_positive_offset = 0.016 #trailing_only_offset_is_reached = True window_buy = IntParameter(60, 1000, default=500, space='buy', optimize=True) bandwidth_buy = IntParameter(2, 15, default=8, space='buy', optimize=True) mult_buy = DecimalParameter(0.5, 20.0, default=3, space='buy', optimize=True) # Optional order time in force. order_time_in_force = { 'buy': 'gtc', 'sell': 'gtc' } use_custom_stoploss = True # Optimal timeframe for the strategy timeframe = '5m' informative_timeframe = '1h' inf_15m = '15m' #use for pump detection timeframe_minutes = timeframe_to_minutes(timeframe) # storage dict for custom info custom_info = {} startup_candle_count: int = 499 # startup_candle_count = 96 process_only_new_candles = True timeperiods = [ # 50 // timeframe_minutes, # 85 // timeframe_minutes, 180 // timeframe_minutes, 360 // timeframe_minutes, 420 // timeframe_minutes, 560 // timeframe_minutes, ] use_sell_signal = False sell_profit_only = False ignore_roi_if_buy_signal = True # trailing stoploss hyperopt parameters pHSL = DecimalParameter(-0.15, -0.08, default=sell_params['pHSL'], decimals=3, space='sell', optimize=True) ProfitMargin1 = DecimalParameter(0.009, 0.019, default=sell_params['ProfitMargin1'], decimals=3, space='sell', optimize=True) ProfitLoss1 = DecimalParameter(0.005, 0.012, default=sell_params['ProfitLoss1'], decimals=3, space='sell', optimize=True) ProfitMargin2 = DecimalParameter(0.033, 0.099, default=sell_params['ProfitMargin2'], decimals=3, space='sell', optimize=True) ProfitLoss2 = DecimalParameter(0.010, 0.025, default=sell_params['ProfitLoss2'], decimals=3, space='sell', optimize=True) plot_config = { 'main_plot': { # fill area between senkou_a and senkou_b 'senkou_a': { 'color': 'green', #optional 'fill_to': 'senkou_b', 'fill_label': 'Ichimoku Cloud', #optional 'fill_color': 'rgba(255,76,46,0.2)', #optional }, # plot senkou_b, too. Not only the area to it. 'senkou_b': {}, }, 'subplots': { 'fan_magnitude': { 'fan_magnitude': {} }, 'fan_magnitude_gain': { 'fan_magnitude_gain': {} } } } slippage_protection = { 'retries': 3, 'max_slippage': -0.02 } def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, current_profit: float, **kwargs): if ((current_time - trade.open_date_utc).seconds / 60 > 1440): return 'unclog' def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: HSL = self.pHSL.value if (current_profit > self.ProfitMargin2.value): sl_profit = self.ProfitLoss2.value elif (current_profit > self.ProfitMargin1.value): sl_profit = self.ProfitLoss1.value + ((current_profit - self.ProfitMargin1.value) * (self.ProfitLoss2.value - self.ProfitLoss1.value) / (self.ProfitMargin2.value - self.ProfitMargin1.value)) else: sl_profit = HSL return sl_profit def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, time_in_force: str, sell_reason: str, current_time: datetime, **kwargs) -> bool: dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1] current_profit = trade.calc_profit_ratio(rate) if 'tesla_' in trade.buy_tag and current_profit > 0.01: return True if (trade.buy_tag == 'telsa_'): if (sell_reason in ['sell_signal'])or (sell_reason in ['roi']) or (sell_reason in ['trailing_stop_loss']): return False if (last_candle is not None): if (sell_reason in ['sell_signal']): if (last_candle['hma_50'] > last_candle['ema_100']) and (last_candle['rsi'] < 45): #*1.2 return False if (last_candle is not None): if (sell_reason in ['sell_signal']): if (last_candle['hma_50']*1.149 > last_candle['ema_100']) and (last_candle['close'] < last_candle['ema_100']*0.951): #*1.2 return False # slippage try: state = self.slippage_protection['__pair_retries'] except KeyError: state = self.slippage_protection['__pair_retries'] = {} candle = dataframe.iloc[-1].squeeze() slippage = (rate / candle['close']) - 1 if slippage < self.slippage_protection['max_slippage']: pair_retries = state.get(pair, 0) if pair_retries < self.slippage_protection['retries']: state[pair] = pair_retries + 1 return False state[pair] = 0 return True age_filter = 30 @informative('1d') def populate_indicators_1d(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['age_filter_ok'] = (dataframe['volume'].rolling(window=self.age_filter, min_periods=self.age_filter).min() > 0) return dataframe def informative_pairs(self): # get access to all pairs available in whitelist. pairs = self.dp.current_whitelist() # Assign tf to each pair so they can be downloaded and cached for strategy. informative_pairs = [(pair, '1h') for pair in pairs] informative_pairs = [(pair, '15m') for pair in pairs] informative_pairs.extend([(pair, self.informative_timeframe) for pair in pairs]) informative_pairs += [("BTC/BUSD", "1m")] informative_pairs += [("BTC/BUSD", "5m")] informative_pairs += [("BTC/BUSD", "1d")] return informative_pairs def get_informative_indicators(self, metadata: dict): dataframe = self.dp.get_pair_dataframe( pair=metadata['pair'], timeframe=self.informative_timeframe) return dataframe def informative_1h_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: tik = time.perf_counter() assert self.dp, "DataProvider is required for multiple timeframes." # Get the informative pair informative_1h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.informative_timeframe) # RSI informative_1h['rsi'] = ta.RSI(informative_1h, timeperiod=14) #Weekly average close price informative_1h['weekly_close_avg'] = informative_1h['close'].rolling(168).mean() return informative_1h ####################################################################### # Informative indicator for pump detection def informative_15m_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: assert self.dp, "DataProvider is required for multiple timeframes." # Get the informative pair informative_15m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_15m) informative_15m['max_flow_price'] = max_pump_detect_price_15m(informative_15m, period=self.pump_period.value, pause=self.pump_pause_duration.value) informative_15m['flow_price'] = flow_price_15m(informative_15m, period=self.pump_period.value, pause=self.pump_pause_duration.value) return informative_15m ####################################################################### def top_percent_change(self, dataframe: DataFrame, length: int) -> float: """ Percentage change of the current close from the range maximum Open price :param dataframe: DataFrame The original OHLC dataframe :param length: int The length to look back """ df = dataframe.copy() if length == 0: return ((df['open'] - df['close']) / df['close']) else: return ((df['open'].rolling(length).max() - df['close']) / df['close']) def normal_tf_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: ### BTC protection if self.config['stake_currency'] in ['USDT','BUSD','USDC','DAI','TUSD','PAX','USD','EUR','GBP']: btc_info_pair = f"BTC/{self.config['stake_currency']}" else: btc_info_pair = "BTC/BUSD" btc_df = self.dp.get_pair_dataframe(pair=btc_info_pair, timeframe=self.timeframe) dataframe['btc_rsi'] = normalize(ta.RSI(btc_df, timeperiod=14), 0, 100) ### BTC protection dataframe['btc_5m']= self.dp.get_pair_dataframe('BTC/BUSD', timeframe='5m')['close'] btc_1d = self.dp.get_pair_dataframe('BTC/BUSD', timeframe='1d')[['date', 'close']].rename(columns={"close": "btc"}).shift(1) dataframe = merge_informative_pair(dataframe, btc_1d, '5m', '1d', ffill=True) # BTC info informative = self.dp.get_pair_dataframe(pair="BTC/BUSD", timeframe="5m") informative_past = informative.copy().shift(1) # BTC 5m dump protection informative_past_source = (informative_past['open'] + informative_past['close'] + informative_past['high'] + informative_past['low']) / 4 # Get BTC price informative_threshold = informative_past_source * self.buy_threshold.value # BTC dump n% in 5 min informative_past_delta = informative_past['close'].shift(1) - informative_past['close'] # should be positive if dump informative_diff = informative_threshold - informative_past_delta # Need be larger than 0 dataframe['btc_threshold'] = informative_threshold dataframe['btc_diff'] = informative_diff # BTC 1d dump protection informative_past_1d = informative.copy().shift(288) informative_past_source_1d = (informative_past_1d['open'] + informative_past_1d['close'] + informative_past_1d['high'] + informative_past_1d['low']) / 4 dataframe['btc_5m'] = informative_past_source dataframe['btc_1d'] = informative_past_source_1d dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) # strategy ClucMay72018 dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=50) dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=30).mean() dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) dataframe['ema55'] = ta.EMA(dataframe, timeperiod=55) # Pump strength dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50) dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) dataframe['zema_30'] = ftt.zema(dataframe, period=30) dataframe['zema_200'] = ftt.zema(dataframe, period=200) dataframe['pump_strength'] = (dataframe['zema_30'] - dataframe['zema_200']) / dataframe['zema_30'] dataframe['pump_strength_2'] = (dataframe['ema_50'] - dataframe['ema_200']) / dataframe['ema_50'] heikinashi = qtpylib.heikinashi(dataframe) dataframe['hk_open'] = heikinashi['open'] # dataframe['close'] = heikinashi['close'] dataframe['hk_high'] = heikinashi['high'] dataframe['hk_low'] = heikinashi['low'] dataframe['trend_close_5m'] = dataframe['close'] dataframe['trend_close_15m'] = ta.EMA(dataframe['close'], timeperiod=3) dataframe['trend_close_30m'] = ta.EMA(dataframe['close'], timeperiod=6) dataframe['trend_close_1h'] = ta.EMA(dataframe['close'], timeperiod=12) dataframe['trend_close_2h'] = ta.EMA(dataframe['close'], timeperiod=24) dataframe['trend_close_4h'] = ta.EMA(dataframe['close'], timeperiod=48) dataframe['trend_close_6h'] = ta.EMA(dataframe['close'], timeperiod=72) dataframe['trend_close_8h'] = ta.EMA(dataframe['close'], timeperiod=96) dataframe['trend_open_5m'] = dataframe['hk_open'] dataframe['trend_open_15m'] = ta.EMA(dataframe['hk_open'], timeperiod=3) dataframe['trend_open_30m'] = ta.EMA(dataframe['hk_open'], timeperiod=6) dataframe['trend_open_1h'] = ta.EMA(dataframe['hk_open'], timeperiod=12) dataframe['trend_open_2h'] = ta.EMA(dataframe['hk_open'], timeperiod=24) dataframe['trend_open_4h'] = ta.EMA(dataframe['hk_open'], timeperiod=48) dataframe['trend_open_6h'] = ta.EMA(dataframe['hk_open'], timeperiod=72) dataframe['trend_open_8h'] = ta.EMA(dataframe['hk_open'], timeperiod=96) dataframe['fan_magnitude'] = (dataframe['trend_close_1h'] / dataframe['trend_close_8h']) dataframe['fan_magnitude_gain'] = dataframe['fan_magnitude'] / dataframe['fan_magnitude'].shift(1) ichimoku = ftt.ichimoku(dataframe, conversion_line_period=20, base_line_periods=60, laggin_span=120, displacement=30) dataframe['chikou_span'] = ichimoku['chikou_span'] dataframe['tenkan_sen'] = ichimoku['tenkan_sen'] dataframe['kijun_sen'] = ichimoku['kijun_sen'] dataframe['senkou_a'] = ichimoku['senkou_span_a'] dataframe['senkou_b'] = ichimoku['senkou_span_b'] dataframe['leading_senkou_span_a'] = ichimoku['leading_senkou_span_a'] dataframe['leading_senkou_span_b'] = ichimoku['leading_senkou_span_b'] dataframe['cloud_green'] = ichimoku['cloud_green'] dataframe['cloud_red'] = ichimoku['cloud_red'] dataframe['atr'] = ta.ATR(dataframe) # MFI dataframe['mfi'] = ta.MFI(dataframe) return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # The indicators for the 1h informative timeframe informative_1h = self.informative_1h_indicators(dataframe, metadata) dataframe = merge_informative_pair(dataframe, informative_1h, self.timeframe, self.informative_timeframe, ffill=True) # The indicators for the normal (5m) timeframe dataframe = self.normal_tf_indicators(dataframe, metadata) #Import 15m indicators informative_15m = self.informative_15m_indicators(dataframe, metadata) dataframe = merge_informative_pair(dataframe, informative_15m, self.timeframe, self.inf_15m, ffill=True) drop_columns = [(s + "_" + self.inf_15m) for s in ['date']] dataframe.drop(columns=dataframe.columns.intersection(drop_columns), inplace=True) #Pump protection dataframe['weekly_close_avg_offset'] = self.pump_recorver_price.value * dataframe['weekly_close_avg_1h'] dataframe['price_test'] = dataframe['close'] > dataframe['weekly_close_avg_offset'] dataframe['pump_price_test'] = dataframe['max_flow_price_15m'] > self.pump_limit.value # Check if a pump uccured during pump_pause_duration and coin didn't recovered its pre pump value dataframe['pump_dump_alert'] = dataframe['price_test'] & dataframe['pump_price_test'] dataframe['buy_ok'] = np.where(dataframe['pump_dump_alert'], False, True) return dataframe ## Confirm Entry def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, **kwargs) -> bool: dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) max_slip = self.max_slip.value if(len(dataframe) < 1): return False dataframe = dataframe.iloc[-1].squeeze() if ((rate > dataframe['close'])) : slippage = ( (rate / dataframe['close']) - 1 ) * 100 if slippage < max_slip: return True else: return False return True def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] dataframe.loc[:, 'buy_tag'] = '' is_protection = ( (pct_change(dataframe['btc_1d'], dataframe['btc_5m']).fillna(0) > self.buy_btc_safe_1d.value) & (dataframe['pump_strength_2'] < self.antipump_threshold_2.value)& (dataframe['buy_ok'])& (dataframe['volume'] > 0) ) if self.buy_params['tesla_enabled'] >= True: tesla = ( (dataframe['rsi'] > dataframe['rsi_1h']) & (dataframe['trend_close_8h'] > dataframe['trend_close_6h'])& (dataframe['trend_close_15m'] > dataframe['trend_close_30m'])& (dataframe['trend_open_5m'] > dataframe['trend_open_15m'])& (dataframe['trend_close_1h']> dataframe['ema55'])& (dataframe['ema21']> dataframe['trend_close_4h'])& (dataframe['trend_open_1h'] > dataframe['trend_open_2h'])& (dataframe['mfi'] < 70)& (dataframe['fan_magnitude_gain'] >= self.buy_min_fan_magnitude_gain.value) & (dataframe['fan_magnitude'] > 0.99) ) conditions.append(tesla) dataframe.loc[tesla, 'buy_tag'] += 'tesla_' if conditions: dataframe.loc[ is_protection & reduce(lambda x, y: x & y, conditions), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] conditions.append(qtpylib.crossed_below(dataframe['trend_close_5m'], dataframe[self.sell_params['sell_trend_indicator']])) if conditions: dataframe.loc[ reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe def rollingNormalize(self, dataframe, name): df = dataframe.copy() df[name + '_nmin'] = df[name].rolling(window=1440 // self.timeframe_minutes).min() df[name + '_nmax'] = df[name].rolling(window=1440 // self.timeframe_minutes).max() return np.where(df[name + '_nmin'] == df[name + '_nmax'], 0, (2.0*(df[name]-df[name + '_nmin'])/(df[name + '_nmax']-df[name + '_nmin'])-1.0)) def normalize(data, min_value, max_value): return (data - min_value) / (max_value - min_value) def pct_change(a, b): return (b - a) / a # smoothed Heiken Ashi def HA(dataframe, smoothing=None): df = dataframe.copy() df['HA_Close']=(df['open'] + df['high'] + df['low'] + df['close'])/4 df.reset_index(inplace=True) ha_open = [ (df['open'][0] + df['close'][0]) / 2 ] [ ha_open.append((ha_open[i] + df['HA_Close'].values[i]) / 2) for i in range(0, len(df)-1) ] df['HA_Open'] = ha_open df.set_index('index', inplace=True) df['HA_High']=df[['HA_Open','HA_Close','high']].max(axis=1) df['HA_Low']=df[['HA_Open','HA_Close','low']].min(axis=1) if smoothing is not None: sml = abs(int(smoothing)) if sml > 0: df['Smooth_HA_O']=ta.EMA(df['HA_Open'], sml) df['Smooth_HA_C']=ta.EMA(df['HA_Close'], sml) df['Smooth_HA_H']=ta.EMA(df['HA_High'], sml) df['Smooth_HA_L']=ta.EMA(df['HA_Low'], sml) return df def pump_warning(dataframe, perc=15): df = dataframe.copy() df["change"] = df["high"] - df["low"] df["test1"] = (df["close"] > df["open"]) df["test2"] = ((df["change"]/df["low"]) > (perc/100)) df["result"] = (df["test1"] & df["test2"]).astype('int') return df['result']