신경망과 디지털 통화 양적 거래 시리즈 ((1) LSTM 비트코인 가격 예측

저자:초목, 2019-07-12 14:28:20에 생성, 업데이트: 2023-10-24 21:42:00

img

1.简单介绍

깊은 신경망은 최근 몇 년 동안 점점 더 인기를 끌고 있으며, 많은 분야에서 과거로 풀 수 없었던 문제를 해결하는 강력한 능력을 보여줍니다. 시간 순위 예측에서 일반적으로 사용되는 신경망 가격은 RNN입니다. RNN은 현재 데이터 입력뿐만 아니라 역사 데이터 입력도 가지고 있기 때문에, 물론, 우리가 RNN 가격 예측에 대해 이야기 할 때 종종 RNN의 한 종류에 대해 이야기합니다. 이 문서는 pytorch를 기반으로 비트코인 가격을 예측하는 모델을 구축합니다. 인터넷에 관련된 정보가 많지만 충분히 철저하지는 않지만, pytorch를 사용하는 것은 비교적 적습니다. 이 튜토리얼은 FMZ의 발명가인 디지털 화폐 양적 거래 플랫폼에서 제공됩니다.www.fmz.com), QQ 그룹:863946592에 오신 것을 환영합니다.

2.数据和参考

비트코인 가격 데이터는 FMZ의 발명가인 양적 거래 플랫폼에서 유래했습니다.https://www.quantinfo.com/Tools/View/4.html이 부분의 본문은 http://www.priceforecasting.com/https://yq.aliyun.com/articles/538484RNN 모델에 대한 자세한 설명:https://zhuanlan.zhihu.com/p/27485750RNN의 입력과 출력을 이해하는 방법:https://www.zhihu.com/question/41949741/answer/318771336피토치에 대한 공식 문서https://pytorch.org/docs다른 정보는 직접 검색하세요. 이 문서를 읽는 데는 다스/레프터/데이터 처리 등과 같은 사전 지식이 필요하지만, 그렇지 않습니다.

3.pytorch LSTM 모델의 매개 변수

LSTM의 매개 변수:

이 문헌에 있는 모든 매개 변수들을 처음 봤을 때, 저는 이렇게 말했습니다.img이 글은 한 번 더 읽어보겠습니다.

img

input_size: 입력 벡터 x의 특성 크기, 닫기 가격으로 예상되는 닫기 가격이라면, input_size=1; 높게 열고 낮게 닫기 예상되는 닫기 가격이라면, input_size=4hidden_size함축층 크기:num_layers: RNN의 계층 수batch_first: True의 경우 입수되는 첫 번째 차이는 batch_size 이면, 이 매개 변수는 또한 혼란스러울 수 있으며, 아래에서 자세히 설명될 것이다.

입력 데이터 파라미터:

img

input: 특정 입력된 데이터는 3차원 텐서이며, 구체적인 형태는: ((seq_len, batch, input_size) 』이다. 이 중, seq_len 계열의 길이는, 즉 LSTM가 얼마나 오랜 시간 동안의 역사적 데이터를 고려해야 하는지, 참고하십시오. 이것은 단지 데이터의 형식을 의미하며, LSTM 내부의 구조가 아닙니다. 동일한 LSTM 모델은 다른 seq_len 데이터를 입력할 수 있으며 예측 결과를 줄 수 있습니다.h_0: 초기 숨겨진 상태, 모양은 ((num_layers * num_directions, batch, hidden_size), 만약 쌍방향 네트워크 num_directions=2c_0: 초기 세포 상태, 모양이 같고, 지정할 수 없습니다.

출력 매개 변수:

img

output: 출력된 모양 (seq_len, batch, num_directions * hidden_size), 주의와 모델 파라미터 batch_firsth_n: t = seq_len 순간 h 상태, h_0과 같은 모양c_n: t = seq_len 순간의 상태 c, 모양은 c_0

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

먼저 필요한 패키지를 가져옵니다.

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

LSTM 모델을 정의합니다

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

입력할 수 있는 데이터

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]]])

x의 모양은 3이고, 4이고, 5입니다.batch_first=True이 때 배치_사이즈는 3이고, sqe_len는 4이고, input_size는 5이다. x[0]는 첫 번째 배치를 나타낸다.

만약 batch_first를 정의하지 않고, 기본으로 False로 설정하면, 이 때 데이터의 대표는 완전히 다릅니다. 배치 크기는 4, sqe_len은 3, input_size는 5이다. 이 때 x[0]는 모든 배치를 t=0의 데이터로 나타냅니다.batch_first=True.

이 두 가지 데이터의 변환은 매우 편리합니다:x.permute(1,0,2)

입력 및 출력

LSTM의 입출력 형태는 쉽게 혼란스럽고, 다음 그림으로 이해가 가능합니다:img
이 글은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])

관찰된 결과의 출력은 이전 파라미터의 설명과 일치한다.hn.size ()) 의 두 번째 값이 3이고, batch_size의 크기가 일치하는 것을 주목하라.hn에서는 중간 상태가 저장되지 않고 마지막 단계만 저장되었다. 우리의 LSTM 네트워크는 두 계층이 있기 때문에, 실제로 hn 마지막 계층의 출력은 출력의 값이며, 출력은 [3, 4, 10]의 모양으로, t=0,1,2,3의 모든 시기의 결과를 저장합니다.

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.准备比特币行情数据

앞서 언급한 내용들이 너무 많아서, LSTM의 입력과 출력을 이해하는 것이 매우 중요하기 때문에, 인터넷에서 임의로 일부 코드를 추출하는 것은 쉽게 잘못 될 수 있습니다.

데이터의 접근

이 데이터는 Bitfinex 거래소 BTC_USD 거래 쌍의 시장 데이터를 사용합니다.

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))

데이터 형식은 다음과 같습니다.img

데이터의 사전 처리

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

데이터의 표준화 방법은 매우 거칠고 몇 가지 문제가 있을 수 있습니다. 단지 시범적으로, 수익률과 같은 데이터 표준화를 사용할 수 있습니다.

훈련 데이터 준비

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))

최종 train_x와 train_y의 형태는 각각:torch.Size (([800, 10, 5]), torch.Size (([800, 10, 1]) 이다. 우리의 모델은 10 회기의 데이터에 기초하여 다음 회기의 종결 가격을 예측하기 때문에, 이론적으로 800 배트는 800 개 예측 종결 가격을 가지고 있는 한 충분하다. 그러나 train_y에는 각 배치에 10 개의 데이터가 있으며, 실제로 각 배치의 예측의 중간 결과가 마지막이 아니라 마지막이 유지된다. 최종 Loss을 계산할 때, 모든 10 개 예측 결과를 고려하여 train_y의 실제 값과 비교할 수 있다. 또한 이론적으로 마지막 예측 결과를 계산할 수 있는 Loss 만이다. 이 문제를 설명하는 대략적인 그래프를 그리는 것이 적합하다. LS의 실제 모델은 seqlenTM 매개 변수를 포함하지 않기 때문에, 모델은 다른 차원에도 적용될 수 있으며, 또한 중간 예측의 길이를 계산할 수 있다.img

훈련 데이터를 준비할 때, 창의 이동이 점프되고, 이미 사용된 데이터가 더 이상 사용되지 않으며, 물론 창도 개별적으로 이동할 수 있으므로 훈련 집합이 많이 얻을 수 있습니다. 그러나 이러한 인접한 팩 데이터가 너무 반복되는 것처럼 느껴지므로 현재 방법을 사용합니다.img

6.构造LSTM模型

최종적으로 만들어진 모델은 다음과 같습니다. 두 계층의 LSTM, 한 계층의 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.开始训练模型

그리고 마침내 훈련이 시작되었습니다. 코드는 다음과 같습니다.

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()))

교육의 결과는 다음과 같습니다.img

8.模型评价

모델의 예측 값:

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
그림에서 볼 수 있듯이 훈련 데이터 (<800 이전) 의 일치율은 매우 높지만, 나중에 비트코인 가격이 상승하면서 모델은 데이터를 보지 못했고 예측은 마음에 들지 않았습니다. 이것은 또한 이전 데이터 표준화에 문제가 있음을 보여줍니다. 가격 예측은 항상 정확하지는 않지만, 하락을 예측하는 정확도는 어떨까요?

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)))

81.4%의 정확도를 기록한 결과, 내 예상보다 훨씬 더 정확했습니다.

물론 이 모델은 실제 가치는 없지만 간단하고 이해하기 쉬우며, 이것만으로도 더 많은 신경망 입문과 디지털 화폐의 양적 응용에 대한 입문 과정이 나올 것입니다.


관련

더 많은

잭마훈련 데이터와 테스트 데이터 같은가요?

a838899무슨 뜻인지 모르겠네요. 800일 전의 자료를 이용해서, 다음 날의 자료를 예측하거나 다음 800일 전의 자료를 이용해서

오리온1708왜 이 모델이 실물 가치가 없다고 말하는 걸까요?