Serie de Tiempo Bitcoin

Bitcoin

Bitcoin es una criptomoneda descentralizada y una forma de dinero digital que opera en una red peer-to-peer (P2P) sin la necesidad de intermediarios como bancos o gobiernos.

Fue creada en 2009 por una persona o grupo de personas bajo el seudónimo de Satoshi Nakamoto. La característica fundamental de Bitcoin es su tecnología subyacente, la cadena de bloques (blockchain), que es un registro público y distribuido de todas las transacciones realizadas con esta moneda.

La cadena de bloques de Bitcoin es un libro mayor digital que registra todas las transacciones de manera segura y transparente. Cada transacción se agrupa en bloques y se enlaza en una cadena continua, lo que garantiza la integridad de la información y la imposibilidad de modificar o eliminar transacciones pasadas.

Bitcoin se distingue por varias características:

  1. Descentralización: No está controlado por ninguna autoridad central, lo que significa que no está sujeto a regulaciones gubernamentales o políticas monetarias.

  2. Anonimato relativo: Aunque las transacciones en la cadena de bloques son públicas y transparentes, las identidades de las partes involucradas en las transacciones suelen permanecer anónimas.

  3. Escasez programada: Existe un límite máximo de 21 millones de bitcoins que se pueden crear, lo que lo convierte en un recurso digital escaso y potencialmente valioso.

  4. Seguridad: La tecnología de criptografía y la descentralización de la cadena de bloques hacen que las transacciones sean seguras y difíciles de falsificar o manipular.

Bitcoin ha ganado popularidad como una forma de inversión y como un medio de intercambio en línea, aunque su volatilidad y su uso en actividades ilícitas han generado controversia. Sin embargo, su impacto en la industria financiera y tecnológica ha sido significativo, alentando el desarrollo de otras criptomonedas y tecnologías basadas en la cadena de bloques.

Implementación en Python

Vamos a implementar una serie de tiempo para predecir el valor de cierre de Bitcoin.

Data Histórica

Damos click al link de CoinMarketCap: https://coinmarketcap.com/es/currencies/bitcoin/historical-data/

Selecionamos el periodo de nuestro interés y descargamos la data histórica (en formato csv) del valor de cierre de Bitcoin.

En este caso utilizaremos el siguiente archivo: https://gist.github.com/mevangelista-alvarado/6f4f28c00f9e683108637cb3c8d5db89

Leer el csv y convertir a un dataframe

En este caso el archivo que nosotros utilizamos tiene el nombre de Bitcoin_1_1_2024-6_9_2024_historical_data_coinmarketcap.csv

Opción 1 (Descarga Manual)

import pandas as pd

_df = pd.read_csv("/content/Bitcoin_1_1_2024-6_9_2024_historical_data_coinmarketcap.csv", delimiter=';')
# Ordenamos correctamente
_df = _df.sort_index(ascending=False)
_df.head()

Opción 2 (Utilizar wget)

!wget https://gist.githubusercontent.com/mevangelista-alvarado/6f4f28c00f9e683108637cb3c8d5db89/raw/1ce753283fce23eeab952fa1d660a7069bbe9104/Bitcoin_1_1_2024-6_9_2024_historical_data_coinmarketcap.csv
import pandas as pd

_df = pd.read_csv("/content/Bitcoin_1_1_2024-6_9_2024_historical_data_coinmarketcap.csv", delimiter=';')
# Ordenamos correctamente
_df = _df.sort_index(ascending=False)
_df.head() 

Obtenemos un dataframe con las siguientes columnas:

'timeOpen', 'timeClose', 'timeHigh', 'timeLow', 'name', 'open', 'high',
       'low', 'close', 'volume', 'marketCap', 'timestamp'

Seleccionamos la data

df = _df[['timeOpen', 'open', 'high', 'low', 'close']]

Convertir los datos a un numpy array

dates = df[['close']].values

Escalar los valores

Utilizamos la clase MinMaxScaler para escalar los valores entre 0 y 1.

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(dates)

Secuencias

Aquí se crean las secuencias de datos a partir de un conjunto y un tamaño de ventana dado.

Definir el tamaño de la ventana de tiempo

window_size = 60

Aquí se establece el tamaño de la ventana de tiempo, que es el número de puntos de datos que se utilizarán para predecir el siguiente punto de datos en una secuencia.

Crear las secuencias de datos

import numpy as np

def create_sequences(data, window_size):
    sequences = []
    labels = []
    for i in range(len(data) - window_size):
        sequences.append(data[i:i+window_size])
        # El precio es la primera columna
        labels.append(data[i + window_size, 0])  
    return np.array(sequences), np.array(labels)

X, y = create_sequences(scaled_data, window_size)

En cada iteración, se crea una secuencia de datos de longitud window_size utilizando el índice i como punto de partida y se agrega a la lista sequences. Además, se agrega la etiqueta correspondiente al siguiente punto de datos después de la secuencia a la lista labels.

Conjunto de entrenamiento y prueba

Dividir los datos en conjuntos de entrenamiento y prueba

split = int(len(X) * 0.8)
X_train, y_train = X[:split], y[:split]
X_test, y_test = X[split:], y[split:]

Modelo RNN

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, SimpleRNN

model = Sequential()
model.add(SimpleRNN(units=120, return_sequences=True, input_shape=(window_size, X_train.shape[2])))
model.add(SimpleRNN(units=60, return_sequences=False))
model.add(Dense(units=30))
model.add(Dense(units=1))

Este modelo está diseñado para procesar secuencias de datos con una red neuronal recurrente simple y luego realizar una predicción utilizando capas completamente conectadas.

Entrenamiento y compilación

from tensorflow.keras.optimizers import Adam

learning_rate = 0.001
adam_optimizer = Adam(learning_rate=learning_rate)

# Compilar el modelo
model.compile(optimizer=adam_optimizer, loss='mean_squared_error')

# Entrenar el modelo
model.fit(X_train, y_train, batch_size=1, epochs=10)

Testing

# Hacer predicciones
predictions = model.predict(X_test)

# Desescalar los datos predichos
predictions = scaler.inverse_transform(np.concatenate((predictions, np.zeros((predictions.shape[0], 3))), axis=1))[:,0]
y_test = scaler.inverse_transform(np.concatenate((y_test.reshape(-1, 1), np.zeros((y_test.shape[0], 3))), axis=1))[:,0]

Graficar los resultados

import matplotlib.pyplot as plt
import numpy as np

valid = df[split:]
# Reiniciar el índice del DataFrame de validación
valid = valid.reset_index(drop=True)
# Inicializar la columna de predicciones con NaN  
valid['Predictions'] = np.nan  

# Añadir las predicciones al DataFrame de validación desde el punto donde inician las predicciones
valid.loc[window_size:, 'Predictions'] = predictions
dates_valid = pd.to_datetime(valid['timeOpen']).apply(lambda x: x.strftime('%Y-%m-%d')).tolist()

plt.figure(figsize=(16,8))
plt.title('Modelo RNN para Predicción de Bitcoin')
plt.xlabel('Fecha')
plt.ylabel('Precio de Bitcoin (USD)')
plt.plot(dates_valid, valid[['close', 'Predictions']])
plt.legend(['Valor Real', 'Predicciones'], loc='lower right')
plt.xticks(rotation=90)
plt.show()

Predicción de valores nuevos

En este caso haremos la predicción del valor de cierre de Bitcoin en los proximos 115 días

# Generar secuencias para los siguientes días
future_sequences = []
# Última secuencia de los valores que tenemos
last_sequence = X[-1]  

days = 10 
for _ in range(days):
    # Predecir el siguiente valor
    next_value = model.predict(np.array([last_sequence]))[0, 0]
    
    # Actualizar la secuencia para la siguiente predicción
    last_sequence = np.concatenate((last_sequence[1:], [[next_value]]), axis=0)
    
    # Añadir la nueva secuencia a las secuencias futuras
    future_sequences.append(last_sequence)

# Convertir las secuencias futuras a un numpy y reshape para la RNN
future_sequences = np.array(future_sequences)
future_sequences = np.reshape(future_sequences, (future_sequences.shape[0], future_sequences.shape[1], 1))

# Hacer predicciones para los siguientes días
future_predictions = model.predict(future_sequences)

# Desescalar los datos predichos para los siguientes días
future_predictions = scaler.inverse_transform(np.concatenate((future_predictions, np.zeros((future_predictions.shape[0], 3))), axis=1))[:,0]

Generar fechas para los siguientes días

# Última fecha en los datos reales
last_date = df['timeOpen'].iloc[-1] 
future_dates = pd.date_range(start=last_date, periods=days)[1:]
future_dates = future_dates.strftime('%Y-%m-%d').tolist() 

Graficar los resultados de los siguientes 30 días

plt.figure(figsize=(16,8))
plt.title('Predicciones de los siguientes días')
plt.xlabel('Fecha')
plt.ylabel('Precio de Bitcoin (USD)')
plt.plot(dates_valid, valid[['close', 'Predictions']], label=['real', 'Predicciones'])
plt.plot(future_dates, future_predictions, label='Predicciones')
plt.legend()
plt.xticks(rotation=90)
plt.show()

En conclusión, el ejercicio de crear una RNN para predecir el valor del Bitcoin es una aplicación práctica del aprendizaje automático en el campo de las finanzas y la predicción de series temporales.

Si el modelo muestra un buen rendimiento en términos de precisión en las predicciones y capacidad para capturar patrones en los datos históricos, puede ser una herramienta valiosa para los inversores y analistas financieros en la toma de decisiones.

Sin embargo, es importante tener en cuenta que las predicciones de cualquier modelo de este tipo están sujetas a incertidumbres y deben utilizarse con precaución junto con otros análisis y consideraciones.

Last updated