
Avertissement: Ce cas n’est qu’une étude et ne constitue pas une recommandation d’investissement.
Les données de prix du bitcoin sont basées sur des séquences chronologiques, de sorte que la plupart des prévisions de prix du bitcoin sont réalisées à l’aide du modèle LSTM.
La mémoire à long terme à court terme (LSTM) est un modèle d’apprentissage en profondeur particulièrement adapté aux données de séquence temporelle (ou aux données avec une séquence temporelle / spatiale / structurée, comme les films, les phrases, etc.) et est le modèle idéal pour prédire l’orientation des prix des crypto-monnaies.
L’article est principalement consacré à la synthèse des données par LSTM, permettant de prédire le prix futur du bitcoin.
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler, LabelEncoder
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from matplotlib import pyplot as plt
%matplotlib inline
Chargement des données
Lire les échanges quotidiens de BTC
data = pd.read_csv(filepath_or_buffer="btc_data_day")
Les données sont disponibles, il y a actuellement 1380 données, composées des colonnes Date, Open, High, Low, Close, Volume (BTC), Volume (Currency) et Prix pondéré. À l’exception de la colonne Date, les autres colonnes de données sont de type float64.
data.info()
Regardez les 10 premières lignes.
data.head(10)

Visualisation des données
Avec matplotlib, on peut tracer le prix pondéré pour voir la distribution et la tendance des données. Dans le graphique, nous avons trouvé une partie de la donnée 0, et nous devons vérifier si la donnée est inhabituelle.
plt.plot(data['Weighted Price'], label='Price')
plt.ylabel('Price')
plt.legend()
plt.show()

Traitement des données inhabituelles
Si vous regardez les données pour voir si elles contiennent des nanogrammes, vous pouvez voir que nos données ne contiennent pas de nanogrammes.
data.isnull().sum()
Date 0
Open 0
High 0
Low 0
Close 0
Volume (BTC) 0
Volume (Currency) 0
Weighted Price 0
dtype: int64
Si vous regardez les données de zéro, vous pouvez voir que nous avons des valeurs de zéro dans nos données, et nous devons traiter les valeurs de zéro.
(data == 0).astype(int).any()
Date False
Open True
High True
Low True
Close True
Volume (BTC) True
Volume (Currency) True
Weighted Price True
dtype: bool
data['Weighted Price'].replace(0, np.nan, inplace=True)
data['Weighted Price'].fillna(method='ffill', inplace=True)
data['Open'].replace(0, np.nan, inplace=True)
data['Open'].fillna(method='ffill', inplace=True)
data['High'].replace(0, np.nan, inplace=True)
data['High'].fillna(method='ffill', inplace=True)
data['Low'].replace(0, np.nan, inplace=True)
data['Low'].fillna(method='ffill', inplace=True)
data['Close'].replace(0, np.nan, inplace=True)
data['Close'].fillna(method='ffill', inplace=True)
data['Volume (BTC)'].replace(0, np.nan, inplace=True)
data['Volume (BTC)'].fillna(method='ffill', inplace=True)
data['Volume (Currency)'].replace(0, np.nan, inplace=True)
data['Volume (Currency)'].fillna(method='ffill', inplace=True)
(data == 0).astype(int).any()
Date False
Open False
High False
Low False
Close False
Volume (BTC) False
Volume (Currency) False
Weighted Price False
dtype: bool
Si vous regardez la distribution et le mouvement des données, la courbe est maintenant très continue.
plt.plot(data['Weighted Price'], label='Price')
plt.ylabel('Price')
plt.legend()
plt.show()

Découpage des ensembles d’entraînement et des ensembles de test
Regroupement des données en 0-1
data_set = data.drop('Date', axis=1).values
data_set = data_set.astype('float32')
mms = MinMaxScaler(feature_range=(0, 1))
data_set = mms.fit_transform(data_set)
Partage des ensembles de test et d’entraînement de 2:8
ratio = 0.8
train_size = int(len(data_set) * ratio)
test_size = len(data_set) - train_size
train, test = data_set[0:train_size,:], data_set[train_size:len(data_set),:]
Créer des ensembles d’entraînement et des ensembles de test en utilisant un jour comme période fenêtre pour créer nos ensembles d’entraînement et de test.
def create_dataset(data):
window = 1
label_index = 6
x, y = [], []
for i in range(len(data) - window):
x.append(data[i:(i + window), :])
y.append(data[i + window, label_index])
return np.array(x), np.array(y)
train_x, train_y = create_dataset(train)
test_x, test_y = create_dataset(test)
Cette fois-ci, nous avons utilisé un modèle simple qui est structuré comme ceci:. LSTM2. Dense。
Il est nécessaire de préciser que la dimension d’entrée de la forme d’entrée de LSTM est: batch_size, time steps, features. Dans ce cas, la valeur des étapes de temps est l’intervalle de la fenêtre de temps au moment de l’entrée des données. Ici, nous utilisons 1 jour comme fenêtre de temps, et nos données sont des données de jour, donc ici nos étapes de temps sont 1.
La mémoire longue courte durée (LSTM) est un type particulier de RNN, principalement conçu pour résoudre les problèmes de disparition de la gradiente et d’explosion de la gradiente lors de l’entraînement à longue séquence.

D’après le diagramme de la structure du réseau de LSTM, on peut voir que LSTM est en fait un petit modèle qui contient 3 fonctions d’activation sigmoïde, 2 fonctions d’activation tanh, 3 multiplications et 1 addition.
État de la cellule
L’état cellulaire est le cœur de la LSTM, il est la ligne noire en haut de la figure, et en dessous de cette ligne noire, il y a des portes, dont nous parlerons plus loin. L’état cellulaire est mis à jour en fonction des résultats de chaque porte.
Les réseaux LSTM peuvent supprimer ou ajouter des informations sur l’état des cellules via une structure appelée porte. La porte peut décider de manière sélective de ce qui doit passer. La porte est une combinaison d’une couche sigmoïde et d’une opération de multiplication de points.
La porte de l’oubli
La première étape du LSTM consiste à déterminer quelles informations l’état cellulaire doit rejeter. Cette partie de l’opération est traitée par une unité sigmoïde appelée porte d’oubli.

Nous pouvons voir que la porte d’oubli, en regardant les informations \(h_{l-1}\) et \(x_{t}\), exporte un vecteur entre 0 et 1, où la valeur 0 à 1 indique combien d’informations sont conservées ou rejetées dans l’état cellulaire \(C_{t-1}\). 0 indique qu’elles ne sont pas conservées et 1 indique qu’elles sont conservées.
L’expression mathématique est \(f_{t} =\sigma\left(W_{f} \cdot\left[h_{t-1}, x_{t}\right]+b_{f}\right)\)
Une entrée
L’étape suivante consiste à décider quelles nouvelles informations ajouter à l’état de la cellule, en ouvrant la porte d’entrée.

Nous voyons que \(h_{l-1}\) et \(x_{t}\) sont placés dans une porte d’oubli (sigmoid) et une porte d’entrée (tanh). Puisque la porte d’oubli a une sortie de 0 à 0, si la porte d’oubli a une sortie de 0, la porte d’entrée \(C_{i}\) n’est pas ajoutée à l’état de la cellule actuelle. Si elle est 1, elle est ajoutée entièrement à l’état de la cellule, donc la porte d’oubli sert à ajouter sélectivement les résultats de la porte d’entrée à l’état de la cellule.
La formule mathématique est \(C_{t} = f_{t} * C_{t-1} + i_{t} *\tilde{C}_{t}\)
Porte de sortie
Après la mise à jour de l’état de la cellule, il est nécessaire de déterminer les caractéristiques de l’état de la cellule de sortie en fonction de la somme des entrées \(h_{l-1}\) et \(x_{t}\), où l’entrée doit être déterminée par une couche sigmoïde appelée porte de sortie, puis l’état de la cellule doit être déterminé par une couche tanh pour obtenir un vecteur de valeur comprise entre -1 et 1, ce vecteur multiplié par la condition déterminée par la porte de sortie donne la sortie de la cellule RNN finale.

def create_model():
model = Sequential()
model.add(LSTM(50, input_shape=(train_x.shape[1], train_x.shape[2])))
model.add(Dense(1))
model.compile(loss='mae', optimizer='adam')
model.summary()
return model
model = create_model()

history = model.fit(train_x, train_y, epochs=80, batch_size=64, validation_data=(test_x, test_y), verbose=1, shuffle=False)
plt.plot(history.history['loss'], label='train')
plt.plot(history.history['val_loss'], label='test')
plt.legend()
plt.show()

train_x, train_y = create_dataset(train)
test_x, test_y = create_dataset(test)
predict = model.predict(test_x)
plt.plot(predict, label='predict')
plt.plot(test_y, label='ground true')
plt.legend()
plt.show()

L’utilisation de l’apprentissage automatique pour prédire la tendance à long terme du prix du bitcoin est encore très difficile, et cet article ne peut être utilisé qu’en tant que cas d’étude.