Lección 1.3.6 · 50 min
Brókeres como fuente de datos
El bróker con el que operas ya te da datos: históricos, cotizaciones y, a veces, el libro. Son los precios a los que ejecutas, pero llegan con reglas propias: un programa intermedio, límites de ritmo estrictos y suscripciones de mercado. Esta lección los recorre con Interactive Brokers, MetaTrader 5 y OANDA, y simula el ritmo de descarga sin conectarse a nada.
- Módulo
- 1.3 · Fuentes de datos de mercado
- Duración
- 50 min
Lecciones del nivel 1
1.1 · Cómo funcionan los mercados
1.2 · Clases de activos
- 1.2.1 Acciones: splits, dividendos y eventos corporativos
- 1.2.2 ETFs: réplica, tracking error, apalancados y UCITS
- 1.2.3 Futuros: especificaciones, margen, roll y contango
- 1.2.4 Forex: pares, pips, lotes, rollover y CFD
- 1.2.5 Opciones: call, put, valor intrínseco y valor temporal
- 1.2.6 Cripto: spot, perpetuos, funding y custodia
- 1.2.7 Renta fija y tipos de interés; CFDs y productos apalancados
1.3 · Fuentes de datos de mercado
- 1.3.1 Tipos de datos de mercado: EOD, barras, ticks, libro y referencia
- 1.3.2 Fuentes de datos gratuitas
- 1.3.3 APIs de datos retail y prosumer
- 1.3.4 Proveedores de datos profesionales
- 1.3.5 Datos de cripto y on-chain
- 1.3.6 Brókeres como fuente de datos
- 1.3.7 Licencias y términos de uso de datos
- 1.3.8 Cómo elegir proveedor de datos
1.4 · Ingeniería de datos financieros
- 1.4.1 Descarga por REST y websockets: paginación, límites y reintentos
- 1.4.2 Limpieza de datos: faltantes, ticks erróneos, huecos y zonas horarias
- 1.4.3 Ajustes por splits y dividendos: precios ajustados y sin ajustar
- 1.4.4 Universos sin sesgo de supervivencia: deslistados, fusiones y cambios de símbolo
- 1.4.5 Construcción de barras: tiempo, ticks, volumen, dólar y desequilibrio
- 1.4.6 Series continuas de futuros: reglas de roll, ajuste por diferencia y ajuste por ratio
- 1.4.7 Almacenamiento: CSV, Parquet, particionado, DuckDB, TimescaleDB y ArcticDB
- 1.4.8 Pipeline reproducible: descarga, validación, actualización incremental y tests de calidad
1.5 · Datos fundamentales y macro
1.6 · Análisis exploratorio financiero
1.7 · Análisis técnico programado
El bróker también es un proveedor
Cualquier bróker que tenga API da, además de la ejecución, datos: cotizaciones en tiempo real, velas históricas y, en algunos casos, profundidad de libro. Para un sistema que opera en ese bróker tienen una ventaja que ningún otro proveedor iguala: son los precios del sitio donde se ejecuta, con su horquilla, su horario y sus comisiones. Un sistema de divisas que calcula señales con los precios de su bróker y ejecuta en él no tiene que preocuparse de que la fuente de datos y el mercado de ejecución no coincidan.
Los inconvenientes son los contrarios: historia corta, límites de peticiones pensados para operar y no para descargar años, y ningún valor deslistado (el bróker solo da lo que se puede operar hoy). Esta lección recorre tres brókeres con API muy usados en Python: Interactive Brokers, MetaTrader 5 (una plataforma que ofrecen muchos brókeres) y OANDA.
Interactive Brokers: TWS, Gateway y ib_async
La API de Interactive Brokers (IBKR) tiene una arquitectura que sorprende la primera vez: el programa no se conecta a los servidores de IBKR, sino a una aplicación que corre en la propia máquina, TWS (Trader Workstation, la plataforma de escritorio) o IB Gateway (la misma conexión sin interfaz gráfica, más ligera para un servidor). Esa aplicación mantiene la sesión con IBKR y expone un puerto local:
Fuente Mermaid
flowchart LR P[Tu programa] --> A[ib_async] A --> G[TWS o Gateway] G --> S[Servidores IBKR]
| Aplicación | Cuenta real | Cuenta de papel |
|---|---|---|
| TWS | 7496 | 7497 |
| IB Gateway | 4001 | 4002 |
Son los puertos por defecto según la documentación de IBKR1Nota 1 · IBKR: Configure the Connecting Socket Port, consultada el 21/10/2026.; cada aplicación los permite cambiar. Cada conexión
lleva además un clientId: varios programas pueden conectarse a la misma TWS a la vez si usan identificadores
distintos. Conectarse a la cuenta de papel (7497 o 4002) es la forma segura de probar: los mismos datos y la misma API,
sin dinero real.
La librería oficial de IBKR para Python (ibapi) es de bajo nivel: callbacks y mensajes. La que usa casi todo el mundo
es ib_async, la continuación de ib_insync. Según su README, Ewald de Wit la creó en 2017 y la mantuvo hasta su
fallecimiento a principios de 2024; los mantenedores la renombraron como ib_async en una organización nueva de GitHub
(ib-api-reloaded) porque ya no podían modificar los repositorios originales. Requiere Python 3.10 o superior y no
necesita el paquete ibapi2Nota 2 · README de ib_async, consultado el 21/10/2026; versión 2.1.0 en PyPI.. El código de ib_insync funciona casi igual cambiando el import.
from ib_async import IB, Stock, util # uv add ib_async
ib = IB()
ib.connect("127.0.0.1", 7497, clientId=1) # TWS, cuenta de papel
contrato = Stock("AAPL", "SMART", "USD")
barras = ib.reqHistoricalData(
contrato, endDateTime="", durationStr="30 D",
barSizeSetting="1 hour", whatToShow="MIDPOINT", useRTH=True,
)
df = util.df(barras)
ib.disconnect()durationStr es cuánto tiempo hacia atrás ("30 D"), barSizeSetting el tamaño de la barra, whatToShow qué precio
(TRADES, MIDPOINT, BID, ASK, BID_ASK…) y useRTH=True limita a la sesión regular. util.df convierte la
lista de barras en un DataFrame.
Suscripciones de mercado
Que la API funcione no significa que haya datos. Según la documentación de IBKR, salvo los datos diferidos, recibir
datos de mercado por la API requiere una suscripción de pago al mercado correspondiente; para pedir datos diferidos
sin suscripción, ib.reqMarketDataType(3) antes de pedir cotizaciones. Cada usuario tiene además un número de líneas
de datos de mercado (100 por defecto) que comparten la plataforma y la API: cada símbolo que se sigue en tiempo real
ocupa una3Nota 3 · IBKR: Pacing Limitations, Market Data Lines y Market Data, consultadas el 21/10/2026..
Límites de ritmo: lo que decide la duración de una descarga
IBKR limita con cuidado lo que se le pide. Hay dos tipos de límite:
- General. El número máximo de peticiones por segundo es el de líneas de datos de mercado dividido entre dos: con las 100 líneas por defecto, 50 peticiones por segundo3.
- Histórico de barras pequeñas. Para barras de 30 segundos o menos, la documentación de la versión anterior de la
API (marcada como obsoleta, pero la única que publica las reglas) considera violación de ritmo: repetir una petición
idéntica en menos de 15 segundos; hacer 6 o más peticiones del mismo contrato, bolsa y tipo de dato en 2
segundos; y hacer más de 60 peticiones en cualquier periodo de 10 minutos. Con
BID_ASK, cada petición cuenta dos veces. Para barras de 1 minuto o más, esas reglas se levantaron, aunque el servidor sigue frenando a quien pide demasiado4Nota 4 · IBKR, documentación anterior de la API: Historical Data Limitations («This documentation is now deprecated»), consultada el 21/10/2026..
Además, cada petición tiene una duración máxima según el tamaño de barra: la documentación actual da, por ejemplo, 2.000 segundos para barras de 1 segundo y 86.400 segundos (un día) para barras de 5 segundos5Nota 5 · IBKR: Historical Bars (OHLC), tabla de duración máxima por tamaño de barra.. Con esas reglas se puede simular un descargador que nunca las viola, con un reloj virtual:
import math
from collections import deque
class RitmoIBKR:
"""Reglas para barras de 30 s o menos (documentación anterior)."""
def __init__(self):
self.hechas = deque() # (t, contrato, clave, peso)
def espera(self, t, contrato, clave, peso=1):
while self.hechas and self.hechas[0][0] <= t - 600:
self.hechas.popleft()
e = 0.0
# más de 60 en 10 minutos (BID_ASK pesa 2)
usadas = sum(h[3] for h in self.hechas)
if usadas + peso > 60:
acum = 0
for h in self.hechas:
acum += h[3]
if usadas - acum + peso <= 60:
e = max(e, h[0] + 600 - t)
break
# 6 o más del mismo contrato en 2 segundos
mismo = [h[0] for h in self.hechas if h[1] == contrato]
if len(mismo) >= 5:
e = max(e, mismo[-5] + 2 - t)
# idéntica en menos de 15 segundos
for h in self.hechas:
if h[2] == clave:
e = max(e, h[0] + 15 - t)
return max(e, 0.0)
def registra(self, t, contrato, clave, peso=1):
self.hechas.append((t, contrato, clave, peso))
def descarga(n_peticiones, peso=1, latencia=0.5):
ritmo, t, horas = RitmoIBKR(), 0.0, []
for i in range(n_peticiones):
clave = ("NOVA", i) # cada petición, otro tramo
while (e := ritmo.espera(t, "NOVA", clave, peso)) > 0:
t += e
ritmo.registra(t, "NOVA", clave, peso)
horas.append(t)
t += latencia
return horas
horas = descarga(252) # un día por petición
print(f"252 peticiones: {horas[-1] / 60:.1f} minutos")
print("primeras:", [round(h, 1) for h in horas[:7]])252 peticiones: 40.1 minutos
primeras: [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]La simulación supone que cada respuesta tarda medio segundo. A ese paso salen cuatro peticiones cada dos segundos, así que la regla de las 6 en 2 segundos no llega a activarse (con respuestas más rápidas sí lo haría). La que manda es la de 60 en 10 minutos: el descargador hace 60 peticiones en medio minuto y espera el resto de la ventana. Cuatro ventanas completas y 12 peticiones más: 40,1 minutos (figura de la cabecera).
Ahora la cuenta que importa: cuánto tarda un año de barras de cada tamaño para un contrato, con la duración máxima de cada petición:
sesion = int(6.5 * 3600) # 23.400 s de sesión regular
casos = {
"5 s, TRADES": (86_400, 1),
"5 s, BID_ASK": (86_400, 2),
"1 s, TRADES": (2_000, 1),
"1 s, BID_ASK": (2_000, 2),
}
for nombre, (max_seg, peso) in casos.items():
por_dia = math.ceil(sesion / max_seg)
n = 252 * por_dia
h = descarga(n, peso=peso)
print(f"{nombre:13} {n:5} peticiones {h[-1] / 3600:5.2f} h")5 s, TRADES 252 peticiones 0.67 h
5 s, BID_ASK 252 peticiones 1.33 h
1 s, TRADES 3024 peticiones 8.34 h
1 s, BID_ASK 3024 peticiones 16.67 hUn año de barras de 5 segundos cabe en 252 peticiones y unos 40 minutos; el mismo año en barras de 1 segundo necesita 12 peticiones por día (23.400 / 2.000, redondeado hacia arriba), 3.024 en total y más de 8 horas, o el doble si se piden bid y ask. Para cien contratos, multiplica. Por eso los históricos largos de barras pequeñas no se bajan del bróker sino de un proveedor (lecciones 1.3.3 y 1.3.4), y el bróker se reserva para lo reciente y para el tiempo real.
Qué pasa si no se respeta
Un bucle que dispara las peticiones sin limitador no sabe que está violando las reglas hasta que IBKR responde con un error de violación de ritmo, y con violaciones repetidas la conexión puede acabar cortada. Con la misma clase se puede contar cuántas peticiones de un bucle ingenuo serían violaciones:
def violaciones(n, latencia=0.5):
ritmo, t, malas = RitmoIBKR(), 0.0, 0
for i in range(n):
clave = ("NOVA", i)
if ritmo.espera(t, "NOVA", clave) > 0:
malas += 1
ritmo.registra(t, "NOVA", clave)
t += latencia
return malas
print(violaciones(252), "de 252 peticiones fuera de las reglas")192 de 252 peticiones fuera de las reglasLas 60 primeras caben en la ventana de 10 minutos; las 192 siguientes la violan. El bucle termina en dos minutos, pero habría recibido 192 errores (y, mucho antes, probablemente una desconexión). La solución no es reintentar más deprisa, sino esperar lo que dicen las reglas antes de pedir.
MetaTrader 5: el terminal como servidor de datos
MetaTrader 5 es una plataforma de trading que ofrecen muchos brókeres de divisas y CFD. Su paquete de Python
(MetaTrader5 en PyPI) no habla con ningún servidor: se conecta a un terminal MetaTrader 5 instalado en la misma
máquina, que es el que tiene la sesión con el bróker. initialize() busca el terminal o recibe la ruta de su
ejecutable; las ruedas publicadas en PyPI son solo para Windows (win_amd64)6Nota 6 · MetaTrader 5: Python Integration e initialize; ruedas win_amd64 de la versión 5.0.6231 en PyPI..
from datetime import datetime, timezone
import MetaTrader5 as mt5 # solo Windows, con el terminal
if not mt5.initialize():
raise RuntimeError(mt5.last_error())
desde = datetime(2025, 6, 2, tzinfo=timezone.utc)
velas = mt5.copy_rates_from("EURUSD", mt5.TIMEFRAME_H1, desde, 500)
ultimo = mt5.symbol_info_tick("EURUSD")
mt5.shutdown()copy_rates_from devuelve las velas anteriores a la fecha dada como un array de numpy con campos con nombre:
time, open, high, low, close, tick_volume, spread y real_volume. La documentación avisa de dos cosas:
el terminal guarda la hora de apertura en UTC (por eso la fecha debe crearse en UTC) y el número de velas que puede
devolver está limitado por el parámetro «Max. bars in chart» del terminal7Nota 7 · MetaTrader 5: copy_rates_from.. Con un array de esa forma, construido con
el EURUSD sintético del curso:
import numpy as np
import pandas as pd
eur = pd.read_parquet("eurusd_1h.parquet").set_index("ts")
h1 = eur.loc["2025-06-02", "mid"]
tipo = np.dtype([("time", "<i8"), ("open", "<f8"), ("high", "<f8"),
("low", "<f8"), ("close", "<f8"),
("tick_volume", "<u8"), ("spread", "<i4"),
("real_volume", "<u8")])
rates = np.zeros(len(h1) - 1, dtype=tipo)
rates["time"] = h1.index[:-1].astype("int64") // 10**6 # segundos
rates["open"] = h1.values[:-1]
rates["close"] = h1.values[1:]
rates["high"] = np.maximum(rates["open"], rates["close"])
rates["low"] = np.minimum(rates["open"], rates["close"])
velas = pd.DataFrame(rates)
velas["time"] = pd.to_datetime(velas["time"], unit="s", utc=True)
velas.set_index("time")[["open", "close"]].head(3) open close
time
2025-06-02 00:00:00+00:00 1.172300 1.172725
2025-06-02 01:00:00+00:00 1.172725 1.173615
2025-06-02 02:00:00+00:00 1.173615 1.173730El campo time viene en segundos desde 1970 (no en milisegundos como en ccxt, lección 1.3.5), y
pd.DataFrame(rates) respeta los nombres de los campos. Aquí el máximo y el mínimo salen de la apertura y el cierre
porque el EURUSD del curso es una cotización por hora, no velas; en el terminal, cada vela trae los suyos. Dos
detalles propios de esta fuente: tick_volume es el número de cambios de precio, no un volumen negociado (en divisas
al contado no hay cinta consolidada, lección 1.2.4), y spread es la horquilla en puntos del bróker, que cambia de un
bróker a otro.
OANDA: una API REST con velas bid, ask y medio
OANDA tiene una API REST, la v20, con dos entornos: práctica (api-fxpractice.oanda.com) y real
(api-fxtrade.oanda.com), y servidores de streaming aparte (stream-fxpractice.oanda.com,
stream-fxtrade.oanda.com). La autenticación es un token en la cabecera Authorization: Bearer. Sus límites, según la
guía de desarrollo: 120 peticiones por segundo en la API REST (por encima, 429), 20 streams activos y no más de
2 conexiones nuevas por segundo; la página de buenas prácticas recomienda, en una conexión ya abierta, no pasar de
100 por segundo8Nota 8 · OANDA v20: Development Guide, Best Practices y Troubleshooting, consultadas el 21/10/2026..
Las velas se piden en GET /v3/accounts/{accountID}/instruments/{instrument}/candles, con granularity (por defecto
S5, cinco segundos), count (por defecto 500, máximo 5.000) y price, que combina M (medio), B (bid) y A
(ask)9Nota 9 · OANDA v20: Pricing (endpoint de velas), Instrument (esquema Candlestick) y Primitives (DateTime)..
import os
from urllib.parse import urlencode
from urllib.request import Request, urlopen
cuenta = os.environ["OANDA_ACCOUNT"]
url = (f"https://api-fxpractice.oanda.com/v3/accounts/{cuenta}"
"/instruments/EUR_USD/candles?"
+ urlencode({"granularity": "H4", "count": 500, "price": "MBA"}))
req = Request(url, headers={
"Authorization": f"Bearer {os.environ['OANDA_TOKEN']}"})
with urlopen(req, timeout=10) as r:
crudo = r.read()La respuesta trae instrument, granularity y una lista candles. Cada vela tiene time (el inicio de la vela, en
RFC 3339 con nanosegundos: AAAA-MM-DDTHH:MM:SS.nnnnnnnnnZ), volume (el número de precios creados en la vela),
complete y un bloque mid, bid o ask con o, h, l y c. Los precios llegan como texto, con la precisión
del instrumento. Una respuesta con ese esquema, construida con el EURUSD sintético en velas de 4 horas:
import json
def bloque(s):
return {"o": f"{s.iloc[0]:.5f}", "h": f"{s.max():.5f}",
"l": f"{s.min():.5f}", "c": f"{s.iloc[-1]:.5f}"}
dia = eur.loc["2025-06-02 00:00":"2025-06-02 15:00"]
velas_json = []
for inicio, g in dia.groupby(pd.Grouper(freq="4h")):
velas_json.append({
"time": inicio.strftime("%Y-%m-%dT%H:%M:%S.000000000Z"),
"volume": len(g), "complete": len(g) == 4,
"bid": bloque(g["bid"]), "ask": bloque(g["ask"]),
"mid": bloque(g["mid"]),
})
velas_json[-1]["complete"] = False # la vela en curso
respuesta = json.dumps({"instrument": "EUR_USD",
"granularity": "H4", "candles": velas_json})
print(respuesta[:118], "..."){"instrument": "EUR_USD", "granularity": "H4", "candles": [{"time": "2025-06-02T00:00:00.000000000Z", "volume": 4, "co ...Y su lectura: texto a número, solo velas completas y horquilla de cierre en pips.
datos = json.loads(respuesta)
filas = []
for v in datos["candles"]:
if not v["complete"]:
continue # nunca al histórico
fila = {"time": v["time"], "volume": v["volume"]}
for lado in ("bid", "ask"):
for k, x in v[lado].items():
fila[f"{lado}_{k}"] = float(x)
filas.append(fila)
oanda = pd.DataFrame(filas)
oanda["time"] = pd.to_datetime(oanda["time"], utc=True)
oanda["spread_pips"] = 1e4 * (oanda["ask_c"] - oanda["bid_c"])
oanda.set_index("time")[["bid_c", "ask_c", "spread_pips"]].round(5) bid_c ask_c spread_pips
time
2025-06-02 00:00:00+00:00 1.17370 1.17376 0.6
2025-06-02 04:00:00+00:00 1.17570 1.17572 0.2
2025-06-02 08:00:00+00:00 1.17466 1.17468 0.2Tres velas completas; la cuarta, marcada como en curso, se descarta. Las velas de un bróker de divisas traen bid y ask por separado, que es justo lo que hace falta para un backtest con costes realistas: la compra al ask, la venta al bid (lección 1.1.5). Las velas de «precio medio» que dan muchas fuentes gratuitas no permiten eso.
Cuándo usar el bróker como fuente
Fuente Mermaid
flowchart TB
Q{¿Para qué?} -- señal en real --> B[Datos del bróker]
Q -- backtest largo --> P[Proveedor]
Q -- universo acciones --> P
B --> C[Contrastar]
P --> C| Uso | ¿Bróker? | Por qué |
|---|---|---|
| Señales y ejecución en tiempo real | Sí | Son los precios donde se ejecuta |
| Costes de un sistema de divisas o CFD | Sí | Su horquilla y su financiación son las que se pagan |
| Histórico largo de barras pequeñas | No | Límites de ritmo y duración máxima por petición |
| Universo de acciones para un backtest | No | Solo tiene lo que cotiza hoy: sesgo de supervivencia (lección 1.3.8) |
| Validar un proveedor | Sí, como contraste | Comparar unos días de precios de ambos detecta diferencias de horario o de ajustes |
La combinación habitual es un proveedor para la historia y el research y el bróker para la operativa, con una comprobación periódica de que los dos cuentan la misma historia en los días que se solapan.
Ejercicios
- Con
descarga, ¿cuánto tarda un año de barras de 5 segundos conBID_ASKpara 10 contratos, si se piden uno detrás de otro con el mismo limitador? (Pista: las reglas de 10 minutos cuentan todas las peticiones, no por contrato.)
Solución
h = descarga(10 * 252, peso=2)
print(f"{len(h)} peticiones: {h[-1] / 3600:.1f} horas")2520 peticiones: 13.8 horas2.520 peticiones que cuentan doble son 5.040 unidades de las 60 por ventana de 10 minutos: unas 84 ventanas, casi 14 horas. Con diez contratos la descarga ya no es «un momento antes de empezar», sino un trabajo de noche que hay que poder reanudar si se corta (lección 1.4.8).
- En la respuesta de OANDA, calcula la horquilla media de las velas completas en pips usando el cierre, y compárala con la de la apertura. ¿Por qué no tienen por qué coincidir?
Solución
oanda["spread_ap"] = 1e4 * (oanda["ask_o"] - oanda["bid_o"])
oanda[["spread_ap", "spread_pips"]].mean().round(2)spread_ap 0.53
spread_pips 0.33
dtype: float64Las horquillas de apertura y de cierre son dos fotos en dos momentos distintos de la vela; la horquilla cambia con la sesión (más ancha en Asia y en el rollover, más estrecha en el solape de Londres y Nueva York, lección 1.2.4). Para un backtest, la horquilla que importa es la del momento de la orden: si el sistema opera al cierre de la vela, la de cierre.
- Tu sistema opera EURUSD con velas de 4 horas en un bróker con MetaTrader 5 y quieres 15 años de historia para probarlo. ¿De dónde sacarías los datos y qué comprobarías?
Solución
El histórico del terminal está limitado por «Max. bars in chart» y por lo que el bróker tenga guardado; para 15 años
conviene un proveedor de divisas con historia larga (lección 1.3.3) y usar el bróker para los años recientes y la
operativa. Comprobaciones: que las horas sean UTC en ambas fuentes (MT5 guarda la apertura en UTC, pero muchos brókeres
muestran la hora del servidor en otra zona), que las velas de 4 horas empiecen en las mismas horas, la diferencia de
precios en los días que se solapan (precio medio frente a bid), y que la horquilla del backtest sea la del bróker
(spread), no la del proveedor.
Footnotes
-
IBKR: Configure the Connecting Socket Port, consultada el 21/10/2026. ↩
-
README de ib_async, consultado el 21/10/2026; versión 2.1.0 en PyPI. ↩
-
IBKR: Pacing Limitations, Market Data Lines y Market Data, consultadas el 21/10/2026. ↩ ↩2
-
IBKR, documentación anterior de la API: Historical Data Limitations («This documentation is now deprecated»), consultada el 21/10/2026. ↩
-
IBKR: Historical Bars (OHLC), tabla de duración máxima por tamaño de barra. ↩
-
MetaTrader 5: Python Integration e initialize; ruedas
win_amd64de la versión 5.0.6231 en PyPI. ↩ -
OANDA v20: Development Guide, Best Practices y Troubleshooting, consultadas el 21/10/2026. ↩
-
OANDA v20: Pricing (endpoint de velas), Instrument (esquema
Candlestick) y Primitives (DateTime). ↩
Respuesta plegada en cada pregunta
Autoevaluación
Conectas
ib_asyncal puerto 7497. ¿A qué te conectas, según la tabla de puertos de IBKR?- AA TWS con la cuenta real
- BA TWS con la cuenta de papel (simulada)
- CA IB Gateway con la cuenta real
- DDirectamente a los servidores de IBKR
Ver respuesta
Respuesta B. A TWS con la cuenta de papel (simulada)
Los puertos por defecto son 7496 (TWS real), 7497 (TWS papel), 4001 (Gateway real) y 4002 (Gateway papel). La API nunca habla directamente con los servidores: siempre pasa por TWS o por IB Gateway en tu máquina.
¿Qué relación hay entre
ib_asynceib_insync?- ASon librerías rivales sin relación
- B
ib_asynces la continuación deib_insync, renombrada en una organización nueva de GitHub tras el fallecimiento de su autor en 2024 - C
ib_asynces la librería oficial de IBKR - D
ib_insynces la versión nueva
Ver respuesta
Respuesta B.
ib_asynces la continuación deib_insync, renombrada en una organización nueva de GitHub tras el fallecimiento de su autor en 2024Su README cuenta que Ewald de Wit creó
ib_insyncen 2017 y la mantuvo hasta su fallecimiento a principios de 2024; los mantenedores la renombraron porque ya no podían modificar el repositorio original.Con las reglas de ritmo de IBKR para barras de 30 segundos o menos, ¿cuántas peticiones de histórico puedes hacer en 10 minutos?
- AIlimitadas
- B60
- C600
- D6
Ver respuesta
Respuesta B. 60
Más de 60 peticiones en cualquier periodo de 10 minutos es una violación de ritmo. Además no se puede repetir una petición idéntica en 15 segundos ni hacer 6 o más del mismo contrato en 2 segundos. Con
BID_ASK, cada petición cuenta doble.OANDA devuelve una vela con
"complete": false. ¿Qué significa?- AQue faltan precios
- BQue es la vela en curso: su final está en el futuro y sus valores cambiarán
- CQue el mercado estaba cerrado
- DQue hubo un error
Ver respuesta
Respuesta B. Que es la vela en curso: su final está en el futuro y sus valores cambiarán
La documentación define una vela completa como aquella cuyo final no está en el futuro. Una vela incompleta no se guarda como histórico.
¿Cuál es la principal ventaja de usar el bróker como fuente de datos?
- AQue siempre es gratis y sin límites
- BQue son los precios del sitio donde ejecutas, con su horquilla y su horario, y no hace falta otro contrato
- CQue tiene más historia que cualquier proveedor
- DQue no tiene sesgo de supervivencia
Ver respuesta
Respuesta B. Que son los precios del sitio donde ejecutas, con su horquilla y su horario, y no hace falta otro contrato
Para un sistema que opera en ese bróker, sus precios son los ejecutables. A cambio, la historia suele ser más corta, los límites más estrictos y no hay valores deslistados (lección 1.3.8).
Ideas clave
- La API de IBKR no habla con los servidores: habla con TWS o IB Gateway en tu máquina, por un puerto (7496/7497 en TWS, 4001/4002 en Gateway) y con un
clientId. ib_asynces la continuación deib_insync; requiere Python 3.10 o superior y no necesita el paqueteibapide IBKR.- Los datos por API necesitan una suscripción de mercado de pago (salvo los diferidos), y las peticiones están limitadas: 50 por segundo en general y reglas propias para el histórico de barras pequeñas.
- El límite de ritmo decide cuánto tarda una descarga histórica: un año de barras de 1 segundo de un contrato son unas 3.000 peticiones y más de 8 horas.
- MetaTrader 5 entrega arrays de numpy con hora en UTC desde un terminal instalado (solo hay ruedas para Windows); OANDA, JSON con precios como texto, hora RFC 3339 y una marca
complete. - El bróker es la mejor fuente de los precios a los que ejecutas, y una mala fuente de historia larga y de universos sin sesgo.