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['date'] = pd.to_datetime(self.datos['date'])
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.











