使用循环神经模型预测比特币(BTC)价格
虽然主观观点对于预测加密货币的未来很有价值,但我们的预测方法从一个不同的角度来处理这个问题,尤其是从算法交易的角度。我们只是计划使用数字历史数据来训练一个循环神经网络(RNN)来预测比特币的价格。
获取历史比特币价格
我们可能会有相当多的资源来获取历史比特币价格数据。虽然其中一些资源允许用户手动下载CSV文件,但其他资源提供的API可以连接到代码。因为当我们使用时间序列数据训练模型时,我们希望它能够进行最新的预测,我更喜欢使用API,这样我们可以在运行程序时始终获得最新的数据。我决定使用CoinRanking.com的API,它提供了我们可以使用的最新coin价格。
循环神经网络
由于我们使用的是时间序列数据集,因此使用仅前馈神经网络是不可行的,因为明天的BTC价格与今天的价格最相关,而不是一个月前。
循环神经网络(RNN)是一类人工神经网络,其中节点之间的连接形成沿序列的有向图。
RNN显示时间序列的时间动态行为,并且它可以使用其内部状态来处理序列。实际上,这可以通过LSTM和GRU层来实现。
在这里,您可以看到常规仅前馈神经网络和递归神经网络(RNN)之间的区别:
实现步骤
为了能够创建一个训练历史BTC价格并预测明天的BTC价格的程序,我们需要完成以下几项任务:
- 1 - 获取,清理和归一化历史BTC价格
- 2 - 使用LSTM构建RNN
- 3 - 训练RNN并保存训练神经网络模型
- 4 - 预测明天的BTC价格和“反序列化”它
其他:反序列化X_Test预测并创建Plot.ly图表
获取BTC数据
如上所述,我们将使用CoinRanking.com的API作为BTC数据集,并使用以下Python代码将其转换为pandas dataframe:
import requests,json,numpy as np,pandas as pd #https://api.coinranking.com/v1/public/coin/:coin_id/history/:timeframe #https://docs.coinranking.com/ def hist_price_dl(coin_id=1335,timeframe = "5y",currency = "USD"): '''It accepts coin_id, timeframe, and currency parameters to clean the historic coin data taken from COINRANKING.COM It returns a Pandas Series with daily mean values of the selected coin in which the date is set as the index''' r = requests.get("https://api.coinranking.com/v1/public/coin/"+str(coin_id)+"/history/"+timeframe+"?base="+currency) coin = json.loads(r.text)['data']['history'] #Reading in json and cleaning the irrelevant parts df = pd.DataFrame(coin) df['price'] = pd.to_numeric(df['price']) df['timestamp'] = pd.to_datetime(df['timestamp'],unit='ms').dt.date return df.groupby('timestamp').mean()['price']
默认情况下,此函数会根据5年BTC / USD价格进行调整。但是,您可以通过传入不同的参数值来更改这些值。
使用自定义函数清理数据
在获得数据并将其转换为pandas dataframe之后,我们可以定义自定义函数来清理我们的数据,将其归一化为神经网络,因为它是获得准确结果的必要条件,并应用自定义训练测试拆分。我们创建了一个自定义训练测试拆分函数(不是scikit-learn),因为我们需要保持时间序列顺序以正确训练我们的RNN。我们可以使用以下Python代码实现此目的,您可以在下面的代码片段中找到更多函数说明:
def price_matrix_creator(data, seq_len=30): ''' It converts the series into a nested list where every item of the list contains historic prices of 30 days ''' price_matrix = [] for index in range(len(data)-seq_len+1): price_matrix.append(data[index:index+seq_len]) return price_matrix def normalize_windows(window_data): ''' It normalizes each value to reflect the percentage changes from starting point ''' normalised_data = [] for window in window_data: normalised_window = [((float(p) / float(window[0])) - 1) for p in window] normalised_data.append(normalised_window) return normalised_data def train_test_split_(price_matrix, train_size=0.9, shuffle=False, return_row=True): ''' It makes a custom train test split where the last part is kept as the training set. ''' price_matrix = np.array(price_matrix) #print(price_matrix.shape) row = int(round(train_size * len(price_matrix))) train = price_matrix[:row, :] if shuffle==True: np.random.shuffle(train) X_train, y_train = train[:row,:-1], train[:row,-1] X_test, y_test = price_matrix[row:,:-1], price_matrix[row:,-1] X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1)) X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1)) if return_row: return row, X_train, y_train, X_test, y_test else: X_train, y_train, X_test, y_test
定义这些函数后,我们可以使用以下Python代码调用它们:
# Not passing any argument since they are set by default ser = hist_price_dl() # Creating a matrix using the dataframe price_matrix = price_matrix_creator(ser) # Normalizing its values to fit to RNN price_matrix = normalize_windows(price_matrix) # Applying train-test splitting, also returning the splitting-point row, X_train, y_train, X_test, y_test = train_test_split_(price_matrix)
使用LSTM构建RNN
在准备好我们的数据之后,是时候构建我们的机器学习模型了,我们稍后将使用清理和归一化的数据进行训练。我们将从导入Keras组件开始,并使用以下Python代码设置一些参数:
from keras.models import Sequential from keras.layers import LSTM, Dense, Activation import time # LSTM Model parameters, I chose batch_size = 2 # Batch size (you may try different values) epochs = 15 # Epoch (you may try different values) seq_len = 30 # 30 sequence data (Representing the last 30 days) loss='mean_squared_error' # Since the metric is MSE/RMSE optimizer = 'rmsprop' # Recommended optimizer for RNN activation = 'linear' # Linear activation input_shape=(None,1) # Input dimension output_dim = 30 # Output dimension
然后,我们将使用以下Python代码创建具有两个LSTM和两个Dense层的Sequential模型:
model = Sequential() model.add(LSTM(units=output_dim, return_sequences=True, input_shape=input_shape)) model.add(Dense(units=32,activation=activation)) model.add(LSTM(units=output_dim, return_sequences=False)) model.add(Dense(units=1,activation=activation)) model.compile(optimizer=optimizer,loss=loss)
训练RNN并保存训练模型
现在是时候用清理过的数据训练我们的机器学习模型了。您还可以测量训练期间所花费的时间。请遵循以下代码:
start_time = time.time() model.fit(x=X_train, y=y_train, batch_size=batch_size, epochs=epochs, validation_split=0.05) end_time = time.time() processing_time = end_time - start_time
别忘了保存它:
model.save('coin_predictor.h5')
预测明天的BTC价格并“反序化”它
在我们训练模型之后,我们需要获得当前的预测数据,并且由于我们将数据归一化,因此预测也将被归一化。因此,我们需要将其反归一化到其原始值。首先,我们将通过以下代码以相似的、部分不同的方式获取数据:
import requests,json,numpy as np,pandas as pd #We need ser, preds, row ser = hist_price_dl(timeframe='30d')[1:31] price_matrix = price_matrix_creator(ser) X_test = normalize_windows(price_matrix) X_test = np.array(X_test) X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
我们将只有预测的标准化数据:没有训练测试拆分。我们还将手动reshape数据,以便能够在我们保存的模型中使用它。
在清理和准备我们的数据后,我们将加载经过训练的RNN模型进行预测并预测明天的价格。
from keras.models import load_model model = load_model('coin_predictor.h5') preds = model.predict(X_test, batch_size=2)
但是,我们的结果将介于-1和1之间,这没有多大意义。因此,我们需要将它们反归一化回原始值。我们可以通过自定义函数实现这一目标:
def deserializer(preds, data, train_size=0.9, train_phase=False): ''' Arguments: preds : Predictions to be converted back to their original values data : It takes the data into account because the normalization was made based on the full historic data train_size : Only applicable when used in train_phase train_phase : When a train-test split is made, this should be set to True so that a cut point (row) is calculated based on the train_size argument, otherwise cut point is set to 0 Returns: A list of deserialized prediction values, original true values, and date values for plotting ''' price_matrix = np.array(price_matrix_creator(ser)) if train_phase: row = int(round(train_size * len(price_matrix))) else: row=0 date = ser.index[row+29:] date = np.reshape(date, (date.shape[0])) X_test = price_matrix[row:,:-1] y_test = price_matrix[row:,-1] preds_original = [] preds = np.reshape(preds, (preds.shape[0])) for index in range(0, len(preds)): pred = (preds[index]+1)* X_test[index][0] preds_original.append(pred) preds_original = np.array(preds_original) if train_phase: return [date, y_test, preds_original] else: import datetime return [date+datetime.timedelta(days=1),y_test]
定义自定义函数后,我们将调用这些函数并使用以下代码提取明天的BTC价格:
final_pred = deserializer(preds, ser, train_size=0.9, train_phase=False) final_pred[1][0]
使用上面的Python代码,您实际上可以获得机器学习模型对明天BTC价格的预测。
反序列化X_Test预测并创建Plot.ly图表
您可能还对RNN模型的整体结果感兴趣,并希望将其视为图表。我们也可以通过使用本教程训练部分的X_test数据来实现这些目标。
我们将首先加载我们的神经网络模型(将其视为单个预测案例的替代方案)并对X_test数据进行预测,以便我们可以使用以下代码对适当的天数进行预测:
from keras.models import load_model model = load_model('coin_predictor.h5') preds = model.predict(X_test, batch_size=2) plotlist = deserializer(preds, ser, train_phase=True)
接下来,我们将导入Plotly并设置属性以获得良好的绘图体验。我们将使用以下代码实现此目的:
from plotly import __version__ from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot import plotly.graph_objs as go import cufflinks as cf init_notebook_mode(connected=True)
设置完所有属性后,我们最终可以使用以下代码绘制预测值和观察值:
prices = pd.DataFrame({'Predictions':plotlist[1], 'Real Prices':plotlist[2]},index=plotlist[0]) iplot(prices.iplot(asFigure=True, kind='scatter', xTitle='Date', yTitle='BTC Price', title='BTC Price Predictions'))
运行此代码时,您将获得以下图表的最新版本:
正如你所看到的,它看起来一点都不差。但是,您需要知道,即使模式非常接近,但是如果您每天查看结果,结果仍然是危险的。因此,必须进一步开发代码以获得更好的结果。
最后
您已经成功创建并训练了可以预测BTC价格的RNN模型,您甚至保存了经过训练的模型供以后使用。您可以通过切换到面向对象编程在Web或移动应用程序中使用此训练模型。