In this post, deep learning neural networks are applied to the problem of predicting Bitcoin and other cryptocurrency prices. A *chartist* approach is taken to predict future values; the network makes predictions based on historical trends in the price and trading volume. A 1D convolutional neural network (CNN) transforms an input volume consisting of historical prices from several major cryptocurrencies into future price information.

# Data Gathering

To facilitate rapid prediction, pricing information is queried using the web API of Poloniex. A URL is provided to the API and a JSON containing the historical price information of a specified cryptocurrency is returned.

import json import urllib.request import pandas as pd def JSONDictToDF(d): ''' Converts a dictionary created from json.loads to a pandas dataframe d: The dictionary ''' n = len(d) cols = [] if n > 0: #Place the column in sorted order cols = sorted(list(d[0].keys())) df = pd.DataFrame(columns = cols, index = range(n)) for i in range(n): for coli in cols: df.set_value(i, coli, d[i][coli]) return df def GetAPIUrl(cur): ''' Makes a URL for querying historical prices of a cyrpto from Poloniex cur: 3 letter abbreviation for cryptocurrency (BTC, LTC, etc) ''' u = 'https://poloniex.com/public?command=returnChartData¤cyPair=USDT_' + cur + '&start=1420070400&end=9999999999&period=7200' return u def GetCurDF(cur, fp): ''' cur: 3 letter abbreviation for cryptocurrency (BTC, LTC, etc) fp: File path (to save price data to CSV) ''' openUrl = urllib.request.urlopen(GetAPIUrl(cur)) r = openUrl.read() openUrl.close() d = json.loads(r.decode()) df = JSONDictToDF(d) df.to_csv(fp, sep = ',') return df #%%Path to store cached currency data datPath = 'CurDat/' if not os.path.exists(datPath): os.mkdir(datPath) #Different cryptocurrency types cl = ['BTC', 'LTC', 'ETH', 'XMR'] #Columns of price data to use CN = ['close', 'high', 'low', 'open', 'volume'] #Store data frames for each of above types D = [] for ci in cl: dfp = os.path.join(datPath, ci + '.csv') try: df = pd.read_csv(dfp, sep = ',') except FileNotFoundError: df = GetCurDF(ci, dfp) D.append(df) #%%Only keep range of data that is common to all currency types cr = min(Di.shape[0] for Di in D) for i in range(len(cl)): D[i] = D[i][(D[i].shape[0] - cr):] #%% A = np.stack((Di[CN] for Di in D), axis = 2) #Scale price and volume to improve numerical stability A = A / np.array([[1000], [1000], [1000], [1000], [1000000]])

# Time Series Sampling

New samples are constructed that pair sequences of samples with the subsequent samples. In this way a regression model can be fit which predicts time periods into the future given data from the past . A helper class which accomplishes this follows.

import numpy as np class PastSampler: ''' Forms training samples for predicting future values from past value ''' def __init__(self, N, K): ''' Predict K future sample using N previous samples ''' self.K = K self.N = N def transform(self, A, Y = None): M = self.N + self.K #Number of samples per row (sample + target) #Matrix of sample indices like: {{1, 2..., M}, {2, 3, ..., M + 1}} I = np.arange(M) + np.arange(A.shape[0] - M + 1).reshape(-1, 1) B = A[I].reshape(-1, M * A.shape[1], *A.shape[2:]) ci = self.N * A.shape[1] #Number of features per sample return B[:, :ci], B[:, ci:] #Sample matrix, Target matrix

The above class is applied to the original time sequence data to obtain the desired sample and target matrices.

NPS, NFS = 64, 8 #Number of past and future samples ps = PastSampler(NPS, NFS) B, Y = ps.transform(A)

# Applying Deep Neural Networks

A 1D convolution neural network is constructed which transforms the input volume of historical data into predictions. The past 64 samples are transformed into a prediction about the next 8 samples. The *C1d* option in the network architecture specification indicates 1-dimensional convolution.

#%%Architecture of the neural network NC = B.shape[2] ns = [('C1d', [8, NC, NC * 2], 4), ('C1d', [8, NC * 2, NC * 2], 2), ('C1d', [8, NC * 2, NC], 2)] #Create the neural network in TensorFlow cnnc = CNNR(B[0].shape, ns, batchSize = 32, learnRate = 2e-5, maxIter = 80, reg = 1e-5, tol = 1e-2, verbose = True) #%%Perform the fit cnnc.fit(B, Y)

The architecture of the CNN is shown below in Figure 1. The top set of parenthesized values indicate the filter dimension while the bottom denote the stride.

Figure 1: 1D CNN Architecture

More information and the source code for the *CNNR* class are available on GitHub.

# Prediction

Using the above network, the next 8 time steps can be predicted. These predictions can in turn be used for subsequent predictions so that prediction can be made an arbitrary amount into the future. Code to accomplish this follows.

P = [B[[-1]]] #Sequence of predictions for i in range(8): #Repeat prediction 8 times YH = cnnc.predict(P[-1]) P.append(np.concatenate([P[-1][:, (NFS * len(CN)):], YH], axis = 1)) P = np.vstack(P)[:, 0:len(CN)] #%%Combine predictions with original data A = np.vstack([A, P])

# Results

The result of the predictions can be visualized using matplotlib.

for i, cli in enumerate(cl): fig, ax = mpl.subplots(figsize = (16 / 1.5, 10 / 1.5)) ax.plot(A[:, 1, i], '-', c = '#ff7f0e', label = 'Prediction') ax.plot(A[:-P.shape[0], 1, i], c = '#1f77b4', label = 'Actual') ax.legend(loc = 'upper left') ax.set_title(cli + ' (High)') ax.set_ylabel('USD (Thousands)') ax.set_xlabel('Time') ax.axes.xaxis.set_ticklabels([]) fig.savefig('CryptoPred' + cli + '.png', dpi = 100) mpl.show()

The resulting plot is shown below in Figure 2.

Figure 2: Cryptocurrency Predictions

The network predicts a dip in the prices of each cryptocurrency followed by a rally. The predicted behavior is similar to Bitcoin’s price over the past few days.