Bitcoin Predictive Price Modeling with Facebook’s Prophet | by BarclayJames | Towards Data Science

This is a quick look at Facebook’s Prophet machine learning package using the example of Bitcoin. It assumes basic Python knowledge and some familiarity with pandas.
Prophet is Facebook’s open source forecasting procedure for time series data. The idea is that it should make fully automatic forecasting easy even with messy data and it’s currently available in R and Python. I shall be using Python 2.7 in this post.
Note from Towards Data Science’s editors: While we allow independent authors to publish articles in accordance with our rules and guidelines, we do not endorse each author’s contribution. You should not rely on an author’s works without seeking professional advice. See our Reader Terms for details.
If you have pip installed, all you need to do to get Prophet is open a console and type
pip install fbprophet
On Windows I ran into some Anaconda-related dependency issue and had to run first
conda clean --allconda update pystan
Once you have it installed we shall import the modules we’ll need
import quandl as qdimport pandas as pdimport numpy as npimport fbprophetimport matplotlib.pyplot as plt
Quandl is an amazing repository with a massive number of extremely varied datasets. You’ll need to register a free account and generate an API. Then we’re ready to start. First download the Bitcoin market data from Quandl and get rid of the zero values (the price data contains zeros in the initial rows for some reason)
KEY = "YOUR_API_KEY"qd.ApiConfig.api_key = KEYbitcoin = qd.get("BCHAIN/MKPRU")bitcoin = bitcoin.loc[(bitcoin !=0).any(1)]
This puts the price data in a pandas dataframe called bitcoin. To inspect the first few rows type
bitcoin.head()
You should end up with one column called ‘Value’ and a datetime index
           ValueDate 2010–08–17 0.0769002010–08–18 0.0740002010–08–19 0.0688002010–08–20 0.0667002010–08–21 0.066899
Now we would like to plot logged data on a linear chart (the reason will become apparent later), so make a new column in bitcoin for the logged price values
bitcoin["log_y"] = np.log(bitcoin["Value"])
The first thing we need to do is a little house keeping. Prophet requires us to change the name of the ‘Date’ column to ‘ds’ and our y-column should simply be called ‘y’
bitcoin = bitcoin.rename(columns={"Date": "ds", "log_y" : "y"})
Most of what Prophet does takes place behind the scenes, but there are some hyperparameters that allow us to easily fine tune our models. We will adjust the changepoint_prior_scale parameter only.
Changepoints are basically points where the trend makes a sudden change in direction, e.g. reversal. Prophet can find these points for you automatically, although it is possible to define them yourself, though for large and idiosyncratic datasets this is impractical. Hey that’s what machines are for, right? The changepoint_prior_scale parameter basically allows you to choose how tightly you want the changepoints to match the data.
The goal of building any model is to be able to generalise it to other data/scenarios and achieve similar results. So we don’t want our model to follow the training data too much, this is called overfitting. Likewise underfitting can also produce models that generalise poorly.
So we will use this one hyperparameter to do all our fine tuning. The higher the value the tighter the fit, and likewise the lower the value the looser the fit. For this demo I have chosen to values (0.0015 and 0.015) separated by an order of magnitude.
priors = [0.0015, 0.015]prophets, labels = [], []for prior in priors:    prophet = fbprophet.Prophet(changepoint_prior_scale=prior)    prophet.fit(bitcoin)     prophets.append(prophet)    labels.append(r"CP Prior = " + str(prior))
At this point you should have a list of two prophet objects and a list of labels for plotting. The next step is to use those prophet objects to generate forecast objects. (We’ll also rename the ‘ds’ columns with the changepoint_prior_scale value prefix just to keep track of the data.)
forecasts = []for prophet in prophets:    forecast = prophet.make_future_dataframe(periods=365 * 2,                                                    freq="D")    forecast = prophet.predict(forecast)     forecast = forecast.rename(columns={"ds" : str(priors[prophets.index(prophet)]) + "_ds"})    forecasts.append(forecast)
And that’s pretty much it. If all went well, you should have generated a list of two forecast objects (really just pandas dataframes). Let’s merge these into a single dataframe and rename one of the ‘_ds’ columns to ‘Date’ and drop the other.
output = pd.merge(forecasts[0], forecasts[1], how = "inner", left_on = "0.0015_ds", right_on = "0.015_ds")output = output.rename(columns={"0.0015_ds": "Date"}).drop("0.015_ds", axis=1)
Finally we set the index to the ‘Date’ column
output = output.set_index(‘Date’)
We’ll now plot everything on one chart
fig, ax = plt.subplots(1, 1, figsize=(10, 8))ax.plot(output.index, output["yhat_x"], label=labels[0])ax.fill_between(output.index, output["yhat_upper_x"], output["yhat_lower_x"], alpha=0.6, edgecolor = "k")ax.plot(output.index, output["yhat_y"], "r", label=labels[1]);ax.fill_between(output.index, output["yhat_upper_y"], output["yhat_lower_y"], alpha=0.6, edgecolor = "k")ax.plot(bitcoin.ds, bitcoin.y, color="green", linewidth=3, label=r"Bitcoin price (logged)")a=ax.get_yticks().tolist()ax.set_yticklabels(np.round(np.exp(a), 1))plt.legend(loc="upper left")plt.ylabel(r"Price /$")plt.show()
The ‘y_hat’ labels are the estimates provided by Prophet and the x or y suffix denotes which dataframe the data originally came from (here x are the 0.0015 parameter values, and y the 0.015).
The goal here was simply to mess around with the Prophet package and I thought Bitcoin would make an interesting dataset.
Just by eyeballing, I think both predictions are pretty sane from a Bitcoin maximalist point of view, by which I mean they match what many bullish investors believe will happen to the price.
The blue fit is perhaps slightly underfitting but you can see that the uncertainty on the estimate remains fairly constant over time, even into the future. In general, it offers more scope for generalisation but it may respond too slowly to trend changes. Hence I think it is unreliable. I would not expect the price to maintain that trend for long.
The red fit on the other hand seems to overfit the data. It follows the historical price action tightly and responds quickly to trend changes, however the uncertainty really blows up into the future making this prediction unreliable too, although the red trend is somewhat more believable.
Personally I do not feel that this kind of price prediction is particularly useful, but it will be interesting to follow this and see how the Facebook algorithms pan out.