Les réseaux neuronaux et la série de transactions quantifiées de devises numériques ((1) LSTM prédit le prix du Bitcoin

Auteur:Le foin, Créé: 2019-07-12 14:28:20, Mis à jour: 2023-10-24 21:42:00

img

1.简单介绍

Les réseaux neuronaux profonds sont devenus de plus en plus populaires ces dernières années et ont montré une capacité puissante à résoudre des problèmes qui n'ont pas pu être résolus dans le passé dans de nombreux domaines. Sur les prévisions de séquences chronologiques, le prix du réseau neuronal le plus couramment utilisé est le RNN, car le RNN contient non seulement des données actuelles, mais aussi des données historiques. Bien sûr, lorsque nous parlons de prévisions de prix RNN, nous parlons souvent d'un type de RNN: LSTM. Ce tutoriel est proposé par FMZ, l'inventeur de la plateforme de trading de devises numériques (QC).www.fmz.comNous sommes heureux de vous inviter à nous rejoindre sur le groupe QQ: 863946592.

2.数据和参考

Les données sur le prix du Bitcoin proviennent de la plateforme de trading quantifié par les inventeurs de FMZ:https://www.quantinfo.com/Tools/View/4.htmlUn exemple de prévision de prix est le suivant:https://yq.aliyun.com/articles/538484Pour plus de détails sur le modèle RNN:https://zhuanlan.zhihu.com/p/27485750Comprendre les entrées et les sorties du RNN:https://www.zhihu.com/question/41949741/answer/318771336À propos de pytorch: Documents officielshttps://pytorch.org/docsPour plus d'informations, faites votre propre recherche. En outre, il est nécessaire d'avoir des connaissances préalables sur les pandas / reptiles / traitement de données, mais cela n'a pas d'importance.

Paramètres du modèle pytorch LSTM

Les paramètres du LSTM sont:

La première fois que j'ai vu ces paramètres dans la documentation, j'ai dit:imgJe pense que c'est une bonne idée de lire lentement et d'avoir une idée de ce que vous lisez.

img

input_size: taille caractéristique du vecteur d'entrée x, si le prix de clôture est prévu au prix de clôture, alors input_size=1; si le prix de clôture est prévu au prix de clôture, alors input_size=4hidden_sizeTaille de la couche implicitenum_layersNombre de couches de RNN:batch_first: Si pour True, la première dimension à entrer est batch_size, ce paramètre peut également être déroutant, qui sera expliqué plus en détail ci-dessous.

Paramètres de saisie:

img

input: les données spécifiquement entrées sont un tensor en trois dimensions, de la forme spécifique suivante: ((seq_len, batch, input_size)); dans ce cas, la longueur de la séquence seq_len, c'est-à-dire LSTM, doit être prise en compte pour la durée des données historiques, notez que cela ne concerne que le format des données, et non la structure interne de LSTM, le même modèle LSTM peut entrer des données différentes de seq_len et donner les résultats prédits; la taille du batch indique le nombre de groupes de données différents; input_size est l'input_size précédent.h_0: l'état caché initial, de la forme ((num_layers * num_directions, batch, hidden_size), si le nombre de directions du réseau bidirectionnel est = 2c_0: l'état initial de la cellule, la même forme, peut ne pas être spécifié.

Paramètres de sortie:

img

output: la forme de la sortie (seq_len, batch, num_directions * hidden_size), l'attention est liée au paramètre de modèle batch_firsth_n: t = h à l'instant seq_len, de la même forme que h_0c_n: t = c à l'instant seq_len, de la même forme que c_0

4.LSTM输入输出的简单例子

D'abord, importez les paquets dont vous avez besoin.

import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import matplotlib.pyplot as plt

Définition du modèle LSTM

LSTM = nn.LSTM(input_size=5, hidden_size=10, num_layers=2, batch_first=True)

Données prêtes à entrer

x = torch.randn(3,4,5)
# x的值为:
tensor([[[ 0.4657,  1.4398, -0.3479,  0.2685,  1.6903],
         [ 1.0738,  0.6283, -1.3682, -0.1002, -1.7200],
         [ 0.2836,  0.3013, -0.3373, -0.3271,  0.0375],
         [-0.8852,  1.8098, -1.7099, -0.5992, -0.1143]],

        [[ 0.6970,  0.6124, -0.1679,  0.8537, -0.1116],
         [ 0.1997, -0.1041, -0.4871,  0.8724,  1.2750],
         [ 1.9647, -0.3489,  0.7340,  1.3713,  0.3762],
         [ 0.4603, -1.6203, -0.6294, -0.1459, -0.0317]],

        [[-0.5309,  0.1540, -0.4613, -0.6425, -0.1957],
         [-1.9796, -0.1186, -0.2930, -0.2619, -0.4039],
         [-0.4453,  0.1987, -1.0775,  1.3212,  1.3577],
         [-0.5488,  0.6669, -0.2151,  0.9337, -1.1805]]])

Donc la forme de x est ((3,4,5)), comme nous l'avons défini précédemment.batch_first=True, la taille du batch_size est alors 3, sqe_len est 4, input_size est 5; x[0] représente le premier batch.

Si on ne définit pas batch_first, par défaut False, alors la représentation des données à ce moment-là est complètement différente, la taille du batch est 4, sqe_len est 3, input_size est 5; à ce moment-là, x[0] représente tous les batches de données à t=0, respectivement. La personne sent que cette configuration n'est pas intuitive, donc des paramètres sont ajoutés.batch_first=True.

Il est également facile de transférer des données entre les deux:x.permute(1,0,2)

Entrée et sortie

La forme des entrées et sorties de LSTM peut facilement être déroutante.img
Le blogueur a écrit:https://www.zhihu.com/question/41949741/answer/318771336

x = torch.randn(3,4,5)
h0 = torch.randn(2, 3, 10)
c0 = torch.randn(2, 3, 10)
output, (hn, cn) = LSTM(x, (h0, c0))
print(output.size()) #在这里思考一下,如果batch_first=False输出的大小会是多少?
print(hn.size())
print(cn.size())
#结果
torch.Size([3, 4, 10])
torch.Size([2, 3, 10])
torch.Size([2, 3, 10])

Le résultat de l'observation est conforme à l'interprétation des paramètres précédents. Notez que la deuxième valeur dehn.size (()) est 3, et que la taille de batch_size est cohérente, indiquant qu'il n'y a pas d'intermédiaire danshn, mais seulement la dernière étape. Puisque notre réseau LSTM a deux niveaux, en fait, la sortie de la dernière couche hn est la valeur de la sortie, la sortie est de la forme de [3, 4, 10], conservant le résultat de t = 0, 1, 2, 3 à tous les moments, donc:

hn[-1][0] == output[0][-1] #第一个batch在hn最后一层的输出等于第一个batch在t=3时output的结果
hn[-1][1] == output[1][-1]
hn[-1][2] == output[2][-1]

5.准备比特币行情数据

Il est important d'avoir une bonne compréhension des données d'entrée et de sortie de LSTM, car il est très facile d'extraire du code du Web, car la capacité de LSTM à tracer les séquences chronologiques est si forte que même si le modèle est erroné, il peut obtenir de bons résultats.

L'accès aux données

Les données sont basées sur les données de marché de la paire BTC_USD de l'échange Bitfinex.

import requests
import json

resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1562658565')
data = resp.json()
df = pd.DataFrame(data,columns = ['t','o','h','l','c','v'])
print(df.head(5))

Le format de données est le suivant:img

Pré-traitement des données

df.index = df['t'] # index设为时间戳
df = (df-df.mean())/df.std() # 数据的标准化,否则模型的Loss会非常大,不利于收敛
df['n'] = df['c'].shift(-1) # n为下一个周期的收盘价,是我们预测的目标
df = df.dropna()
df = df.astype(np.float32) # 改变下数据格式适应pytorch

Les méthodes de normalisation des données sont très rudimentaires et posent quelques problèmes, mais il est possible d'utiliser des données standardisées telles que les taux de rendement.

Préparez les données de formation

seq_len = 10 # 输入10个周期的数据
train_size = 800 # 训练集batch_size
def create_dataset(data, seq_len):
    dataX, dataY=[], []
    for i in range(0,len(data)-seq_len, seq_len):
        dataX.append(data[['o','h','l','c','v']][i:i+seq_len].values)
        dataY.append(data['n'][i:i+seq_len].values)
    return np.array(dataX), np.array(dataY)
data_X, data_Y = create_dataset(df, seq_len)
train_x = torch.from_numpy(data_X[:train_size].reshape(-1,seq_len,5)) #变化形状,-1代表的值会自动计算
train_y = torch.from_numpy(data_Y[:train_size].reshape(-1,seq_len,1))

La forme finale du train_x et du train_y est la suivante: torch.Size (([800, 10, 5]), torch.Size (([800, 10, 1]) ; puisque notre modèle prévoit le prix de clôture du prochain cycle sur la base de 10 cycles de données, 800 lots sont théoriquement suffisants pour 800 prix de clôture prévus. Mais train_y a 10 données par lot, et en fait le résultat intermédiaire de chaque lot est conservé, pas seulement le dernier.img

Notez que lors de la préparation des données d'entraînement, les mouvements des fenêtres sont sautés, les données déjà utilisées ne sont plus utilisées, et bien sûr, les fenêtres peuvent également être déplacées individuellement, ce qui donne beaucoup de rassemblements d'entraînement.img

6.构造LSTM模型

Le modèle finalement construit est le suivant, contenant un LSTM à deux couches et un LINEAR.

class LSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size=1, num_layers=2):
        super(LSTM, self).__init__()
        self.rnn = nn.LSTM(input_size,hidden_size,num_layers,batch_first=True)
        self.reg = nn.Linear(hidden_size,output_size) # 线性层,把LSTM的结果输出成一个值

    def forward(self, x):
        x, _ = self.rnn(x) # 如果不理解前向传播中数据维度的变化,可单独调试
        x = self.reg(x)
        return x
        
net = LSTM(5, 10) # input_size为5,代表了高开低收和交易量. 隐含层为10.

7.开始训练模型

Le code est le suivant:

criterion = nn.MSELoss() # 使用了简单的均方差损失函数
optimizer = torch.optim.Adam(net.parameters(),lr=0.01) # 优化函数,lr可调
for epoch in range(600): # 由于速度很快,这里的epoch多一些
    out = net(train_x) # 由于数据量很小, 直接拿全量数据计算
    loss = criterion(out, train_y)
    optimizer.zero_grad()
    loss.backward() # 反向传播损失
    optimizer.step() # 更新参数
    print('Epoch: {:<3}, Loss:{:.6f}'.format(epoch+1, loss.item()))

Les résultats de la formation sont les suivants:img

8.模型评价

La valeur prédite par le modèle:

p = net(torch.from_numpy(data_X))[:,-1,0] # 这里只取最后一个预测值作为比较
plt.figure(figsize=(12,8))
plt.plot(p.data.numpy(), label= 'predict')
plt.plot(data_Y[:,-1], label = 'real')
plt.legend()
plt.show()

img
Comme vous pouvez le voir sur le graphique, les données de formation (avant 800) sont très correctes, mais la hausse du prix du Bitcoin est très élevée, les modèles n'ont pas vu ces données et les prévisions ne sont pas à la hauteur. Si les prix prédits ne sont pas forcément exacts, quelle est l'exactitude des prévisions de chute?

r = data_Y[:,-1][800:1000]
y = p.data.numpy()[800:1000]
r_change = np.array([1 if i > 0 else 0 for i in r[1:200] - r[:199]])
y_change = np.array([1 if i > 0 else 0 for i in y[1:200] - r[:199]])
print((r_change == y_change).sum()/float(len(r_change)))

Le résultat est de 81,4% de précision, soit plus que ce que j'espérais.

Bien sûr, ce modèle n'a aucune valeur réelle, mais il est simple et facile à comprendre, ce qui est une introduction à d'autres cours d'introduction à la quantification des applications de réseaux de neurones.


Relationnée

Plus de

détectiveLes données de formation sont-elles les mêmes que celles des tests?

a838899Ce qui n'est pas très clair, c'est si vous prédisez les 800 prochains jours, ou les 800 prochains jours.

Orion 1708Pourquoi dire que ce modèle n'a aucune valeur réelle?