I’ve spent countless hours this past week working with Facebook’s forecasting library, Prophet. I’ve seen lots of crypto and stock price forecasting and prediction model tutorials on Medium over the past few months, but this one by Senthil E. focusing on Apple and Bitcoin prices got my attention, and I just finished putting together a Python file that takes his code and builds it into some reusable code.
Now after getting to know it better, I can say that it’s not the most sophisticated package out there. I don’t think it was intended for forecasting stock data, but it is fast and allows one to see trends. Plus I learned a lot using it, and had fun. So what more can you ask for?
As background, I’ve been working on refining the Value Averaging functions I wrote about last week and had been having some issues with the Pandas Datareader library’s integration with the Alpha Vantage stock history API. Senthil uses a different third-party module that doesn’t have any problems, so that was good.
I ran into some dependency hell during my initial setup. I spawned a new pipenv virtual environment and installed Jupyter notebook, but a prompt-toolkit conflict led to some wasted time. I started by copying the original code into a notebook, and go that running first. I quickly started running into problems with the author’s code.
I did get frustrated at one point and setup Anaconda in a Docker container on another machine, but I was able to get my main development machine up and running. We’ll save Conda for another day!
Importing the libraries
Like most data science projects, this one relies on Pandas and matplotlib, and the Prophet library has some Plotly integration. The author had the unused wordcloud package in his code for some reason as well, and it’s not entirely certain how he’s using the seaborn module, since he doesn’t explain his plots. He also listed two different Alpha Vantage modules despite only using one. I believe he may have put the alphaVantageAPI module in first before switching to the more useable alpha_vantage one.
We eventually added pickle, dotenv, and bokeh modules, as we’ll see shortly, as well as os, time, datetime.
import os import pickle import time from datetime import datetime import pandas as pd from fbprophet import Prophet from fbprophet.plot import plot_plotly from bokeh.plotting import figure, output_file, show, save import matplotlib.pyplot as plt # import plotly.offline as py # import numpy as np # import seaborn as sns # from alphaVantageAPI.alphavantage import AlphaVantage from alpha_vantage.timeseries import TimeSeries from alpha_vantage.techindicators import TechIndicators from dotenv import load_dotenv
Protect your keys!
One of the first modules that we add to every project nowadays is python-dotenv. I’ve really been trying to get disciplined about 12-factor applications, and since I’m committing all of my projects to Gitlab these days, I can be sure not to commit my API keys to a repo or post them in a gist on my blog!
Also, pipenv shell automatically loads .env files, which is another reason why you should be using them.
load_dotenv() ALPHAVANTAGE_API_KEY = os.getenv('ALPHAVANTAGE_API_KEY')
Fetch Alpha Vantage data
If there is anything I hate, it’s repeating myself, or having to use the same block of code several times within a document. Now I don’t know whether the author kept the following two blocks of code in his story for illustrative purposes, or if this is just how he had it loaded in his notebook, but it gave me a complex.
from alpha_vantage.techindicators import TechIndicators import matplotlib.pyplot as plt ti = TechIndicators(key='<YES, he left his API KEY here!>',output_format='pandas') data, meta_data = ti.get_sma(symbol='AAPL',interval='daily', time_period=60,series_type = 'close') data.plot() plt.show() from alpha_vantage.techindicators import TechIndicators import matplotlib.pyplot as plt ti = TechIndicators(key='Youraccesskey',output_format='pandas') data, meta_data = ti.get_rsi(symbol='AAPL',interval='daily', time_period=60,series_type = 'close') data.plot() plt.show()
If you look at the Alpha Vantage API documentation, there are separate endpoints for the time series and technical endpoints. The time series endpoint has different function calls for daily, weekly, monthly, &c.., and the Python module we’re using has separate methods for each. Same for the technical indicators. Now in the past, when I’ve tried to wrap APIs I would have had separate calls for each function, but I learned something about encapsulation lately and wanted to give something different a try.
Since the technical indicators functions share the same set of positional arguments, we can create a wrapper function where we pass the the name of the function (the indicator itself) that we want to get, the associated symbol, as well as any keyword arguments that we want to specify. We use the getattr method to find the class’s function by name, and pass on our variables using **kwargs.
def get_technical(indicator, symbol, **kwargs): function = getattr(ti, indicator) data, meta_data = function(symbol=symbol, **kwargs) print(meta_data) return data sma = get_technical('get_sma', symbol, time_period=60) rsi = get_technical('get_rsi', symbol, time_period=60)
Since most of the kwargs in the original were redundant, we only need to pass what we want to override. We’ve not really reduced the original code, to be honest, but we can customize what happens after in a way that we can be consistent, without having to write multiple functions for each function in the original module. Additionally, we can do this for the time series functions as well.
# BEFORE from alpha_vantage.timeseries import TimeSeries import matplotlib.pyplot as plt ts = TimeSeries(key='Your Access Key',output_format='pandas') apple, meta_data = ts.get_daily(symbol='AAPL',outputsize='full') apple.head() #AFTER def get_time_series(time_series, symbol, **kwargs): function = getattr(ts, time_series) data, meta_data = function(symbol=symbol, **kwargs) print(meta_data) return data ticker = get_time_series('get_daily', symbol, outputsize='full')
You can see that both functions are almost identical, except that the getattr call is passing the ts and ti classes. Ultimately, I’ll extend this to the cryptocurrencies endpoint as well, and be able to add any exception checking and debugging that I need for the entire module, and use one function for all of it.
Writing this code was one of those level-up moments when I got an idea and knew that I ultimately understood programming at an entirely different level than I had a few months ago.
Next, we’ll use Pickle to save and load our data, and start manipulating our dataframes before passing them to Prophet