SPY Buy/Sell Points by Bollinger Bands & RSI

import yfinance as yf
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA as arima
import ta
import seaborn as sb
import pandas as pd
from datetime import datetime as dt
from datetime import timedelta

Download stock prices from Yahoo Finance

end_time = dt.now()
start_time = end_time - timedelta(days=365*2)
tickers = 'SPY, MSFT, META, NVDA, AMD'
popular5 = yf.download(tickers, start = start_time, end = end_time)
[*********************100%%**********************]  5 of 5 completed

Calculate indicators Bollinger Bands & RSI, buy/sell
points, and visualize

def calculate_indicators(historical_close):
    historical_close_ma20 = historical_close.rolling(20).mean()
    std = historical_close.rolling(20).std()
    upper = historical_close_ma20 + 2* std
    lower = historical_close_ma20 - 2*std
    rsi14 = ta.momentum.rsi(historical_close, 14)
    # put indicators in a dataframe
    df = pd.concat([historical_close, upper, lower, rsi14], axis=1)
    df.columns = ['close','upper','lower','rsi']
    df['signal']='no action'
    df.loc[(df['close'] < df['lower']) & (df['rsi']<30), 'signal'] = 'buy'
    df.loc[(df.close>df.upper) & (df.rsi > 70), 'signal'] = 'sell'
    # print(df.query('signal == "buy"').shape[0])
    # print(df.query('signal == "sell"').shape[0])
    # visualize
    fig = plt.figure(figsize = (15,6))
    ax = fig.add_axes([0.1,0.1,0.9,0.9])
    ax.plot(historical_close.index, historical_close.values, label = 'daily close')
    ax.plot(historical_close_ma20.index, historical_close_ma20.values)
    ax.plot(upper.index, upper.values, label='upper Bollinger')
    ax.plot(lower.index, lower.values, label='lower Bollinger')

    ax2 = ax.twinx()
    ax2.plot(rsi14, alpha=0.3)
    ax2.axhline(y=70, ls='--', alpha=0.5, c='r')
    ax2.axhline(y=30, ls='--', alpha=0.5, c='g')
    ax.set_title(f'{symbol} Prices & Indicators', fontsize=25)
    ax2.set_ylabel('RSI', fontsize=15)
    ax.set_ylabel('Price', fontsize=15)
    ax.xaxis.set_tick_params(labelsize=15)
    ax.yaxis.set_tick_params(labelsize=15)
    ax2.yaxis.set_tick_params(labelsize=15)
    ax.legend()
    # draw arrow
    signal_colors = {'buy':'green', 'sell':'red'}
#    signal_offsets = {'buy':pd.Timedelta(days=-40), 'sell':pd.Timedelta(days=40)}
    y_offsets = {'buy':-20, 'sell':20}
    signal_offsets = {'buy':pd.Timedelta(days=-40), 'sell':pd.Timedelta(days=40)}
    for signal, color in signal_colors.items():
        signal_data = df[df['signal']==signal]
        ax.scatter(signal_data.index, signal_data.close, marker='o', s=90, c=color, label=signal)
        time_deltas = signal_data.replace(signal_offsets)
        y_ends = signal_data.close - 1
        for i, row in signal_data.iterrows():
            x_end = i
#            x_start = x_end + time_deltas['signal'].loc[i]
            x_start = x_end + pd.Timedelta(days=-40)
            y_start = y_ends[i] + y_offsets[signal]
            y_end = y_ends[i]
            ax.annotate(signal_data.signal[i], xy=(x_end, y_end), xytext=(x_start, y_start), arrowprops=
                        dict(facecolor=signal_colors[row['signal']], shrink=0.1, lw=2))

Pick a stock

symbol = 'SPY'
ts = popular5['Close'][symbol]
calculate_indicators(ts)

returns = ts.pct_change()*100
plot_pacf(returns[1:], zero=False, auto_ylims=True);

Calculate returns

position=False
portfolio_value = 1.0
for index, row in df_tsla.iterrows():
    if not position and row.signal == 'buy':
        position = True
        entry = row.close
    if position:
        if (row.signal == 'sell' or row.close < entry*0.9):
            position = False
            exit = row.close
            portfolio_value *= (exit - entry)/entry + 1

print(f'return = {portfolio_value}')
        
    
return = 3.412705492910159

This entry was posted in Common Technical Indicators and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *