Saltar al contenido

LSTM simple para el pronostico de la bolsa

    LSTM Portada

    Hoy quiero entrar un poco más en lo que es la predicción de resultados que se pueden hacer con las redes neuronales, más específicamente con las Redes Neuronales Recurrentes, y todavía más específicamente con las redes LSTM.

    Las redes LSTM son un tipo muy particular de redes neuronales que tienen en cuenta que los datos pueden ser una serie temporal, donde el anterior datos tiene una importancia clave en el estado del caso siguiente. Esto es lo que pasa en la bolsa que el valor de un día, es necesario para predecir lo que pasará al día siguiente.

    Por esta razón, LSTM es una de las arquitecturas más útiles a la hora de hacer un pronóstico para la bolsa. Y con este artículo vamos a hacer un pequeño acercamiento a como realizar una predicción.

    La descargar de datos

    Existen muchas formas de descargar los datos desde internet, así que podéis optar por el método que más os guste. En el blog ya que he hecho artículos explicando cómo realizar esta descarga como este o este.

    Lo único que en realidad necesitamos para llevar a cabo nuestra prueba es tener lo datos de cierre de los precios. En este caso nosotros solamente utilizaremos el precio de cierre para hacer nuestras predicciones. Esta claro que se pueden poner más características, pero eso queda para futuras entradas del blog.

    La forma que yo he utilizado es la siguiente:

    response = requests.get('https://financialmodelingprep.com/api/v3/historical-price-full/EURUSD?from=1980-01-01&to=2019-03-12&apikey=vuestra_api_key')
    response = response.json()
    data = pd.DataFrame(response['historical'])
    data = data.sort_values("date",ignore_index=True)
    data.set_index('date',inplace=True)
    EURUSD = data.iloc[:, 3:4].values

    Entrenamiento y pruebas

    Después de esto lo más importante es separar los datos entre entrenamiento y test. Vamos a hacerlo así:

    train_size = int(len(EURUSD)*0.67)
    test_size = len(EURUSD)-train_size
    train, test = EURUSD[0:train_size], EURUSD[train_size:len(EURUSD)]

    En este caso podría no ser necesario realizar esta separación. Ya que con los datos de bolsa simplemente podemos, por ejemplo, no descargar los datos de los dos últimos años y luego hacer el pruebas con ellos.

    En el caso de nuestra red solo hemos descargado los datos hasta marzo de 2019, con lo cual tendríamos los datos de los años posteriores para poder realizar pruebas de como funciona nuestra red neuronal.

    Normalización

    Ahora tenemos que prepararlos para que queden listos para trabajar en la red neuronal que vamos a crear. El primero paso para crear esto es la normalización.

    La normalización es un proceso en el cual se ponen todos los valores en el dataset entre 0 y 1. El objetivo de la normalización es poner todos los datos en la misma escala de valores, de esta forma es más fácil trabajar con los datos e incluso, aunque ahora no es el caso, poder compararlos con otros.

    La normalización de nuestro caso la realizaríamos con MinMaxScaler de esta forma:

    scaler = MinMaxScaler(feature_range=(0,1))
    train_scaled = scaler.fit_transform(EURUSD)

    Preparando los datos para la red LSTM

    Los datos para una red LSTM tienen que tener la forma: [muestras, días, características], así que hay que adaptarlos para que tengan esta forma. Esto lo haremos de la siguiente forma:

    features = []
    labels = []
    for i in range(60, train_size):
        features.append(train_scaled[i-60:i, 0])
        labels.append(train_scaled[i, 0])
    
    features = np.array(features)
    labels = np.array(labels)
    
    features = np.reshape(features, (features.shape[0], features.shape[1], 1))

    Como se puede ver además de poner los datos en el formato correcto vamos preparando la variable labels con los valores que tendrá que tener la salida. Es importante tener estos valores en cuenta para el futuro entrenamiento de la red.

    Diseño de la red neuronal

    Ahora vamos a ver como hacemos el modelo de la red neuronal propiamente dicho. La red neuronal tendrá las siguientes capas:

    1. Capa de entrada, en la cual le pasaremos una característica pero con una venta de 60 días.
    2. Tres capas ocultas con 50 neuronas LSTM seguidas de una capa de dropout al 20%.
    3. Capa de salida con una neurona.

    La optimización se hará mediante el optimizador adam y para la función de perdida utilizaremos el error cuadrático medio. El entrenamiento lo haremos con 20 épocas y con un tamaño de batch de 32.

    Con todo esto la red quedaría así:

    model = Sequential()
    model.add(LSTM(50, input_shape=(60, 1), return_sequences=True))
    model.add(Dropout(0.2))
    model.add(LSTM(50, return_sequences=True))
    model.add(Dropout(0.2))
    model.add(LSTM(50, return_sequences=True))
    model.add(Dropout(0.2))
    model.add(LSTM(50))
    model.add(Dropout(0.2))
    model.add(Dense(1))
    model.summary()
    model.compile(loss='mean_squared_error', optimizer='adam')
    model.fit(features, labels, epochs=20, batch_size=32, verbose=1)

    Pruebas

    Lo más importante a la hora de hacer las pruebas es saber con la ventana con la que contamos y tener en cuenta que para hacer la primer predicción tenemos que contar con los datos de esa ventana. Es decir, hay que tirar de parte de los datos de entrenamiento. Eso lo haremos con el siguiente código:

    all_data = data.loc[:, 'close']
    inputs = all_data[train_size-60:].values
    inputs = inputs.reshape(-1,1)
    inputs = scaler.transform(inputs)
    X_test = []
    for i in range(60, test.shape[0]+60):
      X_test.append(inputs[i-60:i,0])
    X_test = np.array(X_test)
    X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
    predicted_stock_price = model.predict(X_test)
    predicted_stock_price = scaler.inverse_transform(predicted_stock_price)

    Visualización de las pruebas

    Como ver los datos completos no nos aportaría gran información (por el gran volumen de datos que solemos manejar), es mejor ir viendo los datos poco a poco. Para ello este código nos irá muy bien:

    plt.figure(figsize=(10,6))  
    plt.plot(test[:100], color='blue', label='Precios reales del Euro/Dolar')  
    plt.plot(predicted_stock_price[0:100], color='red', label='Predicción')  
    plt.title('Predicción de precios del EURO/Dolar')  
    plt.xlabel('Dias')  
    plt.ylabel('Precio EUR/USD')
    plt.legend()  
    plt.show()

    Donde veremos la información así:

    Resultado de la red LSTM para el euro/dolar

    Conclusiones

    A partir de este momento todavía hay mucho trabajo con la red neuronal como para darla como finalizada. Hay muchas mejoras que se le pueden hacer, como optimizar las capas, ver cuantas son las épocas necesarias para conseguir el mejor entrenamiento, o el tamaño de batch óptimo para la red neuronal. También se puede ampliar los datos, ya que en este ejemplo solo hemos usado los datos del EUR/USD, ¿pero qué pasaría con otros datos?. Ya veis que hay mucho trabajo que hacer.

    Como se puede ver en la imagen que mostramos la red neuronal también nos puede servir como indicador personalizado, es decir, que no hace falta que nos de una predicción al 100% verdadera sino que con ello podríamos ya empezar a hacer pruebas de backtest, ver cuando entrar y salir de las posiciones, y mucho más que nos quedaría para tener el robot completo.

    Espero que esta pequeña introducción al mundo de las redes neuronales recurrentes desde el trading os sirva. Como digo siempre, si tenéis cualquier duda o mejora del artículo no dudéis en poneros en contacto conmigo y os contestaré lo antes posible.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *