{"metadata":{"orig_nbformat":4,"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kernelspec":{"name":"python3","display_name":"Python 3 (ipykernel)","language":"python"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"code","source":"# IMPORTING PACKAGES\n\nimport numpy as np\nimport requests\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom math import floor\nfrom termcolor import colored as cl\nimport yfinance as yf\n\nplt.style.use('fivethirtyeight')\nplt.rcParams['figure.figsize'] = (20,10)\n\n# EXTRACTING STOCK DATA\n\ndef get_historical_data(symbol, start_date):\n api_key = 'YOUR API KEY'\n api_url = f'https://api.twelvedata.com/time_series?symbol={symbol}&interval=1day&outputsize=5000&apikey={api_key}'\n raw_df = requests.get(api_url).json()\n df = pd.DataFrame(raw_df['values']).iloc[::-1].set_index('datetime').astype(float)\n df = df[df.index >= start_date]\n df.index = pd.to_datetime(df.index)\n return df\n\n# aapl = get_historical_data('AAPL', '2010-01-01')\n\naapl = yf.download(tickers='AAPL', period='9d', interval='2m')\naapl.tail()\n\n# BOLLINGER BANDS CALCULATION\n\ndef sma(data, lookback):\n sma = data.rolling(lookback).mean()\n return sma\n\ndef get_bb(data, lookback):\n std = data.rolling(lookback).std()\n upper_bb = sma(data, lookback) + std * 2\n lower_bb = sma(data, lookback) - std * 2\n middle_bb = sma(data, lookback)\n return upper_bb, middle_bb, lower_bb\n\naapl['upper_bb'], aapl['middle_bb'], aapl['lower_bb'] = get_bb(aapl['Close'], 20)\naapl.tail()\n\n# BOLLINGER BANDS PLOT\n\nplot_data = aapl[aapl.index >= '2020-01-01']\n\nplt.plot(plot_data['Close'], linewidth = 2.5)\nplt.plot(plot_data['upper_bb'], label = 'UPPER BB 20', linewidth = 2, color = 'violet')\nplt.plot(plot_data['middle_bb'], label = 'MIDDLE BB 20', linewidth = 1.5, color = 'grey')\nplt.plot(plot_data['lower_bb'], label = 'LOWER BB 20', linewidth = 2, color = 'violet')\nplt.title('AAPL BB 20')\nplt.legend(fontsize = 15)\nplt.show()\n\n# KELTNER CHANNEL CALCULATION\n\ndef get_kc(high, low, close, kc_lookback, multiplier, atr_lookback):\n tr1 = pd.DataFrame(high - low)\n tr2 = pd.DataFrame(abs(high - close.shift()))\n tr3 = pd.DataFrame(abs(low - close.shift()))\n frames = [tr1, tr2, tr3]\n tr = pd.concat(frames, axis = 1, join = 'inner').max(axis = 1)\n atr = tr.ewm(alpha = 1/atr_lookback).mean()\n \n kc_middle = close.ewm(kc_lookback).mean()\n kc_upper = close.ewm(kc_lookback).mean() + multiplier * atr\n kc_lower = close.ewm(kc_lookback).mean() - multiplier * atr\n \n return kc_middle, kc_upper, kc_lower\n \naapl['kc_middle'], aapl['kc_upper'], aapl['kc_lower'] = get_kc(aapl['High'], aapl['Low'], aapl['Close'], 20, 2, 10)\naapl.tail()\n\n# KELTNER CHANNEL PLOT\n\nplot_data = aapl[aapl.index >= '2020-01-01']\n\nplt.plot(plot_data['Close'], linewidth = 2, label = 'AAPL')\nplt.plot(plot_data['kc_upper'], linewidth = 2, color = 'orange', label = 'KC UPPER 20')\nplt.plot(plot_data['kc_middle'], linewidth = 1.5, color = 'grey', label = 'KC MIDDLE 20')\nplt.plot(plot_data['kc_lower'], linewidth = 2, color = 'orange', label = 'KC LOWER 20')\nplt.legend(fontsize = 15)\nplt.title('AAPL KELTNER CHANNEL 20')\nplt.show()\n\nplot_data = aapl[aapl.index >= '2020-01-01']\n\nplt.plot(plot_data['Close'], linewidth = 2.5, label = 'AAPL')\nplt.plot(plot_data['upper_bb'], label = 'UPPER BB 20', linewidth = 2, color = 'violet')\nplt.plot(plot_data['lower_bb'], label = 'LOWER BB 20', linewidth = 2, color = 'violet')\nplt.plot(plot_data['kc_upper'], linewidth = 2, color = 'orange', label = 'KC UPPER 20')\nplt.plot(plot_data['kc_lower'], linewidth = 2, color = 'orange', label = 'KC LOWER 20')\nplt.legend(fontsize = 15)\nplt.show()\n\n# RSI CALCULATION\n\ndef get_rsi(close, lookback):\n ret = close.diff()\n up = []\n down = []\n for i in range(len(ret)):\n if ret[i] < 0:\n up.append(0)\n down.append(ret[i])\n else:\n up.append(ret[i])\n down.append(0)\n up_series = pd.Series(up)\n down_series = pd.Series(down).abs()\n up_ewm = up_series.ewm(com = lookback - 1, adjust = False).mean()\n down_ewm = down_series.ewm(com = lookback - 1, adjust = False).mean()\n rs = up_ewm/down_ewm\n rsi = 100 - (100 / (1 + rs))\n rsi_df = pd.DataFrame(rsi).rename(columns = {0:'rsi'}).set_index(close.index)\n rsi_df = rsi_df.dropna()\n return rsi_df[3:]\n\naapl['rsi_14'] = get_rsi(aapl['Close'], 14)\naapl = aapl.dropna()\naapl.tail()\n\n# RSI PLOT\n\nax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)\nax2 = plt.subplot2grid((11,1), (6,0), rowspan = 5, colspan = 1)\nax1.plot(plot_data['Close'])\nax1.set_title('AAPL STOCK PRICE')\nax2.plot(aapl['rsi_14'], color = 'orange', linewidth = 1.5)\nax2.axhline(30, color = 'grey', linestyle = '--', linewidth = 1.5)\nax2.axhline(70, color = 'grey', linestyle = '--', linewidth = 1.5)\nax2.set_title('AAPL RSI 14')\nplt.show()\n\n# TRADING STRATEGY\n\ndef bb_kc_rsi_strategy(prices, upper_bb, lower_bb, kc_upper, kc_lower, rsi):\n buy_price = []\n sell_price = []\n bb_kc_rsi_signal = []\n signal = 0\n \n for i in range(len(prices)):\n if lower_bb[i] < kc_lower[i] and upper_bb[i] > kc_upper[i] and rsi[i] < 30:\n if signal != 1:\n buy_price.append(prices[i])\n sell_price.append(np.nan)\n signal = 1\n bb_kc_rsi_signal.append(signal)\n else:\n buy_price.append(np.nan)\n sell_price.append(np.nan)\n bb_kc_rsi_signal.append(0)\n \n elif lower_bb[i] < kc_lower[i] and upper_bb[i] > kc_upper[i] and rsi[i] > 70:\n if signal != -1:\n buy_price.append(np.nan)\n sell_price.append(prices[i])\n signal = -1\n bb_kc_rsi_signal.append(signal)\n else:\n buy_price.append(np.nan)\n sell_price.append(np.nan)\n bb_kc_rsi_signal.append(0)\n else:\n buy_price.append(np.nan)\n sell_price.append(np.nan)\n bb_kc_rsi_signal.append(0)\n \n return buy_price, sell_price, bb_kc_rsi_signal\n\nbuy_price, sell_price, bb_kc_rsi_signal = bb_kc_rsi_strategy(aapl['Close'], aapl['upper_bb'], aapl['lower_bb'],\n aapl['kc_upper'], aapl['kc_lower'], aapl['rsi_14'])\n\nax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)\nax2 = plt.subplot2grid((11,1), (6,0), rowspan = 5, colspan = 1)\nax1.plot(aapl['Close'])\nax1.plot(aapl.index, buy_price, marker = '^', markersize = 10, linewidth = 0, color = 'green', label = 'BUY SIGNAL')\nax1.plot(aapl.index, sell_price, marker = 'v', markersize = 10, linewidth = 0, color = 'r', label = 'SELL SIGNAL')\nax1.set_title('AAPL STOCK PRICE')\nax2.plot(aapl['rsi_14'], color = 'purple', linewidth = 2)\nax2.axhline(30, color = 'grey', linestyle = '--', linewidth = 1.5)\nax2.axhline(70, color = 'grey', linestyle = '--', linewidth = 1.5)\nax2.set_title('AAPL RSI 10')\nplt.show()\n\n# POSITION\n\nposition = []\nfor i in range(len(bb_kc_rsi_signal)):\n if bb_kc_rsi_signal[i] > 1:\n position.append(0)\n else:\n position.append(1)\n \nfor i in range(len(aapl['Close'])):\n if bb_kc_rsi_signal[i] == 1:\n position[i] = 1\n elif bb_kc_rsi_signal[i] == -1:\n position[i] = 0\n else:\n position[i] = position[i-1]\n \nkc_upper = aapl['kc_upper']\nkc_lower = aapl['kc_lower']\nupper_bb = aapl['upper_bb'] \nlower_bb = aapl['lower_bb']\nrsi = aapl['rsi_14']\nclose_price = aapl['Close']\nbb_kc_rsi_signal = pd.DataFrame(bb_kc_rsi_signal).rename(columns = {0:'bb_kc_rsi_signal'}).set_index(aapl.index)\nposition = pd.DataFrame(position).rename(columns = {0:'bb_kc_rsi_position'}).set_index(aapl.index)\n\nframes = [close_price, kc_upper, kc_lower, upper_bb, lower_bb, rsi, bb_kc_rsi_signal, position]\nstrategy = pd.concat(frames, join = 'inner', axis = 1)\n\nstrategy.tail()\n\n# BACKTESTING\n\naapl_ret = pd.DataFrame(np.diff(aapl['Close'])).rename(columns = {0:'returns'})\nbb_kc_rsi_strategy_ret = []\n\nfor i in range(len(aapl_ret)):\n returns = aapl_ret['returns'][i]*strategy['bb_kc_rsi_position'][i]\n bb_kc_rsi_strategy_ret.append(returns)\n \nbb_kc_rsi_strategy_ret_df = pd.DataFrame(bb_kc_rsi_strategy_ret).rename(columns = {0:'bb_kc_rsi_returns'})\ninvestment_value = 100000\nnumber_of_stocks = floor(investment_value/aapl['Close'][0])\nbb_kc_rsi_investment_ret = []\n\nfor i in range(len(bb_kc_rsi_strategy_ret_df['bb_kc_rsi_returns'])):\n returns = number_of_stocks*bb_kc_rsi_strategy_ret_df['bb_kc_rsi_returns'][i]\n bb_kc_rsi_investment_ret.append(returns)\n\nbb_kc_rsi_investment_ret_df = pd.DataFrame(bb_kc_rsi_investment_ret).rename(columns = {0:'investment_returns'})\ntotal_investment_ret = round(sum(bb_kc_rsi_investment_ret_df['investment_returns']), 2)\nprofit_percentage = floor((total_investment_ret/investment_value)*100)\nprint(cl('Profit gained from the BB KC RSI strategy by investing $100k in AAPL : {}'.format(total_investment_ret), attrs = ['bold']))\nprint(cl('Profit percentage of the BB KC RSI strategy : {}%'.format(profit_percentage), attrs = ['bold']))\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"42795293-5286-49d8-977a-fb7fe5964b7f"},{"cell_type":"code","source":"# SPY ETF COMPARISON\n\ndef get_benchmark(start_date, investment_value):\n spy = get_historical_data('SPY', start_date)['Close']\n benchmark = pd.DataFrame(np.diff(spy)).rename(columns = {0:'benchmark_returns'})\n \n investment_value = investment_value\n number_of_stocks = floor(investment_value/spy[0])\n benchmark_investment_ret = []\n \n for i in range(len(benchmark['benchmark_returns'])):\n returns = number_of_stocks*benchmark['benchmark_returns'][i]\n benchmark_investment_ret.append(returns)\n\n benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(columns = {0:'investment_returns'})\n return benchmark_investment_ret_df\n\nbenchmark = get_benchmark('2010-01-01', 100000)\ninvestment_value = 100000\ntotal_benchmark_investment_ret = round(sum(benchmark['investment_returns']), 2)\nbenchmark_profit_percentage = floor((total_benchmark_investment_ret/investment_value)*100)\nprint(cl('Benchmark profit by investing $100k : {}'.format(total_benchmark_investment_ret), attrs = ['bold']))\nprint(cl('Benchmark Profit percentage : {}%'.format(benchmark_profit_percentage), attrs = ['bold']))\nprint(cl('BB KC RSI Strategy profit is {}% higher than the Benchmark Profit'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))","metadata":{},"execution_count":null,"outputs":[],"id":"7eeb9dbc-d12f-4888-a436-2dae11a2f539"}]}