def _calc_indicator(self, OHLCV_input): """ Calculates the Moving Average Convergence/Divergence using a wrapper for the TA-lib Args: :param OHLCV_input: the dataframe with the Open, High, Low, Close and Volume values :type OHLCV_input: pandas DataFrame Returns: DataFrame with scaled features with size (n_observations, n_features). """ try: close = OHLCV_input['close'].values[:, 0] except IndexError: close = OHLCV_input['close'].values macd, macdsignal, macdhist = MACD(close, self.__fastperiod, self.__slowperiod, self.__signalperiod) macd = DataFrame(macd) macdsignal = DataFrame(macdsignal) macdhist = DataFrame(macdhist) macd.colmuns = ['macd%d' % self.__signalperiod] macdsignal.colmuns = ['macdsignal%d' % self.__signalperiod] macdhist.colmuns = ['macdhist%d' % self.__signalperiod] return concat([macd, macdsignal, macdhist], axis=1, ignore_index=True)
def WADDAH_ATTAR_EXPLOSION(close, high, low, sensitive = 150, fast_period=20, slow_period = 40, channel_period = 20, channel_mult = 2, dead_zone=30): from talib import MACD from talib import BBANDS from talib import ATR from talib import WMA macd, macdsignal, macdhist = MACD(close, fastperiod=fast_period, slowperiod=slow_period, signalperiod=9) upperband, middleband, lowerband = BBANDS(close, timeperiod=channel_period, nbdevup=channel_mult, nbdevdn=channel_mult, matype=0) ind_trend1 = np.full(len(close), np.nan) ind_itrend1 = np.full(len(close), np.nan) ind_explo1 = np.full(len(close), np.nan) tr = WMA(ATR(high, low, close, 20),3) ind_dead = tr*dead_zone / 10 for i in range(0,len(close)): if(i<2): continue trend1 = (macd[i] - macd[i-1]) * sensitive; trend2 = (macd[i-1] - macd[i-2]) * sensitive; explo1 = (upperband[i] - lowerband[i]) #explo2 = (upperband[i-1] - lowerband[i-1]) if(trend1>=0): ind_trend1[i]=trend1 ind_itrend1[i]=0 if(trend1<0): ind_trend1[i]=0 ind_itrend1[i]=(trend1*-1) ind_explo1[i] = explo1 #print(str(i)+"\t "+str(close[i])+"\t "+str(close[i])+"\t "+str(ind_trend1[i])+"\t"+str(ind_itrend1[i])) return ind_trend1, ind_itrend1, ind_explo1, ind_dead
async def handle_buy_side( self, symbols_position: Dict[str, float], data_loader: DataLoader, now: datetime, trade_fee_precentage: float, ) -> Dict[str, Dict]: actions = {} for symbol, position in symbols_position.items(): if position != 0: continue current_price = data_loader[symbol].close[now] sma_50 = ( data_loader[symbol] .close[now - timedelta(days=60) : now] # type: ignore .resample("1D") .last() .rolling(50) .mean() .dropna() .iloc[-1] ) if current_price >= sma_50: macds = MACD( data_loader[symbol].close[now - timedelta(days=100) : now], # type: ignore 12, 26, 9, ) macd = macds[0] macd_signal = macds[1] if macd[-1] > macd_signal[-1] and macd[-1] > 0: buy_indicators[symbol] = { "sma_50": sma_50, "macd": macd[-5:].tolist(), "mac_signal": macd_signal[-5:].tolist(), "current_price": current_price, } shares_to_buy = await self.calc_qty( current_price, trade_fee_precentage, ) tlog( f"[{self.name}][{now}] Submitting buy for {shares_to_buy} shares of {symbol} at {current_price}" ) tlog(f"indicators:{buy_indicators[symbol]}") actions[symbol] = { "side": "buy", "qty": str(shares_to_buy), "type": "limit", "limit_price": str(current_price), } return actions
def calculate_indicators(df): logging.info('Calculating indicators...') # Build dictionary: indicator_dict = dict() # MACD fast = 12 slow = 26 signal = 9 macd, macdsignal, macdhist = MACD(df['price_close'], fast, slow, signal) indicator_dict['macd_current'] = macd[-1] indicator_dict['macd_signal_current'] = macdsignal[-1] # ADX time_period = 14 adx = ADX(df['price_high'], df['price_low'], df['price_close'], time_period) indicator_dict['adx_current'] = adx[-1] # DI+/DI- time_period = 14 di_plus = PLUS_DI(df['price_high'], df['price_low'], df['price_close'], time_period) di_minus = MINUS_DI(df['price_high'], df['price_low'], df['price_close'], time_period) indicator_dict['di_plus_current'] = di_plus[-1] indicator_dict['di_minus_current'] = di_minus[-1] return indicator_dict
def refresh(self, df): df = df[-(MAX_ROWS + 1):-1] open = df.open.astype("f8").values high = df.high.astype("f8").values low = df.low.astype("f8").values close = df.close.astype("f8").values volume = df.volume.astype("f8").values df["price"] = WCLPRICE(high, low, close) #Weighted Close Price df["obv"] = OBV(close, volume) df["ad"] = AD(high, low, close, volume) df["macd"], df["signal"], df["histogram"] = MACD(close) df["rsi"] = RSI(close) #relative strong index #df["willr"] = WILLR(high, low, close) + 100 #will index df["roc"] = ROC(close) #統計 df["beta"] = BETA(high, low) df["linearR"] = LINEARREG(close) #線形回帰 df["linearA"] = LINEARREG_ANGLE(close) ##線形回帰 角度 df["linearI"] = LINEARREG_INTERCEPT(close) #線形回帰 JIEJU df["linearS"] = LINEARREG_SLOPE(close) #線形回帰 坂 df["stddev"] = STDDEV(close) #標準偏差 df["tsf"] = TSF(close) #Time Series Forecast df["var"] = VAR(close) #方差 df["wramount"] = 0 df["amount"] = 0 df["memo"] = 0
def getMACD(price): date = 1 MACD_ = [] macd, macdsignal, macdhist = MACD(price) for ele,ele1,ele2 in zip(macd, macdsignal, macdhist): MACD_.append([date, ele,ele1,ele2]) date = date + 1 return MACD_
def calcMACD(self, dates, price): MACD_ = [] macd, macdsignal, macdhist = MACD(price) for ele, ele1, ele2 in zip(macd, macdsignal, macdhist): MACD_.append([ele, ele1, ele2]) MACD_, isExist = self.createDateFrame( dates, MACD_, ['timestamp', 'macd', 'macdsignal', 'macdhist']) return MACD_, isExist
def execute(self, env, df): ''' Execute a single iteration of algorithmic trading ''' last_row_idx = len(df) - 1 for product_id in env.product_id_list: product_df = df[product_id] rsi = RSI(product_df.close) macd, macd_signal, macd_hist = MACD( product_df.close, fastperiod=self.fast_period, slowperiod=self.slow_period, signalperiod=self.signal_period) if self.states.get(product_id) is None: self.states[product_id] = NO_POSITION next_state = self.next_state(product_id, rsi[last_row_idx], macd[last_row_idx]) if self.states[product_id] != next_state: if next_state == BUY: # buy if len(env.positions) == 0: quantity = env.balance / product_df.close[last_row_idx] ts = product_df.timestamp[last_row_idx] price = product_df.close[last_row_idx] buy_order = BuyMarketOrder(product_id, ts, funds=env.balance) env.process_buy_order(buy_order) else: print("already holding trade") self.states[product_id] = POSITION_HELD elif next_state == SELL: # sell if len(env.positions): for position in env.find_positions( lambda x: x.product_id == product_id): ts = product_df.timestamp[last_row_idx] sell_order = SellMarketOrder( product_id, ts, quantity=position.quantity, ) env.process_sell_order(sell_order) else: print("did not have active trade") self.states[product_id] = NO_POSITION else: self.states[product_id] = next_state
def binaryClassificationInThirtyMinutes(self, df): ''' Predict the price of bitcoin in the next 30 minutes by a given df (dataframe) Example: binaryClassificationInThirtyMinutes(df) = 0 Parameters: df: a dataframe with df.columns = ['open', 'high', 'low', 'close', 'volume'] Returns: prediction: int = a prediction by the model, 0 for down, 1 for same or up ''' # if len(df) != 34: # # due to wma # raise Exception("Dataframe must have 34 rows") data = df.copy() rsi = RSI(data['close']) k, d = STOCH(data['high'], data['low'], data['close']) macd, macdsignal, macdhist = MACD(data['close'], fastperiod=12, slowperiod=26, signalperiod=9) williams_r = WILLR(data['high'], data['low'], data['close']) rate_of_change = ROC(data['close']) on_balance_volume = OBV(data['close'], data['volume']) weighted_moving_average = WMA(data['close']) normalized_average_true_range = NATR(data['high'], data['low'], data['close']) data['rsi'] = rsi data['k'] = k data['d'] = d data['macd'] = macd data['williams_r'] = williams_r data['rate_of_change'] = rate_of_change data['on_balance_volume'] = on_balance_volume data['weighted_moving_average'] = weighted_moving_average data['normalized_average_true_range'] = normalized_average_true_range data = data.dropna(axis=0) data = self.normalizeDataframe(data) with open( pathlib.Path(__file__).resolve().parent / "random_forest_params", "rb") as file: model = pickle.load(file) features = data.values prediction = model.predict(features) return prediction[0]
def compute_macd(df, field=None, fast_period=None, slow_period=None, signal_period=None): df['macd'], df['macd_signal'], df['macd_hist'] = MACD( df[field].values.astype(float), fastperiod=fast_period, slowperiod=slow_period, signalperiod=signal_period) return df
def CalculateIndices(df): MACD_FAST = 10 MACD_SLOW = 21 MACD_SIGNAL = 7 macd, macdSignal, macdHist = MACD(df['c'], MACD_FAST, MACD_SLOW, MACD_SIGNAL) rsi10 = RSI(df['c'], 10) rsi14 = RSI(df['c'], 14) return macd, macdSignal, macdHist, rsi10, rsi14
def create_lots_of_macds(prices): macd, macdsignal, macdhist = MACD(prices, fastperiod=12, slowperiod=26, signalperiod=9) all_macds = np.reshape(macdsignal, (len(prices), 1)) for fast_period in range(9, 16): for slow_period in range(20, 31): for signal_period in range(5, 12): macd, macdsignal2, macdhist = MACD(prices, fastperiod=fast_period, slowperiod=slow_period, signalperiod=signal_period) current_macd = np.reshape(macdsignal2, (len(prices), 1)) all_macds = np.hstack((all_macds, current_macd)) return all_macds
def CalculateIndices(df): MACD_FAST = 10 MACD_SLOW = 21 MACD_SIGNAL = 7 macd, macdSignal, macdHist = MACD(df['c'], MACD_FAST, MACD_SLOW, MACD_SIGNAL) df[ind_columns[0]] = macd df[ind_columns[1]] = macdSignal df[ind_columns[2]] = macdHist return df
def update(self, data): Candle.update(self, data) candles = self.dataline.get_nd_candles( data['token'], self.timeperiod, self.prev, count=200) r = None try: r = MACD(np.array(candles['close']), self.fastperiod, self.slowperiod, self.signalperiod) except: r = {self.k : [0]} print("Exception") self.setd(0 if np.isnan(r[self.k][-1]) else r[self.k][-1]) return self
def get_indicators(df, indicators=[]): if "bbands" in indicators: df["upperband"], df["middleband"], df["lowerband"] = BBANDS( df["close"], timeperiod=20, nbdevup=2, nbdevdn=2, matype=0) if "macd" in indicators: df["macd"], df["macdsignal"], df["macdhist"] = MACD(df["close"], fastperiod=12, slowperiod=26, signalperiod=9) if "price_logreturn" in indicators: df["price_logreturn"] = log_return(df["close"].to_numpy()) if "volume_logreturn" in indicators: df["volume_logreturn"] = log_return(df["volume"].to_numpy()) return df
def handle_data(context, data): # Request history for the stock history = data.history(context.universe, "close", context.index_average_window, "1d") for i in range(len(history.columns)): stock = np.array(history.iloc[:, i]) macd, macdsignal, macdhist = MACD(stock, fastperiod=12, slowperiod=26, signalperiod=9) if macd[-2] <= macdsignal[-2] and macd[-1] > macdsignal[-1]: order_target_percent(history.columns[i], 0.2) if macd[-2] >= macdsignal[-2] and macd[-1] < macdsignal[-1]: order_target_percent(history.columns[i], 0.0)
def execute(self, df): last_row_idx = len(df) - 1 macd, macd_signal, macd_hist = MACD(df.close, fastperiod=self.fast_period, slowperiod=self.slow_period, signalperiod=self.signal_period) macd_state = MACD_HIGH if macd_hist[last_row_idx] > 0 else MACD_LOW if self.signal is None: self.signal = macd_state elif self.signal != macd_state: if macd_state == MACD_HIGH: # buy if self.trade is None: quantity = self.cash / df.close[last_row_idx] product_id = df.product_id[last_row_idx] ts = df.timestamp[last_row_idx] price = df.close[last_row_idx] trade = Trade(product_id, ts, price, quantity, self.cash) print( f"Bought {quantity} shares of {product_id} at " f"{ts} for {price} a share (for a total of {self.cash})" ) self.trade = trade self.cash = 0 else: print("already holding trade") elif macd_state == MACD_LOW: # sell if self.trade is not None: sell_price = df.close[last_row_idx] sell_value = self.trade.quantity * sell_price sell_ts = df.timestamp[last_row_idx] print( f"Sold {self.trade.quantity} shares of {self.trade.product_id} " f"at {sell_ts} for {sell_price} a share (for a total " f"of {sell_value}, profit of " f"{sell_value-self.trade.value}") self.cash = sell_value self.trade = None else: print("did not have active trade") self.signal = macd_state
def calculateIndex(filePath): File = open(filePath, "r") text = File.read() text = text.rstrip() File.close() OHLCV = json.loads(text) timePeriod = np.array(OHLCV['t']) nClose = np.array(OHLCV['c']) rsi = RSI(nClose, timeperiod=RSI_T) macd, macdSignal, macdHist = MACD(nClose, MACD_FAST, MACD_SLOW, MACD_SIGNAL) emaSlow = EMA(nClose, EMA_SLOW) emaMedium = EMA(nClose, EMA_MEDIUM) emaFast = EMA(nClose, EMA_FAST) #print("RSI (first 10 elements)\n", rsi[10:20]) return timePeriod, rsi, macd, macdSignal, macdHist, emaSlow, emaMedium, emaFast
def calculateIndex(filePath): File = open(filePath, "r") text = File.read() text = text.rstrip() File.close() OHLCV = json.loads(text) timePeriod = OHLCV['t'] if timePeriod: nClose = np.array(OHLCV['c']) rsi = RSI(nClose, timeperiod=RSI_T) macd, macdSignal, macdHist = MACD(nClose, MACD_FAST, MACD_SLOW, MACD_SIGNAL) #print("RSI (first 10 elements)\n", rsi[-1]) return rsi, macd, macdSignal, macdHist else: return 100, 0, 0, 0
def create_lots_of_macds(historical_data): prices = historical_data['Adj Close'].as_matrix() all_macds = dict() for fast_period in range(9, 16): for slow_period in range(20, 31): for signal_period in range(5, 12): macd, macdsignal2, macdhist = MACD(prices, fastperiod=fast_period, slowperiod=slow_period, signalperiod=signal_period) all_macds['macd_{}_{}_{}'.format(fast_period, slow_period, signal_period)] = macdsignal2 macds_dataframe = pd.DataFrame(all_macds) return historical_data.join(macds_dataframe)
def execute(self, env, df): last_row_idx = len(df)-1 for product_id in env.product_id_list: product_df = df[product_id] macd, macd_signal, macd_hist = MACD(product_df.close, fastperiod=self.fast_period, slowperiod=self.slow_period, signalperiod=self.signal_period) macd_state = MACD_HIGH if macd_hist[last_row_idx] > 0 else MACD_LOW if self.signals.get(product_id) is None: self.signals[product_id] = macd_state elif self.signals[product_id] != macd_state: if macd_state == MACD_HIGH: # buy if len(env.positions) == 0: quantity = env.balance/product_df.close[last_row_idx] ts = product_df.timestamp[last_row_idx] price = product_df.close[last_row_idx] buy_order = BuyMarketOrder(product_id, ts, funds=env.balance) env.process_buy_order(buy_order) else: print("already holding trade") elif macd_state == MACD_LOW: # sell if len(env.positions): for position in env.find_positions(lambda x: x.product_id == product_id): ts = product_df.timestamp[last_row_idx] sell_order = SellMarketOrder( product_id, ts, quantity=position.quantity, ) env.process_sell_order(sell_order) else: print("did not have active trade") self.signals[product_id] = macd_state
def execute(dates, price): macd, macdsignal, macdhist = MACD(price, fastperiod=12, slowperiod=26, signalperiod=9) indicator = { 'series': macdsignal, 'go_up': macdsignal > 0, 'go_down': macdsignal < 0 } all_orders = stragegy_helper_single_indicator.get_orders( dates, price, indicator) statistics = trade_helper.compute_statistics_from_orders(all_orders) new_stats = copy.deepcopy(statistics) new_stats['name'] = 'macd' return new_stats
def calculate_macd(pair, agg=60, fast=12, slow=26, signal=9): now = str(pd.Timestamp.today())[0:16] logging.info('Calculating MACD for {now}...'.format(now=now)) # Calculate metrics try: df = k.get_ohlc_data(pair, interval=agg, ascending=True)[0] df.index = df.index.tz_localize(tz='UTC').tz_convert('US/Central') macd, macdsignal, macdhist = MACD(df['close'], fastperiod=fast, slowperiod=slow, signalperiod=signal) macd_current = macd[-1] signal_current = macdsignal[-1] current_price = df['close'][-1] logging.info('MACD is: {macd} and Signal is: {signal}'.format( macd=macd_current, signal=signal_current)) return current_price, macd_current, signal_current except: logging.info('Data Request Error.') pass
def main(): file_content = file_io_service.load_historical_data('PETR4.SA') file_content = file_content.dropna() close = file_content['Adj Close'].values date = np.array( list( map(lambda x: date_helper.parse_date_to_datetime(x), file_content['Date']))) rsi = RSI(close, timeperiod=14) macd, macdsignal, macdhist = MACD(close, fastperiod=12, slowperiod=26, signalperiod=9) up, mid, low = BBANDS(close, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0) fig, (ax0, ax1, ax2) = plt.subplots(3, 1, sharex=True, figsize=(12, 8)) ax0.plot(date, close, label='Close') ax0.set_xlabel('Date') ax0.set_ylabel('Close') ax0.grid() ax1.plot(date, rsi, label='Close', linewidth=.5) ax1.set_xlabel('Date') ax1.set_ylabel('Close') ax1.grid() ax2.plot(date, up, label='BB_up', color='BLUE', linewidth=.5) ax2.plot(date, close, label='AdjClose', color='BLACK', linewidth=.5) ax2.plot(date, low, label='BB_low', color='RED', linewidth=.5) ax2.fill_between(date, y1=low, y2=up, color='#adccff', alpha='0.3') ax2.set_xlabel('Date') ax2.set_ylabel('Bollinger Bands') ax2.grid() fig.tight_layout() plt.show()
def execute(dates, price): rsi = RSI(price, timeperiod=14) macd, macdsignal, macdhist = MACD(price, fastperiod=12, slowperiod=26, signalperiod=9) rsi_buy = (rsi < 30) + 0 rsi_sell = (rsi > 70) + 0 macd_buy = (macdsignal > 0) + 0 macd_sell = (macdsignal < 0) + 0 indicator = { 'series': macdsignal, 'go_up': (rsi_buy + macd_buy) == 2, 'go_down': (rsi_sell + macd_sell) == 2 } all_orders = stragegy_helper_single_indicator.get_orders(dates, price, indicator) statistics = trade_helper.compute_statistics_from_orders(all_orders) new_stats = copy.deepcopy(statistics) new_stats['name'] = 'rsi+macd' return new_stats
def cut_losses(context,data): """ Sells/Invert positions according to returns. """ for stock in context.portfolio.positions: #current_position = context.portfolio.positions[stock].amount prices = data.history(stock,fields='close', bar_count=context.bar_count, frequency='1m') hist = data.history(stock, fields=['price', 'open', 'high', 'low', 'close', 'volume'], bar_count=context.bar_count, frequency='1d') try: macd = MACD(prices, fastperiod=context.fastperiod, slowperiod=context.slowperiod, signalperiod=context.signalperiod) price = context.portfolio.positions[stock].last_sale_price predicted = predict_prices(hist['close'], prices, context.returns_lookback) # print('Current price: Predicted price', price, predicted) if stock in context.long_secs.index: if macd < 0 and predicted < 1.2*price: order_target_percent(stock, 0) else: if macd > 0 and 1.1*predicted > price: order_target_percent(stock, 0) except Exception as e: print(e)
def get_new_data(self, now): # If the current dataset has gaps in it, we refresh it from Kraken if self.data_has_gaps(now): self.init_data() new_row = {'timestamp': now.strftime("%Y-%m-%d %H:%M")} # Calculate moving averages and RSI values for a_kraken_ticker, a_robinhood_ticker in config['ticker_list'].items( ): if not config['simulate_api_calls']: try: result = get_json( 'https://api.kraken.com/0/public/Ticker?pair=' + str(a_kraken_ticker)).json() if len(result['error']) == 0: new_row[a_robinhood_ticker] = round( float(result['result'][a_kraken_ticker]['a'][0]), 3) except: print('An exception occurred retrieving prices.') return False else: new_row[a_robinhood_ticker] = round( float(randint(400000, 500000)), 3) # If the new price is more than 40% lower/higher than the previous reading, assume it's an error somewhere percent_diff = (abs(new_row[a_robinhood_ticker] - self.data.iloc[-1][a_robinhood_ticker]) / self.data.iloc[-1][a_robinhood_ticker]) * 100 if percent_diff > 30: print('Error: new price ($' + str(new_row[a_robinhood_ticker]) + ') differs ' + str(round(percent_diff, 2)) + '% from previous value, ignoring.') return False self.data = self.data.append(new_row, ignore_index=True) # If the Kraken API is overloaded, they freeze the values it returns if (self.data.tail(4)[a_robinhood_ticker].to_numpy()[-1] == self.data.tail(4)[a_robinhood_ticker].to_numpy()).all(): print('Repeating values detected for ' + str(a_robinhood_ticker) + '. Ignoring data point.') self.data = self.data[:-1] elif self.data.shape[0] > 0: self.data[a_robinhood_ticker + '_SMA_F'] = self.data[a_robinhood_ticker].rolling( window=config['moving_average_periods'] ['sma_fast']).mean() self.data[a_robinhood_ticker + '_SMA_S'] = self.data[a_robinhood_ticker].rolling( window=config['moving_average_periods'] ['sma_slow']).mean() self.data[a_robinhood_ticker + '_SMA_S'] = self.data[a_robinhood_ticker].rolling( window=config['moving_average_periods'] ['sma_slow']).mean() self.data[ a_robinhood_ticker + '_EMA_F'] = self.data[a_robinhood_ticker].ewm( span=config['moving_average_periods']['ema_fast'], adjust=False, min_periods=config['moving_average_periods'] ['ema_fast']).mean() self.data[ a_robinhood_ticker + '_EMA_S'] = self.data[a_robinhood_ticker].ewm( span=config['moving_average_periods']['ema_slow'], adjust=False, min_periods=config['moving_average_periods'] ['ema_slow']).mean() self.data[a_robinhood_ticker + '_RSI'] = RSI( self.data[a_robinhood_ticker].values, timeperiod=config['rsi_period']) self.data[a_robinhood_ticker + '_MACD'], self.data[ a_robinhood_ticker + '_MACD_S'], macd_hist = MACD( self.data[a_robinhood_ticker].values, fastperiod=config['moving_average_periods'] ['macd_fast'], slowperiod=config['moving_average_periods'] ['macd_slow'], signalperiod=config['moving_average_periods'] ['macd_signal']) if config['save_charts'] == True: self.save_chart([ a_robinhood_ticker, str(a_robinhood_ticker) + '_SMA_F', str(a_robinhood_ticker) + '_SMA_S' ], str(a_robinhood_ticker) + '_sma') self.save_chart([ a_robinhood_ticker, str(a_robinhood_ticker) + '_EMA_F', str(a_robinhood_ticker) + '_EMA_S' ], str(a_robinhood_ticker) + '_ema') self.save_chart_rescale( [a_robinhood_ticker, str(a_robinhood_ticker) + '_RSI'], str(a_robinhood_ticker) + '_rsi') self.save_chart_rescale([ a_robinhood_ticker, str(a_robinhood_ticker) + '_MACD', str(a_robinhood_ticker) + '_MACD_S' ], str(a_robinhood_ticker) + '_macd') return True
def init_data(self): print('Starting with a fresh dataset.') # Download historical data from Kraken column_names = ['timestamp'] for a_robinhood_ticker in config['ticker_list'].values(): column_names.append(a_robinhood_ticker) self.data = pd.DataFrame(columns=column_names) for a_kraken_ticker, a_robinhood_ticker in config['ticker_list'].items( ): try: result = get_json( 'https://api.kraken.com/0/public/OHLC?interval=' + str(config['minutes_between_updates']) + '&pair=' + a_kraken_ticker).json() historical_data = pd.DataFrame( result['result'][a_kraken_ticker]) historical_data = historical_data[[0, 1]] # Be nice to the Kraken API sleep(3) except: print( 'An exception occurred retrieving historical data from Kraken.' ) # Convert timestamps self.data['timestamp'] = [ datetime.fromtimestamp(x).strftime("%Y-%m-%d %H:%M") for x in historical_data[0] ] # Copy the data self.data[a_robinhood_ticker] = [ round(float(x), 3) for x in historical_data[1] ] # Calculate the indicators self.data[a_robinhood_ticker + '_SMA_F'] = self.data[a_robinhood_ticker].shift( 1).rolling(window=config['moving_average_periods'] ['sma_fast']).mean() self.data[a_robinhood_ticker + '_SMA_S'] = self.data[a_robinhood_ticker].shift( 1).rolling(window=config['moving_average_periods'] ['sma_slow']).mean() self.data[a_robinhood_ticker + '_EMA_F'] = self.data[a_robinhood_ticker].ewm( span=config['moving_average_periods']['ema_fast'], adjust=False, min_periods=config['moving_average_periods'] ['ema_fast']).mean() self.data[a_robinhood_ticker + '_EMA_S'] = self.data[a_robinhood_ticker].ewm( span=config['moving_average_periods']['ema_slow'], adjust=False, min_periods=config['moving_average_periods'] ['ema_slow']).mean() self.data[a_robinhood_ticker + '_RSI'] = RSI( self.data[a_robinhood_ticker].values, timeperiod=config['rsi_period']) self.data[a_robinhood_ticker + '_MACD'], self.data[ a_robinhood_ticker + '_MACD_S'], macd_hist = MACD( self.data[a_robinhood_ticker].values, fastperiod=config['moving_average_periods']['macd_fast'], slowperiod=config['moving_average_periods']['macd_slow'], signalperiod=config['moving_average_periods'] ['macd_signal'])
def compute_macd(close): macd = MACD(close)[0] return (macd - np.mean(macd)) / np.std(macd)
async def run( self, symbol: str, shortable: bool, position: int, minute_history: df, now: datetime, portfolio_value: float = None, trading_api: tradeapi = None, debug: bool = False, backtesting: bool = False, ) -> Tuple[bool, Dict]: data = minute_history.iloc[-1] prev_min = minute_history.iloc[-2] morning_rush = ( True if (now - config.market_open).seconds // 60 < 30 else False ) if ( await super().is_buy_time(now) and not position and not open_orders.get(symbol, None) and not await self.should_cool_down(symbol, now) ): # Check for buy signals lbound = config.market_open.replace(second=0, microsecond=0) ubound = lbound + timedelta(minutes=15) try: high_15m = minute_history[lbound:ubound]["high"].max() # type: ignore except Exception as e: tlog(f"{symbol}[{now}] failed to aggregate {ubound}:{lbound}") return False, {} if data.close > high_15m or ( hasattr(config, "bypass_market_schedule") and config.bypass_market_schedule ): close = ( minute_history["close"] .dropna() .between_time("9:30", "16:00") ) close_5m = ( minute_history["close"] .dropna() .between_time("9:30", "16:00") .resample("5min") .last() ).dropna() macds = MACD(close) # sell_macds = MACD(close, 13, 21) macd = macds[0] macd_signal = macds[1] macd_hist = macds[2] macd_trending = macd[-3] < macd[-2] < macd[-1] macd_above_signal = macd[-1] > macd_signal[-1] * 1.1 macd_hist_trending = ( macd_hist[-3] < macd_hist[-2] < macd_hist[-1] ) if ( macd[-1] > 0 and macd_trending and macd_above_signal and macd_hist_trending and ( data.vwap > data.open > prev_min.close and data.vwap != 0.0 or data.vwap == 0.0 and data.close > data.open > prev_min.close ) ): macd2 = MACD(close, 40, 60)[0] if macd2[-1] >= 0 and np.diff(macd2)[-1] >= 0: if debug: tlog( f"[{self.name}][{now}] slow macd confirmed trend" ) # check RSI does not indicate overbought rsi = RSI(close, 14) if debug: tlog( f"[{self.name}][{now}] {symbol} RSI={round(rsi[-1], 2)}" ) rsi_limit = 75 if rsi[-1] < rsi_limit: if debug: tlog( f"[{self.name}][{now}] {symbol} RSI {round(rsi[-1], 2)} <= {rsi_limit}" ) else: tlog( f"[{self.name}][{now}] {symbol} RSI over-bought, cool down for 5 min" ) cool_down[symbol] = now.replace( second=0, microsecond=0 ) + timedelta(minutes=5) return False, {} stop_price = find_stop( data.close if not data.vwap else data.vwap, minute_history, now, ) target_price = ( 3 * (data.close - stop_price) + data.close ) target_prices[symbol] = target_price stop_prices[symbol] = stop_price if portfolio_value is None: if trading_api: retry = 3 while retry > 0: try: portfolio_value = float( trading_api.get_account().portfolio_value ) break except ConnectionError as e: tlog( f"[{symbol}][{now}[Error] get_account() failed w/ {e}, retrying {retry} more times" ) await asyncio.sleep(0) retry -= 1 if not portfolio_value: tlog( "f[{symbol}][{now}[Error] failed to get portfolio_value" ) return False, {} else: raise Exception( f"{self.name}: both portfolio_value and trading_api can't be None" ) shares_to_buy = ( portfolio_value * config.risk // (data.close - stop_prices[symbol]) ) if not shares_to_buy: shares_to_buy = 1 shares_to_buy -= position if shares_to_buy > 0: buy_price = max(data.close, data.vwap) tlog( f"[{self.name}][{now}] Submitting buy for {shares_to_buy} shares of {symbol} at {buy_price} target {target_prices[symbol]} stop {stop_prices[symbol]}" ) buy_indicators[symbol] = { "macd": macd[-5:].tolist(), "macd_signal": macd_signal[-5:].tolist(), "vwap": data.vwap, "avg": data.average, } return ( True, { "side": "buy", "qty": str(shares_to_buy), "type": "limit", "limit_price": str(buy_price), } if not morning_rush else { "side": "buy", "qty": str(shares_to_buy), "type": "market", }, ) else: if debug: tlog(f"[{self.name}][{now}] {data.close} < 15min high ") if ( await super().is_sell_time(now) and position > 0 and symbol in latest_cost_basis and last_used_strategy[symbol].name == self.name and not open_orders.get(symbol) ): if ( not self.whipsawed.get(symbol, None) and data.close < latest_cost_basis[symbol] * 0.98 ): self.whipsawed[symbol] = True serie = ( minute_history["close"].dropna().between_time("9:30", "16:00") ) if data.vwap: serie[-1] = data.vwap macds = MACD(serie, 13, 21,) macd = macds[0] macd_signal = macds[1] rsi = RSI( minute_history["close"].dropna().between_time("9:30", "16:00"), 14, ) movement = ( data.close - latest_scalp_basis[symbol] ) / latest_scalp_basis[symbol] macd_val = macd[-1] macd_signal_val = macd_signal[-1] round_factor = ( 2 if macd_val >= 0.1 or macd_signal_val >= 0.1 else 3 ) scalp_threshold = ( target_prices[symbol] + latest_scalp_basis[symbol] ) / 2.0 macd_below_signal = round(macd_val, round_factor) < round( macd_signal_val, round_factor ) bail_out = ( ( latest_scalp_basis[symbol] > latest_cost_basis[symbol] or movement > 0.02 ) and macd_below_signal and round(macd[-1], round_factor) < round(macd[-2], round_factor) ) bail_on_whiplash = ( data.close > latest_cost_basis[symbol] and macd_below_signal and round(macd[-1], round_factor) < round(macd[-2], round_factor) ) scalp = movement > 0.04 or data.vwap > scalp_threshold below_cost_base = data.vwap < latest_cost_basis[symbol] rsi_limit = 79 if not morning_rush else 85 to_sell = False partial_sell = False limit_sell = False sell_reasons = [] if data.close <= stop_prices[symbol]: to_sell = True sell_reasons.append("stopped") elif ( below_cost_base and round(macd_val, 2) < 0 and rsi[-1] < rsi[-2] and round(macd[-1], round_factor) < round(macd[-2], round_factor) and data.vwap < 0.95 * data.average ): to_sell = True sell_reasons.append( "below cost & macd negative & RSI trending down and too far from VWAP" ) elif data.close >= target_prices[symbol] and macd[-1] <= 0: to_sell = True sell_reasons.append("above target & macd negative") elif rsi[-1] >= rsi_limit: to_sell = True sell_reasons.append("rsi max, cool-down for 5 minutes") cool_down[symbol] = now.replace( second=0, microsecond=0 ) + timedelta(minutes=5) elif bail_out: to_sell = True sell_reasons.append("bail") elif scalp: partial_sell = True to_sell = True sell_reasons.append("scale-out") elif bail_on_whiplash: to_sell = True sell_reasons.append("bail post whiplash") if to_sell: sell_indicators[symbol] = { "rsi": rsi[-3:].tolist(), "movement": movement, "sell_macd": macd[-5:].tolist(), "sell_macd_signal": macd_signal[-5:].tolist(), "vwap": data.vwap, "avg": data.average, "reasons": " AND ".join( [str(elem) for elem in sell_reasons] ), } if not partial_sell: if not limit_sell: tlog( f"[{self.name}][{now}] Submitting sell for {position} shares of {symbol} at market with reason:{sell_reasons}" ) return ( True, { "side": "sell", "qty": str(position), "type": "market", }, ) else: tlog( f"[{self.name}][{now}] Submitting sell for {position} shares of {symbol} at {data.close} with reason:{sell_reasons}" ) return ( True, { "side": "sell", "qty": str(position), "type": "limit", "limit_price": str(data.close), }, ) else: qty = int(position / 2) if position > 1 else 1 tlog( f"[{self.name}][{now}] Submitting sell for {str(qty)} shares of {symbol} at limit of {data.close }with reason:{sell_reasons}" ) return ( True, { "side": "sell", "qty": str(qty), "type": "limit", "limit_price": str(data.close), }, ) return False, {}