神経ネットワークとデジタル通貨量化取引シリーズ ((1) LSTMのビットコイン価格予測

作者: リン・ハーン小草作成日:2019年7月12日 14:28:20 更新日:2023年10月24日 21:42:00

img

1.简单介绍

深層ニューラルネットワークは,過去には解決できなかった難題を解決し,多くの分野で強力な能力を発揮している. タイムシーンの予測では,一般的なニューラルネットワーク価格はRNNです. RNNには現在のデータ入力だけでなく,歴史的なデータ入力も含まれています. もちろん,RNNの価格予測について話すとき,RNNの一種について語ることが多い:LSTM. この記事はpytorchをベースに,Bitcoinの価格を予測するモデルを構築します. 関連情報はたくさんありますが,まだ十分ではありません. このチュートリアルは,FMZの発明者,デジタル通貨量化取引プラットフォームによって提供されています.www.fmz.comQQグループ:863946592へようこそ.

2.数据和参考

ビットコインの価格データは,FMZの発明者による量化取引プラットフォームから得られたものです.https://www.quantinfo.com/Tools/View/4.html価格予測の例として,https://yq.aliyun.com/articles/538484RNNモデルについて詳しくは,https://zhuanlan.zhihu.com/p/27485750RNNの入力と出力を理解する:https://www.zhihu.com/question/41949741/answer/318771336パイトーチについて: 公式ファイルhttps://pytorch.org/docsこの記事へのトラックバック一覧です. この記事を読むには,panda/爬虫/データ処理などの知識が必要ですが,それは問題ではありません.

3.pytorch LSTMモデルのパラメータ

LSTMのパラメータ:

文書のパラメータを初めて見たとき,私はこう反応しました.imgゆっくり読めば 分かりやすくなります

img

input_size: 入力ベクトルxの特性の大きさは,閉じる価格で予想された閉じる価格の場合,input_size=1;開く価格で予想された閉じる価格が高く低くなると,input_size=4hidden_size暗示層の大きさnum_layersRNNの層数batch_first: True の場合,最初に入力した次元が batch_size である場合,このパラメータも混乱します.

入力するデータパラメータ:

img

input: 特定の入力されたデータは,三次元テンサールで,具体的な形は: ((seq_len, batch, input_size) 』である.其中,seq_len 指数列の長さは,すなわちLSTMは,どの程度の時間間の歴史的データかを考慮する必要がある.注意してください.これは単にデータのフォーマットを指し,LSTM内の構造ではなく,同じLSTMモデルは,異なるseq_lenのデータを入力することができ,予測された結果を与える.バッチ指数は,バッチの大きさを指し,異なるデータ群を代表する;input_sizeは前のinput_sizeである.h_0:初始 Hidden状態,形は ((num_layers * num_directions, batch, hidden_size) であるが,双方向ネットワークnum_directions=2の場合c_0:初期セル状態,形状は同じ,指定できない.

輸出パラメータ:

img

output:出力形状 (seq_len, batch, num_directions * hidden_size),注意はモデルパラメータ batch_first に関するh_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は,xの形状で,xが,xが,xが,xが,xが,xがbatch_first=Trueこのときのbatch_sizeのサイズは3,sqe_lenは4, input_sizeは5である. x[0]は最初のバッチを代表する.

バッチ_ファーストが定義されていない場合,デフォルトはFalseで,この時点でデータの代表はまったく異なっており,バッチサイズは4で,sqe_lenは3で,インプット_サイズは5である.このとき,x[0]はすべてのバッチをt=0のデータで代表し,順番推移する.個人はこの設定が直感的ではないと感じたため,パラメータを追加した.batch_first=True.

この2つのデータとの間の変換も便利です.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 ()) の2番目の値が3であり,batch_sizeの大きさは一致していることに注意してください.hnでは中間状態は保存されていませんが,最後のステップのみが保存されています. LSTMネットワークには2つの層があるため,実際には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の入力と出力を理解することは非常に重要です.そうでなければ,インターネットから任意にいくつかのコードを抽出することは容易です.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の実際の値と比較することができる.理論的には最後の予測結果のみを計算できる.この問題を説明する粗略な図を描く.LSTMの実際のモデルは,seqlen_seqlen参数を含まないので,モデルが異なる長さに対応できるので,中間予測も意図的に計算する傾向があります.img

訓練データを準備する際に,ウィンドウの移動は跳ね上がりであり,既に使用されているデータはもはや使用されません. もちろん,ウィンドウも個別に移動できます. これにより,多くの訓練集合が得られます. しかし,このような隣接するバッチデータがあまりにも重複していると感じて,現在の方法を採用しました.img

6.构造LSTM模型

最終的に構築されたモデルは以下のとおり,LSTMの2層,Linearの1層を含む.

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前) の一致性は非常に高いが,Bitcoinの価格が上昇した後,モデルはこれらのデータを見ていないため,予測は注意を払っていない.これは,以前のデータ標準化に問題があることを示している. 予想される価格は必ずしも正確ではないが,下落を予測する確率は?

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%の精度で予想しましたが,予想を上回りました.

このモデルには実用的な価値はないが,単純でわかりやすいので,これだけで,デジタル通貨の量化への導入課程がさらに増えていく.


関連性

もっと

ジャックマ訓練データとテストデータと同じですか?

a838899800日間のデータで,次の日のデータ,または次の800日のデータを予測する.

オリオン1708このモデルが実物価値がないとどうして言えるのでしょう?