Saltar al contenido
Mejora y potencia tu  trading algorítmico

Mejora y potencia tu
trading algorítmico

Conoce todos los recursos y aprende todo lo necesario para llevar tu trading
al siguiente nivel.

¡Accede a la masterclass gratuita ahora!

¡Accede ya!

Ultimas entradas
Como ya hace casi un año, vuelvo a lanzar el curso de trading algorítmico para aquellos que quieran dar un paso más allá en la programación de sus propios robots de trading. La idea del curso es hacer que podáis tener todos los conocimientos necesarios para la creación de cualquier estrategia que se os ocurra, y además contar con compañeros y conmigo mismo para seguir adelante en este mundo y que no os pare un simple error de código o un fallo de programación. Aquí os dejo el enlace al curso para que le podáis echar un ojo y apuntaros: https://cursos.garcia-ferreira.es/p/curso-completo-de-trading-algoritmico Aunque en el enlace tenéis toda la información os voy detallar un poco como será el curso. Plan de Estudios El curso está diseñado para llevarte de la mano desde los fundamentos hasta las técnicas más avanzadas de forma sencilla y una progresión de nivel muy suave para que no te quedes atascado en ningún momento. Introducción al curso Comenzamos con una Presentación dinámica que te sumerge de lleno en lo que el trading algorítmico puede ofrecerte. Te daré una lista de recursos necesarios para asegurar que estás perfectamente equipado para el viaje. Además de integrarte en la comunidad: accederás a grupos exclusivos de Discord y Telegram, y tendrás la oportunidad de participar en directos semanales de preguntas y respuestas. Crea tu Entorno de Trading Algorítmico En esta sección te guiaré a través de la configuración de tu estación de trabajo con herramientas como Jupyter Notebook, Google Colab, Anaconda, Spyder, y Visual Studio. Además, aprenderás a utilizar Git y GitHub para gestionar tus proyectos de código. Manejo de Datos y Obtención de Datos de Mercado Dominarás el arte de manejar datos con Pandas y NumPy, y aprenderás a cargar y guardar datos utilizando formatos como CSV, Excel, JSON, y Feather. Además, te enseñaremos cómo obtener datos de mercado en tiempo real de fuentes como Darwinex, Alpaca, Yahoo Finance, Financial Modelling Prep y otras fuentes de datos que resulten interesantes para vuestro trading. Visualización y Análisis Visualizarás datos de mercado con herramientas como Matplotlib, MplFinance, Plotly, y Dash, y explorarás librerías de análisis técnico como Ta-Lib, Finta, Pandas-TA, y sabrás como poder hacer Fibonacci para utilizarlo en tu robot algorítmico. Backtesting de Estrategias y Robots en Tiempo Real Aprenderás a probar tus estrategias de trading con Backtrader, backtesting.py, y vectorbt antes de llevarlas a la práctica. Y cuando estés listo, te sumergirás en el mundo de los robots de trading en tiempo real, utilizando APIs y librerías especializadas. Integración con Tecnologías Avanzadas Incorporo ChatGPT y otras herramientas como BlackBox, analizador de sentimientos, y simulaciones de Montecarlo para añadir una capa extra de inteligencia a tus estrategias. Puesta en Producción Finalmente, te guiaremos a través de la puesta en producción de tus estrategias de trading, enseñándote sobre infraestructuras propias y el uso de VPS para operar 24/7. Más que un curso, un acompañamiento Al inscribirte, no solo estarás accediendo a un plan de estudios exhaustivo y actualizado; sino que contarás todas las semanas con unas clases en vivo donde se analizará cualquier problema que te pueda suceder en tu programación, o se discutirán como utilizar el temario que toque esa semana para mejorar tu trading. No solo cuentas con esa ayuda puntual, en cualquier momento puedes comentar tus dudas por telegram o discord, ya sea en los grupos públicos como en los privados. En ambos casos tendrás una rápida respuesta para que puedas continuar con la programación de tu robot sin problemas. ¿Listo Para Transformar Tu Trading? Si estás pensando en pasar esa estrategia que no acaba de funcionar del todo bien a un robot para que no influya tu estado de ánimo o para hacer miles de backtest hasta encontrar una estrategia ganadora este es tu curso. Empieza el próximo lunes 1 de Abril de 2024 con la apertura de las primeras clases, así que apuntaros para coger las clases desde el principio. Como digo siempre, cualquier pregunta o duda podéis contactar conmigo y os responderé lo antes posible. También recordaros que hay una sección de preguntas frecuentes en el curso donde seguro que también podéis resolver alguna duda. Espero que os animéis y os vea la próxima semana en el curso. [...] Leer más...
La conexión con Interactive Brokers usando Python siempre ha sido un tema bastante complejo. La forma de conectarse a ellos desde Python no es lo fácil que es con otros brokers, y también requiere software corriendo en nuestras máquinas. Además, programar utilizando la librería que nos ofrece el acceso fácil a esta plataforma tampoco es sencilla, ya que se tiene que realizar a través de un wrapper. Esta forma de conexión para algunos programadores es compleja de entender y mucho más de manejar. En este artículo espero dejar claro cómo hacer la conexión con este bróker y cómo descargar datos históricos (poner órdenes y demás ya lo dejo para otros artículos). Así que espero que a partir de ahora le perdáis un poco el miedo a este bróker, que nos ofrece mucha información (la descarga de datos es solo raspar la superficie de todo lo que nos puede dar). Vamos a lio. Crear cuenta demo en IB Lógicamente, lo primero es tener una cuenta creada con IB, no vamos a ningún lado sin ello. No voy a entrar en todo el detalle de como crear una cuenta en Interactive Brokers, ya que hay mucha información sobre ello (como por ejemplo este vídeo de wowate). Solo voy a poner como, ya teniendo una cuenta, os podéis crear una cuenta demo (o simulada como ellos dicen) para la descarga de los datos. Una vez que abrimos nuestra cuenta normal de IB tendremos que ir a ajustes, dando sobre el icono de nuestro usuario, tal y como vemos en la imagen: Una vez dentro de los ajustes hay una sección con el nombre de “Cuenta de negociación simulada” sobre el cual deberemos de pulsar para crear la cuenta demo que tanto deseamos. Aquí deberemos rellenar los datos que nos piden para crear esta cuenta. En este caso es simplemente es un nombre de usuario y contraseña para la cuenta: Una vez que la hemos creado, ya podemos entrar con nuestra cuenta demo y ver algo similar a esta pantalla: Como ves de principio no sale una aviso de que que el estado de la solicitud está en curso, con lo cual todavía no lo podemos utilizar. La aceptación de la solicitud suele tardar un máximo de un día, así que ahora toca tener paciencia y esperar al día siguiente para poder entrar en nuestra cuenta y que nos muestre los datos como si fuera una cuenta real. IB Gateway El segundo paso es descargar desde la propia página el software necesario de IB para poder conectar. En este caso usaremos IB Gateway, es un programilla que se quedará en nuestro ordenador funcionando sin molestar y sin casi consumir recursos (lo cual es genial para poner el futuro robot en una nube). Así que iremos a esta web y nos lo descargaremos desde aquí. Un vez descargado lo ejecutamos y veremos como los pasos muy simples: Solo hay que configurar la ruta en la que queremos que se instale, después ya se puede ejecutar sin problemas como si fuera un programa normal. Configuración de IB Gateway Una vez instalado, cuando lo ejecutemos nos encontraremos con esta pantalla: Tenemos que fijarnos en que esté marcado IB API y negociación simulada, para meter los datos de nuestra cuenta demo. Una vez abierta la sesión ya nos informan que es una cuenta demo: Vale, parece que ya está todo abierto y funcionando, así ahora vamos a configurar tres cosas para que podamos conectarnos sin problemas desde Python. Para acceder a al configuración hay que ir en el menú a “Configuración” y luego otra vez al submenú “Configuración”, y acto seguido veremos una pantalla como esta: Las opciones que hay que tocar son: API de solo lectura: Normalmente está marcado y hay que dejarlo sin la marca, ya que sino no nos permitirá hacer operaciones (ya nos sirve para el futuro). Socket Port: El puerto es importante para saber nosotros hacia donde tenemos que conectar. Lógicamente podemos cambiarlo, pero hay que tenerlo en cuenta para cuando hagamos la conexión y poner el mismo puerto que hemos configurado. Permitir conexiones solo de localhost: Es importante para la seguridad del entorno y que no se pueda conectar alguien externo. Instalando la librería Ibapi La librería para implementar la conexión con Python se llama Ibapi. Es una librería muy completa que nos permite hacer todo lo que nos muestra IB en su web. Si quereis profundizar más sobre esta librería podéis encontrar la información técnica sobre ella en su web. La manera fácil de instalar la librería es así: pip install ibapi Aunque como os he comentado, la información sobre la librería está muy bien, la mayor fuente de conocimiento sobre qué es cada llamada a cada función está en la web de IB, donde se explica cada punto de la conexión y además viene para varios lenguajes de programación. Lógicamente para ver la documentación para nuestros propósitos hay que poner Python en el menú: Desde ahí podéis ya ver las múltiples opciones que nos da la API de Interactive Brokers usando Python, que es realmente potente. Os recomiendo que gastéis unos minutos observando todo lo que se puede hacer con ella. Las clases de Ibapi La forma de trabajar con la librería ibapi es poco común ya que se hace creando un wrapper de la clase EWrapper. Es decir, tenemos que crear una clase que a su vez herede todo lo de esta clase. Lo se, suena un poco lio, así que creo que es mejor verlo con el ejemplo. Lo primero es que vamos a importar las librerías que vamos a necesitar para la descarga de datos históricos: from ibapi.client import EClient from ibapi.wrapper import EWrapper from ibapi.contract import Contract import pandas as pd Como veis hemos importado 3 librerías: EClient: Esta es la clase con la que se hace la conexión con el IB Gateway, así que puede ser la más importante. La documentación la tenéis aquí. EWrapper: Esta es la clase que realiza la comunicación, y todos los eventos que se generan por el IB Gateway son recogidos por esta clase. Si queréis más información sobre lo mucho que se puede hacer, lo tenéis aquí. Contract: La clase en la que se definen los contratos. La documentación la podéis consultar aquí. Como veis con estas tres librerías tenemos lo imprescindible para hacer una conexión, definir el contrato que queremos y esperar todas las respuestas del IB Gateway. Ahora que ya lo tenemos listo todo, vamos a implementar la forma más sencilla de conexión y de descargar los datos (Para complicarnos ya tenemos tiempo más adelante). Entendiendo el wrapper Para hacer la descarga de los datos necesitamos una clase que tenga las siguientes funciones: nextValidId: La función donde se comienza las peticiones de cualquier comando que se pasa a IB Gateway. historicalData: En esta función llega cada nueva vela y si queremos hacer algún cálculo o añadir información sobre cada vela deberemos de hacerlo en esta función. historicalDataEnd: Una vez que finaliza la descarga de datos se llama a esta función así que aquí es donde debemos de hacer las operaciones finales sobre los datos. Error: Creo que no es el mejor método para llamar a esto porque aquí es donde vienen todos los mensajes ya sean de error o no, así que importante tenerlo en cuenta para ver lo que pasa en todo momento que intentamos conectar al IB Gateway. Además de esto tenemos que crear un tipo de dato “Contrato” para definir los datos que queremos y además hay que llamar a la clase “reqHistoricalData” para hacer la llamada al IB Gateway y así descarga ya los datos desde Interactive Brokers usando Python. Vamos a ver como hacemos la clase con todo esto. Creando el wrapper Vamos a poner el código del wrapper y lo vamos comentando: class MyWrapper(EWrapper): def __init__(self): self.datos_list = [] self.datos = None def nextValidId(self, orderId:int): print("Comienza la petición con Id:", orderId) self.start() def historicalData(self, reqId, bar): # Por cada linea vamos sacando las variables y # añadiéndola a la lista self.datos_list.append(vars(bar)); def historicalDataEnd(self, reqId: int, start: str, end: str): # Al finalizar ponemos los datos en formato dataframe, # la fecha en formato datetime y la ponemos como indice print("Final. ReqId:", reqId, "(", start, "/", end,")") self.datos = pd.DataFrame(self.datos_list) self.datos = pd.to_datetime(self.datos) self.datos.set_index('date', inplace=True) app.disconnect() def error(self, reqId, errorCode, errorString): # Mostramos los mensajes que devuelve el IB Gateway print(errorString," (Id:", reqId, " Code:", errorCode,")") def start(self): # Creamos en contrato contrato = Contract() contrato.symbol = "SPY" contrato.secType = "STK" contrato.currency = "USD" contrato.exchange = "ARCA" # Hacemos la petición de los datos app.reqHistoricalData(1, contrato, "", "1 D", "1 min", "MIDPOINT", 0, 1, False, []) Creo que las funciones que ya hemos explicado antes se explican por si solas así que voy a comentar la función start, que es la donde se define el contrato y se hace la petición. Como se puede ver lo primero que se hace es la instanciación de la clase contrato, en este caso hemos descargado los datos del SP500, pero se pueden descargar los datos de muchos tipos de contrato diferentes: Forex, Criptos, Stocks, Indices, CFDs, Futuros, Opciones, Bonos, Warrants, etc. Entrar aquí para ver como configurar cada una de ellas, como poner las diferentes opciones y así no tenéis que liaros mucho más. Sobre la forma de descargar los datos con reqHistoricalData también tenéis toda la información en la web. Pero resumiendo mucho los campos que hay que pasarle son los siguientes: tickerId: Un identificador para identificar las operaciones. contract, El contrato que se ha definido. endDateTime: La fecha y hora de la solicitud (si está vacio toma el momento de la petición). durationString, La cantidad de tiempo para volver atrás y empezar a descargar los datos. barSizeSetting, El tamaño de la barra. whatToShow, El tipo de datos para recibir. useRTH, 1 recibe los datos solos dentro de las horas regulares de trading, 0 recibe todos los datos. formatDate, Formato de la fech keepUpToDate, True para suscribirse a las actualizaciones cuando estén disponibles (que habría que controlar con la función historicalDataUpdate), False para recibir solo los datos que has solicitado. Recibiendo los datos Para recibir los datos, lógicamente, tenemos que realizar la conexión y, una vez conectado, recoger los resultados obtenidos. No es muy complicado ya que solo hay que instanciar nuestra clase pasársela al cliente, y hacer la conexión: wrap = MyWrapper() app = EClient(wrap) app.connect("127.0.0.1", 4002, clientId=999) app.run() Una vez lanzado esto veremos que nos devuelve algo así: Como veis aunque la clase de los mensajes se llama “error” está claro que los mensajes que nos devuelve son de conexiones exitosas, por eso es importante también que veamos estos mensajes para ver que todo va correctamente. Una vez que finalice esta celda (doy por sentado que lo estamos haciendo desde una celda de jupyter), podemos ver directamente los datos que hemos descargado así: print(wrap.datos) Y ya veremos que los datos que hemos descargado: Si queremos guardar los datos en un csv es tan sencillo como: wrap.datos.to_csv("SP500.csv") Y para ver lo datos que hemos descargado de manera simple lo podemos hacer así: %matplotlib inline wrap.datos.close.plot() Y veremos el gráfico de salida correspondiente a los precios de cierre (aquí, como siempre, ya os podéis complicar la vida para que os muestre velas o lo que queráis usando otras librerías): Conclusiones La descarga de los datos desde Interactive Brokers usando Python no es tan sencilla como desde otros brokers que tienen una API más directa y que hace esta tarea mucho más sencilla. Aun así hemos visto como instalando el IB Gateway y la librería Ibapi se puede lograr la descarga de datos históricos con unas pocas líneas de código. Aunque el tema de hacer la programación a través de un wrapper no es tan intuitiva como puede ser hacerlo con otros métodos, es verdad que la documentación que ofrece Interactive Brokers en su web es muy completa y se puede seguir con bastante facilidad. Gracias a este nivel de detalle en la documentación han conseguido que te puedas poner a programar tu propio wrapper en poco tiempo. Si miráis la documentación veréis que hay mucha más chicha que rascar para descargar los datos así que si estáis interesados tenéis mucho donde mirar. Como 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. [...] Leer más...
Muchos me habéis pedido si era posible sacar el creek de Wyckoff programando, así que ya tocaba hacer un artículo explicando como hacerlo y, lógicamente, que funcione para cualquier valor con el que estemos trabajando. He conocido varias personas que hacen trading utilizando Wyckoff con muy buenos resultados. Uno de ellos es Rubén Villarmosa que tiene varios libros sobre Wyckoff y un canal de Youtube sobre el tema que no os podéis perder; y otro es Ferran Font que lo usa mucho en sus cursos y que tiene un magnífico video explicando qué es el creek de y como usarlo. He de decir que para calcular el creek nos vamos a basar un poco en conceptos matemáticos pero estar tranquilos, son muy simples, de los que dan los niños en el colegio, así que no preocuparse. No me entretengo más, vamos al lio. ¿Qué es el creek de Wyckoff? El creek es una formación de velas que se observa en los gráficos de precios de las acciones. Richard Wyckoff le puso este nombre, creek, que significa arroyo o rio en inglés, debido a que su formación se asemeja a los meandros que hace un rio. He encontrado un gráfico en PCBolsa en el que se ve muy bien qué es el creek y el momento de la rotura, que es donde entraríamos: Al final son roturas de canales, con suficientemente volumen para entender que va a haber un cambio de tendencia. No voy a entrar a explicar en detalle como se hace trading con esta técnica ya que, como os dije, hay grandes expertos en este tema que lo explican mucho mejor que yo. Así que si no tenéis claro como funciona os recomiendo los enlaces que he puesto en la introducción. Para hacer trading con el creek lo primero es identificar cual es el creek lo que parece difícil hacerlo mediante programación, pero es vital si queremos crear un robot que lo haga, así que vamos a ver como nos apañamos no solo para dibujarlo sino para tener una forma de usarlo en el trading algorítmico. Librerías y descarga de datos Vamos a empezar como siempre, con las librerías que necesitaremos para hacer nuestro código, y también descargando los datos necesarios para poder hacer nuestros cálculos con las gráficas. Las librerías que vamos a necesitar son estas: import yfinance as yf import matplotlib.pyplot as plt import numpy as np import scipy.signal La que más nos puede llamar la atención de todas ellas es “scipy.signal” que es la que utilizaremos para determinar cuando hay un pico significativo, pero eso lo veremos más adelante. Para descargar los datos utilizamos yfinance, así que lo vamos a hacer así: TICKER = "AAPL" ticker_values = yf.Ticker(TICKER) data = ticker_values.history(period="3mo") Vamos a usar nuestro querido Apple para hacer las pruebas, así que nos descargamos los datos diarios de tres meses, que considero el margen necesario para determinar un creek (podéis probar con más o menos datos, pero yo en gráfico diario me parece el más acertado). Ahora vamos a quedarnos con las columnas necesarias para este ejercicio: # Quitamos las fechas para hacerlo más fácil data = data.reset_index() data = data] Hacemos un reset del index, ya que en este caso no me interesa para nada la fecha, pero si tener un índice con una numeración seguida (también entenderemos el por qué más adelante), así que hacemos el reset del index y quedan ya los datos como los necesito. Por otro lado, aunque podía coger la información del volumen para determinar si la rotura del creek es consistente, ahora me voy a centrar solo en conseguir determinar si un precio puede romper el creek o no, así que me quedo solo con el precio de cierre. Vamos a dibujar la gráfica así tenemos claro que es lo que tenemos: plt.plot(data) plt.title(TICKER) plt.xlabel('Unidades de tiempo') plt.ylabel('Precio') plt.show() Y nos devuelve esto: Perfecto, ya tenemos los datos que necesitamos así que ahora vamos a intentar sacar cual sería el creek, empezaremos por el canal alcista. Buscamos los picos Aquí es donde utilizamos la librería de Scipy que hemos importado al principio. picos, picos_dict = scipy.signal.find_peaks(data, width=1) print(f"Picos: {(picos)}") Como veis usamos la función “find_peaks” al que le pasamos nuestros precios de cierre y al que también le pasamos como argumento “width=1” para decirle que queremos una secuencia de un array. El resultado sería así: Además como podéis ver, también nos devuelve otra variable con unos valores en un diccionario: De todos los valores que vemos en el diccionario el que nos interesa a nosotros es el de “prominences” que nos devuelve cuanto destaca un pico de la linea base que tiene alrededor, y se mide como la distancia vertical que tiene entre su pico el valor más bajo. Sabiendo esto vamos a coger los dos valores más prominentes para poder trazar una recta: indice_pico1 = picos indice_pico2 = picos] Y aquí ya tendremos la posición de los dos picos dentro del array de picos prominentes (que en este caso son las posiciones 18 y 45). Así que ya tendremos dos puntos que es lo que siempre necesitamos para trazar una recta. Ecuación de la recta Ahora vamos un poco con las matemáticas y a refrescar como se hacía una recta de forma matemática. Esto es lo que nos va a servir a nosotros para poder dibujar una recta y luego conseguir cualquier valor a través de esa ecuación. La ecuación de la recta se representa comúnmente como: \begin{equation} y = mx +b \end{equation} Para entenderlo mejora ya sabemos que tanto la $x$ como la $y$ son las coordenadas en las cuales estará siempre definida la recta. La $m$ es la pendiente de la recta y $b$ es el punto donde la recta corta con el eje $y$. Si por ejemplo tenemos esta recta: La ecuación de la recta sería muy sencilla ya que tenemos dos puntos cuando la x es cero, que la y es uno (0,1), y cuando la y es cero que la x es 2. Lo primero sería calcular la pendiente que se calcula con esta fórmula: \begin{equation} m = \frac{y_2-y_1}{x_2-x_1} \end{equation} Así que sustituyendo valores con los puntos que tenemos A(0,1) y B(2,0) sería así: \begin{equation} m = \frac{0-1}{2-0} = \frac{-1}{2} = -0.5 \end{equation} Y ahora sustituyendo, por ejemplo la A, en la fórmula que ya conocemos podemos calcular la b: \begin{equation} y = mx +b \\ 1 = -0.5 \cdot 0+b \\ b=1 \end{equation} Con lo cual la ecuación de esta recta sería: \begin{equation} y = -0,5x + 1 \end{equation} Con esto ya podemos saber cualquier punto de la recta en cualquier momento. Es decir (y por hacer un cálculo redondo), si queremos saber que valor tomará y en el punto x -2 solo tendremos que sustituir. \begin{equation} y = -0,5\cdot(-2) + 1 \\ y = 2 \end{equation} Supongo que ahora ya entendéis también por qué he prescindido de las fechas y he colocado números, es mucho más facil de seguir para un eje de coordenadas y para el cálculo de la recta. Pues bien siguiendo esa lógica vamos a trazar nuestras propias rectas en nuestro gráfico. Implementación para la línea de tendencia superior Vamos a crear una función que pasándole los dos puntos nos devuelva la m y la b para calcular la recta: def encontrar_linea_entre_puntos(punto1, punto2): x1, y1 = punto1 x2, y2 = punto2 if x2 - x1 != 0: # calculamos la m m = (y2 - y1) / (x2 - x1) # calculamos la b b = y1 - m * x1 return m, b else: # Error return None Perfecto, ahora vamos a transformar los dos puntos en tuplas y se los pasamos a la función: # Define los dos puntos como tuplas (x, y) punto1 = (indice_pico1, data.iloc) punto2 = (indice_pico2, data.iloc) # Encuentra la línea entre los dos puntos linea = encontrar_linea_entre_puntos(punto1, punto2) m, b = linea print(f"La ecuación de la línea es: y = {m}x + {b}") Si ejecutamos esto vemos que nos devolverá la ecuación de la recta, que es lo que estamos buscando: Y ahora vamos a dibujarla para ver que realmente lo está haciendo bien: x_values = , data.index] y_values = plt.plot(x_values, y_values, label=f'Línea entre puntos', color='red') plt.plot(data) plt.title(TICKER + " linea de tendencia superior") plt.xlabel('Unidades de tiempo') plt.ylabel('Precio') plt.legend() plt.show() Y la gráfica que nos muestra es esta: Parece que lo ha hecho perfecto, así que vamos a ver ahora como lo haríamos para capturar la inferior. Implementación para la línea de tendencia inferior El código sería el mismo exactamente, solo cambia que a la hora de conseguir los valles en vez de los picos se pasan los datos negados: valles, valles_dict = scipy.signal.find_peaks(-data, width=1) print('Valles: %s' % (valles)) El resto del código no lo pongo porque básicamente es idéntico no hace falta, solo copia y pega y conseguirás sacar esta gráfica: Rotura del creek Una vez que ya hemos calculado la recta con los datos que teníamos, ahora tenemos que ir comprobando en cada nuevo tick que nos llegue si el nuevo valor esta por debajo del valor que nos da la y de la ecuación de la recta. Haciéndolo con los datos históricos sería así: rotura = 0 for x in range(punto1, data.index): if data.iloc > (m*x+b) and rotura == 0: print(f"Rotura del creek en {x} con valor {data.iloc}") x_rotura = x y_rotura = data.iloc rotura=1 He puesto alguna línea más para dibujarlo bien, pero ya os podéis hacer a la idea de como se haría en tiempo real. Si lo graficamos se vería así: En la gráfica vemos donde sería el primer punto donde se detecta que se ha roto el creek, y en el cual sería posible entrar en una estrategia con esta temporalidad (podríamos bajar la temporalidad para hilar más fino y entrar más rápido). Más pruebas Para probar que funciona bien, lo lógico es hacer más pruebas con más valores a ver si funciona correctamente en todos los casos. Así que he probado con unas cuantas acciones famosas en las que se pudiera ver una rotura del creek y parece que funciona correctamente: AMD UBER Microsoft Conclusión Como podéis ver con unos conceptos matemáticos muy simples hemos sido capaces de encontrar como ver la línea de tendencia y saber cuando el precio rompe el creek. Recordar que no solo hay que mirar la rotura del creek sino también el volumen, e incluso hay gente que prefiere usar más indicadores para confirmar. Como habéis visto he hecho las pruebas con varios valores para ver que graficaba correctamente y parece que siempre detecta correctamente las líneas de tendencia y cuando rompe el creek, pero si encontráis algún valor que este funcionando mal me lo comentáis y corrijo el código. Como 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. [...] Leer más...
Hace unos días he iniciado una colaboración con el blog de trading Quantdemy junto con los compañeros de Komalogic. Para ello, he escrito un articulo sobre diferentes formas de calcular la volatilidad de un activo con Python, algo que seguro que os resulta muy interesante. A partir de ahora, además de los post que seguiré poniendo en este blog, crearé también contenido para Quantdemy, así que estar atentos también. En Quantdemy se tocan muchos más temas que los que toco yo en este blog, lo cual es muy interesante para todo aquél que le guste el trading algorítmico. Así que animaros a seguirlo. También pondré estas entradas en el canal de Discord así que si estáis dentro de la comunidad os iréis enterando de todas las novedades que vayan saliendo. No me lio más, aquí tenéis el articulo: https://quantdemy.com/7-maneras-de-calcular-la-volatilidad/ Como siempre si tenéis alguna pregunta no dudéis en poneros en contacto conmigo y lo vamos hablando. [...] Leer más...
Hay veces que hay que salir un poco de lo común para encontrar técnicas o estrategias que pueden llegar a vencer al mercado. Una de las formas de romper con las formas tradicionales de ver el mercado puede ser cambiando la forma en la que unimos la información al visualizar el mercado. Normalmente vemos las velas japonesas y poco más, ya que las plataformas como metatrader o tradingview no nos lo ofrecen. Hay veces que cambiamos la forma de visualizar estas velas pasando a velas Renco o similiares. ¿Pero hay otras formas de ver el mercado siguiendo con las velas japonesas a las que ya estamos tan acostumbrados. La respuesta es sí, existen otras formas de poder ver el mercado y de poder buscar inconsistencias en ellas o de buscar patrones distintos a los que ya estamos acostumbrados a ver. En este articulo vamos a repasar un poco las distintas formas de visualizar la información que nos da el broker. Así que no me lio más y vamos a ello. Descargando la información Lo primero es que vamos a descargar la información en modo tick para con este modo poder empezar a jugar los diferentes modos de visualización del mercado. Para ello utilizaremos Darwinex que nos da una información a nivel de tick y no de velas que es lo que necesitamos para poder hacer nuestro estudio. No me voy a parar a explicar como hacer esto ya que existe ya una entrada en el blog para hacerlo. Así que directamente tendré los datos de los ticks almacenados en un directorio llamado “darwinex ticks” y los leemos así: # Variables directorio_datos = "darwinex ticks" onlyfiles = Con esto ya tendremos los datos en la variable onlyfiles, y ahora para descomprimirla hacemos lo siguiente: appended_data = [] for stock_file in onlyfiles: with open(directorio_datos+"/"+stock_file, 'rb') as fd: gzip_fd = gzip.GzipFile(fileobj=fd) appended_data.append(pd.read_csv(gzip_fd,names=)) df_stock = pd.concat(appended_data) df_stock = pd.to_datetime(df_stock,unit='ms') df_stock = df_stock.set_index('Date') También generaremos una función para que nos sea más fácil ver las gráficas utilizando la librería plotly: def dibujar_grafica(data_stock, titulo): fig = go.Figure(data= , high = data_stock, low = data_stock, close = data_stock)] ) fig.update_layout( height=500, title=titulo, yaxis_title="Precio ($)" ) fig.update_layout(xaxis_rangeslider_visible=False) fig.show() Con esto ya estamos preparados para hacer el estudio de las nuevas gráficas. Velas típicas En esta parte poco voy a entrar muy a fondo, son las típicas barras que hemos visto toda la vida desde que nos ha gustado el trading. Todos ya sabemos como son y como se ven. En la barra de abajo es donde se ven las temporalidades, en este caso son temporalidades de 5 minutos, las velas muestran la variación del precio dentro de esos 5 minutos. Creo que este es un concepto que ya tenemos todos claro así que no me voy a parar aquí. Velas de tick Las barras de también son muy fáciles de explicar y ya cambia bastante la forma de ver el mercado. Si ponemos unas barras de volumen de 100 ticks, pues las barra esperará a completar 100 ticks para poder mostrar la vela. Sería igual que en las barras de tiempo que esperamos 60 segundos para completar una barra de minuto, pues aquí esperaríamos 100 ticks (o los que quisiéramos) para completar una barra de tick. Lo primero que tenemos que hacer es crear una función para que no nos queden barras sueltas, es decir si tenemos 1000 ticks y queremos barras de 11 ticks (sí hay que ser retorcido), pues para que no quede mal calcularemos el total de barras que podremos analizar (que en el ejemplo serían de 990) def barras(total, deseado): return np.int64(total/ deseado) * deseado Con esto ya podemos hacer la agrupación de manera muy sencilla: df_ticks = df_stock.groupby(barras(np.arange(len(df_stock)), 10)).agg({'Price': 'ohlc', 'Size': 'sum'}) Y dibujar la gráfica así: Velas de volumen Estas barras son similares a las barras de ticks, pero aquí lo que contabilizamos es el total de volumen que queremos por barra, es decir, si decimos que haga barras de 100.000 de volumen, veremos que las barras se completan. Para crear las barras lo que hay que hacer antes es descomponer los volumenes de cada tick en un volumen, para tener operaciones de volumen 1 y así calcular bien. Sino podría darse el caso de que al tener en una sola compra la venta de varias unidades veamos gráficas que serían correctas. Es decir si miramos los ticks de las operaciones podremos ver lo siguiente: Como vemos hay tamaños de operación muy grandes y que si no lo separamos tendríamos diferentes volúmenes en cada vela. Así que por ejemplo en el primer ejemplo tendríamos que separar ese tick de 159.29, en 95 operaciones de ese tipo. Para hacer eso creamos una función que nos lo haga de la siguiente manera: def multiply(data): df = pd.DataFrame(columns=) for tick in data.itertuples(): for i in range(int(tick)): s = pd.DataFrame({'Date': tick, "Price":tick, 'Size':1}, index=) df = pd.concat(, ignore_index=True) return df Después ya solo nos queda pasar el dataframe por esta función para que nos separe cada operación Velas de dólar Muy similares también a las demás. Estas barras se producen cuando se gastan una cantidad de dólares, es decir si hacemos barras de 100 dólares tendremos que comprobar el volumen y el precio para ver cuando se llega a comprar la cantidad total de 100 dólares y en ese momento completaremos una barra. df_dolar = df_stock.groupby(bar(np.cumsum(df_stock), 1000)).agg({'Price': 'ohlc', 'Size': 'sum'}) dibujar_grafica(df_dolar.head(100), "Grafica de Dolar") Normalmente se suele hacer con dólares, ya que los precios suelen venir en gráficas con los precios de esta unidad monetaria, pero lógicamente podríamos hacer velas de Euro, Yen, o lo que quisiéramos haciendo la transformación que corresponda. Ver el mercado en conjunto Veamos las diferencias que supone sobre un mismo periodo de tiempo la vista en los distintos formatos: Como se puede ver si ajustamos lo suficiente las gráficas son muy parecidas, pero en algunos casos podemos ver más limpias las subidas y las bajadas de los precios sin tantos vaivenes. Igual os podéis estar preguntando si estas gráficas sirven para algo ya que se ven muy parecidas, pues os voy a dejar un ejemplo de un caso de volumen donde se ve claramente una operación de venta al mismo precio con mucho volumen: Estas anomalías que se pueden ver en un gráfico de volumen no sería posible visualizarlas en ninguno de los otros gráficos. Así que como veis es importante tener al menos conocimiento de estos gráficos para intentar buscar oportunidades en los valores en los cuales estamos trabajando. Viendo estas gráficas creo que todos deberíamos, al menos, probar si estos nuevos tipos de gráfica nos sirven más que los clásicos. Así que ¿a qué estáis esperando? Ya podéis empezar a hacer vuestros propios estudios con estos nuevos gráficos. Conclusiones Como se puede observar en este artículo hay más de una forma de ver el mercado, es decir, la información de las operaciones que se realizan en la bolsa, aunque los visualizadores habituales siempre nos muestran las mismas gráficos o, en aquellos que nos dejan algo más de libertad, solo se pueden hacer muy pocos cambios. Ahora con estas nuevas formas de visualización podemos abordar otras formas de poder llegar a ser rentables, ya que podemos hacer los mismos análisis técnicos que hacíamos con las gráficas de tiempo en este nuevo tipo de gráficas y obtendremos resultados muy diferentes (quizá hasta más rentables, quién sabe). Ahora os podéis estar preguntando: ¿Hay más formas de ver los datos de la bolsa? ¿Hay más formas de poder ver los datos que nos muestren incluso más información? Pues tengo que decir que “Sí” que las hay y pueden aportarnos incluso mucho más valor. Pero por no hacer este artículo muy largo lo retomaré más adelante. Como 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. [...] Leer más...
Muchos llevabais tiempo preguntándome cuando iba a sacar los cursos, y en eso es en lo que he estado trabajando estos últimos meses. En crear una plataforma en la que pudiera ir subiendo clases. Fruto de este trabajo hoy presento la primera masterclass de trading algorítmico totalmente gratuita y la nueva sección de cursos del blog. Esto es un nuevo comienzo para todo el blog, ya que a partir de ahora mucho del contenido que he ido haciendo también será en video, ya sea en el canal de youtube (Un poco más dedicado al trading con Machine learning) como en los propios cursos. Masterclass gratuita Como gran estreno de esta sección he decido hacer una masterclass de trading algorítmico con python completa, en la que cuando la terminéis tendréis vuestro robot funcional completo. En la Masterclass se verá el siguiente contenido: Descargar el material necesario Conectar con un broker. Descarga y análisis de datos históricos. Un backtesting para probar una estrategia. Conexión para recibir los datos en tiempo real. Ejecución del robot con la estrategia definida. Como veis está todo lo necesario para crear vuestro propio robot de trading así que espero que os sirva mucho para ir avanzando en vuestra transformación a traders algorítmicos. Podéis entrar directamente a la masterclass con un vídeo en el que se explica todo lo que se va a ver aquí: https://cursos.garcia-ferreira.es/p/masterclass-de-trading-algoritmico Nueva sección de cursos Desde ahora si vais al botón de cursos ya entráis directamente en el que he llamado “Algorithmic Trading Lab“, la nueva sección donde iré poniendo todos los cursos que vaya haciendo sobre el trading algorítmico. El nombre de Lab es debido a que quiero formar una especie de cursos completos con las novedades que vayan saliendo en el mercado, y por ello la denominación de “laboratorio” porque los que entren en los cursos tendrán acceso ilimitado y para siempre de todas las novedades que yo vaya haciendo tanto en los cursos como en mis robots de trading. Si dais en la sección de cursos en el menú podréis acceder a todo lo que voy ofreciendo, aunque las novedades del Lab también las iré poniendo en el blog y en la comunidad Discord para que todos estéis al corriente. Dentro de poco más contenido Dentro de poco también ofreceré algo completamente revolucionario y que no es algo que todo el mundo ofrezca, pero que creo que puede aportar muchísimo a la comunidad del trading en español, ya que no hay nada creado como lo que voy a hacer que sea hecho y creado por alguien de una comunidad en español. ¡Así que estad muy atentos al blog! Como siempre cualquier cosa que me queráis comentar sobre el nuevo Lab me lo podeos dejar en los comentarios o en la comunidad Discord. [...] Leer más...
Muchas veces deseamos hacer un buen backtesting utilizando unos datos históricos que tenemos almacenados e importar un csv a Metatrader, pero no es que sea una tarea muy intuitiva, la verdad. En esta entrada voy a explicar como descargar datos de Darwinex y subirlos a MT4 (supongo que en MT5 será igual, pero si alguien me lo confirma en los comentarios resuelvo mi duda). Para hacer la descarga utilizaremos mi herramienta DarwinexDownloader y así explicaremos un paso a paso para que no se pierda nadie. Para aquellos que no dominen mucho Python o directamente no sepan programar, lo voy a hacer de tal manera que sin saber programar nada también lo puedan hacer sin herramientas instaladas ni nada extra. Así que vamos a allá! Datos de conexión En este caso que vamos a descargar los datos desde Darwinex lógicamente tenemos que tener una cuenta en este broker y solicitar los datos para poder acceder a su FTP, tal y como lo expliqué en el articulo dedicado a la descarga de datos desde este broker. Si tenemos otro broker que nos permita descargarnos los datos de otra forma o si ya tenemos un fichero .csv con los datos descargados podemos saltarnos la siguiente sección con total tranquilidad e ir directamente a la parte de la importación de los datos en Metatrader 4. Descarga de datos Lo primero que vas a hacer es entrar en Google Colab entrando en la URL https://colab.research.google.com/?hl=es. Una vez dentro te saldrá una pantalla similar a esta donde le tendrás que dar a nuevo cuaderno: En ese momento se abre un nuevo entorno para que puedas programar y ahí vas a poner el siguiente código: !pip install darwinexDownloader Ahora le damos a “Mayusculas+Intro” y ejecutará ese código. Le costará un ratillo pero estará instalando la librería para hacer descargas directamente desde Darwinex. Veremos que queda algo así: Ahora vemos que ya tenemos otra línea para poner código y vamos a poner lo siguiente: import DarwinexDownloader dwnx = DarwinexDownloader.Connection('your_user', 'your_password') data = dwnx.download('EURUSD', "28-06-2022", "29-06-2022", '15Min') data.to_csv("datos_darwinex.csv") En este código hay que cambiar varias cosas para adaptar a los datos que queremos descargar. Lo primero poner el usuario y password de Darwinex para entrar en el FTP, después poner el ticker del símbolo del cual queremos descargar los datos, las fechas entre las que va a estar el datos y el periodo de las velas de trading. Si tenéis alguna duda de como poner los periodos, tenéis más ayuda en la web de la herramienta DarwinexDownloader. Una vez que lo tengas todo tienes que ver que te queda en la pantalla algo así (Con tus datos, claro): Le damos otra vez a “Mayusculas+Intro” y veremos dos cosas. La primera que te hace la descarga de los datos: Y la segunda, que en la parte izquierda de la pantalla, en los archivos ya tenemos un fichero que se llama “datos_darwinex.csv”: Si ponemos el ratón encima de “datos_darwinex.csv” veremos que aparecen tres puntos: Haciendo click sobre estos tres puntos ya vemos como nos aparece una opción para descargar el fichero con todos los datos que hemos obtenido: Y con esto ya tendremos los datos de Darwinex del periodo que queramos en nuestro PC listos para meterlos en MT4. Importar en MT4 Al abrir Metatrader 4 nos vamos directamente a “Herramientas” y luego “Centro de historiales”: Se nos abrirá una nueva ventana con los posibles datos que tiene en ese momento metatrader 4: Como yo me he descargado los datos del EURUSD voy a buscar este ticker. En la parte izquierda en “D-TS-FX-PLAIN” damos al más que está a la izquierda y veremos que se despliegan los símbolos del Forex, así que busco el ticker que corresponde con los datos que he descargado: Hacemos doble click sobre el símbolo y se desplegará un nuevo árbol con los diferentes periodos: Escogemos periodo correspondiente a los datos que hemos descargado (en este caso yo me he descargado la de 15 minutos), y le damos al botón importar: En ese momento se abre una nueva ventana en la que ya podemos importar nuestros datos dándole a botón “Examinar“: Buscamos la ruta donde hemos descargado los datos de Darwinex y al agregarlos ya veremos como nos muestra los datos en la pantalla: Le damos a aceptar y ya veremos como en la ventana anterior nos salen los datos ya cargados. Le damos a “Cerrar” y ya tendremos los datos cargado en nuestro Metatrader 4, pero lo más normal es que no veamos nada porque tenemos la ventana cerrada. En este caso hay que ir a la ventana de símbolos, dar botón derecho sobre el símbolo que hemos cargado los datos y luego luego hacer click en “ventana de gráfico“. Si os pasa como a mí veréis que parece que no carga los datos y se queda en una ventana como esta: Lo que hay que hacer en este momento es seleccionar en la parte de arriba el periodo que hemos descargado, que en mi caso era de 15 minutos. Y una vez seleccionado… Ya tenemos nuestros datos cargados en Metatrader y listos para hacer las pruebas que queramos con ellos. Conclusión Como veis no es que sea sencillo pero creo que con este tutorial ya queda claro como subir datos a Metatrader desde cualquier CSV, e incluso hemos descargado datos desde Darwinex para, si tenemos un Darwin, hacer las pruebas directamente con los datos de este broker. Como siempre si veis que algo está mal o que me he saltado algún paso y os perdéis no dudéis en comentármelo. [...] Leer más...
Muchas veces no encontramos el sitio ideal donde estar informados de todo este mundillo del trading algorítmico y el machine learning. Siempre me he encontrado con mucha información y he tenido que buscar mucho hasta encontrar información de calidad sobre estos temas. Por esta razón he querido ponerlo más fácil a todos los que leéis este blog (y ahora veis el canal de youtube) haciendo una comunidad en Discord con la que estar al día de todo lo que sucede en este mundo, podáis opinar sobre los temas del momento, solucionar dudas y demás cosillas que vayan saliendo. Por eso os presento el canal Discord de este blog y os explico un poco qué vais a poder encontrar en esta pequeña comunidad. Noticias Tanto en trading algorítmico como en machine learning es muy importante estar al día de las noticias que van surgiendo. En la comunidad iré poniendo todas las novedades que vayan surgiendo en estos campos, tanto noticias normales como nuevas librerías o código que nos puedan ayudar en nuestro trading. Si ves una noticia que te parezca relevante siempre puedes ponerla en el chat general o avisarme para abrir un nuevo tema de debate sobre ese punto en particular dentro de la comunidad. Posibilidad de hacer preguntas Hacer trading algorítmico siempre es una actividad muy solitaria. Para que no nos sintamos tan solos están los canales generales de cada área y la posibilidad de hacer preguntas y que yo, u otros integrantes de la comunidad os echen una mano, o incluso hablar en el canal general de cualquier tema con otros miembros. Estás atascado con el código o has visto un código que quieres compartir, pues perfecto. En los canales de código tenemos un rincón para exponer todas las dudas que os puedan ir surgiendo. Muchos recursos para ayudaros Algo muy importante es tener material en el que basarse para empezar, así que hay una sección con recursos donde podréis encontrar valiosos enlaces a librerías, artículos y demás contenido que os pueda ayudar. Además de los enlaces a las charlas en cada uno de los hilos se podrán poner comentarios para saber si las habéis probado, si es buena herramienta y que pensáis sobre ella, haciendo más valiosa todavía la comunidad. Charlas conmigo e invitados Dentro de la comunidad se hará charlas online en las cuales se irán tratando diferentes temas relativos al trading y machine learning. Estas charlas se irán publicitando en Discord y serán en exclusiva para los miembros de la comunidad. Además en alguna ocasión se conectarán otros traders algorítmicos para que nos aporten sus puntos de vista y nos digan como hacen ellos su operativa. Canales exclusivos para cursos Los alumnos de los cursos tendrán su propio canal donde tendrán muchos recursos y vídeos en exclusiva que les ayuden en la creación de sus propios sistemas algorítmicos. Los alumnos también tendrán su espacio de preguntas y charlas exclusivas para tener ese extra de ayuda para llevar sus sistemas de trading a un entorno real. Otros temas No solo de trading y machine learning se puede vivir, hay temas que también pueden llamar la atención de los que estamos aquí y que se irán incluyendo como canales extra. Por ahora se ha creado un canal de matemáticas para tratar esos temas que pueden ser un poco más numéricos dentro del trading y del machine learning, y otro canal sobre computación cuántica, que parece ser el futuro al cual acabaremos llegando parece que antes de lo que pensamos. Comunidad viva Todo esto puede ir cambiando respecto a nuevas necesidades o nuevos campos que podamos ir tocando. Pero los temas y contenidos del canal lo decidiréis vosotros según como vaya creciendo la comunidad ya que siempre será una comunidad para compartir y ayudar a los demás. Si en algún momento piensas que es necesario otro canal, que el canal debería tener un contenido u otro, puedes hablarlo y con ello iremos creando una mejor comunidad. Esta es una comunidad que acaba de crearse y va a ir adaptandose y moldeando sus canales y contenidos. ¡Entra ya! Vamos no lo dudes, entra ya y empieza a beneficiarte desde hoy mismo de todo el contenido que ya he ido subiendo y del que día a día iré compartiendo con todos vosotros. ¡No lo pienses más, haz click en el enlace y empecemos esta comunidad! [...] Leer más...
Hoy he publicado un nuevo video en el canal de youtube donde explico uno de los algoritmos más simples (aunque no por ello menos potentes) de aprendizaje por refuerzo, el Q-Learning. En el video explico detalladamente la teoría y posteriormente hago un agente de utilizando Q-Learning para el juego que nos ofrece la librería Gym: Mountain Car. Es un juego muy sencillo pero me parece perfecto y muy rápido de programar para que se vea la efectividad de esta técnica. El video os lo dejo aquí, pero también lo podéis ver directamente en youtube, donde también tenéis el anterior video donde explico el aprendizaje por refuerzo. Espero que os guste. Y como siempre cualquier comentario o pregunta sobre el vídeo lo podéis poner aquí o en Youtube y os contestaré lo antes posible. [...] Leer más...
Dentro del campo del aprendizaje por refuerzo existe una gran problema a la hora de realizar el entrenamiento, y ese es el problema del la exploración o explotación. Nunca se sabe realmente si al llegar a un punto determinado es mejor seguir explorando o quedarse con el máximo resultado de recompensa que tenemos en ese momento. En problemas pequeños puede ser muy fácil ver esto, pero en problemas donde toda la complejidad no cabe en la memoria es un gran problema, ya que por cada paso que tome el algoritmo este tendrá que volver a calcularlo todo. El caso más famoso para ver esto es el dilema del bandido multibrazo (o en inglés Multi-armed bandit), que ya expuso Herbert Robbins en el año 1952 Herbert Robbins, y que ya se usa en finanzas para calcular que opciones sobre una acción van a tener mejor resultado. He encontrado muy poca información en castellano sobre esto así que aquí va mi pequeña aportación al tema. Introducción La idea principal de este problema es que un día decides gastar tu fortuna de 1.000€ que tienes ahorrados desde hace tiempo. Como no tienes hobbies se te ocurre y te gustan las mátemáticas se te ocurre ir a una sala de juegos o casino donde existen una máquinas tragaperras o tragamonedas, que en inglés se llaman one-arm bandid (de ahí el nombre del problema) e intentar ganar el máximo de dinero posible. Cuando entras ves que hay cinco máquinas cada una diferente a las demás, y por tanto das por echo que cada uno tendrá premios distintos y distintas probabilidades de ganar. También en este caso hay que tener en cuenta que este casino es de lo más legal del mundo y no está para ganar dinero. La pregunta es ¿Cómo podemos averiguar qué máquina es más rentable de todas ellas? Podemos escoger una al azar, pero nunca sabremos si esa es la mejor o la peor máquina y siempre nos quedaríamos con la duda. También podemos jugar en las máquinas aleatoriamente, pero siempre tendríamos la sensación de estar desperdiciando nuestro dinero en máquinas equivocadas. ¿Cómo podríamos averiguar cual es la mejor máquina? Y, antes de seguir, ¿Se os ocurre alguna forma de conseguirlo? Primer acercamiento Imaginemos que empiezas a gastar el mismo dinero en todas las máquinas y vas apuntado si te dan premio o no. Después de varias rondas por todas las máquinas tendrás alguna máquina que te ha dado más premios que otras. Así que a partir de ese momento podrías decidir apostar siempre a esa máquina. Pero ¿qué pasaría si esa máquina solo dio premios al principio y no los vuelve a dar más? Quizá la máquina que daría más premios a la larga no da un resultado significativo en ese periodo? Con todo esto surge otra pregunta ¿cuánto hay que probar hasta que los resultados nos devuelvan las verdaderas probabilidades de premio de una máquina? Con todo esto ya tenemos el verdadero problema de la exploración o explotación, tenemos que saber el equilibrio justo para aplicar un caso u otro. Así que vamos a ver las posibles soluciones que tenemos a esto. Estrategias Epsilon-avaricioso Esta estrategia es la más simple de todas donde balanceamos la exploración entre y la explotación aleatoriamente. Por ello, epsion $\epsilon$ se refiere a la probabilidad de escoger explorar, con lo que según pongamos el valor decidirá entre explorar o explotar. Con lo que podemos decir que: \begin{equation} acción(t)\left\{\begin{matrix} accion\;con\;mayor\;recompensa &con\;probalidad\;1-\epsilon \\ accion\;aleatoria &con\;probalidad\;\epsilon \end{matrix}\right. \end{equation} Esto visto en python sería así: epsilon = 0.1 aleatorio = np.random.random() if aleatorio > epsilon: print("Echo en la máquina con mayor recompensa") else: print("Escojo una máquina aleatoria") Epsilon-primero Esta estrategia también es muy sencilla y va por fases. Primero tendremos una fase completa de exploración durante un numero de veces $N$, después de eso siempre iremos a la opción con más recompensa. En python sería así: N=20 # Fase de exploración for i in range(N): print("Escojo una máquina aleatoria") # Una vez que se ha hecho toda la labor de investigación # Ya siempre escoge la mejor print("Escojo la máquina con mayor recompesa") Epsilon-decreciente Es similar a Epsilon-avaricioso pero, en este caso, el valor de epsilon va decreciendo con el paso del tiempo. Con lo que si la estrategia va cambiando desde el valor inicial con un porcentaje de exploración determinado hasta un momento donde el algoritmo solo hará explotación de la mayor recompensa. Con esto aseguramos que la exploración sea en las primeras etapas del experimiento y según se va experimentando, el algoritmo se volverá más eficaz. Un ejemplo muy tonto python sería así: pruebas = 100 for prueba in range(pruebas): aleatorio = np.random.random() epsilon = 1/((prueba+1)/10) if aleatorio > epsilon: print("Echo en la máquina con mayor recompensa") else: print("Escojo una máquina aleatoria") donde utilizamos la fórmula $\frac{1}{(n+1)/10}$ para hacer un descenso muy gradual de la fórmula. Nota: Para aquellos que nunca entendieron los Límites en matemáticas este es un buen ejemplo de que al saber que $\lim_{x\rightarrow +\infty}\frac{1}{x}=0$ solo necesitamos hacer que vaya hacía 0 de la forma gradual que nosotros queramos. Valores iniciales optimistas Esta forma de buscar los mejores valores también es muy simple. Simplemente tenemos que poner unos valores iniciales a las máquinas muy superiores pruebas = 100 maquinas = for prueba in range(pruebas): # Escoger la máquina con la mayor recompansa mayor = np.argmax(maquinas) print("Echo en la máquina con mayor recompensa") # guardaríamos la recompensa que da la máquina con una media # y una desviación estandar para saber lo que puede variar Estrategias más avanzadas Existen otras muchas estrategias que son bástante más complejas y que requieren una entrada a solo para cada una de ellas debido a su complejidad, pero paso a explicar alguna de ellas: Estrategia Epsilon-avaricioso adaptativa basada en diferencias de valor: Esta estrategia, también llamada VDBE (del inglés Value-Difference Based Exploration) es similar a la anterior, pero aquí en vez de bajar el epsilon de forma manual lo hace en base a un aprendizaje similar a la técnica del Q-Learning. Podeis leer más en su paper original. Estrategia del bandido bayesiano: Esta estratégia como su nombre indica esta basada en el teorema de Bayes y en el distribución $\beta$. Esta no es que sea más complicada que el resto, pero creo que explicarla bien también llevaría un ratillo y prefiero dedicarle una entrada aparte. Algoritmos de bandido con límite de confianza superior: Se busca conseguir un límite superior en la recompensa promedio de cada bandido, usando los datos que hemos recopilado hasta ahora. En cada paso, seleccionamos al bandido con el índice de confianza superior más alto, obtenemos la recompensa y posteriormente actualizamos su índice. Más información la podéis encontrar en el paper original. Conclusiones Esto ha sido una breve introducción al problema y a las soluciones más sencillas con un poco de pseudo-código, para que se pudieran entender. Aun hay muchas más soluciones que se pueden analizar, así que si miráis por internet podréis encontrar cual es la mejor fórmula para resolver este problema con el que seguro que os encontraréis incluso en vuestra primera inmersión en el aprendizaje por refuerzo. También podréis crear aquí vuestras propias soluciones a este problema (como he hecho yo en el epsilon-decreciente para que entendierais el ejemplo) y seguro que si os poneis a pensar y os gustan un poco las matemáticas podéis sacar vuestros propios algoritmos para resolver este problema. Como 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. [...] Leer más...
Hace unos días tuve el placer de poder hablar con Rubén Martínez que me entrevistó para su podcast de “La City”. Estuvimos hablando durante casi una hora sobre un poco de mí (así también me conocéis un poco más) y bastante sobre trading algorítmico y machine learning. Os recomiendo echarle un vistazo al podcast así como suscribiros al canal/podcast ya que merece mucho la pena los temas que toca Rubén, así como los invitados con los que habla y de los que siempre se pueden aprender cosas. Si os gusta el trading algorítmico en su web también podéis ver los temas que toca y como trabaja él en este campo. Vlog Aquí os dejo en enlace a la entrevista: Como os he comentado echarle un ojo al canal entero sobre todo a la parte del las listas que tiene muy bien ordenado por temáticas y hace que sea muy sencillo seguir el tema que más te interese. Podcast Para aquellos que seáis como yo y os guste ir a todos lados escuchando podcast, también podeis ir escuchando a la city en spotify: Y también en Apple Podcast: [...] Leer más...
Descargar los datos siempre es la primera tarea si queremos hacer un análisis de datos, y en Darwinex no ha sido nunca una tarea fácil. Por esta razón, y después de la buena acogida del artículo para descargar datos de esta plataforma he creado darwinexDownloader, una librería para python que con solo instalarla y ejecutar una línea nos devolverá los datos que queremos. No pensaba publicarla tan pronto, pero creo que aun estando en una fase tan temprana ayudará a mucha gente a descargar código, y a mí a que la vosotros encontréis fallos, propongáis mejoras y nuevas funcionalidades que igual a mi no se me han ocurrido. La librería se encuentra en el repositorio de Github donde podéis ver el código fuente con el que se hace la librería y el paquete para la instalación se encuentra en Pypi, donde también tenéis una breve documentación de como funciona la herramienta. Sin más os paso a presentar la herramienta con la que podemos descargar datos desde Darwinex en solo 3 líneas! Instalación La herramienta darwinexDownloader se instala de forma muy sencilla utilizando pypi. Para instalarla solo deberemos hacer: pip install darwinexDownloader Con esto ya tendremos la librería instalada en nuestro entorno y lista para funcionar a partir de este momento. Funcionamiento Con la librería ya instalada solo nos queda importarla en nuestro código para empezar a funcionar con ella. Esto se realiza de la siguiente forma: import DarwinexDownloader Una vez importado lo siguiente que debemos hacer es inicializar la librería que vamos a utilizar, esto se hace con el siguiente código: dwnx = DarwinexDownloader.Connection('your_user', 'your_password') Donde ya tendremos en la variable dwnx la conexión con la que vamos a poder realizar la descarga. Como se puede ver en el código la forma de conexión es muy sencilla utilizando darwinexDownloader ya que solo tenemos que pasarle el usuario y contraseña que nos da Darwinex para realizar la descarga del código a través de su FTP.. Acto seguido ya podemos realizar la descarga de código de una forma muy sencilla a través del método “download”: data = dwnx.download('EURUSD', "28-06-2022", "29-06-2022", '15Min') En el código podemos ver que necesitamos cuatro datos para la descarga de los datos: Ticker: que lógicamente debe de existir dentro de Darwinex para poder ser descargado, como podemos comprobar en la web de Darwinex. Fecha de inicio: Fecha desde la cual se quiere empezar a descargar los datos. El formato de la fecha tiene que ser dd-mm-yyyy. Fecha de Fin: Fecha hasta la que descargaremos los datos. El formato de la fecha, al igual que en la anterior, tiene que ser dd-mm-yyyy. Frecuencia: la temporalidad con la que queremos ver los datos de Darwinex una vez descargados. Una vez que se ejecute este comando ya tendremos los datos en la variable data de esta forma: DateopenhighlowcloseVolume2022-06-28 00:00:001.057971.058501.057891.05810952330000.02022-06-28 00:15:001.058121.058521.058071.05825549950000.02022-06-28 00:30:001.058241.058531.057731.05779503900000.0………………2022-06-29 23:30:001.052181.052381.052041.05237244950000.02022-06-29 23:45:001.052361.052381.052171.05220291050000.0 Para la frecuencia con la que se pueden descargar los datos utilizamos los timeframes de la librería pandas. Los que más utilizaremos para descargar los datos de trading serán las siguientes: ‘1Min’ ‘5Min’ ’15Min’ ’30Min’ ‘1H’ ‘4H’ ‘1D’ ‘Week’ ‘Month’ Pero si miráis en la librería de timeframes podéis poner los datos en el formato que vosotros queráis. Prueba rápida Si quereís realizar alguna prueba de como funciona la librería de forma rápida podéis hacerlo desde google colab. En la primera celda poner: !pip install darwinexDownloader Y en la segunda celda podeis poner lo siguiente: import darwinexDownloader dwnx = darwinexDownloader.Connection('igarciaferreira', 'T8059Bb39v238p') data = dwnx.download('EURUSD', "28-06-2022", "29-06-2022", '15Min') data Con solo esto ya podéis hacer pruebas de librería para ver como funciona y como os devuelve los datos. Preguntas, sugerencias y problemas Si durante la ejecución de la librería surge algún problema podéis ir poniéndola en el github de darwinexDownloader e iré resolviendo los errores según vaya pudiendo. Para abrir un nuevo error se hace sobre el botón “New issue” con vuestra cuenta de github abierta: Una vez pulsado irás a otra pantalla donde ya puedes poner el problema que has encontrado y así yo podré solucionarlo lo antes posible: Al igual que con los problemas, si veis alguna funcionalidad que os falta y que pudiera hacer mejor la librería también la podeis poner en el mismo Github y de la misma forma, y en cuanto pueda subiré una nueva versión con los cambios que se han producido, tanto al github como a pypi para que os lo podáis descargar sin problemas. Conclusiones Aunque es una versión muy temprana de la herramienta y soy consciente de que todavía le queda mucho por mejorar espero que os pueda ayudar a la descarga de los datos y que os haga la vida más sencilla al no tener que preocuparos de esta parte de código. Como veis ahora con darwinexDownloader es muy sencillo descargar los datos históricos directamente desde Darwinex: Importar la librería Inicializarla con nuestros datos Descargar los datos que queremos. Esta librería hará que solo os tengáis que preocupar de analizar los datos para como lo hacen nuestros amigos de Quantdemy en su artículo sobre backtesting o simplemente para realizar cualquier estrategia como esta esta con LSTM que ya hemos visto en el blog. Como siempre, y más en este caso, cualquier duda o aclaración no dudéis en ponerla en los comentarios o enviarme un mensaje por cualquiera de los medios y os contestaré lo antes posible. [...] Leer más...
Esta es solo una entrada rápida para anunciar que he estrenado un canal en youtube donde iré compartiendo videos sobre el aprendizaje por refuerzo, machine learning, trading algorítmico y tantos otros temas que tratamos en el canal pero en formato video para que se haga más agradable. La dirección del canal es: https://www.youtube.com/@garcia-ferreira A partir de ahora intentaré combinar tanto el blog como el canal de youtube para hacer el aprendizaje más ameno y más interactivo en todos los sentidos y así salimos todos ganando. Espero que disfrutéis viendo el vídeo tanto como yo he disfrutado haciéndolo. Como siempre cualquier comentario tanto aquí como en el video será bienvenido. [...] Leer más...
Aunque backtrader es una herramienta potente para hacer backtesting, hay otras que han evolucionado a partir de esta herramienta. Y una de las más potentes es backtesting.py, un framework ligero, potente y muy fácil de usar. Una de las características que nos puede sorprender de esta herramienta es que no tiene una librería técnica pero está completamente integrado con librerías de análisis técnico como TA-Lib, Tulipy, PyAlgoTrade, NumPy, SciPy, con lo que nos permite hacer estrategias muy completas utilizando estas dos librerías. Instalación La instalación de este paquete es igual no tienen ninguna complicación y se instala igual que el resto de paquetes de python: pip install backtesting Una vez, y como siempre, se debe de importar la librería para poder empezar a utilizarla, pero esto ya lo vamos a ir viendo poco a poco para conocer cuales son las clases que tiene esta librería y como podemos utilizarlas para poder sacar el mayor provecho posible. Datos Para utilizar esta librería tenemos que tener los datos en formato “dataframe” y que tengan los datos ohlc, es decir las columnas open, high, low y close. En este caso nosotros hemos optado por conseguir los datos a través de la librería yfinance, que nos proporciona los datos que tiene yahoo finance, y la cual nos da los datos que necesitamos para realizar el backtesting con backtesting.py. La forma de conseguir los datos que he utilizado es esta: Como vemos ya tenemos los datos que necesitamos, incluso alguno más que en este caso no vamos a utilizar. Estrategias Ahora que ya tenemos los datos que vamos a necesitar, lo siguiente es pensar la estrategia que vamos a utilizar. En este caso no nos vamos a complicar mucho con la estrategia (ya que no es el objetivo de esta entrada) y crearemos una estrategia simple de cruce de medias utilizando la librería Ta-lib para realizar los cálculos. La estrategia que vamos a utilizar para esta técnica es la del cruce dorado que ya hemos visto cuando hemos probado backtrader, y a la vez hacemos una comparativa con el mismo caso en ambas librerías. El cruce dorado es el cruce de medias de la media de 50 y la media de 200, así que implementarlo es sencillo. Como novedad y por ver la sencillez de esta librería vamos a hacer que cuando la media de 50 cruce la media de 200 opere en largo, y cuando la media de 50 cruce la de 200 opere en corto. from backtesting import Strategy from backtesting.lib import crossover import pandas as pd import talib as ta class GoldenCross(Strategy): # Definimos las medias que vamos a utilizar n1 = 50 n2 = 200 def init(self): # Configuramos las dos medias self.sma50 = self.I(ta.MA, self.data.Close, self.n1) self.sma200 = self.I(ta.MA, self.data.Close, self.n2) def next(self): # Si la media de 50 cruza hacia arriba la media de 200 # cierra cualquier posicion que estuviera abierta compra if crossover(self.sma50, self.sma200): self.position.close() self.buy() # si la media de 50 cruza hacía abajo la media de 200 # cerramos cualquier posicion anterior y vendemos elif crossover(self.sma200, self.sma50): self.position.close() self.sell() Como se puede ver al principio se puede que importamos varias librerías. La clase “Strategy” que es la que luego usaremos como base para nuestra propia clase, y la “crossover” que es la que utilizaremos para comprobar si una media cruza a otra. El trozo que puede ser más complejo es la configuración de las medias, donde como vemos utilizamos el método “self.I”. Para este método hay que pasarle como primer argumento la función que vamos a llamar para para hacer los cálculos (en este caso la media simple que nos da la librería Ta-lib) y los siguientes parámetros son los argumentos que le vamos a pasar a la función. Si quisiéramos poner stop-loss, take profit u ordenes de límite, tanto la orden buy como la orden sell tiene parámetros para hacer esto y podríamos ponerlo así: buy(size=1, limit=None, stop=None, sl=self.data.close-3, tp=self.data.close+10) Backtesting.py trae más funciones que pueden ayudarnos a crear estrategias más rápido o mucho más complejas. Todo esto puede verse en su amplia documentación. Lanzar las pruebas La forma de lanzar las pruebas también es muy sencilla con Backtesting.py. Simplemente hay que importar la clase “Backtest” que es la que hará la magia. Si miramos la definición de la clase en la documentación de backtesting.py le podemos pasar varios parámetros: class Backtest(data, strategy, *, cash=10000, commission=0.0, margin=1.0, trade_on_close=False, hedging=False, exclusive_orders=False) Las opciones son las siguientes: data: Los datos que le tenemos que pasar de tipo ohlc para que haga el backtesting. strategy: La clase de la estrategia que hemos definido anteriormente cash: Dinero inicial commision: Las comisiones del brocker por operaciones trade_on_close: si es True la orden de mercado se hará se hará sobre el precio de la barra de cierre actual y no sobre la apertura de la siguiente barra, lo cual hará si es False. hedging: Si es True permitirá operaciones simultaneas en ambas direcciones, si es False cerrará las operaciones contrarias antes de hacer la actual. exclusive_orders: si es True solo permitirá una operación a la vez y cerrará la anterior automáticamente. Nosotros vamos a ejecutarlo de la siguiente manera: from backtesting import Backtest bt = Backtest(data, GoldenCross, cash=10000, commission=.005) stats = bt.run() stats Como se puede ver en la llamada a esta clase podemos pasarle como parámetros varios datos. En este caso le pasamos la cantidad de dinero con la que empezará a realizar el trading y la comisión que nos cobrará el broker. Luego haremos la llamada a “run()” de backtesting.py, la cual nos devolverá las estadísticas de todas las operaciones realizadas: Si queremos hacer operaciones con alguna de estas estadísticas para sacar las nuestra propias se puede acceder a cada valor de “stats” utilizando el nombre de la estadística que deseamos obtener: Gráficos Si queremos ver en un gráfico las operaciones que se han realizado utilizando esta librería es extremadamente sencillo con backtesting.py. Solo tendremos que hacer la llamada a la función “plot()”: bt.plot() Y la salida que tendremos será así: Donde, como vemos en la imagen, en la parte izquierda tenemos unas herramientas con las cuales podemos manejar el gráfico completamente haciendo zoom y otras muchas herramientas para ver mejora las operaciones: Utilizar modelos de Machine learning Si estamos utilizando modelos también podemos hacer backtesting con backtesting.py, Solo habría que cargar el modelo en la clase estrategia y a partir de ese momento. Si por ejemplo tenemos un modelo muy simple al que le pasamos los datos ohlc y nos devuelve 1 si hay que comprar y 2 si hay que cerrar la posición, la estrategia sería así: from backtesting import Strategy from backtesting.lib import crossover import pandas as pd import talib as ta import joblib class MLmodel(Strategy): def init(self): # Cargamos el modelo loaded_model = joblib.load('modelo.joblib') def next(self): # Aquí es donde tendréis que hacer la extracción de datos, normalizar o # cualquier operación que necesitéis hacer con los datos antes de pasarlos if self.loaded_model.predict(data) == 1: self.buy() if self.loaded_model.predict(data) == 2: self.position.close() Como se puede ver es muy sencillo hacer backtesting de modelos de aprendizaje automático utilizando backtesting.py. Conclusiones Como se puede la utilización de esta librería nos facilita muchísimo la labor de hacer el backtesting y obtener resultados de forma muy sencilla, con unas estadísticas que nos puede ayudar mucho a la hora de probar si nuestra estrategia (ya sea de ML o no) es buena o hay que mejorarla de alguna forma. La documentación que trae esta herramienta también está muy completa y echándole un ojo podemos llegar a hacer estrategias muy complejas con muy pocas líneas de código (aunque lamentablemente no hay muchos ejemplos prácticos para probar. Como siempre cualquier duda o aclaración no dudéis en ponerla en los comentarios o enviarme un mensaje y os contestaré lo antes posible. [...] Leer más...
Existen muchos artículos sobre como se debe crear modelos de machine learning para que haga trading, pero poco se habla de como poner un modelo en producción usando un servidor VPS. Los tutoriales siempre terminan enseñando como el algoritmo funciona correctamente con el conjunto de validación y ahí nos quedamos. Aunque ya vimos como hacer más pruebas con la simulación de montecarlo la mejor forma de probar un modelo es ponerlo una temporada con los datos reales y ver como funciona. Lógicamente, no estoy diciendo de ponerlo directamente en real y que empiece a hacer las operaciones con dinero de verdad, sino hacerlo con una cuenta demo para que veamos como funciona. En este caso pondremos nuestro robot de trading en la nube utilizando https://clouding.io/ una plataforma que nos permite tener nuestro propio pc en la nube (en el futuro lo haré con contenedores y sus ventajas) y la conexión con una cuenta demo de Darwinex. Nuestro modelo Lógicamente para subir un modelo a producción hay que tener un modelo ya creado y entrenado con unos hiperparámetros definidos. Esto como es normal es diferente para cada caso y según como sea vuestro modelo tendréis que meter unos datos u otros. También hay que tener en cuenta que se puede guardar de diferentes formas según sea el modelo que has entrenado por ejemplo un modelo entrenado en sklearn se puede guardar así: joblib.dump(model, 'mi_modelo.joblib') Mientras que modelo creado creado usando redes neuronales se puede guardar por ejemplo usando HDF5: model.save('mi_modelo.h5') Es importante saber como se ha guardado el modelo para saber como hay que cargarlo, ya que esto sí que diferiere mucho de una forma a otra, y existen muchas formas de guardar el modelo. Una vez guardado el modelo ya podemos empezar a pensar como ponerlo en producción. Pasar del análisis al robot La forma del robot es muy similar a como hemos hecho en el artículo de nuestro primer robot de trading, solo que ahora la “inteligencia” de nuestro robot la va a dar el modelo y no nuestra estrategia como hicimos en ese artículo. Imaginemos que tenemos un robot de trading que está haciendo muy buena operativa basándose en las bandas de Bollinger y ya lo tenemos guardado en formato “joblib”. En __init__ de la clase “tick_processor” de la conexión con Darwinex lo cargaremos haciendo lo siguiente: # Cargamos el modelo de categorización de velas self.loaded_model = joblib.load('robot_bollinger.joblib') En el momento que queramos hacer una predicción utilizando este modelo sería: acción = self.loaded_model.predict(pd.DataFrame()) Y con esa acción ya podríamos hacer muestro trading. Simplificando mucho podríamos tener un modelo que simplemente hiciera trading de posiciones en largo y cerrase estas posiciones, con lo cual nuestro código podría ser algo así: # Si la acción es compra if action == 1: self.dwx.open_order(symbol=symbol, order_type='buy', price=close_price, lots=0.01) # Si la acción es venta if action == 2: self.dwx.close_all_orders() if action == 0: print("No hacer nada") Lo más importante es que hay que pasarle a vuestro modelo exactamente los mismos datos y en la misma forma en la que hicisteis el entrenamiento, sino es imposible que funcione correctamente. Este punto es esencial para que al robot de trading le lleguen los mismo datos con los que he hecho el entrenamiento y produzca las mismas salidas que lo ha hecho durante tanto el entrenamiento como en la validación. Otro detalle que tenemos que tener en cuenta es, ¿cuales son nuestras salidas del modelo? Es decir, ¿nuestro robot solo hace operaciones en largo? ¿hace operaciones en corto?, ¿pone stop loss y take profit?, ¿Siempre compra la misma cantidad o es variable?, etc.. Todas estas operaciones las habrá que realizar en nuestro siguiente código y dependiendo de la salida del código tendremos que hacer que esa salida se transforme en código de Darwinex. Todos estos detalles tiene que ir en el código de python para que haga bien la conexión de todo el proceso de trading. Pequeño test Pre-producción Una vez que ya tengais todo esto estaría bien realizar un test pre-producción para saber que tal y como teneis vuestro robot funciona en vuestra máquina. Para ello me vuelvo a remitir al articulo donde explico como poner un robot en funcionamiento y teneís todos los pasos para hacerlo, aunque ahora con nuestro modelo entrenado. Una vez que veáis que vuestro robot ya funciona en local es cuando ya podemos empezar a prepararnos para ponerlo en producción. ¡Así que vamos allá! ¿Qué vamos a necesitar? Para poner un modelo en producción no podemos hacerlo con nuestro PC de casa porque no son ordenadores preparados para ello y además no tienen una serie de características que nos pueden ofrecer los servidores en la nube. La forma más sencilla de hacerlo es replicar nuestro entorno de trabajo en servidor VPS, que son las siglas de Servidor virtual privado. Un servidor VPS es un tipo de servidor al que nos podemos conectar y trabajar como si fuera nuestro propio ordenador y poner ahí nuestro robot de trading a funcionar. ¿Y por que hacerlo en un servidor y no en tu ordenador? En tu ordenador hay muchas cosas que pueden fallar y hacer que tu operativa sea un desastre, como que se vaya la luz de tu casa cuando tienes una operación abierta o que a proveedor de internet le de por hacer pruebas y te quedes sin internet. Lo que solo sería una molestia en tu día a día puede ser un trauma en tu operativa, así que no conviene arriesgar con esto. Tipos de VPS hay muchos y a precios muy variados, pero nosotros no necesitamos un gran servidor, pero lo que si nos interesa son los tiempos de uptime que nos dan. Algunos de los más famosos son: IonosContaboKamateraClouding Nosotros no necesitaremos mucha máquina y el único requisito que vamos a poner es que sea Windows (lo que eleva un poco más el precio) más que nada por evitar complicaciones (la instalación en linux ya la explicaremos en otra entrada del blog). Así que por unos 10 o 20 euros podemos encontrar un servidor que cumpla nuestras espectativas. En esta entrada no voy a centrarme en uno solo ya que son todos muy similares y explicaré como hacerlo para que os sirva para cualquier servidor VPS. Conectando con el servidor VPS Una vez que ya tengamos el servidor VPS os tienen que dar tres cosas para conectaros: Una URL o IP donde está vuestro servidorUsuarioContraseña del usuario. Con estos datos ya podemos conectarnos al servidor y empezar configurarlo. Para hacer esto utilizaremos el programa que ya nos viene con Windows “Conexión a escritorio remoto”: Al abrir esta aplicación ya podemos poner nuestros datos, pero hay una opción muy importante que debemos activar. Para acceder a ella tenemos que desplegar las opciones que nos da este programa: Una vez que pulséis sobre “Mostrar opciones” veréis que se despliegan muchas más opciones separadas por pestañas. En ese momento tendréis que ir a “Recursos locales” y luego en la parte de abajo ir a “Más”: Y ahí se abrirá una nueva ventana en la cual se podrán ver gran parte de vuestros dispositivos para poder hacer que la máquina virtual también los tenga. A nosotros lo que nos interesa es compartir el disco que es donde tenemos nuestro código. Así una vez que nos conectemos a la IP del servidor VPS que nos han dado e introduzcamos el usuario y contraseña, al ir a al explorador de archivos podremos ver nuestro disco duro con todos los datos, entre los que estarán nuestro robot. ¿Qué necesitamos para nuestro robot? Nuestro lo básico que necesitamos es: Python: Exactamente la misma versión con la que habéis creado el robot.El Metatrader de Darwinex: Para la conexión a los datos. La descarga de python la podeis hacer desde la propia web de python y la instalación tan sencilla como siempre (Acordarse de poner la carpeta “bin” de python en el path de windows para poder lanzarla desde línea de comandos). La descarga de metatrader desde Darwinex ha cambiado un poco desde la último tutorial que realicé sobre el tema, ahora se encuentra en el menú de “Cuentas de trading”, “Plataformas” y después teneis que darle a “Ver más”: Una vez que le deis a “Ver más” ya os aparecerá el enlace para poder descargar Metatrader: Una vez descargado hay que seguir los pasos del tutorial para poner el asesor experto, tal y como expliqué en la entrada del primer robot de trading con dwxconnect. Lanzando todo Una vez creado ya el ambiente solo nos queda lanzar el script y ver si conecta bien y realiza operaciones. Por ser un poco organizado vamos a repasar qué es lo imprescindible para tener el robot funcionando en el servidor VPS: Metatrader descargado desde Darwinex con la cuenta (empieza con una demo) configuradaEl asesor experto que nos va a dar la conexión entre python y metatrader.Python en la misma versión que el que hiciste las pruebasEl modelo de machine learning (normalmente) en la misma carpeta del robotTu código con el robot en el cual se encuentra la carga del modelo y toda la lógica de programación Una vez que tengamos esto podríamos lanzar nuestro script y todo debería de funcionar sin problemas. Futuro A partir de ese momento ya podrás empezar a ver tus estadísticas de trading en tu cuenta de Darwinex. Y podrás tener tu propia cuenta demo auditada como si fuera real viendo todos los datos como si tuvieras tu propio Darwin. Y en el momento que decidas pasarla a real el proceso será muy sencillo, y así que tendrás tu propio Darwin con el que podrás dar envidia a los demás. Conclusiones Como se puede ver no es tan difícil tener un robot de trading en producción. Por unos 10 euros (incluso alguno menos si pillas una oferta) puedes llegar a tener tu infraestructura montada con un servidor VPS y lista para empezar a hacer trading algorítmico más en serio de lo que lo hacías hasta ahora. Lógicamente esto es un primer paso, ya que no vas a tener un robot ganador al primer entrenamiento que has realizado. Aquí es donde empieza verdaderamente la labor de programador y de empezar a jugar con el machine learning, pero a estas alturas ya deberías de tener un buen robot funcionando con todo lo que se está mostrando en este blog. Como 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. [...] Leer más...
No todo es machine learning en las pruebas que podemos hacer para mejorar nuestro robot de trading. La permutación de parámetros es otro sistema que puede ayudarnos a encontrar los mejores parámetros para nuestro algoritmo de trading. Muchas veces nos fiamos de nuestras pruebas manuales o de estrategias que leemos por internet y las aplicamos sin pensar si hay otros parámetros que podrían ir mejor. ¿Por qué el cruce dorado se realiza con la media de 50 y de 200? ¿Por que el RSI se mira con 30 y 70? ¿Por qué las bandas de Bollinger tienen que ser con la media de 20 periodos? Puede que nunca os hayáis hecho estas preguntas preguntas, pero en este artículo vamos a ver si mediante código podemos encontrar la forma de mejorar estos patrones que parece que tenemos grabados a fuego y que nunca tocamos. Para ello veremos como hacerlo con la estrategia del cruce dorado. ¿Qué es la permutación de parámetros? La permutación de parámetros o System Parameter Permutation (SPP) fue una idea creada por Dave Walton en 2014 para mejorar las estrategias de trading (si te gusta ir a las fuentes aquí puedes ver el artículo original). La idea es conocer si una estrategia de trading con unos valores fijos es la mejor o todavía se puede optimizar mucho más. Para probarlo lo que se hace es probar todas las combinaciones posibles de parámetros de la estrategia y con todos los datos encima de la mesa saber si una estrategia es optimizable y hacernos con una idea realista de cuál será el rendimiento de la estrategia. Para saber si una estrategia es buena o no utiliza los valores medios para las estadísticas de rendimiento de cada estrategia: Beneficio, drawdrown, ratio de Sharpe, etc. Lógicamente cuantos más valores utilicemos para saber si nuestra estrategia es buena o no, más fiable será que no tengamos sorpresas en la operativa de nuestro robot. A su vez, en vez de probar todas las posibilidades, crearemos números aleatorios suficientes para probar que la estrategia cumple con la mayor parte de las posibilidades. Según Walton con estos valores ya nos podemos hacer una idea realistas de como será el rendimiento de una estrategia de trading. Probamos el cruce dorado Para hacer la prueba más simple y no liarnos con nuevas estrategia vamos a reutilizar el código que vimos para probar backtrader, donde probamos el trading del cruce dorado y vimos cual era su resultado en esa herramienta. También provecharemos que backtrading también nos puede dar los valores que necesitamos para ver si nuestra estrategia es rentable como el retorno, el drawdown y el ratio de Sharpe para ver como escoger los valores adecuados para el cruce dorado El código cambia muy poco respecto al que vimos en el anterior ejemplo: class cruce50_200(bt.Strategy): params = ( ('slowPeriod', 50), ('fastPeriod', 200), ) def __init__(self): # Inicializamos la media de 50 y la de 200 self.sma50 = bt.indicators.SimpleMovingAverage(self.data, period=self.params.slowPeriod, plotname="slow SMA") self.sma200 = bt.indicators.SimpleMovingAverage(self.data, period=self.params.fastPeriod, plotname="fast SMA") self.cruce = bt.ind.CrossOver(self.sma50,self.sma200) # Inicializamos la variable order, que usaremos para el control de las ordenes # Para mantener el seguimiento de las órdenes pendientes self.order = None self.buyprice = None self.sellprice = None # guardamos el último dato de cierre self.dataclose = self.datas.close def next(self): # Comprobamos si estamos en el mercado # si no lo estamos seguimos para adelante if not self.position: # Si la media de 50 es mayor que la media de 200 compramos # print("{}: {} - {}".format(self.datas.datetime.date(0), self.sma50, self.sma200)) if self.cruce > 0: self.order = self.buy() # Si estamos en el mercado else: if self.cruce < 0: # Si es así vendemos (con todos los parametros por defecto posibles) # Mantenemos un seguimiento de la orden para evitar abrir una segunda orden self.order = self.sell() # Creamos este método para el control de las ordenes def notify_order(self, order): # Orden de compra o de venta aceptada por el brocker - Nada que hacer if order.status in : return # Orden de compra completada # Comprobamos si es de compra o de venta y mostramos los resultados if order.status in : if order.isbuy(): self.buyprice = order.executed.price elif order.issell(): self.sellprice = order.executed.price Lo más significativo es que ahora le pasamos los parámetros de la estrategia como argumentos y no como estaban anteriormente, que eran fijos. Esto, lógicamente, es imprescindible para poder hacer la permutación de los parámetros y probar todas las combinaciones posibles de esta técnica. También hemos quitado la función log y todas las líneas que mostraban la información por pantalla ya que en este caso no nos aportan información o incluso pueden obstaculizar para ver unos resultados claros. El cerebro Ahora vayamos a la parte central. Aquí respecto a la anterior hemos añadido la parte donde introducimos los analizadores para que nos muestre tanto el retorno, el drawdown y el ratio de sharpe. También los hemos metido en una función a la cual le vamos a pasar los parámetros que van a ir variando para hacer correcta la técnica de la permutación de parámetros. def run_test(parametro1, parametro2): cerebro = bt.Cerebro() # Añadimos los datos que hemso descargado previamente data1 = bt.feeds.PandasData(dataname=starbucks) cerebro.adddata(data1) # Añadimos la cantidad inicial de dinero con la que vamos a realizar el trading cerebro.broker.setcash(10000.0) # Añadimos la comisión - 0.1% cerebro.broker.setcommission(commission=0.001) # Tamaño de los lotes que queremos comprar cerebro.addsizer(bt.sizers.FixedSize, stake=1) # añadimos analizadores para ver los valores que necesitamos cerebro.addanalyzer(bt.analyzers.DrawDown, _name = "drawdown") cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name = "sharpe") cerebro.addanalyzer(bt.analyzers.Returns, _name = "returns") cerebro.addstrategy(cruce50_200, slowPeriod=parametro1, fastPeriod=parametro2) analisis = cerebro.run() return analisis Como se ve nada complicado, simplemente cogemos la salida que devuelve cerebro en la ejecución y lo devolvemos para que pueda ser tratado en la función que se le llama. La permutación de parámetros Aquí es donde creamos el código que verdaderamente hace la permutación de parámetros. def sweep_parameters(pruebas): slow = np.random.randint(5,200,pruebas) fast = np.random.randint(200,500,pruebas) resultados = [] parametros = {} for i in range(pruebas): if slow == fast: continue resultado = run_test(slow, fast) analisis = , x.analyzers.drawdown.get_analysis(), x.analyzers.drawdown.get_analysis(), x.analyzers.drawdown.get_analysis(), x.analyzers.sharpe.get_analysis(), x.params.slowPeriod, x.params.fastPeriod ] for x in resultado] resultados.append(analisis) return pd.DataFrame(resultados, columns=) Como puedes ver en la primera parte creamos números aleatorios entre los valores que queremos que vayan nuestras dos variables. En este caso queremos que la media lenta sea de unos valores entre 5 y 200 y la media rápida de unos valores entre 200 y 500. Luego comprobamos que no coincidan (solo en el caso de 200 y 200) y sino lanzamos la prueba con los valores creados. De lo que nos devuelve el backtrader sacamos los valores del retorno varios con el drawdown y el Sharpe ratio. Finalmente, y por motivos estéticos devolvemos una Dataframe en vez de una lista como se había creado dentro del bucle. La función solo recibe un parámetro que es el número de veces que queremos que se lance la prueba. Aquí podemos ser todo lo amplio que queramos, cuantas más valores aleatorios pruebe el algoritmo mejor, pero también más tardará en darnos los resultados. Resultados Veamos que resultados podemos obtener con la permutación de parámetros si lanzamos el código para que haga las pruebas 10 veces: resultados = sweep_parameters(10) Si luego mostramos el valor que tiene la variable resultados podemos ver algo así: Aquí podemos observar todas las ejecuciones que se han realizado tanto los valores que ha devuelto la estrategia como los valores que hemos utilizado tanto en el periodo lento como en el rápido. Aunque se puede ver a simple vista haremos una línea para que nos devuelva algunos valores máximos, ya que si lanzamos 1000 veces la prueba verlo a mano puede ser una locura. resultados == resultados.max()] Aquí lanzamos para ver cual es la prueba que nos ha devuelto más beneficios, y el resultado es: Parece que la prueba numero 1 es la mejor candidata, pero veamos cual ha tenido un drawdown más bajo con el siguiente comando: resultados == resultados.min()] Y la salida es: Parece que otra vez la prueba numero 1 es la mejor, ahora veamos que nos dice el valor del ratio de Sharpe: resultados == resultados.max()] Aquí parece que la prueba 9 es la que se lleva la palma, pero como vemos el ratio de sharpe es muy negativo, mostrando que esta forma de hacer trading tiene un riesgo muy elevado. Mejoras al algoritmo propuesto Lógicamente se pueden hacer muchas mejoras en este algoritmo de permutación de parámetros como hacer que los valores de las parámetros no se repitan o poner más valores para probar la técnica. La forma de hacer la estrategia también es bastante mejorable pero por aprovechar el ejemplo anterior de backtrader y no cambiar mucho lo que se explicó en esa entrada he decidido mantenerlo así. La posibilidad de hacer otras técnicas siempre está ahí. Una de las mejoras más importantes que podría tener este algoritmo sería hacer el procesamiento utilizando GPUs y que cada prueba se realice en un núcleo de GPU diferente. Con ello reduciríamos mucho el tiempo de pruebas haciendo que pudiéramos realizar muchas pruebas en un tiempo relativamente corto. Conclusiones Como se puede ver la técnica de la permutación de parámetros puede ayudarnos mucho a hacer nuestro trading mucho más efectivo. Combinado con la técnica de la simulación de Montecarlo que hemos visto en la anterior entrada puede llevarnos a conseguir unos robots de trading muy estables y que nos den muy poco sustos. Ahora lo que nos queda es ir probando estrategias, adaptarlas a backtrader y lanzar las simulaciones para conseguir saber cual puede ser el rendimiento real si lo ponemos a trabajar. Como 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. [...] Leer más...
Cuando creamos una estrategia de trading es muy importante probarla bajo todos los posibles escenarios que puedan darse y ver que nuestro modelo sigue funcionando bien, es decir hacer unas buenas pruebas de robustez. Una de las formas de más conocidas de hacer este tipo de pruebas es mediante la simulación de Montecarlo. Si un modelo de trading es capaz de soportar con un buen desempeño una test de robustez como el la simulación de Montecarlo se podría decir que ya está listo para pasar a un entorno real, así que es muy importante que tu modelo funcione con este tipo de pruebas. Sigue leyendo para ver como te puede ayudar a mejorar tus estrategias de trading esta simulación. ¿Qué es la simulación de Montecarlo? Lo que hace esta simulación es generar números aleatorios usando una distribución de probabilidad y luego hacer muchas muchas repeticiones para de esta forma evitar la incertidumbre que lógicamente tenemos en el trading, ya que solo tenemos muestras limitadas de lo que puede llegar a suceder. Al final este modelo lo que hace es jugar con la probabilidad y el volumen. Esto cumple la ley de los números grandes que es un teorema matemático que viene a decir algo así: Si repetimos un experimento un número enorme de veces, la frecuencia de que suceda un evento tiende a ser una constante. Esto se puede ver muy fácil con el ejemplo del lanzamiento de una moneda al aire, si lanzas muy pocas veces la moneda al aire, es probable que no veas que la probabilidad de que salga cara o cruz es del 50%, pero si lanzas la moneda muchas veces al aire, observarás como se cumple esta probabilidad. Con esto creo que queda muy claro porque es importante la simulación de Montecarlo dentro del trading, ya que si tenemos una estrategia y la repetimos muchas veces sabremos cual será nuestra constante de ganancia o pérdida con ese sistema. Se puede decir que una valor ya está estable cuando tanto la media aritmética como la varianza de los valores que estamos midiendo está estable. Por este hecho siempre hay que buscar la estabilidad de las mismas para saber que nuestro valor es constante. Empezando Aunque en un principio podríamos pensar que hacer la simulación de Montecarlo podría ser tan simple como lanzar números aleatorios y dejarnos llevar esa no es la realidad. Si hiciéramos eso podrían darse unos valores demasiado grandes o demasiado pequeños y salirnos elementos que podrían no tener ningún sentido dentro de lo que es el movimiento normal de un precio, así que tenemos que idear la forma de hacer eso. Por suerte la forma de conseguir esta aleatoriedad ya está estudiada desde antes de los tiempos de la segunda guerra mundial, donde lo utilizaban para la simulación de la difusión de los neutrones en la fusión. Las librerías que vamos a necesitar para hacer nuestro código son las siguiente: # Librería para descargar los datos from yahoo_fin import stock_info # Librería para datos import numpy as np # Librería para calcular la desviación estandar from scipy.stats import norm # Librería para mostrar los datos import matplotlib.pyplot as plt Ahora vamos con la chica de verdad de la simulación de Montecarlo. Movimiento Browniano Nosotros para nuestro cálculos vamos a utilizar el movimiento browniano geométrico que es el más utilizado dentro del mundo de las finanzas. Su fórmula es la siguiente: \begin{equation} $S_{t+1} = S_t\cdot e^{(\mu – \frac{\sigma^2}{2})+\sigma \cdot \epsilon }$ \end{equation} Donde por cada caso tendremos lo siguiente: $\mu$: es la media$\sigma^2$: la varianza$\delta t$: la desviación estándar$\epsilon$: Este es el componente estocástico de nuestra función y que nos asegura que el movimiento sea completamente aleatorio. Lógicamente tiene que cumplir que el movimiento de un paso no tenga correlación con el anterior. Para conseguir cada uno de los valores de la fórmula lo haremos en varios pasos de los cuales el primero es descargar los valores que vamos a utilizar, para ello tiraremos directamente de la librería de Yahoo, que nos hace este cometido más fácil: netflix = stock_info.get_data("nflx", start_date="01/01/2020", end_date="01/01/2021") En este caso nos hemos descargado los precios de Netflix pero podría ser cualquier otra acción o divisa que quisiéramos. Lo primero que vamos a hacer es calcular la rentabilidad logarítmica (o capitulación compuesta) de un valor. Esto se hace primero calculando la rentabilidad simple: $rentabilidad\ simple = (precio\ inicial – precio\ final)$ y aplicamos el logaritmo: $Rentabilidad\ logarítmica = ln(1+rentabilidad\ simple)$ Esto con python se hace de la siguiente forma: rent_algo = np.log(1 + netflix.pct_change()) Y con esto ya podemos obtener el resto de valores que nos hace falta para la fórmula: # Obtenemos la media mu = rent_algo.mean() # Obtenemos la varianza var = rent_algo.var() # obtenemos el valor del drift (primer parentesis) drift = mu - (var/2) # Obtenemos el valor de la desviación estandar desvest = rent_algo.std() Para el epsilon (la parte aleatoria) vamos a utilizar una función que nos facilita python (además de la de conseguir los números aleatorios), la de la función de densidad de probabilidad (norm.ppf). Esta función describe la probabilidad relativa por la cual una variable aleatoria tomará un determinado valor: # Decimos cuantos días queremos simular (o el timeframe que corresponda) days = 30 # El número de simulaciones que queremos realizar n_simulations = 10000 # Hacemos la fórmula epsilon = norm.ppf(np.random.rand(days, n_simulations)) Con esto ya tendremos todo lo necesario recrear nuestra fórmula. Empezamos con la parte de función exponencial: daily_returns = np.exp(drift + desvest * epsilon) Y ahora ya solo tenemos que hacer un bucle para ir consiguiendo los nuevos datos por cada paso paso y para todos los días que queremos hacer: returns = drift + desvest * epsilon S = np.zeros_like(returns) S = netflix.iloc for t in range(1, days): S = S*np.exp(returns) Graficando Y con esto ya tenemos todos los valores en la variable S. Ahora podemos hacer un gráfico con lo que hemos sacado para ver todos los valores tal y como los hemos generado: plt.plot(S) plt.show() Y la salida se vería así: Con lo cual ya vemos todos los valores que nos ha generado nuestro simulación de Montecarlo. Conclusiones Aquí no está todo el trabajo terminado ya que si queréis probar vuestros algoritmos con este método es posible que no solo necesitéis hacer esto con la parte de cierre de los precios sino con todos los posibles valores que puedan tomar los precios, aunque la forma de trabajo es similar cambiando el precio objetivo También hay que señalar que esta no es la única forma de hacer una simulación de Montecarlo ya que se puede realizar realizando la generación de los números aleatorios de distintas formas a como lo hace el movimiento Browniano, pero esta es una de las más utilizadas. Como hemos visto no es tan complicado crear una simulación de Montecarlo, aunque entender el por qué de cada operación si que puede llegar a ser más complicado, pero con las explicaciones que hemos dado aquí espero que os haya quedado más claro. Como 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. [...] Leer más...
Antes de crear un robot de trading basado en inteligencia artificial es importante conocer como se realiza un robot simple que conecte con Darwinex y realice operaciones. Así tendremos la base para ir analizando como realizar operativas más avanzadas a solo comprar y vender acciones sin mucho sentido. Para hacer esto utilizaremos una librería que nos proporciona Darwinex para conectar Python de forma muy simple y que facilita mucho la vida de los que hacemos código Python para hacer trading algorítmico. Vamos a ver como conectar nuestro robot desde principio a fin para tener un robot (algo tonto eso sí) que este haciendo operaciones y que se vea en nuestra cuenta de Darwinex como si fuera un robot de trading operando en real. Cuenta demo en Darwinex Lo primero que tenéis que hacer es crear vuestra propia cuenta demo de Darwinex, lo que podéis hacer entrando directamente pulsando en la siguiente imagen: Nos tendremos que registrar como lo haríamos en cualquier otra web. Una vez que hemos creado la cuenta ya podemos entrar para crear nuestra cuenta demo. Al entrar en Darwinex la primera vez puede parecer un poco confuso encontrar donde crear una cuenta demo, pero la forma más sencilla es irnos directamente a “Fx & CFDs” y pulsar sobre dicho botón: Y luego ir a la parte izquierda donde pone mis cuentas: Y le damos al botón de “Mis cuentas” y luego al de “Cuentas Demo”. Desde ahí ya podemos ver la opción de crear nuestra cuenta demo: Una vez abierta la cuenta demo y que nos llegue un correo indicando el número de cuenta y la clave nos descargamos el Metatrader de Darwinex desde el mismo menú de “Mis cuentas” y dándole a “Descargar terminal de trading” y donde deberéis escoger entre Metatrader 4 o 5. La instalación de Metatrader es sencilla, siguiendo las instrucciones de la pantalla tendréis ya instalado el cliente para hacer las operaciones. En la primera ejecución ya os saldrá la pantalla para que introduzcáis los datos de vuestra cuenta demo de Darwinex, con lo que ya tendréis los datos de Darwinex llegando correctamente a Metatrader y unido a vuestra cuenta de Darwinex. Ahora vamos a ver como hacemos el robot en Python. Librería dwxconnect La forma de instalación de esta librería es mucho más simple de la que vimos en el anterior artículo, simplemente hay que entrar aquí y descargarse el fichero que la versión de Metatrader que corresponda con la que tenemos instalada. Aunque hay otro fichero de “Test” este no nos interesa así que no lo descargamos. Una vez descargado el fichero seleccionado nos vamos a nuestro Metatrader y entramos en la carpeta de datos desde “Archivo“: En la estructura de fichero que veremos tendremos que entrar en las carpetas “MQL4” y luego en “Experts” y en esa ruta dejar el fichero que hemos descargado anteriormente. Acto seguido reiniciamos nuestro Metatrader y ya tendremos que ver nuestro nuevo “Asesor Experto” en el navegador de ficheros. Ahora lo que tenemos que hacer es compilar el “Asesor Experto” para ello le damos a “Modificar” haciendo click derecho sobre él. En cuanto se nos abra el editor solo tendremos que darle al botón Compilar en la parte superior de la ventana para tener nuestro Asesor Experto listo (y ya podemos también cerrar la ventana del editor) Para usar el Asesor Experto en igual que en la anterior forma de conexión, solo hay que arrastrarlo sobre la ventana de datos que queramos utilizar. Al igual que la anterior vez hay que activar las opciones de trading automático como se puede ver en la imagen: En la pestaña de los parámetros de entrada podemos configurar varias opciones, como el máximo de ordenes que permitiremos o el tamaño máximo de lotes que permitiremos (que veremos más adelante). Una vez configurado, hay que fijarse que esté el botón AutoTrading activado y que aparezca la cara sonriente en la esquina de la ventana donde queremos hacer el trading algorítmico, como podemos ver en la siguiente imagen. Estructura de la carpeta del robot Después entraremos aquí y nos descargaremos fichero dwx_client.py y aquí y nos descargamos el fichero dwx_client_example.py. Después creamos una carpeta donde vamos a alojar nuestro robot, y dentro de ella copiamos el fichero dwx_client_example.py. En esa misma carpeta creamos otra llamada api y dejamos ahí el fichero dwx_client.py. La carpeta resultante debería de verse así (donde la carpeta del proyecto se llama robot: robot ├──── dwx_client_example.py └──── api └──── dwx_client.py Ahora vamos a analizar como es la estructura del fichero dwx_client_example.py para ver como funciona. dwx_client_example.py Si abrimos el fichero “dwx_client_example.py” y nos quedamos con la estructura de la clase principal llamada tick_processor podremos ver lo siguiente: class tick_processor(): # Clase inicial def __init__(self, MT4_directory_path, sleep_delay=0.005, # 5 ms for time.sleep() max_retry_command_seconds=10, # retry to send the commend for 10 seconds if not successful. verbose=True): def on_tick(self, symbol, bid, ask): def on_bar_data(self, symbol, time_frame, time, open_price, high, low, close_price, tick_volume): def on_historic_data(self, symbol, time_frame, data): def on_historic_trades(self): def on_message(self, message): def on_order_event(self): Paso por paso veremos lo que es cada clase: __init__: Método inicial donde se realizan todas las inicializaciones de la clase, como los datos que nos queremos descargar, si hay operaciones realizados, numero de operaciones, etc.. on_tick: Método que se llama cada vez que se produce un nuevo movimiento en el mercado y nos da el bid y el ask del momento actual. on_bar_data: Cada vez que una nueva barra sale (ya sea una vela japonesa o de cualquier de los otros métodos de ver la información) nos devuelve los valores típicos como se puede ver en él método. on_historic_data: Esta función es muy útil para llamar a datos históricos para hacer nuestras operaciones. Un buen ejemplo es conseguir una media de 200 para sacar los datos, llamaremos a esta función para que nos devuelva las últimas 200 barras y poder realizar la media que queremos. on_historic_trades: Al llamarla consigue un histórico de las operaciones que se han ejecutado. on_message: Por cada mensaje que sale en Metatrader este método lo captura. Resto del robot Las líneas que quedan son muy simples: MT4_files_dir = 'C:/Program Files (x86)/MT_Darwinex/MQL4/Files/' processor = tick_processor(MT4_files_dir) while processor.dwx.ACTIVE: sleep(1) La carpeta que hay que poner en esa ruta es la que vemos cuando abrimos la carpeta de datos donde hemos dejado el Asesor Experto, pero en esta caso en vez de la carpeta “Experts” apunta a la carpeta “Files”. Luego simplemente hace un bucle infinito para que el robot esté siempre funcionando. Ejecutando nuestro primer robot de trading Si ejecutamos el robot desde la línea de comandos lo haremos con un simple: python dwx_client_example.py Y en ese momento veremos como empieza a soltarnos datos similares a esto: on_tick: 2022-09-15 16:46:58.120337 EURUSD 1.00027 1.00029 on_tick: 2022-09-15 16:46:58.130334 GBPUSD 1.14748 1.14753 on_tick: 2022-09-15 16:46:58.210325 EURUSD 1.00028 1.0003 on_tick: 2022-09-15 16:46:58.211327 GBPUSD 1.14748 1.14753 on_tick: 2022-09-15 16:46:59.036252 GBPUSD 1.14749 1.14755 on_tick: 2022-09-15 16:46:59.209043 GBPUSD 1.14749 1.14754 on_tick: 2022-09-15 16:46:59.927424 GBPUSD 1.14748 1.14753 Son los datos que tenemos en el método “on_tick” es decir, los datos de cada tick con el bid y el ask como hemos comentado antes. Pero no vemos que haga ninguna operación, aunque parece que en el robot hay código para que abra aleatoriamente ordenes y las cierre a los pocos segundos. La forma de que funcione es poniendo a “True” la variable self.open_test_trades, que como vemos en el código esta a “False” (en la línea 32): self.open_test_trades = False Y con esto ya tendría que empezar a funcionar nuestro robot de trading haciendo y cerrando órdenes. Cuando el robot abra una orden lo podemos ver en los logs de nuestro robot así: INFO | Successfully sent order 209454587: EURUSD, sell, 0.01, 1.00088 New order: {'magic': 0, 'symbol': 'EURUSD', 'lots': 0.01, 'type': 'sell', 'open_price': 1.00088, 'open_time': '2022.09.15 20:22:52', 'SL': 0.0, 'TP': 0.0, 'pnl': -0.02, 'commission': -0.05, 'swap': 0.0, 'comment': ''} on_order_event. open_orders: 1 open orders y cuando la cierre mostrar algo así: Order removed: {'magic': 0, 'symbol': 'EURUSD', 'lots': 0.01, 'type': 'sell', 'open_price': 1.00088, 'open_time': '2022.09.15 20:22:52', 'SL': 0.0, 'TP': 0.0, 'pnl': -0.02, 'commission': -0.05, 'swap': 0.0, 'comment': ''} on_tick:INFO 2022-09-15 17:22:59.859054| on_order_event. open_orders: 0 open ordersSuccessfully closed order: 209454587, EURUSD, 0.01EURUSD Y en Metatrader podemos ver las ordenes así: Después de ver estos número ya sabemos que no es mejor robot del mundo, pero es un punto de partida para tener algo funcionando. Posibles errores Hay algunos errores sencillos que os pueden salir a la hora de ejecutar este robot de trading. Pero los más comunes son: ERROR | OPEN_ORDER | Could not open order: trade is not allowed in the expert properties Cuando sale este error es que no hemos pulsado el botón de “autotrading” que hemos visto al principio o bien que no se ha activado el check del trading automático en la configuración del “Asesor Experto”. Otro error que nos podemos encontrar es este: ERROR | OPEN_ORDER_LOTSIZE_TOO_LARGE | Lot size (0.10) larger than MaximumLotSize (0.01). Esto es un bloqueo debido a que el “Asesor Experto” tiene un límite de 0.01 lotes por operación. Esto lo podemos resolver de dos formas. En el código: Bajando el tamaño de los lotes que hay predefinido en las líneas que lanzan el trading a 0.01 En Metatrader: En la configuración de nuestro “Asesor Experto” subiendo el parámetro “MaximumLotSize” a 0.1 o superior. Comprobación en Darwinex Las operaciones en Darwinex no se pueden comprobar en tiempo real y tendrás que esperar al día siguiente para ver como salen las estadísticas de tu robot. Pero una vez que tu robot esté funcionando podéis ir a cuentas demo y allí veréis vuestra cuenta (en mi caso la he llamado “puebasAgentes”): Una vez que entréis ya podéis ver los datos de vuestro agente como si fuera real, pero con la ventaja de ser una cuenta demo: Ahora ya podéis hacer todas las pruebas en vuestros robots como si fueran reales con una cuenta de Darwinex en modo demo y, cuando estéis preparados, pasarlo a real y ser capaz de tener un DARWIN capaz de conseguir una subvención. Conclusiones Con esto tenemos la base para hacer cualquier tipo de robot de trading con python. El ejemplo es muy tonto y las operaciones que hace son casi siempre perdedoras solo por el spread y que abre y cierra muy rápido, pero sirve para ver como se hacen las operaciones. Como se puede ver hacer un robot de trading completamente programado por nosotros cada día es más fácil gracias a las librerías publicas que ya nos hacen el trabajo sucio. Nosotros ya solo tenemos que dedicarnos a hacer unas estrategias efectivas. Con este artículo y con el de las librerías esenciales de trading, ya tenemos todo lo necesario para poder hacer la operativa en tiempo real tal y como la hacen muchas herramientas de creación de robots de trading, pero con la ventaja de que nosotros tenemos totalmente el control de todo lo que pasa mediante código. También os invito a jugar con el código y lo adaptándolo a vuestro gusto, bajando datos de otras divisas, cambiando temporalidades, añadiendo vuestra estrategia, etc. Seguro que disfrutáis mucho haciendo vuestro propio robot de trading algorítmico. Como 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. [...] Leer más...
Una vez que tenemos realizado nuestro robot de trading es importarte probarlo antes de ponerlo en producción. Hay gente que directamente lo hace con una cuenta demo y en datos reales, pero otros prefieren asegurarse de forma más rápida que su estrategia funciona. Para este cometido nos ayuda mucho la librería Backtrader. Backtrader te facilita mucho para probar todas aquellas estrategias que se te van ocurriendo que pueden funcionar en la bolsa de una forma muy rápida y con muy pocas líneas de código, lo cual se agradece mucho, ya que lo que normalmente queremos es probar rápido nuestro robot, que ya nos costó construir y no queremos perder mucho más tiempo en tener que programar nuevamente un nuevo código para hacer las pruebas. Con Backtrader además veremos claramente donde falla nuestro robot o estrategia y podemos ir poniendo rápidamente mejoras en aquellos puntos donde vemos carencias graves que nos hacen perder muchos puntos en nuestro trading. Todo el código de esta entrada lo podéis encontrar en mi github para que os sea más fácil el copiar y pegar el código y empezar a trastear directamente. No me enrollo más vamos allá con la herramienta. Instalación y primeros pasos La instalación de esta librería es tan simple como ya estamos acostumbrados a hacerlo en cualquier librería de Python: pip install backtrader No hay mucha complicación con esto, ¿no? Ahora vayamos a la estructura general de como se utiliza backtrader. La estructura más básica para utilizar Backtrader es muy sencilla: # Importamos la librería para hacer el backtest import backtrader as bt # Creamos la clase donde voy a tener mi estrategia class estrategia(bt.Strategy): def next(self): # Metodo para definir como se va a comportar el robot # Instanciamos la clase Cerebro cerebro = bt.Cerebro() # Añadimos nuestra estrategia a la clase anterior cerebro.addstrategy(estrategia) # Ejecutamos la clase cerebro.run() # Mostramos un gráfico donde se ve como ha funcionado nuestra estategia cerebro.plot() Como vemos en el código no hay mucha complicación en lo que es la base de Backtrader, aunque también es verdad que se puede ver muy básico lo que hace, porque podemos ver que hay mucho trabajo todavía por hacer si queremos probar un robot. Además de definir la estrategia que va a tener ese robot podemos complicarnos mucho más. Así a primera vista parece que no tenemos nada que gestione el capital, pero eso también lo trae implementado y lo veremos más adelante. Ejemplo: El cruce dorado Vamos a hacer un ejemplo simple de como sería el cruce de medias de 50 y de 200, a estos cruces se les suele conocer como cruce dorado (cuando se cree que el precio va a empezar a subir) que es cuando la media de 50 cruza hacía arriba sobre la media de 200 y hay que comprar. También existen el contrario, llamado cruce de la muerte, que es cuando la media de 50 cruza sobre la media de 200 y hay que vender, pero este no lo vamos a implementar aquí, solo por hacer el código más corto. De todas formas cualquiera que entienda como funciona el backtesting de el cruce dorado no tardará más de 10 minutos en implementar el cruce de la muerte, ya que es añadir unos cuantos detalles más. Descarga de datos Lo primero que vamos a hacer es descargarnos los datos para poder introducirlos en nuestra estrategia. Backtrader ya implementa lo que ellos llaman “Data feeds” que son unos conectores con las fuentes de datos para intentar facilitarnos la vida con la carga de datos. Se llevan especialmente bien con los datos que ofrece yahoo, así que nosotros vamos también a utilizar esa fuente por hacer las cosas más sencillas para el tutorial, pero funciona perfectamente con otras fuentes de datos como las que ya vimos en Financial Modeling Prep o Darwinex. Nosotros vamos a descargar los datos de Yahoo utilizando la librería “yahoo_fin“, que podéis instalar como cualquier otra librería con el comando pip. Y luego para descargar los datos es tan sencillo como hacer lo siguiente: from yahoo_fin.stock_info import get_data starbucks= get_data("sbux", start_date="01/01/2015", end_date="01/01/2022", index_as_date=True, interval="1d") Y con esto ya tendremos los datos diarios de los últimos 12 años para poder hacer nuestro backtesting. Es un buen periodo así que tendremos que ver bien como se producen estos cruces varias veces. Hemos escogido la acción de Starbucks ya que parece que tiene más cruces que otras acciones y así veremos como nuestra estrategia entra y sale varias veces. Creando nuestra estrategia Nuestra estrategia va a ser muy sencilla: Si la media de 50 cruza sobre de la media de 200: Comprar Si la media de 50 cruza debajo de la media de 200: Vender Solo una operación a la vez (como es lógico con esta estratégia) Aunque la clase que podíamos desarrollar podría ser sencilla vamos a incluir algo más para que se puedan ver las primeras pinceladas de como realizar códigos más complejos. Veamos como lo implementamos: class cruce50_200(bt.Strategy): def __init__(self): # Inicializamos la media de 50 y la de 200 self.sma50 = bt.indicators.SimpleMovingAverage(self.data, period=50, plotname="50 SMA") self.sma200 = bt.indicators.SimpleMovingAverage(self.data, period=200, plotname="200 SMA") self.cruce = bt.ind.CrossOver(self.sma50,self.sma200) # Inicializamos la variable order, que usaremos para el control de las ordenes # Para mantener el seguimiento de las órdenes pendientes self.order = None self.buyprice = None self.sellprice = None # guardamos el último dato de cierre self.dataclose = self.datas.close def next(self): # Comprobamos si estamos en el mercado # si no lo estamos seguimos para adelante if not self.position: # Si la media de 50 es mayor que la media de 200 compramos # print("{}: {} - {}".format(self.datas.datetime.date(0), self.sma50, self.sma200)) if self.cruce > 0: self.order = self.buy() self.log('Orden de compra lanzada: %.2f' % self.dataclose) # Si estamos en el mercado else: if self.cruce < 0: # Si es así vendemos (con todos los parametros por defecto posibles) self.log('Orden de venta lanzada: %.2f' % self.dataclose) # Mantenemos un seguimiento de la orden para evitar abrir una segunda orden self.order = self.sell() # Creamos este método para el control de las ordenes def notify_order(self, order): # Orden de compra o de venta aceptada por el brocker - Nada que hacer if order.status in : return # Orden de compra completada # Comprobamos si es de compra o de venta y mostramos los resultados if order.status in : if order.isbuy(): self.buyprice = order.executed.price self.log('COMPRA EJECUTADA ' % (order.executed.price, order.executed.comm)) elif order.issell(): self.sellprice = order.executed.price self.log('VENTA EJECUTADA ' % (order.executed.price, order.executed.comm)) # Orden de compra cancelada elif order.status == order.Canceled: self.log('Orden Cancelada') # Orden de compra cancelada por el margen de tu dinero elif order.status == order.Margin: self.log('Orden de Margen') # Orden de compra rechazada elif order.status == order.Rejected: self.log('Orden Rechazada') # Metodo para mostrar de manera más fácil los logs por pantalla # incluyendo la fecha en la que se producen los eventos def log(self, txt, dt=None): # Vamos mostrando los datos dt = dt or self.datas.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) Dentro de la clase que hemos llamado "cruce50_200" vemos que hemos implementado 4 métodos distintos: __init__: Donde se produce la inicialización de los elementos, como en cualquier clase normal. next: Esta es la clase que se llamará por cada paso que da nuestro algoritmo. En el caso que estamos examinando tenemos datos diarios, así que cada día que vaya examinando entrará en este método y evaluará lo que haya dentro. notify_order: Aquí controlaremos como está la orden que hemos ejecutado por parte del broker y controlaremos todos los estados que pueden darse log: Esta clase es simplemente de apoyo para mostrar los datos por pantalla con la fecha de forma más bonita. Como he dicho anteriormente hay muchas cosas que se podrían quitar y dejar esto aun más simple, pero creo que era necesario ponerlas por dos puntos. Uno para que podáis ver como se controlarían las cosas si se complica la estrategia (cosa que si os metéis en esto seguramente haréis) y dos, para como se podrían ejecutar otras estrategias muy distintas a la que estamos implementando. Examinando la estrategia en profundidad Vamos a analizar un poco más el método “next” para dar claridad sobre algún punto que pudiera quedar poco claro solo viendo el código. Al principio en la inicialización de la clase (en el "__init__") vemos como inicializamos los valores de la media de 50, 200 e incluso su cruce. Esto es algo que nos da ya hecho Backtrader y que nos facilita mucho la vida. Existen muchísimos indicadores que ya vienen preprogramados y que podemos ver en su web. Los indicadores que hemos utilizado aquí son dos: Media móvil simple(SimpleMovingAverage) Cruce de una línea sobre otra (crossOver) Con estas dos inicializaciones hacemos que backtrader nos calcule la media y luego que nos mire el cruce entre ambas medias. Como veis es muy fácil cambiar y poner cualquier otro indicador y ver cuando cruza uno sobre otro y así poder crear la estrategia con facilidad. Otra línea que puede parece curiosa es: self.dataclose = self.datas.close Que luego nos referimos a ella como: self.dataclose Aquí lo que hacemos es coger el último dato de cierre de la vela actual que se está mirando dentro del método “next”. Si quisiéramos el valor de cierre de la anterior vela sería “Self.dataclose" y sucesivamente. Es una forma fácil de tener los valores anteriores para también poder hacer cálculos para nuestras estrategias, y Backtrader también nos lo pone bastante fácil. Vemos que la forma de hacer una compra y una venta es muy sencilla, mediante self.buy() o self.sell(), pero también se pueden poner poner ordenes de Stop y de Limit, decir el tamaño de acciones o lotes que se quieren comprar y mucho más. Podéis ver todas estas opciones aquí. El resto de la clase de puede entender fácilmente. Datos económicos Una de las partes que debemos tener en cuenta son los datos económicos de las transacciones que vamos a hacer, dinero inicial, etc. Esto se puede controlar muy fácilmente desde la parte del código donde hacemos correr nuestra estrategia de esta manera: cerebro = bt.Cerebro(stdstats=False) # Añadimos los datos que hemso descargado previamente data1 = bt.feeds.PandasData(dataname=starbucks) cerebro.adddata(data1) # Añadimos la cantidad inicial de dinero con la que vamos a realizar el trading cerebro.broker.setcash(10000.0) # Añadimos la comisión - 0.1% cerebro.broker.setcommission(commission=0.001) # Tamaño de los lotes que queremos comprar cerebro.addsizer(bt.sizers.FixedSize, stake=1) cerebro.addstrategy(cruce50_200) # Mostramos los valores tanto inicial como final durante la ejecución del # proceso de backtesting print('Valor inicial del portfolio: %.2f' % cerebro.broker.getvalue()) cerebro.run() print('Valor final del porfolio: %.2f' % cerebro.broker.getvalue()) Como se puede ver añadir la cantidad de dinero, las comisiones e incluso el tamaño por defecto que queremos comprar se hace muy fácil. Lógicamente en estrategias más complejas esto puede ir variando y se puede ir modificando sobre la marcha durante la ejecución de backtrader. También hemos puesto un par de líneas junto antes y después de la ejecución de Backtrader para ver el saldo inicial y final de la estrategia y así tener mucho más claro si estamos haciendo bien o mal nuestro trabajo. Si ejecutamos ahora mismo este código lo que nos mostraría la pantalla sería esto: Valor inicial del portfolio: 10000.00 2017-01-06, Orden de compra lanzada: 57.13 2017-01-09, COMPRA EJECUTADA 2017-08-17, Orden de venta lanzada: 53.04 2017-08-18, VENTA EJECUTADA 2018-01-09, Orden de compra lanzada: 59.18 2018-01-10, COMPRA EJECUTADA 2018-06-25, Orden de venta lanzada: 50.66 2018-06-26, VENTA EJECUTADA 2018-10-30, Orden de compra lanzada: 58.59 2018-10-31, COMPRA EJECUTADA 2020-03-05, Orden de venta lanzada: 76.19 2020-03-06, VENTA EJECUTADA 2020-09-16, Orden de compra lanzada: 88.38 2020-09-17, COMPRA EJECUTADA 2021-11-18, Orden de venta lanzada: 112.90 2021-11-19, VENTA EJECUTADA Valor final del porfolio: 10025.78 Donde vemos exactamente todas las operaciones realizadas y como ha sido la comisión. Lógicamente estos datos se puede poner mucho más bonitos y dar mucha más información pero eso ya os lo dejo a vosotros ya que simplemente es trabajo de picar código. Mostrando la gráfica La gráfica con el resultado se puede mostrar simplemente con el comando “cerebro.plot()”. Pero yo por hacerlo un poco más bonito incluyo algo más: cerebro.plot(style='candle', iplot=False, volume = True, barupfill = False, bardownfill = False, barup='green', bardown='red') Y en la salida que obtenemos con Backtrader es está: Las opciones que se pueden poner con "plot()" son muchas, y recomiendo echar un ojo a su documentación para ponerlo a gusto de cada uno. En esta gráfica muestro como se han realizado las operaciones, la cantidad de beneficio que hemos obtenido, si las operaciones han sido buenas o malas e incluso cuando el cruce de líneas me daba un valor u otro, lo cual es muy interesante para ver si se han hecho las cosas bien. Conclusiones Como podéis ver Backtrader tiene mucho potencial, y aquí solo hemos rascado un poco la superficie de todo lo que se puede llegar a conseguir. Creo que es importante ver la parte de documentación en su web ya que tiene mucho contenido y muy bien explicado, aunque lamentablemente en inglés solamente. El ejemplo que hemos visto aquí era muy tonto, pero empezando con esto ya se pueden empezar a ver como se puede mejorar esta estrategia. Podríamos incorporar otros indicadores para tener más confianza en nuestras entradas o quizá implementar nuestro propio medidor en código para controlar algo nuevo que hemos visto y mirar la tendencia, ya que esta estrategia falla mucho si no hay una tendencia clara. Como veis las posibilidades son muy grandes, así que recomiendo jugar un poco con esta librería y sacarle el máximo provecho. Como siempre cualquier duda o aclaración no dudéis en ponerla en los comentarios o enviarme un mensaje y os contestaré lo antes posible. [...] Leer más...
Los procesos o cadenas de Markov puede que a muchos les suenen vagamente de su época de estudiante, de haber leído que Jim Simons empezó a hacer trading con ellas o simplemente que algo tienen que pueden ayudarnos con el trading, haciendo un trading más probabilístico. Estas cadenas son ampliamente utilizadas en muchos campos: biología, ciencias políticas, patrones de compras, control de morosos, juegos de azar, etc. Pero… ¿Pueden ayudarnos en el trading? En esta entrada voy a hacer una introducción a las cadenas de Markov para que quede claro el concepto, primero de forma matemática, luego con un poco de código y al final explicaré como las podemos utilizar en nuestro trading. Intentaré hacer las matemáticas sencillas para que sea llevadero y que aquellos que no están acostumbrados a las matemáticas puedan seguirlo. ¿Qué son las cadenas de Markov? Vamos a empezar por la base, dejando claro qué son estas cadenas. Sin meternos en términos matemáticos podemos decir que una cadena de Markov es una serie de eventos que pueden llegar a suceder, donde la probabilidad de que suceda un evento u otro depende del estado en el que nos encontremos. Una cadena de Markov simple podría ser la siguiente: Imaginemos que tenemos tres posibles estados de las acciones: acciones que suben, acciones que bajan y acciones que se mantienen. Ahora haríamos un estudio sacando cual es el porcentaje de los cambios de estado en cada una de ellas, es decir, si la última vela es de subida, ¿cuál es el porcentaje de que la siguiente sea de subida, bajada o que se quede igual? Imaginemos que ya tenemos todos los números y los plasmamos en una matriz de probabilidades de transición: SubeBajaIgualSube0.420.460.12Baja0.450.440.11Igual0.470.480.05 Esto matemáticamente es una matriz que hemos visto muchas veces, y creo que se entiende bastante bien. Si la última vela es de subida “Sube”, la probabilidad de que vuelva a subir es del 42%, de que baje del 46% y de que se quede igual es de un 12%. Esta matriz de probabilidades tiene que cumplir tres reglas muy simples: Debe de ser cuadrada (en este caso es de 3×3) Los valores tienen que estar entre cero y uno La suma de cada fila debe de ser uno Esta matriz también se puede representar de otra forma con un dígrafo. Con esto tenemos de un solo vistazo de una manera mucho más visual como son las conexiones entre un estado y otro. También vemos claramente si estamos en el estado de “Sube” cuales son las probabilidades de ir al siguiente estado. Calculando las probabilidades Al principio tendremos tres estados. Los que hemos visto en la imagen anterior, pero ahora vamos a representarlo matemáticamente en un vector donde la primera posición será la de “Sube“, la segunda la de “Baja” y la tercera la de “Igual“: \begin{equation} Sube = \\ \end{equation} \begin{equation} Baja = \\ \end{equation} \begin{equation} Igual = \end{equation} Esto se podría entender como que para la posición “Sube” al ser tendremos un 100% de posibilidades de que suba y 0% de que baje o de que se quede igual, y lo mismo con el resto de posiciones. En este caso como es un estado conocido las probabilidades son del 100%, porque lógicamente ya sabemos cual es el estado inicial. También convertiremos la tabla que hemos visto anteriormente en una matriz de probabilidades. Esa tabla vista desde un punto matemático es: \begin{equation} T=\begin{bmatrix}0,42 & 0,46 & 0,12 \\ 0,45 & 0,44 & 0,11 \\ 0,47 & 0,48 & 0,05\end{bmatrix} \end{equation} Para aplicar Markov lo que hay que hacer es una multiplicación de matrices entre el vector inicial y la matriz de probabilidades. En este ejemplo vamos a suponer que la posición en la que estamos que la última vela es de bajada, así que vamos a empezar por el estado “Baja” (o también ). Así que haremos la multiplicación así: \begin{equation} P = \begin{bmatrix}0,42 & 0,46 & 0,12 \\ 0,45 & 0,44 & 0,11 \\ 0,47 & 0,48 & 0,05\end{bmatrix} \end{equation} Como recordatorio rápido de la multiplicación de matrices (para profundizar más) vamos a decir que lo que hay que hacer es multiplicar por cada columna (primer número por el de arriba, segundo número por el del medio y tercer número por el de abajo) y sumar los valores que nos da en cada columna. Es decir, en nuestro caso sería algo así: \begin{equation} P = \;\; \end{equation} Después se realiza la suma normal de cada columna y así a su vez tendremos las probabilidades de cada estado. \begin{equation} P = \end{equation} Esto podríamos decir que es la primera predicción que hacemos para saber las probabilidades del siguiente estado. En este caso las probabilidades de que la siguiente posición sea de subida son del 45%, de bajada del 44% y de que se quede igual son del 11%. Pero, ¿y si quisiéramos conocer las probabilidad de otro estado más? ¿Cuales son las posibilidades dentro de dos días de cada vela? Pues para hacer esto sería igual pero el vector de inicio sería el que acabamos de calcular, ya que partimos del estado que hemos intentado predecir. Con lo que la ecuación quedaría así: \begin{equation} P=\begin{bmatrix}0,42 & 0,46 & 0,12 \\ 0,45 & 0,44 & 0,11 \\ 0,47 & 0,48 & 0,05\end{bmatrix} \end{equation} Los pasos a seguir son los mismos que en la operación anterior, así que toca multiplicar el vector nuevo por la matriz de probabilidad que ya conocíamos: \begin{equation} P = \;\; \end{equation} Y con esto tendremos las probabilidades de como puede ser la vela dentro de dos días: \begin{equation} P = \end{equation} Si quisiéramos saber cuanta serían las probabilidades en un tercer estado, cuarto o quinto sería igual, siempre la multiplicación de matrices con el estado previo. Y esto es todo lo necesario para entender las cadenas de Markov desde el punto de vista matemático. Ahora incluso podríamos calcular con lápiz y papel las probabilidades de las próximas velas, pero para nosotros no es necesario ya que teneos software que lo puede hacer por nosotros de una manera más rápida y más simple. Vamos a verlo. Implementación en python Podemos ver las cadenas de Markov con la librería pydtmc, y dentro de esa librería la clase MarkovChain. Veamos como funciona esta librería: from pydtmc import MarkovChain Instanciamos directamente la clase que nos interesa ya que pydtmc trae otras muchas funcionalidades que no vamos a utilizar. Después solo tenemos que crear nuestra matriz de probabilidad y pasársela directamente en la inicialización de la clase, junto con los nombres de cada estado. matriz = ,,] cadena_markov = MarkovChain(matriz, ) La forma simple de ver cuales son las probabilidades del tercer paso es: print(cadena_markov.redistribute(3,'Baja')) # Salida: Aquí le pasamos el número de pasos que queremos que nos den las predicciones (en este caso el del tercer día) y el estado inicial en el cual queremos empezar (en este caso ‘Baja’), con ello ya nos dará la distribución de los próximos siguientes eventos. Esto ya se ve más fácil, y no hace falta saber muchas matemáticas, con tener los cálculos de las probabilidades es suficiente. Eso sí, el cálculo de estas probabilidades es algo que os lo tenéis que currar, aunque no es difícil saber las probabilidades de una vela después de otra con un simple script en Python. Posibilidades en el trading Existen muchas formas de sacar ventaja de esta forma simple de la cadena de Markov (realmente hay más formas y el tema puede dar para rato), aquí vamos a exponer unas pequeñas pinceladas para que sepáis como el estudio de la probabilidad os puede ayudar en el trading. Esta claro que si miramos solo velas individuales las posibilidades son prácticamente del 50% de que suba o baje, es decir como tirar una moneda al aire. Pero ¿qué pasaría si empezásemos a mirar dos o más velas? ¿Y si empezamos a mirar patrones? En estos casos las probabilidades serían muy distintas y los casos serían un poco más complejos. El dígrafo podría ser diferente y más complejo. No habría una conexión total entre todos los posibles estados y seguramente las probabilidades de ir de un estado a otro cambiarán. ¿Y si con indicadores técnicos sacamos nuestros propios estados (imagina los estados y luego miramos las probabilidades de cambio entre varios de ellos a los largo de los días? Como se puede ver, con solo pensar un poco ya aparecen muchas otras formas de poder usar la forma más simple de Markov. El resto ya os lo dejo a vuestra imaginación y a que os entretengáis sacando probabilidades de vuestros conjuntos de datos. Conclusiones Aunque este ejemplo puede llegar a ser un poco tonto creo que era necesario para poder entender bien qué es la cadena de Markov y porque funciona como funciona. Las cadenas de Markov aun pueden ser mucho más complejas e incluso se le pueden añadir otras características, como las recompensas, acercándonos mucho más al aprendizaje por refuerzo, pero que explicaré en otro momento. Las cadenas de Markov son también claves para entender otros procesos que también veremos más adelante como el método Montecarlo, pero no penséis que el tema de las cadenas de Markov acaba aquí, o invito a seguir investigando un poco sobre este tema y otras ecuaciones que derivan de ella. Es un tema muy interesante y que os puede dar muchas ideas para aplicar en vuestro trading. Como siempre cualquier duda o aclaración no dudéis en ponerla en los comentarios o enviarme un mensaje y os contestaré lo antes posible. [...] Leer más...
Como hemos visto anteriormente para conectar nuestro robot con nuestro broker podemos hacerlo a través de un programa que es un viejo conocido para todos los que hemos hecho operativa manual: Metatrader, ya sea en su versión 4 o en la versión 5. Optimizar Metatrader puede parece algo que nunca es necesario, pero en trading algorítmico puede ser crítico. Tanto la cantidad de memoria como la CPU son dos aspectos muy importantes a cuidar cuando estamos haciendo trading algorítmico. Quedar escaso de uno u otro puede traer consecuencias imprevisibles a nuestro trading. Un retraso al hacer los cálculos necesarios antes de hacer el trading puede hacer que el sistema entre tarde y la entrada no sea correcta. Metatrader viene con muchas funcionalidades para realizar un trading manual, pero nosotros solo lo utilizaremos como herramienta para conectarnos al broker. Como no queremos que nada más esté ocupando los recursos de la máquina, es interesante optimizar Metatrader con las mínimas opciones posibles para que consuma menos recursos en la máquina donde esté funcionando nuestro robot y que nuestro robot tenga acceso a todos los recursos de la máquina. Así que vamos a ver como poner a dieta a nuestro Metatrader para nuestros fines. Optimizando la gráfica Lo primero que hay que hacer es cerrar todas las ventanas que no nos sirvan y dejando solo aquellas ventanas con las que realmente vayamos a realizar las operaciones. Si por ejemplo solo vamos a hacer operaciones con el EURUSD es un gasto de recursos innecesario tener abiertas el resto de ventanas, así que solo habría que dejar esta. Los indicadores tampoco son necesarios así que es mejor borrarlos, ya que también ocupan memoria sin que sea necesario. Si quisiéramos indicadores los implementaríamos en nuestro código para hacer nuestros cálculos. Por esta razón, tenerlos en la pantalla de Metatrader no nos sirve de nada más que para consumir recursos. Para borrarlos simplemente damos botón derecho sobre la ventana y luego le damos a “Eliminar ventana del indicador”, y con ello nos quedará la ventana limpia. Si tenemos la ventana de hacer trading con un solo click (que sale arriba a la izquierda) también debemos desactivarla ya que tampoco nos sirve. Esto se hace haciendo click en la pantalla y pulsando en “Trading de un solo click”. Si tenemos algún indicador más como en este caso (que se nos muestran las bandas de bolinger) también las vamos a quitar. En este caso hacemos click derecho sobre ellas y las quitamos seleccionando “eliminar indicador”. Después de esto ya tenemos la pantalla lista para nuestros fines. Barra lateral Si nos fijamos ahora en la izquierda de la pantalla veremos que tenemos muchos símbolos que también podemos eliminar. Para ello damos botón derecho sobre la lista y damos luego a “Ocultar todo” y con ello solo nos quedarán los símbolos que tenemos en la ventana. Opciones de Metatrader Luego iremos a herramientas→Opciones donde veremos alguna configuración más. Lo primero es ir a la pestaña de “Asores Expertos” y tener marcado todo lo que tenemos. Si ya tenemos un asesor experto funcionando esto lo tendréis ya hecho, pero si estáis configurando metatrader por primera vez para vuestro trading esto es esencial para que funcione vuestro robot. Después de esto iremos a charts. En esta pestaña podemos configurar dos cosas, las barras de historial que nos devolverá Metatrader cuando arranquemos y las barras que mostraremos en el gráfico. El “Max. barras en historial” es importante porque al comenzar nuestro robot puede ser que necesitemos datos atrasados para nuestro trading para hacer algún cálculo. Si por ejemplo queremos calcular la media de 200 tendremos que tener 200 barras al comenzar, con lo cual en este valor hay que poner 200. También vamos a quitar los eventos de sonido ya que nos los necesitamos para nada si lanzamos esto en un servidor. Para ello nos vamos a la pestaña “Eventos” y nos aseguramos que el checkbox de “Activar” no esté activo. Luego presionas “Aceptar” y listo, ya lo tenemos todo preparado para que nuestro Metatrader consuma lo menos posible donde lo tengamos funcionando. Lógicamente también podemos ocultar tanto la barra lateral como la inferior y con ello conseguiremos dejar la pantalla completamente anulada. Es lo más parecido a tener el programa funcionando en segundo plano sin tener un entorno gráfico (Algo que Metaquotes podría apuntar para un futuro desarrollo) Conclusiones Como hemos dicho al comienzo de la entrada cuidar la máquina en donde se encuentran nuestros robots funcionando es vital, y hay que cuidar que todos los aspectos de la máquina donde se ejecuta para que nunca se quede sin recursos. Como hemos visto con unos pocos pasos tendremos nuestra plataforma lista para realizar nuestro trading con un Metatrader muy liviano, pero aun así cumpliendo su labor perfectamente. Como 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. [...] Leer más...
En el artículo de conexión a Darwinex ya comentamos un poco como es el funcionamiento de ese broker y como nos puede apoyar si somos buenos con nuestra operativa. Hoy vamos a tratar como realizar la descarga de datos desde este broker para utilizar sus mismos datos. Como ya sabéis tener buenos datos es esencial para nuestro trabajo de trading algorítmico (como para todas las tareas realizadas en machine learning) y es importante que si vamos a trabajar con un broker realizar el entrenamiento con los datos del propio broker y de esta forma no caeremos en el error de utilizar otros datos que pueden no coincidir con los de Darwinex a la hora de operar. Darwinex no lo pone tan fácil como podemos estar acostumbrados a conseguir estos datos y es posible que esto sea una gran barrera para muchos, así que con esta entrada voy a intentar facilitaros un poco esta tarea para que podáis realizar entrenamientos también con este bróker. Y seguro que final os daréis cuenta que los datos que nos da Darwinex pueden darnos ventaja respecto a otras descarga de datos Conseguir el acceso El primer paso que tenemos que realizar para poder realizar la descarga de datos de Darwinex es solicitar el acceso a los mismos, que se realiza desde una página que se encuentra en la web: https://www.darwinex.com/es/tick-data y luego dando al botón “Obtener acceso FTP”. Para conseguir el acceso al FTP y la descarga de datos os piden los datos necesarios para abrir una cuenta, pero no os preocupéis, no hay necesidad de hacer un ingreso para conseguir descargar los datos y tener nuestro entorno de prueba. Una vez que rellenéis todos los datos en poco tiempo ya os enviarán un correo con vuestros datos para poder acceder al FTP. Donde os envían tanto la dirección a la que debemos conectar como vuestro nombre de usuario y contraseña (que es totalmente distinto al de vuestra cuenta ya que son dos entornos separados. Acceso al FTP Voy a explicar que es esto del FTP (resumidamente y sin tecnicismos) ya que puede parecer un poco raro al principio. Estamos más acostumbrados a que el acceso a los datos de la operativa sea por una API o incluso por una librería que nos permita descargar los datos directamente con Python y tenerlos en un formato cómodo para tratarlo. En este caso el acceso no es así, sino por FTP. FTP es un protocolo de transferencia de datos que nace incluso antes de lo que ahora conocemos como internet, y permite descargar ficheros de manera muy rápida y segura sin mucho esfuerzo. La forma de hacerlo es similar a navegar por el sistema de carpetas del servidor y cuando veamos un fichero que estamos buscando descargarlo sin problemas. Una vez que tenemos el usuario y contraseña ya podemos acceder al FTP de Darwinex para realizar la descarga de datos. Si queremos hacerlo de manera simple se podría hacer con herramientas como Filezilla, en la cual introduciendo nuestro usuario y contraseña podremos ver todo el directorio. En la imagen vemos como nos hemos conectado al FTP de Darwinex y hemos entrado en la carpeta de Apple (AAPL). Dentro de esta carpeta vamos que existen ficheros que son los ASKs y los BIDs de cada hora de operativa. Si descargamos, descomprimos (vienen en formato .gz que es un comprimido) y abrimos uno de estos ficheros veremos que es un .csv normal con tres datos: la fecha en un formato UNIX (que luego transformaremos), el precio de la compra, y la cantidad que se ha comprado: 1618234260475,132.61,1500.0 1618234260731,132.57,1500.0 1618234260797,132.58,1500.0 1618234261623,132.59,1500.0 1618234261681,132.55,1500.0 1618234262326,132.54,1500.0 1618234262378,132.55,1500.0 1618234262492,132.54,1500.0 1618234262886,132.53,1500.0 1618234263527,132.52,1500.0 1618234263587,132.49,1500.0 1618234264271,132.46,1500.0 1618234264546,132.48,1500.0 1618234264608,132.51,1500.0 1618234264662,132.52,1500.0 Simple, no? Veamos como conectarnos con Python y como hacer algo de magia con esto. Conexión y descarga de datos con Python La conexión con Python es muy sencillo solo necesitamos la librería “ftplib” para conectarnos así que esto será lo primero que hay que hacer: import ftplib Una vez instanciada la librería la conexión es muy sencilla. En una línea se realiza la conexión y se mete en una variable: # Abrir la conexión FTP ftp = ftplib.FTP('tickdata.darwinex.com', 'TU_USUARIO', 'TU_CONTRASEÑA') La forma de descargar una fichero es muy sencilla. Imaginemos que queremos descargar los datos de Apple de las 17:00 horas del día 27 de Junio de 2022 . Sería tan sencillo como este comando: # Descargamos el fichero ftp.retrbinary("RETR /AAPL/AAPL_BID_2022-06-27_17.log.gz" ,open("Apple.log", 'wb').write) Con esto ya tendremos un fichero llamado “Apple.log” en nuestro directorio local dentro de la carpeta donde ejecutemos este script. Pero como he dicho antes, el fichero es un .csv pero está comprimido, así que hay que hacer es descomprimirlo y leer el .csv como hacemos otras veces para transformarlo en formato dataframe. Para hacer esto hay que importar dos nuevas librerías, con la que descomprimiremos el fichero y, una vieja conocida, la librería pandas para el manejo de los datos. import gzip import pandas as pd # Abrimos el fichero con los logs with open('Apple.log', 'rb') as fd: # Descomprimos el fichero gzip_fd = gzip.GzipFile(fileobj=fd) # Metemos los datatos en un dataframe df = pd.read_csv(gzip_fd,names=) Con esto ya tenemos en la variable “df” el dataframe con los datos. Las columnas del dataframe las he puesto como “Date”, “Price” y “Size”, pero esto ya es gusto personal y podéis poner lo que os sea más cómodo. Si vemos que hay dentro de las variables pero todavía tendremos la fecha en el formato UNIX. Para transformarla solo hace falta esta línea: df = pd.to_datetime(df,unit='ms') Y si vemos la variable “df” ya veremos algo así: Con esto ya podríamos empezar a trabajar ya que lo tenemos en un formato perfecto para empezar a realizar nuestro Machine learning o Aprendizaje por refuerzo. Descargar más datos Con lo anterior hemos conseguido realizar la descarga de datos, pero solo un fichero de una hora y la hemos puesto en el formato correcto para realizar nuestro trabajo, pero ¿Si quiero descargar más datos, como una semana entera, cómo hago eso? Vamos a ello. La forma de hacerlo sería creando un bucle que me descargue todos los datos que necesitemos. from datetime import date, timedelta import os fecha_inicio = "26-06-2022" fecha_fin = "27-06-2022" # Creo la carpeta data para guardar los datos try: os.mkdir('data') except: pass # Preparo las fechas para trabajar más fácil con ellas fecha_inicio_split = fecha_inicio.split("-") fecha_fin_split = fecha_fin.split("-") fecha_inicio_datetime = date(int(fecha_inicio_split), int(fecha_inicio_split), int(fecha_inicio_split)) fecha_fin_datetime = date(int(fecha_fin_split), int(fecha_fin_split), int(fecha_fin_split)) # Calculo la diferencia entre las fechas para ir hacíando el bucle # que va descargar todos los datos delta = fecha_fin_datetime - fecha_inicio_datetime for i in range(delta.days + 1): day = fecha_inicio_datetime + timedelta(days=i) # Pongo para que descargue todas las horas para casos de divisas # Si no encuentra el fichero (al ser una acción normal) continua for i in range(24): hora = str(i).rjust(2, '0') try: download_file = TICKER+"_BID_"+str(day.year)+"-"+str(day.month).rjust(2, '0')+"-"+str(day.day).rjust(2, '0')+"_"+hora+".log.gz" ftp.retrbinary("RETR /"+TICKER+"/"+download_file ,open("data/"+download_file, 'wb').write) except: pass Con este código indicamos al principio las fechas desde las que queremos descargar y luego el código hace el resto. Para leer todo lo descargado y meterlo en un dataframe se haría lo siguiente: from os import listdir from os.path import isfile, join onlyfiles = appended_data = [] for stock_file in onlyfiles: with open("data/"+stock_file, 'rb') as fd: gzip_fd = gzip.GzipFile(fileobj=fd) appended_data.append(pd.read_csv(gzip_fd,names=)) df_stock = pd.concat(appended_data) df_stock = pd.to_datetime(df_stock,unit='ms') De esta forma en la variable df_stock tenemos ya el dataframe con el que ya podemos empezar a trabajar para realizar todos nuestros proyectos. Sacar los datos OLHC en diferentes rangos temporales Vale, hasta el momento tenemos toda la operativa pero normalmente estamos acostumbrados a trabajar con los datos de las velas japonesas y con los precios de apertura, máximo, mínimo y cierre (o olhc). ¿Como sacamos estos datos? Pues con pandas esto se hace muy fácil. Lo único es que hay que poner la fecha como el índice del dataframe pero una vez hecho esto lo resolvemos en par de líneas. Vamos a ver un ejemplo de como hacerlo para lo que serían velas de 15 minutos. df_stock = df_stock.set_index('Date') stock_15min_ohlc = df_stock.resample('15Min').ohlc(_method='ohlc') stock_15min_ohlc = df_stock.resample('15Min').sum() Una vez hecho esto ya podemos ver que en la variable stock_15min_ohlc tenemos todos los datos en el formato ohlc listo para trabajar. Conclusiones Aunque al principio parece complicado la descarga de datos de Darwinex vemos que al final los datos que nos permiten descargar nos da más información de la que nos ofrecen otras plataformas al darnos los datos de cada movimiento del mercado. Con los scripts que os he dejado aquí y con la conexión del otro artículo ya podéis empezar a trabajar utilizando Darwinex en todo el proceso, desde los datos a la operativa y hacer vuestro propio robot de trading. Como 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. [...] Leer más...
Uno de los elementos más importantes a la hora de ver los datos es poder visualizarlos correctamente. Para ello Python nos da más de una librería para realizar estas visualizaciones y realizar múltiples vistas de como están los datos. Una de las librerías más fáciles de para ver la representación de los datos de cualquier valor dentro de la bolsa es mplfinance. Está librería es mucho menos conocida que otras como matplotlib, pero para ver los datos que tienes de forma rápida es mucho más sencilla y más rápida de entender. Esta entrada está a modo de apuntes para que sea sencillo copiar y pegar los datos adaptándolos a vuestros propios datos, y que con solo tener esta pantalla delante se pueda rápidamente mostrar los datos. Utilizar el índice para ir directamente a la parte que os interese si ya conocéis la librería. Instalación La instalación de la librería mplfinance es como cualquier otra. Ya sea desde vuestro propio ordenador o desde google colab (donde yo suelo trabajar), la forma de instalación es: pip install mplfinance Si estamos trabajando desde google colab, solo hay que poner el signo de exclamación delante: !pip install mplfinance Después de la instalación ya solo nos queda importar la librería dentro de nuestro código: import mplfinance as mpf Obtención de datos El siguiente paso es la obtención de los datos para guardarlos en forma de dataframe de pandas. Aquí no voy a entrar en como realizarlo ya que hay ya artículos sobre ello en el propio blog como este o este, pero si que hay que tener en cuenta un detalle: la fecha tiene que estar como “Index” y tiene que estar en formato datetime. Si tenemos los datos de Apple y una columna con la fecha con el nombre “date”, la forma de hacerlo sería así: # Ponemos la fecha como datetime apple = pd.to_datetime(apple) # Ponemos la fecha como índice apple = apple.set_index('date') Con esto ya tendremos los datos preparados para poder empezar a mostrarlos con la librería con la vamos a practicar. Mostrar los datos La forma más simple de mostrar los datos es la siguiente: mpf.plot( apple, type='candle', title='Apple', ylabel='Precio ($)' ) Y la salida sería: Como vemos está mostrando todos los datos sin ningún formato en particular, pero para tener una visión de qué datos tenemos puede estar bien. Estilos de visualización Dentro de mplfinance existen diferentes estilos de visualización de los datos. Si queremos verlos todos podemos ejecutar la línea: mpf.available_styles() Donde la salida nos mostrará todos los estilos que podemos darle a nuestra gráfica, desde el por defecto hasta el típico de las velas alcistas en verde y las bajistas en rojo. El que nos trae por defecto con los colores que hemos visto en la anterior gráfica, pero podemos cambiarlo desde el clásico: mpf.plot( apple.tail(20), type='candle', title='Apple', ylabel='Precio ($)', style='classic' ) Cuya salida se muestra así: Hasta el que tiene yahoo por defecto: mpf.plot( apple.tail(20), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo' ) Que se muestra así: Depende de gustos, como todo. Podéis probar y quedaros con el que más os guste de entre la oferta que nos dan. Incluir el volumen Para que una gráfica muestre el volumen solo hay que añadir “volumen=True”: mpf.plot( apple.tail(20), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True ) Y veremos la gráfica con el volumen ya incluido: Incluir las medias Hay muchos datos que la propia librería hace el cálculo, como las medias, e incluirlo en la gráfica es muy sencillo. Si por ejemplo queremos incluir las medias de 5 y 20 sería así: mpf.plot( # Aumentamos el número de datos a mostrar para que se vea más fácil apple.tail(200), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5) ) Y ya veremos como salen las medias en nuestra gráfica: Guardar la gráfica Si queremos que la gráfica no se muestre pero se guarde, (lo que resulta muy útil en programas automatizados para saber como se están recibiendo los datos), sería simplemente incluir la opción “savefig” junto con el nombre que queremos darle al fichero de salida: mpf.plot( apple.tail(200), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5), savefig='img.png' ) Quitar los márgenes de la imagen Si queremos quitar los márgenes de la imagen para que la gráfica ocupe toda la imagen hay que incluir la línea “tight_layout=True”: mpf.plot( apple.tail(200), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5), tight_layout=True, ) Y la salida no mostrará el hueco para el título sino que estará dentro de la gráfica, entre otros ajustes: Otros tipos de gráficas Como no todo en la vida son los gráficos de velas japonesas, con la librería mplfinance nos da la opción de realizar otros tipos de gráficos, simplemente cambiando el “type”. Para mostrar una gráfica tipo “ohlc” sería así: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(100), type='ohlc', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5), tight_layout=True, ) También podemos mostrar el gráfico de línea simple: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(100), type='line', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, # Comentamos esta línea de las medias para que no se mezcle con la principal # mav=(20,5), tight_layout=True, ) Y también podemos hacer gráficos menos conocidos, como el Renko: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(200), type='renko', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, tight_layout=True, ) O un gráfico de punto y figura para aquellos que sepan hacer trading con ellos: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(400), type='pnf', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, # Comentamos esto para que salga la figura completa, sino las letras entorpecian # tight_layout=True, ) Días que no hay trading En algunos casos puede ser interesante ver los días que no hay trading, y mplfinance nos lo pone muy fácil, ya que con incluir la línea “show_nontrading=True” lo veremos: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(100), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5), tight_layout=True, show_nontrading=True ) Y en la gráfica veremos como se muestran los huecos correspondientes a los días en los que no hay operativa de trading: Cambiar el tamaño de la gráfica También puede ser que la gráfica sea pequeña o grande para los datos que queremos mostrar, esto se puede ajustar mediante el parámetro “figratio”: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(100), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5), tight_layout=True, show_nontrading=True, figratio=(10,5) ) Y vemos como cambiamos el aspecto respecto al gráfico anterior: Quitar los ejes Otra de las opciones que nos da la librería es la posibilidad de quitar los ejes mediante la línea “axisoff=True”. Lo que puede ser útil cuando queremos ver la gráfica sin ningún tipo de ruido: mpf.plot( # Aumentamos el número para que se vea más fácil apple.tail(100), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(20,5), tight_layout=True, show_nontrading=True, figratio=(10,5), axisoff=True ) Y como vemos la vista sin los ejes es mucho más limpia. Incluir una subgráfica En muchos casos es necesario incluir otros datos en una gráfica separada. Aunque ya empieza a complicarse un poco más el código aun así es más sencillo que en otros casos. Lo primero es crear una variable con los nuevos subgrafos que queremos mostrar: ap0 = .tail(100),color='#ffa500', panel=0, title="VWAP") ] En este caso solo incluimos un subgrafo con el valor del VWAP y lo ponemos en la posición 0. Si quisiéramos añadir más gráficos solo habría que incluir una línea por cada subgrafo nuevo e ir añadiendo números secuenciales a la variable panel. Después de esto la creación del gráfico sería así: mpf.plot( apple.tail(100), panel_ratios=(.05, .2, .05), type='candle', title='Apple', ylabel='Precio ($)', style='yahoo', volume=True, mav=(50, 20,5), show_nontrading=True, figratio=(10,5), addplot=ap0, main_panel=1, volume_panel=2, num_panels=3, ) Las novedades aquí son: panel_ratios: Donde se pone lo que se quiere que ocupe cada panel add_plot: En el cual se pone la variable anterior con los distintos subgrafos main_panel: Que sería el número siguiente al último “panel” que hemos puesto en los subgrafos. volume_panel: Con el número siguiente al que haya en main_panel num_panels: Con el total de subgrafos que tenemos en la gráfica. El resultado de esto sería así: Conclusiones Aunque la entrada ha sido un poco larga creo que era necesario para poder incluir las opciones más importantes que nos da esta librería y tenerlas siempre a mano. Como hemos visto la versatilidad de la librería mplfinance es bastante grande y la simpleza para realizar las previsualizaciones es muy grande. Aunque no ofrece tantas opciones como otras librerías más complejas creo que para las visualizaciones básicas es suficiente. En alguna ocasión podemos llegar a ver como se mezcla esta librería con matplotlib creando gráficas mucho más complejas pero eso ya es materia para otra entrada. [...] Leer más...
Siempre que hablamos de machine learning se muestra el método para encontrar un algoritmo capaz de conseguir unos resultados esperados: clasificación, detección de anomalías, pronósticos, etc. Pero una vez que conseguimos los resultados nos podemos dar cuenta que es muy costoso también poner ese modelo en producción, es decir, ponerlo a funcionar en un entorno real. Lo más importante es saber como guardar un modelo y luego volver a cargarlo. Esto depende un poco de con qué hayáis hecho el modelo ya que varía si lo haceis con Scikit-Learn, tensorflow, pytorch o, si estáis haciendo aprendizaje reforzado, stable baselines 3(aunque hay más yo aquí me centraré en estos que son las principales librerías para hacer ML). En este artículo vamos a ver el código necesario para realizar el guardado y carga en cada una de estas librerías, y que será el primer paso para poner nuestro modelo a funcionar en un entorno que no requiera de nuestra interacción. Scikit-Learn Si estamos realizando Machine Learning utilizando las funcionalidades que nos aporta la librería Scikit-Learn (una de las mejores para clasificación, regresión y clustering, entre otras) es muy sencillo guardar los datos de nuestro modelo. Para ello utilizaremos la librería Pickle, una librería que implementa una serie de funcionalidades para la serialización y des-serialización de objetos en Python. La forma de guardar un modelo con esta librería es: import pickle pickle.dump(model, open('trading_model.p', 'wb')) La extensión no tiene por que ser esa pero yo la uso así para saber que se trata de un fichero guardado con Pickle y cuando vea este fichero en el futuro, de un vistazo, ya pueda saber cómo ha sido guardado y cómo tengo que volver a cargarlo. Para cargar los datos sería: import pickle loaded_model = pickle.load(open('trading_model.p', 'rb')) Aunque el formato Pickle es muy sencillo, como Scikit-Learn utiliza conceptos sencillo sin hiperparámetros que regular, es posible guardarlo en este formato sin necesitar otros datos. Tensorflow Una vez creado el modelo la forma de guardar los modelos de tensorflow es con HDF5. Aunque también se puede guardar en otros formatos como JSON, actualmente se está imponiendo la forma de guardar los modelos mediante este formato, ya que mejora en muchos aspectos a las anteriores formas de guardar los modelos. En JSON por ejemplo se guarda por un lado el modelo y por otro los pesos de los hiperparámetros del modelo. No es que sea mucho más complicado, pero es un paso a más a tener en cuenta. Con lo cual es mucho más sencillo guardar un modelo y usarlo más tarde utilizando este formato. La forma de guardar un modelo que ya ha sido entrenado es: # Venimos de un model.fit() ejecutado correctamente model.save('trading_model.h5') Y para cargarlo posteriormente: from keras.models import load_model model = load_model("trading_model.h5") Al contrario que sucedía en Scikit-Learn, el guardado de un modelo en tensorflow sí que necesita de no solo la forma de la red neuronal, sino también de otros muchos parámetros como: PesosArquitecturaDetalles de compilación del modelo (pérdidas y métricas)Estado del optimizador del modelo Pero al realizar el guardado con HDFS5 esto viene todo incluido, lo que facilita mucho la tarea. Pytorch Aunque los modelos desde pytorch también se pueden guardar con el formato pickle, esta librería también trae su propio sistema de guardar modelos (que de hecho utilizan “pickle.dump()” y “pickle.load()”). La forma de guardar un modelo con esta librería es la siguiente: torch.save(model, "trading_model.pt") Al igual que sucede con Tensorflow, con esta forma no solo guardamos los datos del propio algoritmo sino también los pesos, arquitectura y otros detalles que necesita la librería para una correcta carga. model = torch.load("trading_model.pt") Una vez que ya tenemos la variable “model” ya podemos trabajar con el modelo tal y como lo hubiéramos hecho en el propio proyecto en el cual se guardó. Stable Baselines 3 Si estamos haciendo modelos de aprendizaje reforzado ya nos tendremos que tirar por esta librería, que ya hemos visto en otras entradas. La forma de guardar un modelo con esta librería también es muy sencilla: model_PPO.save("trading_model_ppo.sb3") Para cargar el modelo en este caso se complica un poco más ya que hay que saber el algoritmo con el que se ha generado el modelo anterior (de hay que yo ponga un “_ppo” para reconocer que este modelo se ha hecho con el algortimo de Proximal Policy Optimization). Así que para cargar el modelo anteriormente generado con este algoritmo tendremos que importar el algoritmo y luego hacer un “.load”: from stable_baselines3 import PPO loaded_model = PPO.load("trading_model_ppo.sb3") Una vez cargado el modelo con el algoritmo correspondiente ya podemos empezar a trabajar de forma normal. Conceptos importantes para guardar un modelo No todo es tan sencillo como parece, hacerlo como se ve en muchos tutoriales por internet esta chupado, porque es el mismo código en donde se hace el “save” y el “load” del modelo, pero al hacer el guardado en un entorno y cargarlo en otro pueden surgir problemas. Hay que tener en cuenta que los datos que tiene que recibir el nuevo algoritmo tienen que tener el exactamente el mismo forma que con los que se ha realizado el guardado. Si varía algo en la estructura de los datos el modelo puede no funcionar o mostrar unos resultados completamente distintos a los que esperábamos. Otro detalle importante es que las versiones con las que estemos trabajando sean las idénticas. Me he encontrado muchos errores que eran debidos a un cambio en la versión, no solo de la librería con la que estemos trabajando, sino con la versión de Python con la que estamos haciendo nuestro código. Conclusiones Guardar un modelo y volver a cargarlo con los datos de nuestros algoritmos es uno de esos detalles que son cruciales pero poca gente tiene en cuenta, ya que no forma parte de, lo que llamaré, la parte divertida de hacer Machine Learning. Este problema surge cuando quieres realmente pasar a la acción con tu código y es ahí donde empiezan los dolores de cabeza. Tener claro cual es la librería que utilizamos, la versión de python que tenemos y como son los datos que estamos entregando al modelo son las partes que hay que tener muy claras a la hora de pasar un modelo a real. Tres pasos importantes que, si uno sale mal, puede que nuestro algoritmo no funcione como esperábamos. [...] Leer más...
Uno de los grandes problemas que sucedía con el aprendizaje por refuerzo es que no existía una base común que reúna todos los posibles agentes que se hacían para poder ser comparados. Debido a esto cada programador hacía su propio entorno, lo que hacía que fuera muy difícil poder comparar entre un agente desarrollado por una persona y otro desarrollado por otra persona. Cada programación se hacía su propio entorno que, normalmente, solo era válido ese agente. Algo similar a este problema es lo que yo mismo he hecho en la anterior entrada sobre aprendizaje por refuerzo. En ella creamos un entorno para jugar a tres en línea desde cero, creando todo, desde el entorno hasta el modo de crear un poco de inteligencia. Para intentar resolver este problema y para, además, hacer la vida más fácil a los programadores surge stable baselines (que ahora se encuentra ya en su versión 3). Para ver realmente como funciona este framework vamos a hacer lo mismo que en la entrada anterior: Un tres en raya. Así que vayamos a ello. ¿Qué es stable baselines 3? La respuesta más sencilla es decir que esta librería sirve para ofrecernos unas implementaciones de algoritmos de aprendizaje por refuerzo utilizando pyTorch. Es decir, que nos fácilita mucho más la creación de algoritmos para nuestros agentes, lo que antes nos iba a costar programar un buen rato, utilizando stable baselines 3 nos saldrán muy pocas líneas de código. Otro de los placeres que nos brinda utilizar esta librería es que tiene muy buena documentación (eso sí, en perfecto inglés) lo cual hace que la curva de aprendizaje para realizar aprendizaje por refuerzo no sea tan elevada. En la documentación nos podemos encontrar desde como hacer la instalación hasta ejemplos muy complejos, que merecen la pena ser analizados para ver entender como realizan ellos mismos el código. Además de que su código ha sido muy probado, con lo que la fiabilidad es muy alta, está basado en la interfaz más importante que existe sobre aprendizaje reforzado OpenAI Gym. Todos los algoritmos que implementa stable baselines 3 tienen detrás código de OpenAI, lo cual es una garantía de seguridad. La instalación de stable baselines es tan sencilla como cualquier otra en python. Solo hace falta poner: pip install stable-baselines3 Pero dejémonos de presentaciones y vayamos al grano que es lo que estamos deseando. También comentaros que todo el código fuente de esta entrada lo tenéis en mi github (o en la sección de código fuente), donde he colgado el cuaderno Jupyter con el que he hecho esta entrada (en el cual he utilizada google colab, por si queréis probar vosotros también) La clase principal GYM Antes de empezar con el código principal hay que hacer unos imports que nos van ser utilidad: import numpy as np # Para los tipos de las variables import gym # El entorno del gimnasio from gym import spaces # Para la declaración del entorno import random # Para hacer un jugador aleatorio sin mucha inteligencia La clase que vamos a generar tiene que heredar todo lo que tiene la clase gym.Env, y necesita que tenga dentro lo siguiente: __ init__: El sitio donde es obligatorio crear dos variables: self.action_space y self.observation_space. Estas dos variables solo pueden ser de varios tipos pero las que más se usan son: “Discrete” para espacios de una dimensión y “Box” para espacios de más dimensiones.Reset: devuelve un valor dentro del “observation_space” donde, como su palabra indica, se resetearán los valores del entorno a los iniciales. Si se usa Discrete tiene que devolver un integer, y si se usa box un numpy.array.Step: Esta función tendrá un parámetro de entrada que se llamará action y que estará dentro del “action_space”. En esta variable es donde el agente lleva la acción que va a hacer y el entorno le devuelve el estado en el que se encuentra después de esa acción. El valor de retorno es una tupla cuádruple (en este orden):State: es igual que la variable que devuelve Reset, un valor para action_space.Reward: El numero de la recompensa que ha recibido el agente por su acción.Done: Cuando se acabe la tarea devolverá True (y habría que hacerle un reset) mientras tanto será False.Info: Un diccionario con información complementaria de la ejecución.Render: Es la función que hará que el resultado que tenemos en “state” se muestre de una forma más entendible para los humanos. Para esto también hay que definir al inicio la variable “metadata = {‘render.modes’: }”.Close y seed: Estas dos funciones no las vamos a necesitar, al menos por ahora, ya que “close” se utiliza para dar por finalizada la ejecución y limpiar el sistema y “seed” es para cuando utilicemos una variable aleatoria y queremos que el resultado sea reproducible. El código que vamos a introducir en la clase será muy similar al que introducimos en el anterior juego de 3 en raya desarrollado desde cero, pero adaptado a stable baselines. Además de las librerías obligatorias incluiremos algunas nuevas. Como no hemos querido complicar el código en exceso, nuestro agente siempre empezará él la partida y otro jugador simplemente pondrá fichas aleatorias sin mucho sentido. Con ello simplificamos algo más el código y así veremos resultados antes. Probar la clase Stable baselines 3 nos proporciona una función que comprueba si la clase está bien desarrollada y tiene todo lo necesario para poder llevar a cabo un aprendizaje por refuerzo (otra cosa es que la lógica y las recompensas estén bien, claro). El código para hacer esta comprobación es muy simple: from stable_baselines3.common.env_checker import check_env env = tresEnRaya() check_env(env) Si se ejecuta este código y no devuelve nada la clase estará bien hecha y preparada para hacer el aprendizaje por refuerzo. Si algo falla aquí nos devolverá un error indicándonos de forma bastante precisa donde se encuentra el fallo en la clase que hemos generado. No se trata de un error normal que nos devolvería Python en condiciones normales, ya que aquí comprueba que la estructura de la clase sea la correcta para hacer el aprendizaje, cosa que Python no realizaría. Es muy normal que si hacéis este proyecto en Jupyter y ejecutáis este código en una celda funcione correctamente, pero luego al probar la clase os falle, lo cual significa que el código es correcto para Python, pero no para stable baselines. Probar el entorno El siguiente paso es probar el entorno. Esto también nos lo facilita bastante stable baselines, ya que solo son necesarias 2 líneas para hacerlo (sin incluir los imports): from stable_baselines3 import PPO from stable_baselines3.ppo.policies import MlpPolicy env = tresEnRaya() model = PPO(MlpPolicy, env, verbose=0).learn(int(50000)) Esta parte requiere un poco más de explicación ya que aquí está la parte en la que se le introduce la forma en la que queremos que haga el aprendizaje. En nuestro caso hemos utilizado PPO y la política MlpPolicy, pero existen muchas otras, como podéis observar en la siguiente imagen. También como se puede observar en la última línea, hemos puesto un entrenamiento de 50.000 partidas. Lo cual ya es bastante para este caso de prueba. Probar el entorno Después de todo el entrenamiento ya estamos listos para probar como funciona nuestro agente con la nueva inteligencia artificial que ha aprendido. Para ello utilizamos el siguiente código: env = tresEnRaya() recompensas_finales = [] num_episodes = 5 for i in range(num_episodes): recompensas_episodio = [] done = False obs = env.reset() while not done: action, _ = model.predict(obs) obs, reward, done, info = env.step(action) recompensas_episodio.append(reward) env.render() recompensas_finales.append(sum(recompensas_episodio)) Con esto haremos que el agente con el entrenamiento realice 5 partidas, y las puntuaciones que vaya obteniendo por cada partida las vamos a ir almacenando en la variable “recompensas_finales”. Como se ve en cada iteración se resetea el entorno entero y luego se entra en un bucle en el cual el agente va dando predicciones y va almacenando las recompensas por episodio (por si las queremos luego comprobar una a una, que siempre viene bien para hacer debug). Después de que termine cada iteración hacemos un “render” para mostrar como quedó el tablero de juego en cada partida. Conclusiones Como se ha podido ver programar con stable baselines hace que la programación sea mucho más sencilla que cuando realizamos el mismo juego desde cero. La programación del algoritmo ya viene predefinida y no es necesario pensar como nuestro agente va aprender desde cero, sino que podemos ir probando los diferentes algoritmos hasta probar cual se adapta mejora a nuestro agente. El agente para el tres en raya que hemos desarrollado todavía es muy mejorable: solamente juega empezando él la partida, siempre con las mismas fichas; y seguro que hay más detalles que son mejorables, pero no era el fin de esta entrada hacer un juego perfecto sino hacer una pequeña introducción a stable baselines para realizar aprendizaje reforzado. Espero que os hayan quedado claras las bases de como hacerlo. Como siempre, cualquier duda o aclaración os podéis poner en contacto conmigo por cualquiera de los medios disponibles para ello. [...] Leer más...
Estamos cansados de escuchar a gurús que ganan millones en un día, pero todos sabemos que eso no es cierto. Es posible que tengas un buen día, pero lo difícil es tener buenos días siempre y tener unas ganancias estables a lo largo del tiempo. Eso es precisamente lo que hacen los fondos de inversión, conseguir una rentabilidad alta y sostenible a través del tiempo. Si miramos las ganancias históricas de los fondos de inversión siempre vemos que suelen tener unas ganancias anuales mayores del 20%, incluso alguna puede llegar a superar un 30%, pero es lo menos común. Pero hay un fondo que nunca aparece en estas listas aunque tiene unas ganancias superiores, “Medallion” un fondo de inversión de la empresa “Renaissance Technologies” creada por Jim Simons que utiliza el trading algorítmico para conseguir estas cifras. Pero ¿Quién es Jim Simons? ¿Cómo hace para tener un fondo tan potente? En este artículo voy a analizar un poco a Jim Simons y a su empresa para intentar analizar como consigue estas cifras. ¿Quién es Jim Simons? Para aquellos que no lo conozcan, y resumiendo mucho, es un genio matemático que fue profesor del MIT y de Harvard, creador de la teoría Chern-Simons, ganador del premio Oswald Veblen de Geometría y que además estuvo descifrando códigos para el Instituto de análisis de Defensa (o IDA en inglés) de los EEUU. Aunque de este último fue expulsado al oponerse a la guerra de Vietnam. Jim Simons en su etapa en el IDA Gracias a este hecho Simons se centro en el trading, y se dio cuenta de que parecía que podría llegar a encontrar patrones reconocibles después de tantos años aplicando y enseñando matemáticas. Pero rápidamente se dio cuenta de que iba a necesitar ayuda. Con el dinero que tenía ahorrado creo su propia compañía y empezó a contratar a los mejores matemáticos que conocía fundando la empresa “Monemetrics” en honor a las dos palabras que tanto le estaban aportando “dinero” (money) y “econometría” (econometrics) Al principio el terreno era demasiado virgen para Simons y no tenía claro exactamente por donde empezar; estaba claro que necesitaba una ayuda más potente para encontrar patrones de comportamiento dentro de los caóticos datos del mercado de valores. Empezó a insistir a su amigo Leonard Baum, el cual conocía de su pasado de descifrador y que ya hacía predicciones en entornos caóticos, el cual después de mucho tiempo acepto dejarlo todo y unirse a Jim Simons. Leonard Baum Después de varios años sin tener claro el futuro de la empresa cambió el nombre a “Renaissance Technologies Corporation” para intentar acaparar algo más que no solo el mundo de las finanzas ya que se estaba viendo a si mismo como una especie de comerciante. En 1984 Baum estaba operando prácticamente por intuición y en el crack de la bolsa de ese año llegó a perder mucho dinero, lo que propició que Simons lo tuviera que despedir, lo cual hizo mella en su moral para seguir trabajando. En ese momento Simons empezó a recopilar datos para realizar modelos que hicieran predicciones del mercado por si solos, y aunque tardo años al final descubrió una formula para vencer a los mercados. Desde ese momento está trabajando tan duro para seguir mejorando su algoritmo como para mantener el secreto de este, ya que nadie sabe a ciencia cierta como funciona. Oficialmente dejó de trabajar en Renaissance en 2009 y actualmente él junto a su mujer están centrados en la filantropía donando millones a estudios científicos principalmente en astrofísica, biología y física cuántica. Si queréis saber más de la vida de Jim Simons os recomiendo su biografía en la cual salen todos estos datos con muchos otros y que ya está disponible en español. Datos de Renaissance Tech La verdad es que la empresa que creó Simons está formada pensando en mantener el talento y ser puntera desde su base. Para ello siempre se ha contratado a las personas más inteligentes en su campo y siempre ha habido una total confianza para que todos y cada uno de los trabajadores supieran que estaban haciendo los demás y hasta pueden ayudar en líneas que no son de ellos. En la empresa hay más de 300 trabajadores y más de 90 son doctores (PhD) en las diversas áreas que componen la compañía. Edificio de Renaissance Technologies Otra de las máximas que tienen en Renaissance Technologies es que todo lo que se vaya a hacer tiene que ser hecho por ordenador, no existen acciones manuales (Supongo que es debido a la experiencia pasada de Simons). No existen jamás las excusas de que algo ha salido mal por culpa del ordenador, ni cosas que no se pudieran hacer (siempre que el hardware lo permita). Por esta razón también Jim Simons tiene una amplia plantilla de programadores que están mejorando cada uno de los algoritmos de forma continua. Como Simons ya dijo en alguna ocasión cada semana semana se hace una reunión de nuevas ideas dentro de la empresa, donde cada empleado expone cosas nuevas que ha descubierto. Esto aporta a la empresa una gran base de I+D en la cual se basa que no haya dejado de perder desde los años 90 sin importar crisis ni otros acontecimientos. El reto de trabajar con otros 90 PhD que te pueden destrozar tus ideas cada vez que las proponen es altísimo y esto motiva muchísimo a los trabajadores, haciendo que siempre haya un ambiente de mejora continua. Han conseguido hacer mejoras utilizando campos muy alejados tanto de las matemáticas tradicionales como de la informática y en alguna ocasión han llegado a reconocer que los astrofísicos tienen una gran importancia a la hora de encontrar patrones y que incluso la teoría de cuerdas ha sido vital para el filtrado de datos. La gran potencia de esta empresa está fundamentada en los datos. Simons siempre ha dicho que manejan gran cantidad de datos (Actualmente ingesta más de un Terabyte de datos al año para mejorar su sistema), y para ello necesitan una gran infraestructura que seguramente esté muy bien protegida dentro de su edificio. En el año 2013 ya se comentó que tenían más de 10.000 procesadores continuamente buscando señales para hacer entradas en el mercado, así que ahora tienen que tener muchísimos más. Una cuarta parte de del sueldo de los empleados es para el fondo de inversión, con lo cual tienen unas ganancias bastante grandes. Eso más el ambiente familiar, la capacidad de crecer enormemente en conocimientos gracias al I+D continuo hace que muy pocos se quieran ir de la empresa, y es muy raro el caso en el que un trabajador se va de la compañía. ¿Cómo predicen el mercado? Como ya he comentado es muy difícil saber exactamente qué es lo que utiliza Jim Simons para batir al mercado debido a su tremendo secretismo. Solo nos queda entrevistas que ha ido haciendo, libros y poco más. Aunque una de las fuentes más buenas las encontré en este hilo de twitter y en la Audiencia de la Subcomisión Permanente de Investigaciones del Senado. Así que voy a hacer un resumen de lo que he encontrado. La principal estrategia es el arbitraje estadístico a nivel de cartera ejecutado con una precisión increíble. Para este fin crean carteras de posiciones largas y cortas que cubren el riesgo de mercado, el riesgo sectorial y cualquier otro tipo de riesgo que Renaissance pueda haber predicho estadísticamente. Esta forma de hacer trading puede reducir mucho el rendimiento, pero la volatilidad de la cartera se reduce en un factor aún mayor, lo que proporciona una mayor seguridad. Por lo tanto al ejecutar un gran número de operaciones, y por la ley de los números grandes, la pérdida será muy pequeña. Debido a todo esto, el apalancamiento multiplica tanto el rendimiento esperado como la volatilidad por el mismo múltiplo, por lo que incluso con un alto apalancamiento, la probabilidad de pérdida sigue siendo muy pequeña. Sobre los fundamentos en los que se basan para hacer las operaciones hay algunos detalles que he encontrado y que nos dan pistas sobre qué sistema usan. En los primeros días de Renaissance parece que lo que más utilizaban eran las ecuaciones diferenciales estocásticas, pero no he encontrado ningún indicio de que realmente ahora sigan haciendo eso. También en el libro deja entrever que utiliza los modelos ocultos de markov (algo en lo que se basa el aprendizaje por refuerzo), más concretamente el algoritmo de Baum-Welch, pero al igual que el caso anterior no he encontrado más referencias que apoyen esta afirmación. Además de todo esto, la base sobre la que se realizan las operaciones es la de encontrar patrones de anomalías en los datos históricos que sean estadísticamente significativas y se mantengan a lo largo del tiempo. Raramente hay hipótesis sino que dejan que los datos hablen. Llegan al extremos de que si no llegan a entender porque está funcionando una señal la cambian. Al día realizan entre 150.000 y 300.000 operaciones y los mantiene en periodos muy cortos que como mucho duran dos días. De estas operaciones solo ganan en el 50,75% de los casos, lo cual resulta un número muy bajo, pero después de ver lo anterior resulta hasta comprensible. Según ha comentado Jim Simons en alguna ocasión la parte más clave es estimar el tamaño exacto de la operación para que no afecte negativamente, según los cálculos que he comentado anteriormente. Normalmente en sus operaciones se apalanca 12,5x (y puede llegar hasta 20x). Si no efectuasen estos apalancamientos sus rendimientos serían muy similares a los que ofrece el S&P 500. Como ejecuta miles de operaciones por día lo que hace el fondo es conseguir que los bancos que les dan los préstamos para poder apalancarse (antes Deutsche Bank y ahora Barclays) le dan va libre para ejecutar las operaciones directamente desde sus sistemas. Utilizan diversas técnicas para que no se vean las técnicas que utiliza en sus operaciones. Por ejemplo descubrieran una señal rentable, por ejemplo, que el EURUSD va a subir un 0,1 % entre las 9 y las 10 todos los días, nunca ejecutaría esta operación a las 9 en punto ya que eso daría una pista muy grande a los competidores de que algo pasa siempre en el mismo momento y podrían copiar la operativa. En cambio, realizan operaciones a lo largo de esa hora de forma lo más impredicible posible. También se sabe que cuentan con un sistema de protección contra eventos del tipo cisne negro y se supone que será algún tipo de red neuronal que ha detectado cuando suceden este tipo de eventos y que haga salir del mercado automáticamente a las posiciones implicadas. Conclusiones Una de las grandes lecciones que se pueden aprender de Jim Simons es que basar un método en la intuición y no en los datos no es sostenible a largo plazo. Su compañero Baum lo aprendió a lo bestia. Como todos sabemos, la base de cualquier machine learning es encontrar patrones, para ello se necesitan datos, y si los datos son muy complejos con mucha información mejor. Esto también lo tuvo Simons en cuenta ya que, como hemos visto, cuenta con los mejores datos del mercado día a día. Renaissance lo crearon matemáticos que luego aprendieron a programar. Esto es importante ya que normalmente es al contrario (al menos mi caso), son los programadores los que suelen aprender matemáticas o incluso tirar directamente a programar sin tener en cuenta las matemáticas que hay detrás. Así que toca seguir aprendiendo matemáticas ya que son la base de todo el buen trading algorítmico. Y algo muy importante es que tardaron 4 años en hacer que todo funcionase, el fracaso era algo casi diario en la vida de Simons llegando incluso a decir: “A veces miro esto y siento que soy un tipo que realmente no sabe lo que está haciendo” Hasta aquí la entrada sobre uno de los mejores traders algorítmicos hasta el momento, como siempre cualquier duda o aclaración no dudéis en ponerla en los comentarios o enviarme un mensaje para tenerla en cuenta. [...] Leer más...
Últimamente siempre escuchamos hablar de que una inteligencia artificial ha sido capaz de ganar a personas en determinados juegos y quizá no sepas del todo bien que hace para conseguir esta inteligencia una aplicación. Todo empezó por el ajedrez (donde se pueden jugar 10100.000 partidas diferentes), continuó por el famoso juego go y de lo último que hemos oído es como han derrotado al campeón del dota 2, uno de los juegos más jugados actualmente con miles de jugadores jugando desde todo el mundo. En el siguiente vídeo podemos ver como una inteligencia artificial aprende a jugar al escondite, ¡incluso llegando a hacer trampas con fallos en el sistema! Nosotros no vamos a ir tan lejos (al menos ahora), pero vamos a entrar un poco en detalle de qué es y cómo dar los primeros pasos en aprendizaje por refuerzo y como está cambiando el mundo con un ejemplo muy simple. El tres en raya. ¿Cómo funciona aprendizaje por refuerzo?Se puede decir que el aprendizaje por refuerzo es una rama del machine learning en la que una inteligencia artificial va a entender su entorno, tomará acciones y aprenderá la forma optima de afrontar el problema. Este aprendizaje se lleva a cabo mediante recompensas, en las que se premian los buenos comportamientos y se castigan los malos.Al igual que en las redes neuronales la inteligencia artificial necesita un entrenamiento, en el cual el agente experimentará con el ambiente e irá poco a poco optimizando su comportamiento. La gran diferencia con estas últimas es que en estas no se le dice cómo tiene que ser la salida, sino que es la misma inteligencia artificial la que descubre cual es la mejor forma de conseguir un resultado. Fundamentos Antes de empezar vamos a empezar describiendo un poco la jerga que se utiliza en el esta rama para que no nos perdamos más adelante. Es importante comprender bien cada uno de ellos, no solo por esta entrada sino por futuras entradas (o que leas más sobre el tema). Así que vamos a ello: Agente: Así llamaremos a la inteligencia artificial que toma las decisiones. En nuestro futuro caso nuestro agente será un jugador de tres en raya que irá aprendiendo.Entorno: El ambiente como su nombre indica es el lugar donde se realiza el aprendizaje del agente. en nuestro futuro caso será el tablero del juego.Política: Es lo que define el comportamiento que va a tener nuestro agente en el tiempo. En la práctica es un mapa donde se ven los estados del entorno a las acciones que se pueden dar en un determinado estado.Recompensa: Es el objetivo del problema que estamos intentando resolver. El objetivo del agente es encontrar la recompensa más grande. En nuestro ejemplo es el conseguir formar tres en línea.Función de valor: Especifica cual es el total de recompensas que se puede dar a través del tiempo desde un estado dado.Modelo: El lo que imita el comportamiento del entorno, y se usan para planear las estrategias a seguir. Primeros pasos en aprendizaje por refuerzo: El tres en raya El juego es el típico juego de tres en línea que todos conocemos y no creo que haga falta explicar mucho más que es un juego de dos jugadores (uno pone X y el otro pone O) donde el primero en conseguir poner tres X o O en línea gana. Aunque el juego es muy simple la realización de un algoritmo que sea capaz de jugar ganándote no es tan simple (como se puede ver en este ejemplo). En nuestro ejemplo utilizamos aprendizaje por refuerzo desde cero para que aprenda a jugar y al final nos acabe venciendo. Nuestro agente buscará las políticas con alta probabilidad de ganar para aplicarla e intentar ganar a un adversario humano. En este ejemplo una política le dice al agente como tiene que jugar para ganar. Para cada política se obtendrá una probabilidad de ganar. Así que vamos a utilizar una función de valor para ver cual sería la jugada que deberíamos hacer en cada uno de los estados. Para ello crearemos una tabla con números, uno para cada uno de los estados del juego. Cada número será la probabilidad de que ganemos en ese estado. Si asumimos que siempre jugamos con las Xs entonces si se da el caso de que se encuentras 3 Xs seguidas la probabilidad de ganar es de 1. Si por el contrario, nos encontramos con tres Os seguidas la probabilidad de ganar es de 0. Y establecemos todos los demás estados con una probabilidad de ganar de 0.5. Mientras vamos jugando vamos cambiando los valores, para que nuestro juego vaya mejorando mediante predicciones más precisas y lo vamos guardando en la tabla. Vamos actualizando la tabla de la siguiente manera: El valor actual del estado anterior se ajusta para estar más cerca del estado posterior. Esto se hace por medio una “tasa de aprendizaje” que se llama alpha y lo hacemos así: Si llamamos s al estado antes del movimiento y s0 al estado después del movimiento la actualización del valor estimado de s, que se representa como V(s) se puede escribir como: \begin{equation} V(s) \leftarrow V(s) + \alpha \end{equation} Este modelo es un buen ejemplo de como se puede realizar un método de aprendizaje diferencial, llamado así porque sus cambios se basan en una diferencia, V(s0)−V(s), entre estimaciones en dos momentos diferentes. El código No voy a entrar en la programación completa del juego ya que no me parece necesario, pero sí os dejo el código completo de la aplicación para que lo probéis y podáis empezar con el aprendizaje por refuerzo. El código lo podéis encontrar en mi GitHub: https://github.com/igarciaferreira/tres-en-raya Lo que si voy a explicar es la parte en la que se realiza el aprendizaje de la inteligencia artificial. Está basado en la ecuación que hemos visto anteriormente así que será muy sencillo de entender. Iré haciendo la explicación por pasos para que se más sencillo de seguir. La lógica de nuestro agente La función donde se realizá toda la lógica de la inteligencia artificial es la función “turno” dentro de la clase “jugador_IA”. Antes de entrar a explicar que hace realmente esa función creo importante repasar unas inicializaciones que se dan al principio de la clase. self.tasa_aprendizaje = 0.2 self.estado_valor = {} self.cargar_politica() self.ultima_posicion_jugada = np.zeros((FILAS, COLUMNAS), dtype=int) La tasa de aprendizaje es el alfa que vimos en la fórmula anterior que ibamos a utilizar. Como vemos está multiplicando a la diferencia de la nueva probalidad de ganar entre la actual, así que cuanto mayor sea este valor mayor será lo que aprenda al hacer esta operación. Aunque se pueda pensar que esto es bueno y deberiamos ponerlo siempre a uno no es así. Una tasa de aprendizaje demasiado alta hará que el aprendizaje fluctúe muchísimo entre una decisión u otra y eso no es bueno. Pero una tasa de aprendizaje demasiado baja tardará demasiado en aprender una buena combinación. En este caso he optado por el 0.2 pero se puede cambiar e ir jugando con él y ver cual es el valor ideal. La variable “estado_valor” es el valor donde se iran guardando los pares de “posición-posibilidad de ganar” y que se irán consultando para cada poder saber cual es probabilidad de ganar de cada posición y para realizar la fórmula. Las otras dos variables se explica por si mismo. Ahora vayamos a ver la función “turno” que es donde se realiza la magia. aleatorio = random.randint(0, 1) if self.serializar(tablero) != "000000000": self.estado_valor = self.probabilidad(self.ultima_posicion_jugada)+self.tasa_aprendizaje*(self.probabilidad(tablero)-self.probabilidad(self.ultima_posicion_jugada)) Al comienzo se saca un valor aleatorio para determinar si la siguiente jugada es de exploración o de razonamiento. Este es un problema también muy amplio dentro de la inteligencia artificial, ya que hay momentos en los cuales la IA tiene que tomar un valor no esperado ya que sino constantemente iría tomando siempre las mismas decisiones y nunca exploraría el tablero (este es un tema muy amplio que tendrá una entrada a parte en el blog). En este trozo de código también se mira si el es la primera posición del tablero y no hay fichas en ella, y si no es así se guarda la probabilidad de la posición actual. if aleatorio: colocada = False tablero_antiguo = tablero.copy() while colocada == False: fila = random.randint(1, 3) columna = random.randint(1, 3) if tablero == 0: tablero = self.ficha colocada = True self.estado_valor = self.probabilidad(tablero_antiguo)+self.tasa_aprendizaje*(self.probabilidad(tablero)-self.probabilidad(tablero_antiguo)) Esta el la parte de exploración que hablamos anteriormente. Simplemente coloca una ficha aleatoria en el tablero y se calcula la probabilidad de ganar de la posición actual. else: posiciones = self.conseguir_posiciones(tablero) mejor_valor = 0 mejor_jugada = np.zeros((FILAS, COLUMNAS), dtype=int) for posicion in posiciones: valor = self.probabilidad(posicion) if valor > mejor_valor: mejor_valor = valor mejor_jugada = posicion self.estado_valor = self.probabilidad(tablero)+self.tasa_aprendizaje*(self.probabilidad(mejor_jugada)-self.probabilidad(tablero)) Esta es la parte donde se produce toda la lógica de la IA. Primero se ven las posiciones que quedan disponibles y por cada posición se busca la mejor jugada. Una vez que se ha encontrado la mejor jugada se calcula cual será la nueva probabilidad de ganar de esa posición y se guarda en el diccionario. self.guardar_politica() self.ultima_posicion_jugada = mejor_jugada.copy() return mejor_jugada Después de esto se guardan las políticas nuevamente, se guarda en una variable cual ha sido la jugada seleccionada (para futuros cálculos como hemos visto antes) y se devuelve al tablero la jugada seleccionada. Recompensas Cuando empieza el juego todas las posiciones en el diccionario tendrían un valor de ganar de 0.5, y solo las que son de victoria devuelven un 1. ¿Con esto que se consigue? Pues muy fácil. Cuando una posición es previa a ganar tendrá una probabilidad de ganar inicial de 0.5, pero una vez que haya ganado la formula le dará un nuevo valor: \begin{equation} Nuevo\; valor = 0.5 + 0.2\cdot (1-0.5)= 0.5 + 0.1 = 0.6 \end{equation} Con lo cual la siguiente vez que juege y se encuentre con esta posición al recorrer todas las posiciones encontrará que esta es la mejor posición para ganar la partida, ya que anteriormente la ganó. Así que la volverá a jugar para ganar y si vuelve a ganar la probabilidad volverá a subir. Esto hecho con todas las posiciones del tablero hará que tengamos en cada posición posible una probabilidad de ganar que hará que la IA escoja esa posición. Conclusiones ¿Se podría mejorar este algoritmo? Sí, mucho. En este caso solo hemos introducido un sistema de recompensa, pero no de penalización. Si introducimos uno el sistema sería capaz de evitar malas jugadas y quizá evitaría que el contrincante ganase la mayoría de las veces. En este caso solo está centrado en ganar y no se da cuenta de que hay veces que hay que protegerse porque sino pierdes. También existen optimizaciones al propio algoritmo, como lo es que al tratarse de un cuadrado puede haber situaciones muy similares y no hace falta guardar todas las posiciones, con el consiguiente gasto de memoria al guardarlo y de CPU al recorrerlo para buscar la mejor posición. Incluso se podría optimizar la función de exploración y explotación para que no fuera solo un aleatorio, sino que de verdad vea la posibilidad de explotar cuando realmente es necesario. Todas estas opciones se verán en próximas entradas del blog, así que estar atentos. Esta entrada solo esperaba ser una introducción al aprendizaje por refuerzo, un tema del que espero que te enganches como lo he hecho yo. ¿Se os ocurre alguna mejora más? No dudéis en ponerla en los comentarios o enviarme un mensaje para incluirla. [...] Leer más...
Seguramente cuando veis el código fuente de muchas páginas por internet os preguntareis porque hay veces que las redes funcionales las hacen con un código y otras veces otro completamente distinto. Podríais pensar ¿Son distintas versiones de Keras y por eso se ven así? Pero no, la realidad es que hay dos formas de hacer las redes neuronales, de forma secuencial y de forma funcional, y en estas últimas es donde se encuentran las redes neuronales complejas. ¿Qué son las redes neuronales complejas? Cuando empezamos a estudiar las redes neuronales siempre tienen la forma de una o varias entradas, una o varias capas ocultas y una varias salidas, pero esto no siempre tiene que ser así. En la imagen anterior podemos ver la estructura de GoogleNet. Un modelo de red convolucional que ha diseñado Google para la clasificación de imágenes, en la que se puede observar la complejidad que puede llegar a tener una red neuronal. No es tan complicado realizar redes neuronales complejas, solo hay que tener en mente que las redes no tienen porque ser un único bloque que tenga una entrada una red neuronal y una salida. Aquí os mostramos como realizar algunas de ellas, y al final del artículo seréis capaces de crear vuestras propias redes complejas. Modelo secuencial Un modelo secuencial es cuando al crear una red neuronal vamos poniendo capas unas detrás de otras. Esta es la forma más sencilla de hacer las redes neuronales y la que hasta ahora hemos utilizado, como por ejemplo cuando hicimos LSTM. Vamos a ver un ejemplo rápido de como sería la programación de un modelo de forma secuencial: model = models.Sequential() model.add(Dense(100, input_shape(10,), activation='relu') model.add(Dense(100, activation='relu') model.add(Dense(100, activation='relu') model.add(Dense(100, activation='relu') model.add(Dense(1, activation='relu') Si lo vemos gráficamente la red neuronal sería así: Como veis esta red neuronal es muy sencilla. Son simplemente capas puestas de forma secuencial, es decir una detrás de otra. Modelo funcional Ahora la pregunta sería ¿pero si quiero que la salida de una capa se salte la siguiente como lo hago? Pues para eso nos sirve el nivel funcional. En esta red hay que indicar cual es la capa de entrada una capa dada. Vamos a ver como se hace esto con un ejemplo: input1 = Input(shape=(10,2)) lay1 = Dense(32, input_shape=(10,2))(input1) lay2 = Dense(8)(lay1) out1 = Dense(1)(lay2) out2 = Dense(1)(lay2) out3 = Dense(1)(lay2) merged1 = concatenate() merged2 = concatenate() output = Dense(30, activation='relu')(merged1) func_model = Model(inputs=input1, outputs=) Hay varios detalles en los que fijarse en esta red neuronal. El primero es que se puede observar que para pone la capa de salida de una red neuronal como la entrada de la siguiente hay que indicarlo. Para indicarlos se hace poniendo la capa de entrada entre paréntesis, justo cuando terminamos de declarar la nueva capa. También podemos ver la forma de juntar dos capas mediante “concatenate”, donde señalamos las redes que vamos a unir para crear una nueva capa. Esto puede ser muy útil cuando tenemos unas capas que sabemos que van a dar una salida determinada y esas salidas juntas nos pueden ayudar a crear un nuevo algoritmo. También podemos ver como esta red neuronal tiene dos salidas, no solo una como estamos acostumbrados. Esto puede suceder cuando, por ejemplo, tratamos de predecir el valor que van a tomar dos variables distintas. Esto que hemos explicado gráficamente se vería así: Vamos como vamos avanzando un poco más en la complejidad de las redes neuronales, y esta ya se ve mucho más compleja que la anterior. Modelos con más entradas Ahora nos queda el último supuesto: cuando necesitamos más de una entrada. Un ejemplo típico de este tipo de red es cuando vamos a meter dos imágenes distintas. Veamos como se hace esto: visible1 = Input(shape=(64,64,1)) conv11 = Conv2D(32, kernel_size=4, activation='relu')(visible1) pool11 = MaxPooling2D(pool_size=(2, 2))(conv11) flat1 = Flatten()(pool11) visible2 = Input(shape=(32,32,3)) conv21 = Conv2D(32, kernel_size=4, activation='relu')(visible2) pool21 = MaxPooling2D(pool_size=(2, 2))(conv21) flat2 = Flatten()(pool21) merge = concatenate() output = Dense(1, activation='sigmoid')(merge) model = Model(inputs=, outputs=output) Hemos querido seguir con el ejemplo de las imágenes, así que lo hacemos con capas convolucionales. La entrada de cada imagen entraría directamente a una capa convolucional que haría operaciones con ellas y los resultados de estas dos operaciones acabarían en una capa densa que nos mostraría el resultado deseado. Conclusiones Como hemos visto las redes neuronales pueden ser todo lo complejas que nosotros queramos, y seguro que no somos capaces de ver todo el provecho que les podemos sacar. Pero como nota me gustaría que dejaros una imagen que he visto por internet, y que después de leer este artículo espero que ya no veáis tan complicada. Espero que viendo esto también se os ocurra como aplicar esto al trading, que seguro que algo se os viene a la cabeza. Si tenéis cualquier duda o mejora del artículo no dudéis en poneros en contacto conmigo y os contestaré lo antes posible. [...] Leer más...
Cuando empezamos a trabajar con las redes neuronales es muy sencillo caer en el sobre entrenamiento de los modelos. Actualmente existen varias técnicas para este problema, pero muchas de ellas son bastante costosas de llevar a cabo, y eso es un gran problema con el que hay que lidiar. Una de las técnicas más famosas para intentar no sobreentrenar un modelo es el dropout. ¿Que es Dropout exactamente? Resumiendo mucho se podría decir que es una técnica para hacer las redes neuronales más pequeñas con el tamaño justo para que aprendan lo que tienen que aprender sin a aprender demasiado. Es decir que aplicando en Dropout adecuado nuestra red aprenderá lo justo para que no haya sobreentrenamiento. En realidad lo que Dropout hace es ir desconectando neuronas con cada entrenamiento hasta conseguir el valor optimo. Es decir si establecemos un valor de Dropout de un 50% estaremos diciendo que en cada entrenamiento que se haga con la red neuronal se deshabilitará un 50% de las neuronas de esa capa. Un buen ejemplo para ver visualmente cómo funciona el dropout, lo podemos ver en el siguiente video, como vemos como mientras se realiza el entrenamiento el algoritmo va probando entre las posibles combinaciones. Consejos para usar dropout Los principales consejos que hay que tener en cuenta para usar dropdown son los siguientes: Según el autor del artículo en el basamos esta entrada los valores óptimos de son de 20% en la capa de entrada y 50% en las capas ocultas. Aunque yo recomiendo empezar también por 20% en las capas ocultas e ir subiendo hasta un valor máximo de 50%. Un valor más bajo puede no tener efectos y un valor más alto seguramente hará infra entrenamiento.Dropout se comporta mucho mejor en redes grandes que en pequeñas. Lo cual si lo piensas tiene lógica.Usarlo también en las capas de entrada. Algo que mucha gente no hace, y solo lo aplica a las capas de ocultas.Funciona mucho mejor usando la normalización de maxnorm, grandes tasas de aprendizaje y en la optimización un momentum alto. Como usarlo La forma de usar el dropout es como lo hemos visto en el articulo sobre LSTM. Aunque en esta ocasión no aplicamos alguno de los puntos que indicamos anteriormente (ojo, posible mejora del modelo LSTM), pero sirve muy bien para ver como se ponen las capas de dropout en un modelo. 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)) Como se puede ver no es algo sumamente complejo, solo es necesario poner la capa del dropout justo de la capa sobre la que queremos hacer esta técnica. La salida que obtuvimos para este modelo fue la siguiente: ¿Qué pasa si no lo usamos? Si no usamos está técnica es posible que acabemos teniendo un sobre entrenamiento, ya que, como hemos visto antes, está técnica es lo busca. Al no incluirlo todas las neuronas de la capa funciona y todas aprenden lo que hace que tengamos que ser mucho más precisos en el número de neuronas con el que vamos a entrenar nuestro modelo. Por seguir con el ejemplo del articulo sobre LSTM, veamos que sucede si no incluimos dropout. model = Sequential() model.add(LSTM(50, input_shape=(60, 1), return_sequences=True)) model.add(LSTM(50, return_sequences=True)) model.add(LSTM(50)) model.add(Dense(1)) Si ejecutamos el código y hacemos todos los pasos como se ve en el artículo al final veremos un salida similar a esta. Como vemos hay un sobre entrenamiento bastante claro. Al funcionar todas las neuronas el modelo está siendo incapaz de aprender correctamente y está mostrando una especie de copia del estado anterior que tuvo el modelo. Conclusiones ¿Se pueden crear modelos sin usar dropout? Claro que sí, pero seguramente tardaremos más tiempo en saber cuantas neuronas son necesarias por capa. Por esta razón, está técnica nos hace ahorrar mucho tiempo a la hora de calcular el tamaño óptimo de la red neuronal. Como vemos no es una técnica muy complicada de usar y los beneficios pueden ser muchos. Solo hay que tener en cuenta los consejos que el propio autor de la técnica nos mostró en el artículo original y que os he expuesto aquí. Si tenéis cualquier duda o mejora del artículo no dudéis en poneros en contacto conmigo y os contestaré lo antes posible. [...] Leer más...
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) data = data.sort_values("date",ignore_index=True) data.set_index('date',inplace=True) EURUSD = data.iloc.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, 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: , 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) labels.append(train_scaled) features = np.array(features) labels = np.array(labels) features = np.reshape(features, (features.shape, features.shape, 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: Capa de entrada, en la cual le pasaremos una característica pero con una venta de 60 días.Tres capas ocultas con 50 neuronas LSTM seguidas de una capa de dropout al 20%.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 inputs = all_data.values inputs = inputs.reshape(-1,1) inputs = scaler.transform(inputs) X_test = [] for i in range(60, test.shape+60): X_test.append(inputs) X_test = np.array(X_test) X_test = np.reshape(X_test, (X_test.shape, X_test.shape, 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, color='blue', label='Precios reales del Euro/Dolar') plt.plot(predicted_stock_price, 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í: 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. [...] Leer más...

Blog powered by:

Estudios de técnicas

¿Son realmente efectivas las técnicas que estamos cansados de ver explicadas una y otra vez? Aquí lo veremos.

Ejemplos prácticos

No nos quedaremos en teoría. Aplicaremos la práctica y mostraremos como obtener resultados.

Últimas tendencias

Ejemplos actuales con las últimas tendencias en todos los campos que afectan al trading algorítmico.

¡No te pierdas ningún post!

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