diff --git a/04 Strategy Library/00 Strategy Library/01 Strategy Library.php b/04 Strategy Library/00 Strategy Library/01 Strategy Library.php index 6144105..8d51bde 100644 --- a/04 Strategy Library/00 Strategy Library/01 Strategy Library.php +++ b/04 Strategy Library/00 Strategy Library/01 Strategy Library.php @@ -634,15 +634,6 @@ 'description' => 'We apply Simple Moving Averages to manage the risk of holding leveraged ETFs in an attempt to beat the S&P500', 'tags' => 'Simple Moving Average, Risk Management, S&P500, ETF' ], - [ - 'name' => 'Leveraged ETFs with Systematic Risk Management', - 'link' => 'leveraged-etfs-with-systematic-risk-management', - 'sources' => [ - 'The Lead-Lag Report' => 'https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2741701' - ], - 'description' => 'We apply Simple Moving Averages to manage risk in holding leveraged ETFs in an attempt to by the S&P500', - 'tags' => 'Simple Moving Average, Risk Management, S&P500, ETF' - ], [ 'name' => 'Ichimoku Clouds in the Energy Sector', 'link' => 'strategy-library/ichimoku-clouds-in-the-energy-sector', @@ -678,6 +669,15 @@ ], 'description' => "Mathematically Deriving the Optimal Entry and Liquidation Values of a Pairs Trading Process", 'tags'=>'Pairs Trading, Ornstein-Uhlenbeck Process, Optimal Stopping' + ], + [ + 'name' => 'Forecasting Bitcoin Prices with ARIMA Models', + 'link' => 'strategy-library/bitcoin-arima-forecasting', + 'sources' => [ + 'arXiv' => 'https://arxiv.org/pdf/1904.05315.pdf' + ], + 'description' => "We attempt to forecast the prices of Bitcoin using an ARIMA model", + 'tags'=>'Bitcoin, ARIMA, Forecasting, Time-Series Models' ] ]; diff --git a/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/01 Abstract.html b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/01 Abstract.html new file mode 100644 index 0000000..eea28ff --- /dev/null +++ b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/01 Abstract.html @@ -0,0 +1,3 @@ +

+ In this tutorial, we attempt to forecast Bitcoin prices with an ARIMA model. +

diff --git a/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/02 Introduction.html b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/02 Introduction.html new file mode 100644 index 0000000..101c100 --- /dev/null +++ b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/02 Introduction.html @@ -0,0 +1,3 @@ +

+ In recent years, more and more complicated models have been developed for predicting financial time-series, namely Deep Learning. However, in this tutorial, we go back to the classic time-series models, employing the ARIMA Model in an attempt to forecast Bitcoin prices. +

diff --git a/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/03 Method.html b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/03 Method.html new file mode 100644 index 0000000..f23a1ef --- /dev/null +++ b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/03 Method.html @@ -0,0 +1,89 @@ +

+ An ARIMA model requires a stationary time-series, that is, the mean and variance stay relatively the same over time. + However, Bitcoin went from a few hundred dollars to tens of thousands of dollars in just the past few years, so + clearly Bitcoin prices aren't stationary. To transform the price data into a stationary series, we take the first order + difference of the log of the prices. Given X as the Bitcoin closing prices, we use the following code: +

+ +
+
+    import numpy as np
+    X = np.diff(np.log(X))
+
+
+ +

then to ensure the stationarity of our transformed data, we pass it into the following function:

+ +
+
+    def __is_stationary(self, X, significance_level=.05):
+        # include above: from statsmodels.tsa.stattools import adfuller
+        result = adfuller(X)
+        p_value = result[1]
+        return p_value < significance_level
+
+
+ +

After taking the most recent 400 points of Bitcoin closing prices and performing the transformation, we get a p-value of 2.5e-16 for stationarity, far below our critical value of .05. Since we only want to use stationary data with our ARIMA model, our algorithm stops trading when the recent historical data is no longer stationary after the transformation.

+ +

We then want to grid search different ARIMA orders to find the model that minimizes the Mean Squared Error (MSE) on unseen data. The ARIMA order is represented by (p, d, q), where p stands for the past values for Auto-Regression (hence AR in ARIMA), d stands for the degree of differencing (or the order of Integration, hence I in ARIMA), and q stands for how the past errors are accounted for in future predictions (which is a Moving Average model, hence MA in ARIMA). The possible p and q values range between 0 and 5, while the d term is kept at 1. Then, we want to iterate over each (p, d, q) combination to minimize our MSE. Before we show the code for the grid search, let’s see how we can evaluate an ARIMA model given a single order:

+ +
+
+    def evaluate_arima_model(X, arima_order, oos_size=20):
+        train_data, oos_data = X[:-oos_size], X[-oos_size:]
+        history = deque([x for x in train_data], maxlen=len(train_data))
+
+        predictions = []
+        for i in range(len(oos_data)):
+            model = ARIMA(np.array(history), order=arima_order)
+            model_fit = model.fit(disp=0)
+            y_hat = model_fit.forecast()[0]
+            predictions.append(y_hat)
+            history.append(oos_data[i])
+        # include above: from sklearn import metrics
+        return metrics.mean_squared_error(oos_data, predictions)
+
+
+ +

We essentially have a rolling window with 80% of the data from the left, and fit an ARIMA model using these points of data along with the specific (p, d, q) order. We forecast out one time-step into the future, record this value along with the actual value. Then, we shift this window to the right, and repeat the last step. We repeat this process until we’ve forecasted the remaining values, and then we compute the MSE by plugging in the forecasted and actual values into sklearn’s mean_squared_error function. Now for the grid search:

+ +
+
+    def Train(X, p_values=range(6), d_values=[1], q_values=range(6)):
+        data = transform_data(X)
+
+        if not is_stationary(data):
+            return None
+
+        best_score, best_pdq = float("inf"), None
+        for p in p_values:
+            for d in d_values:
+                for q in q_values:
+                    order = (p,d,q)
+                    try:
+                        mse = evaluate_arima_model(data, order)
+                        if mse < best_score:
+                            best_score, best_pdq = mse, order
+                    except:
+                        continue
+
+        return best_pdq
+
+
+ +

As described earlier, we iterate over and evaluate all possible (p, d, q), and choose the best model.

+ +

+ The trading logic is quite simple. At the start of each month, we take the past 70 points of data to find the ARIMA + order that maximizes the out-of-sample MSE. Every day, we fit 50 points of the most recent historical data to an ARIMA + model given our order, using the order of that month, to forecast one value into the future. Because our data was + transformed through a logarithm and differencing, we would need to undo the transformation on the forecasted value + first, and this can be seen in the __undo_forecast_transform method in Model.py + under the Algorithm section. We then calculate the percent change in price using: + forecasted price / current price - 1. Then, we emit an Insight based on the direction of the percent + change with the weight of the Insight as the absolute value of the percent change. We use the + InsightWeightPortfolioConstructionModel so that the weight of the Insight determines the portfolio + allocation percentage, which means larger forecasted moves will have larger allocation. +

+ diff --git a/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/04 Algorithm.html b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/04 Algorithm.html new file mode 100644 index 0000000..8c7b8df --- /dev/null +++ b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/04 Algorithm.html @@ -0,0 +1,6 @@ +
+
+
+ +
+
diff --git a/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/05 Results.html b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/05 Results.html new file mode 100644 index 0000000..d77e9b1 --- /dev/null +++ b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/05 Results.html @@ -0,0 +1,7 @@ +

The performance of the algorithm was poor. It achieved a Sharpe Ratio of only 0.262, while simply holding Bitcoin over the same period would have yielded a Sharpe Ratio of 1.688. 

+

Here are some ideas for improvement:

+ +

If a user comes across any interesting results, we’d love to hear about it in the Community Forum.

\ No newline at end of file diff --git a/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/06 References.html b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/06 References.html new file mode 100644 index 0000000..d340761 --- /dev/null +++ b/04 Strategy Library/1032 Bitcoin ARIMA Forecasting/06 References.html @@ -0,0 +1,6 @@ +
    +
  1. + Amin Azari (2019). Bitcoin Price Prediction: An ARIMA Approach. CoRR, abs/1904.05315. + Online Copy. +
  2. +
\ No newline at end of file