Saltar al contenido

Clasificación Binaria De Velas: Secretos De Las Redes Neuronales Y El Trading

    redes neuronales portada

    El tema de las redes neuronales es un tema que a muchos le parecen muy complejo y enigmático. Por esta razón quiero empezar aquí una serie de entradas en el blog que vayan explicando un poco los entresijos de las redes neuronales comenzando por las más sencillas hasta ir abordando temas más complejos.

    La idea de esta primera clasificación se me ocurrió al terminar el artículo sobre la clasificación de velas. Después de realizar unas pruebas me dio la impresión que no estaba clasificando del todo bien algunas velas, sobre todo las velas Doji. Con esto empecé a darle vueltas a que una red neuronal igual lo podría hacer mejor, así que empecé a hacer algún experimento. Aquí os dejo el resultado como iniciación a las redes neuronales: una red neuronal para la clasificación binaria de velas Doji.

    Conjunto de datos

    Para sacar el conjunto de datos podemos conseguir los datos como ya expliqué anteriormente en otras entradas, como esta, pero cualquier otra forma de conseguir datos históricos es válida. En este ejemplo, he descargado los datos utilizando la librería de yahoo por dar otro enfoque diferente.

    Una vez que tengamos los datos vamos a quedarnos solo con las columnas que más nos interesan para hacer las predicciones de las velas. Estas son: Precio de apertura, precio de cierre, valor más alto del día y el valor más bajo del día. Esto lo podemos hacer así:

    import yfinance as yf
    apple = yf.Ticker("AAPL")
    appl = apple.history(period="max")
    appl = appl.reset_index()
    appl = appl[['Open', 'High', 'Low', 'Close']]

    Como ya tenemos el dataframe con los datos que necesitamos. Ahora vamos a utilizar la librería de Talib (ya cual ya vimos en esta otra entrada) para que nos ponga cuando una vela es Doji o no.

    appl['Doji'] = talib.CDLDOJI(appl['Open'], appl['High'], appl['Low'], appl['Close'])
    appl['Doji'] = np.where(appl['Doji'] == 100, 1, 0)

    La segunda línea puede ser un poco más compleja de entender, pero es como si fuera una función donde si encuentra que la vela es Doji la pone a 1 y sino lo pone a cero. Os podéis preguntar: ¿Por qué hago esto? Es muy simple, haciendo esto tengo una salida binaria, que es 1 o 0. Tener los datos en forma binaria siempre le hará el trabajo más fácil a la red neuronal.

    Separando los datos

    Una vez que ya tenemos los datos vamos a empezar a trabajar con la red neuronal. Para ello lo primero que tenemos que hacer es dividirlos entre los que van a ser datos de entrada a los que van a salir datos de salida.

    X = appl.iloc[:,:4]
    y = appl.iloc[:,4]

    En la variable “X” guardamos los 4 valores de entrada de la red neuronal, y en la variable “y” la salida, es decir si es una vela Doji o no.

    En este punto podríamos dividir los datos entre los datos de prueba y entrenamiento, para valorar si existe un sobre entrenamiento o cual es realmente el comportamiento de nuestra red en la red neuronal. Por ahora dejaremos esto para más adelante por no complicar más la entrada para aquellos que nunca han visto una red neuronal.

    Diseñando la red neuronal

    Ahora vamos a crear una red neuronal muy simple:

    Clasificación binaria de velas doji

    Como vemos tendremos 4 entradas, una capa oculta y una capa de salida con solo una neurona. La primera capa como veis es muy simple, solo son los parámetros de entrada. La capa oculta, son las neuronas donde se va a producir la inteligencia del modelo y que más tarde explicaremos cuantas neuronas van en ella. La capa de salida será la neurona que dará uno si es una vela de tipo Doji y un cero si no lo es.

    Creando la red neuronal

    Veamos como hacemos el código para esto:

    model = Sequential()
    model.add(Dense(3, input_dim=4, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))

    Explico un poco que es lo que he hecho aquí. Inicializamos el modelo como una red de tipo secuencial, es decir, que irá una capa después de otra. La siguiente línea es donde fijamos la primera capa oculta, diciéndole que tiene 3 neuronas y 4 entradas, y que la función de activación es de tipo “relu” (el tema de las funciones de activación también da para mucho y será abordado más adelante). Y por último, la última capa donde solo tiene una neurona de salida y le ponemos la función de activación sigmoidal, que nos devolverá un la salida binaria.

    El asunto de cuantas neuronas son necesarias en las capas ocultas da para mucho debate por la comunidad científica. Pero resumiendo mucho se dice que existen tres reglas (un poco tontas) para tomar esta decisión al comenzar una red neuronal:

    1. El número de neuronas deberá estar entre el tamaño de la capa de entrad y el tamaño de la capa de salida.
    2. El número de neuronas deberá ser 2/3 del tamaño de la capa de entrada más el tamaño de la capa de salida.
    3. El número de neuronas debe ser inferior al doble del tamaño de la capa de entrada.

    Con estas tres reglas ya tenemos una buena base para poner un número de neuronas. Y siguiendo estas reglas he puesto 3 neuronas, lo cual cumple todas las reglas.

    Compilando el modelo

    La compilación del modelo se usa el método “compile”:

    # Compilar el modelo keras
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

    Los argumentos que le pasamos son los siguientes:

    • loss=’binary_crossentropy’: Aquí definimos la función de perdida que usaremos. Este valor mide la diferencia entre los valores reales y las predicciones que estamos generando. Aquí utilizaremos “binary_crossentropy” al tratarse de un modelo que devuelve una salida binaria.
    • optimizer=’adam’: En este artículo se demostró que el optimizador Adam es el que mejor funciona en este tipo de problemas
    • metrics=[‘accuracy’]: La medida que usaremos para conocer la precisión que tiene nuestro modelo.

    Entrenando el modelo

    Se utiliza la función “fit” del modelo:

    model.fit(X, y, epochs=10, batch_size=8)

    Le pasamos los siguientes argumentos:

    • X: Entrada de datos. Los valores de: open, high, low y close.
    • y: Salida de datos. En este caso cuando una vela es Doji y cuando no.
    • epochs=10: Número de veces que entrenará el modelo intentando ajustarse a los resultados. Este número también se debe de ajustar para no producir sobre entrenamientos en el modelo.
    • batch_size=8: Este es el número de ejemplos que se introducen en la red para que entrene de cada vez. También hay mucha discusión aquí de cual es el número correcto. Los números más comunes suelen ser 16 o 32, como se ve en este estudio, pero yo en este caso he obtenido mejores resultados con 8.

    Cuando lo ejecutamos veremos como va ejecutando el entrenamiento en las diferentes épocas.

    Entrenamiento del modelo

    Evaluando las predicciones del modelo

    Para saber cual es la mejor precisión que ha encontrado el modelo utilizaremos las siguientes líneas de código:

    _, accuracy = model.evaluate(X, y)
    print('Accuracy: %.2f' % (accuracy*100))

    Donde la salida, en este caso nos mostrará la mejor precisión lograda por el modelo:

    precision

    ¡¡¡Hemos tenido una precisión de un 83%!!!, lo cual no está nada mal para un modelo tan simple como el que hemos tenido.

    Como no hemos separado los datos entre conjunto de entrenamiento y de pruebas veremos como hace las predicciones sobre los mismos datos con los que ha entrenado, y así podremos ver también donde ha fallado.

    predictions = (model.predict(X) > 0.5).astype("int32")

    Ahora ya tenemos las predicciones en la variable “predictions“. Si queremos saber donde hemos fallado lo podemos hacer con estas líneas:

    for i in range(len(appl)):
        if(appl.iloc[i]['Doji'] != predictions[i]):
            print("Error en la vela: %d:\n %s\n" % (i, appl.iloc[i]))

    Conclusiones

    Este era un modelo muy simple para entrar un poco a entender como funcionan las redes neuronales y como pueden ayudarnos en el trading. Hay mucho margen de mejora en este modelo, como añadir más datos para enriquecer los datos de entrada o dividir los datos entre entrenamientos y validación.

    Recomiendo que, si hacéis las pruebas por vuestra cuenta, probéis diferentes valores en cada uno de los puntos en los que tenéis dudas. De esta forma entenderéis para que sirven realmente y así veréis como van cambiando los valores en las salidas.

    Como he dicho al principio esto es un acercamiento al machine learning y el trading, aun queda muchos temas que tratar. El futuro haré redes más complejas y como nos ayudarán a crear nuestros robots de trading algorítmico.

    Espero que os haya gustado esta nueva serie de entradas que empiezan aquí y, como siempre, cualquier duda o mejora del artículo no dudéis en poneros en contacto conmigo y os contestaré lo antes posible.

    Oval@3x 2

    ¡No te pierdas ningún post!

    ¡No enviamos spam! Lee nuestra política de privacidad para más información.

    Deja una respuesta

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