def add_bbands(df, period=5, stddev=2): l = len(df.close.values) (bbands_lower, bbands_middle, bbands_upper) = ti.bbands( (df.close.values), period, stddev,) df[f'bbands_upper_{period}{stddev}'] = pad_left(bbands_upper, l) df[f'bbands_lower_{period}{stddev}'] = pad_left(bbands_lower, l) df[f'bbands_middle_{period}{stddev}'] = pad_left(bbands_middle, l)
def _Bull(self, data, timeframe=None, symbol=None): timeframe = '1h' ohlcv_close = self.ohlcv[:, 3].copy(order='C') __bbands = ti.bbands(ohlcv_close, period=20, stddev=2) self.BBands = { 'low': __bbands[0][-1], 'middle': __bbands[1][-1], 'high': __bbands[2][-1] }
def test_TA_basics(): rsi_result = tulipy.rsi(DATA, period=9) assert all(74 < v < 86 for v in rsi_result) assert len(rsi_result) == 6 sma_result = tulipy.sma(DATA, period=9) assert all(74 < v < 86 for v in sma_result) assert len(sma_result) == 7 bands = tulipy.bbands(DATA, period=9, stddev=2) assert all(80 < v < 89 for band in bands for v in band) assert len(bands) == 3
def get_mean_open_close(number=120, kline_size='1m'): prices = [] # A utiliser que pour testnet !! # link = str(settings.BASE_URL) + "trade?symbol=XBTUSD&count="\ # + str(number * binsizes[kline_size]) + "&columns=price&reverse=true" link_ohlc = "https://www.bitmex.com/api/v1/trade/bucketed?binSize=1m&partial=true&symbol=XBTUSD&count=20&reverse=true" f = requests.get(link_ohlc) ohlc = pd.DataFrame(f.json()) ohlc = ohlc[['open', 'high', 'low', 'close']] # datta = TA.bb link = str(settings.BASE_URL) + "trade?symbol=.BXBT&count="\ + str(number * binsizes[kline_size]) + "&columns=price&reverse=true" f = requests.get(link) for x in f.json(): prices.append(float(x['price'])) prices = get_prices_binsize(prices, binsizes[kline_size]) prices.reverse() # Library Tulipy DATA = np.array(prices) bbands = ti.bbands(DATA, period=5, stddev=2) res = TA.BBANDS( get_all_bitmex('XBTUSD', kline_size, False, nb=(number * 2 * binsizes[kline_size]))) temp_df = pd.DataFrame() temp_df['BB_LOWER'] = bbands[0][-1:] temp_df['BB_MIDDLE'] = bbands[1][-1:] temp_df['BB_UPPER'] = bbands[2][-1:] # # AFFICHAGE COURBES # low = list(bbands[0]) middle = list(bbands[1]) high = list(bbands[2]) low = list(res.BB_LOWER[-number:]) middle = list(res.BB_MIDDLE[-number:]) high = list(res.BB_UPPER[-number:]) # plt.plot(high, color='orange') # plt.plot(middle, color='g') # plt.plot(low, color='yellow') # plt.plot(prices, color='red') # plt.show() # return temp_df return res[-number:], bbands
def calculate(self, candles): candles_len = len(candles) if candles_len < self.period: return float(0) val_array = np.array([float(x['ohlc'].close) for x in candles[-self.period:]]) #calculate (upperband, middleband, lowerband) = ti.bbands (val_array, period=self.period, stddev=self.stddev) return (upperband[-1], middleband[-1], lowerband[-1])
async def evaluate(self, cryptocurrency, symbol, time_frame, candle_data, candle): self.eval_note = commons_constants.START_PENDING_EVAL_NOTE if len(candle_data) >= self.period_length: # compute bollinger bands lower_band, middle_band, upper_band = tulipy.bbands( candle_data, self.period_length, 2) # if close to lower band => low value => bad, # therefore if close to middle, value is keeping up => good # finally if up the middle one or even close to the upper band => very good current_value = candle_data[-1] current_up = upper_band[-1] current_middle = middle_band[-1] current_low = lower_band[-1] delta_up = current_up - current_middle delta_low = current_middle - current_low # its exactly on all bands if current_up == current_low: self.eval_note = commons_constants.START_PENDING_EVAL_NOTE # exactly on the middle elif current_value == current_middle: self.eval_note = 0 # up the upper band elif current_value > current_up: self.eval_note = 1 # down the lower band elif current_value < current_low: self.eval_note = -1 # regular values case: use parabolic factor all the time else: # up the middle band if current_middle < current_value: self.eval_note = math.pow( (current_value - current_middle) / delta_up, 2) # down the middle band elif current_middle > current_value: self.eval_note = -1 * math.pow( (current_middle - current_value) / delta_low, 2) await self.evaluation_completed( cryptocurrency, symbol, time_frame, eval_time=evaluators_util.get_eval_time(full_candle=candle, time_frame=time_frame))
def analyse_recent_trend_changes(data, delta_function): # compute bollinger bands lower_band, middle_band, upper_band = tulipy.bbands(data, 20, 2) # if close to lower band => low value => bad, # therefore if close to middle, value is keeping up => good # finally if up the middle one or even close to the upper band => very good current_value = data[-1] current_up = upper_band[-1] current_middle = middle_band[-1] current_low = lower_band[-1] delta_up = current_up - current_middle delta_low = current_middle - current_low # its exactly on all bands if current_up == current_low: return commons_constants.START_PENDING_EVAL_NOTE # exactly on the middle elif current_value == current_middle: return 0 # up the upper band elif current_value > current_up: return -1 # down the lower band elif current_value < current_low: return 1 # delta given: use parabolic factor after delta, linear before delta = delta_function(numpy.mean([delta_up, delta_low])) micro_change = ((current_value / current_middle) - 1) / 2 # approximately on middle band if current_middle + delta >= current_value >= current_middle - delta: return micro_change # up the middle area elif current_middle + delta < current_value: return -1 * max(micro_change, (current_value - current_middle) / delta_up) # down the middle area elif current_middle - delta > current_value: return max(micro_change, (current_middle - current_value) / delta_low) # should not happen return 0
def eval_impl(self): self.eval_note = START_PENDING_EVAL_NOTE period_length = 20 if len(self.data[PriceIndexes.IND_PRICE_CLOSE.value]) >= period_length: # compute bollinger bands lower_band, middle_band, upper_band = tulipy.bbands( self.data[PriceIndexes.IND_PRICE_CLOSE.value], period_length, 2) # if close to lower band => low value => bad, # therefore if close to middle, value is keeping up => good # finally if up the middle one or even close to the upper band => very good current_value = self.data[PriceIndexes.IND_PRICE_CLOSE.value][-1] current_up = upper_band[-1] current_middle = middle_band[-1] current_low = lower_band[-1] delta_up = current_up - current_middle delta_low = current_middle - current_low # its exactly on all bands if current_up == current_low: self.eval_note = START_PENDING_EVAL_NOTE # exactly on the middle elif current_value == current_middle: self.eval_note = 0 # up the upper band elif current_value > current_up: self.eval_note = 1 # down the lower band elif current_value < current_low: self.eval_note = -1 # regular values case: use parabolic factor all the time else: # up the middle band if current_middle < current_value: self.eval_note = math.pow( (current_value - current_middle) / delta_up, 2) # down the middle band elif current_middle > current_value: self.eval_note = -1 * math.pow( (current_middle - current_value) / delta_low, 2)
def inds(self): Indicators = {} for i in range(len(self.time)): #i/o? ''' 2 = High, 3 = Low, 4 = Close, 5 = Volume collects the needed market data into one list to push to the indicators''' close = self.time[i][4].values.copy(order='C') high = self.time[i][2].values.copy(order='C') low = self.time[i][3].values.copy(order='C') volume = self.time[i][5].values.copy(order='C') # !!!This needs to be changed. Each volume of the base time must be indexed up to the slice __time = self.time[i][6] # these are the indicators currently being used, and recored Indicators[i] = { 'stochrsi': ti.stochrsi(close, 5), 'rsi': ti.rsi(close, 5), # indicators that need to be doublechecked 'mfi': ti.mfi(high, low, close, volume, 5), 'sar': ti.psar(high, low, .2, 2), 'cci': ti.cci(high, low, close, 5), 'ema': ti.ema(close, 5) } # this one is good Indicators[i]['stoch_k'], Indicators[i]['stoch_d'] = ti.stoch( high, low, close, 5, 3, 3) # check on this, to see if it functions properly Indicators[i]['bbands_lower'], Indicators[i]['bbands_middle'], Indicators[i]['bbands_upper'] = ti.bbands(close, 5, 2) Indicators[i]['macd'], Indicators[i]['macd_signal'], Indicators[i]['macd_histogram'] = ti.macd(close, 12, 26, 9) Indicators[i]['time'] = __time Indicators[i]['close'] = close ''' below changes the length of each array to match the longest one, for a pandas df np.nan for the tail of the shorter ones''' Indicators[i] = to_pd(Indicator=Indicators[i]).dropna(how='all') return Indicators
def analyze(self, historical_data, period_count=20): """Performs a bollinger band analysis on the historical data Args: historical_data (list): A matrix of historical OHCLV data. period_count (int, optional): Defaults to 21. The number of data points to consider for our bollinger bands. Returns: pandas.DataFrame: A dataframe containing the indicators and hot/cold values. """ dataframe = self.convert_to_dataframe(historical_data) bb_columns = { 'upperband': [numpy.nan] * dataframe.index.shape[0], 'middleband': [numpy.nan] * dataframe.index.shape[0], 'lowerband': [numpy.nan] * dataframe.index.shape[0] } bb_values = pandas.DataFrame( bb_columns, index=dataframe.index ) bb_df_size = bb_values.shape[0] close_data = numpy.array(dataframe['close']) if close_data.size > period_count: bb_data = tulipy.bbands(close_data, period_count, 2) for index in range(period_count, bb_df_size): data_index = index - period_count bb_values['lowerband'][index] = bb_data[0][data_index] bb_values['middleband'][index] = bb_data[1][data_index] bb_values['upperband'][index] = bb_data[2][data_index] bb_values.dropna(how='all', inplace=True) return bb_values
def strategy(): import smtplib, ssl # E-Mail from website import config from website.helpers import helpers from website.models import Param_stock_strategy_bollinger, Stock_strategy, Strategy, Stock, Market from website.extensions import db, alpaca_api from sqlalchemy import asc import tulipy import pandas as pd import time t0 = time.time() DEBUG = False ## TODO: # - Database for opening-times Market and times to apply the strategy. # - Backtesting strategy with UI current_date = '2021-06-24' # Check on specific day (DEBUG) # current_date = helpers.get_date_today() # Check today (Script) if DEBUG == True: print(f"Current date: {current_date}") context = ssl.create_default_context() # Email messages = [] # Placeholder messages # [cursor, connection] = helpers.init_database() # Init Database strategy_id = db.session.query(Strategy).with_entities( Strategy.id, ).filter( Strategy.name == 'bollinger_bands').first()[0] # Get Stocks which get handled with bollinger band strategy stocks = db.session.query(Stock).join( Market, Market.id == Stock.market_id # join market on market.id = stock.market_id ).join( Stock_strategy, Stock_strategy.stock_id == Stock.id # join stock_strategy on stock_strategy.stock_id = stock.id ).join( Param_stock_strategy_bollinger, Param_stock_strategy_bollinger.parameter_id == Stock_strategy.parameter_id # join param_stock_strategy_breakdown on param_stock_strategy_breakdown.id = stock_strategy.parameter_id ).with_entities( # select stock.symbol, stock.name, market.market_open_local, market.market_close_local, # market.timezone, param_stock_strategy_breakdown.observe_from, # param_stock_strategy_breakdown.observe_until, # param_stock_strategy_breakdown.trade_price Stock.symbol, Stock.name, Market.market_open_local, Market.market_close_local, Market.timezone, Param_stock_strategy_bollinger.period, Param_stock_strategy_bollinger.stddev, Param_stock_strategy_bollinger.trade_price).filter( Stock_strategy.strategy_id == strategy_id # where stock_strategy.strategy_id = ? ).order_by(asc(Stock.symbol)).all() # symbols = [stock.symbol for stock in stocks] # extract symbols from stocks (stock) # for stock in stocks: # if DEBUG == True: print(stock.name) # for symbol in symbols: # if DEBUG == True: print(symbol) # orders = alpaca_api.list_orders() # get list of all orders orders = alpaca_api.list_orders( status='all', after=current_date ) # get list of all orders from today (we only want to trade once a day) existing_order_symbols = [ order.symbol for order in orders if order.status != 'canceled' # if any order not been placed, trade it (List) ] for stock in stocks: start = helpers.get_timestamp( current_date, stock.market_open_local, stock.timezone ).isoformat() # start-date and time market-opening end_time = helpers.get_timestamp(current_date, stock.market_close_local, stock.timezone) end = end_time.isoformat() # end-date and time market-closing if DEBUG == True: print("Ready_steady") # end-date and time market-closing if not pd.Timestamp.today().strftime("%H:%M") < end_time.strftime( "%H:%M"): # if market is open if DEBUG == True: print("go bollinger") # end-date and time market-closing time_bars = alpaca_api.get_barset( stock.symbol, 'minute', start=start, end=end ).df # get stock-specific minute bars for the day online # minute_bars = alpaca_api.polygon.historic_agg_v2(stock['symbol'], 1, 'minute', _from='2020-10-28', to='2020-10-29').df if DEBUG == True: print(time_bars) if DEBUG == True: print(start) # if DEBUG == True: print(helpers.get_timestamp2(f"{time_bars[stock.symbol].index[0]}", stock.timezone).isoformat()) market_open_mask = [ (helpers.get_timestamp2( f"{index}", stock.timezone).isoformat() >= start) & (helpers.get_timestamp2(f"{index}", stock.timezone).isoformat() < end) for index in time_bars[stock.symbol].index ] market_open_bars = time_bars[ stock.symbol].loc[market_open_mask] if len(market_open_bars) >= 20: closes = market_open_bars.close.values lower, middle, upper = tulipy.bbands( closes, stock.period, stock.stddev) current_candle = market_open_bars.iloc[-1] previous_candle = market_open_bars.iloc[-2] if current_candle.close > lower[ -1] and previous_candle.close < lower[-2]: print( f"{stock.symbol} closed below the lower bollingerband" ) if stock.symbol not in existing_order_symbols: limit_price = current_candle.close candle_range = previous_candle.high - previous_candle.low message = f"placing order for {stock.symbol} at {limit_price}" if DEBUG == True: print(message) f = open("logfiles/bollinger_bands.txt", "a") f.write(message + "\r") f.close() messages.append(message) try: alpaca_api.submit_order( symbol=stock.symbol, side='buy', type='limit', qty=helpers.calculate_quantity( stock.trade_price, limit_price), time_in_force='day', order_class='bracket', limit_price=limit_price, take_profit=dict(limit_price=limit_price + candle_range * 3, ), stop_loss=dict( stop_price=previous_candle.low, )) except Exception as e: print(f"could not submit order {e}") else: print( f"Already an order for {stock.symbol}, skipping" ) # print(messages) if len(messages) > 0: with smtplib.SMTP_SSL(config.EMAIL_HOST, config.EMAIL_PORT, context=context) as server: server.login(config.EMAIL_ADDRESS, config.EMAIL_PASSWORD) email_message = f"Subject: Trade Notification for {current_date}\n\n" email_message += "\n\n".join(messages) server.sendmail(config.EMAIL_ADDRESS, '*****@*****.**', email_message) t1 = time.time() - t0 print("Time elapsed bollinger: ", t1) # CPU seconds elapsed (floating point)
for symbol in symbols: # REPLACE with tda-stream # minute_bars = api.polygon.historic_agg_v2(symbol, 1, 'minute', _from=current_date, to=current_date).df # REPLACEMENT minute_bars = get_latest_tda_minute_bars(symbol, conn) market_open_mask = (minute_bars.chart_time >= start_minute_bar) & ( minute_bars.chart_time < end_minute_bar) market_open_bars = minute_bars.loc[market_open_mask] if len(market_open_bars) >= 20: closes = market_open_bars.close.values lower, middle, upper = tulipy.bbands(closes, 20, 2) current_candle = market_open_bars.iloc[-1] previous_candle = market_open_bars.iloc[-2] # entry signal if current_candle.close > lower[-1] and previous_candle.close < lower[ -2]: if symbol not in existing_order_symbols: limit_price = current_candle.close candle_range = current_candle.high - current_candle.low qty = calculate_quantity(limit_price) print(f"placing order for {symbol} at {limit_price}")
def bbands(self): try: return bbands(self.data, self.period, self.stddev) except Exception: logging.exception('')
def get_BollingerBands(close, signal, stddev): bbands = np.zeros([3, len(close)]) bbands[:,(signal-1):] = np.array(ti.bbands(close, signal,stddev)) return bbands
def compute(self, data_dict): close = data_dict.get('close') return ti.bbands(close, self.per, self.std)[1]