Previsão do preço do Bitcoin em tempo real usando o framework LSTM

Autora:Nuvem de lagoa, Criado: 2020-05-20 15:45:23, Atualizado: 2020-05-20 15:46:37

img

Dica: Este caso é apenas para fins de estudo e pesquisa e não constitui uma recomendação de investimento.

Os dados de preço do Bitcoin são baseados em sequências de tempo, portanto, as previsões de preço do Bitcoin são realizadas principalmente usando o modelo LSTM.

A memória de curto prazo (LSTM) é um modelo de aprendizagem profunda especialmente adaptado para dados de sequência de tempo (ou dados com ordem de tempo / espaço / estrutura, como filmes, frases, etc.) e é o modelo ideal para prever a direção do preço das criptomoedas.

Este artigo foi escrito principalmente para combinar dados através do LSTM para prever o preço futuro do Bitcoin.

importar bibliotecas para usar

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

Análise de dados

Carregamento de dados

Leia os dados diários de negociação do BTC

data = pd.read_csv(filepath_or_buffer="btc_data_day")

Os dados disponíveis são de 1380 colunas: Data, Open, High, Low, Close, Volume (BTC), Volume (Currency) e Weighted Price. As colunas restantes são de tipo float64, exceto a coluna Date.

data.info()

Veja as 10 primeiras linhas.

data.head(10)

img

Visualização de dados

Usando o matplotlib, traçamos o preço ponderado para ver a distribuição e a tendência dos dados. No gráfico, encontramos uma parte de dados 0 e precisamos confirmar se há alguma anomalia nos dados abaixo.

plt.plot(data['Weighted Price'], label='Price')
plt.ylabel('Price')
plt.legend()
plt.show()

img

Processamento de dados anormais

Primeiro, vamos ver se o nosso dado contém dados de nanos, e podemos ver que o nosso dado não tem dados de nanos.

data.isnull().sum()

Date                 0
Open                 0
High                 0
Low                  0
Close                0
Volume (BTC)         0
Volume (Currency)    0
Weighted Price       0
dtype: int64

Então, se você olhar para baixo para o dado 0, você pode ver que o nosso dado tem um valor zero, e nós precisamos de processá-lo.

(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

Agora, se olharmos para a distribuição dos dados e para a tendência, a curva já é muito contínua.

plt.plot(data['Weighted Price'], label='Price')
plt.ylabel('Price')
plt.legend()
plt.show()

img

Segmentação dos conjuntos de dados de treinamento e de teste

Unificar dados para 0 a 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)

Divide os conjuntos de dados de testes e de treinamento em 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),:]

Criar um conjunto de dados de treinamento e de teste, com um dia como janela para criar nosso conjunto de dados de treinamento e de teste.

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)

Definição e treinamento do modelo

Desta vez, usamos um modelo simples, que tem a seguinte estrutura: 1. LSTM2. Dense.

Aqui é necessário explicar o formato de entrada do LSTM. A dimensão de entrada do Input Shape é batch_size, time steps, features. Aqui, o valor de time steps é o intervalo de janela de tempo no momento da entrada de dados.

A memória de curto prazo (LSTM) é uma espécie de RNN especializada, principalmente para resolver problemas de desaparecimento de gradientes e explosão de gradientes durante o treinamento de séries longas.

img

A partir do gráfico de estrutura da rede do LSTM, pode-se ver que o LSTM é, na verdade, um modelo pequeno, que contém três funções de ativação sigmoide, duas funções de ativação tanh, três multiplicações e uma adição.

Estado celular

O estado da célula é o núcleo do LSTM, ele é a linha preta no topo do gráfico acima, e abaixo desta linha preta há algumas portas, que vamos descrever mais adiante. O estado da célula é atualizado com base nos resultados de cada porta.

A rede LSTM pode remover ou adicionar informações sobre o estado da célula através de uma estrutura chamada porta. A porta pode ter uma decisão seletiva sobre qual informação passar. A estrutura da porta é uma combinação de um sigmoide e uma operação de multiplicação de pontos.

A porta esquecida

O primeiro passo do LSTM é decidir qual informação o estado celular precisa descartar. Esta parte da operação é processada por uma unidade sigmoide chamada porta do esquecimento.

img

Podemos ver que a porta de esquecimento produz um vetor entre 0 e 1 ao olhar para as informações $h_{l-1}$ e $x_{t}$, onde o valor 0 a 1 indica o quanto da informação no estado celular $C_{t-1}$ é mantida ou descartada. 0 significa não mantida e 1 significa mantida.

A expressão matemática: $f_{t}=\sigma\left ((W_{f} \cdot\left[h_{t-1}, x_{t}\right]+b_{f}\right) $

A entrada

O próximo passo é decidir que novas informações devem ser adicionadas ao estado da célula, o que é feito através da entrada.

img

Vemos que as informações de $h_{l-1}$ e $x_{t}$ são novamente inseridas em um segmoide e na entrada tanh. Como o resultado do segmoide é um valor de 0-1, portanto, se o segmoide é 0, o resultado $C_{i}$ após a entrada não será adicionado ao estado atual da célula, se for 1, tudo será adicionado ao estado da célula, portanto, o papel do segmoide aqui é adicionar seletivamente o resultado do segmoide ao estado da célula.

A fórmula matemática é: $C_{t}=f_{t} * C_{t-1} + i_{t} * \tilde{C}_{t}$

Portão de saída

Após a atualização do estado da célula, é necessário determinar quais características de estado da célula são feitas com base nos sumos de $h_{l-1}$ e $x_{t}$, onde a entrada é feita através de uma camada sigmoide chamada porta de saída, e o estado da célula é feito através da camada tanh para obter um vetor de um valor entre -1 e 1, que é multiplicado pelas condições de decisão obtidas pela porta de saída e obtém a saída da unidade final do RNA.

img

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

img

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

img

train_x, train_y = create_dataset(train)
test_x, test_y = create_dataset(test)

Previsão

predict = model.predict(test_x)
plt.plot(predict, label='predict')
plt.plot(test_y, label='ground true')
plt.legend()
plt.show()

img

No momento, é muito difícil prever o movimento do preço do Bitcoin a longo prazo usando o aprendizado de máquina, e este artigo só pode ser usado como um caso de aprendizagem. O caso será lançado em uma imagem demo da nuvem de matrizes, para que os usuários interessados possam experimentar diretamente.


Mais.