Aprender/Series temporales

Tipos de cambio históricos y series temporales

Usa /v1/range para obtener historia de varias divisas y cargarla en pandas u otra herramienta.

ERexchangerate.dev·19 jun 2026·6 min de lectura

El rango devuelve observaciones guardadas con paginación, fuente y marcas de relleno.

Puntos clave
Cada página JSON contiene hasta 366 observaciones; sigue next_cursor mientras has_more sea true.
1.830 días es el límite, no una promesa de profundidad para cada pareja. Comprueba source, filas y data: [].
El sábado 2026-06-13 no aparece porque el rango devuelve observaciones guardadas, no una fila por día.
No. Son tipos indicativos; revisa notice y source.

Usa el endpoint de rangos

start_date y end_date son inclusivos. base usa USD por defecto y symbols se separa con comas. Abre también la herramienta histórica en inglés.

data contiene filas guardadas. Sigue has_more y next_cursor; CSV y Parquet cubren la ventana admitida.

GET /v1/rangecopy
$ curl -G "https://api.exchangerate.dev/v1/range" \
    -H "Authorization: Bearer exr_live_..." \
    --data-urlencode "base=USD" \
    --data-urlencode "symbols=EUR,GBP" \
    --data-urlencode "start_date=2026-06-10" \
    --data-urlencode "end_date=2026-06-13"

Lee la respuesta

data contiene filas guardadas. Sigue has_more y next_cursor; CSV y Parquet cubren la ventana admitida.

JSONcopy
{
  "result": "success",
  "base": "USD",
  "start_date": "2026-06-10",
  "end_date": "2026-06-13",
  "data": [
    { "date": "2026-06-10", "rates": { "EUR": 0.86663, "GBP": 0.74727 },
      "source": "ecb_daily", "is_forward_filled": false },
    { "date": "2026-06-11", "rates": { "EUR": 0.86678, "GBP": 0.74829 },
      "source": "ecb_daily", "is_forward_filled": false },
    { "date": "2026-06-12", "rates": { "EUR": 0.86453, "GBP": 0.74613 },
      "source": "ecb_daily", "is_forward_filled": false }
  ],
  "has_more": false,
  "next_cursor": null
}

Fechas del calendario ausentes

El sábado 2026-06-13 no aparece porque el rango devuelve observaciones guardadas, no una fila por día.

Paginación con Python

Usa este bucle para seguir cada cursor.

Python · requestscopy
import requests

API = "https://api.exchangerate.dev/v1"
KEY = "exr_live_..."   # free key at https://exchangerate.dev/signup

params = {
    "base": "USD",
    "symbols": "EUR,GBP",
    "start_date": "2026-06-10",
    "end_date": "2026-06-13",
}

rows = []
while True:
    resp = requests.get(
        f"{API}/range",
        headers={"Authorization": f"Bearer {KEY}"},
        params=params,
        timeout=10,
    )
    resp.raise_for_status()
    data = resp.json()
    rows.extend(data["data"])
    if not data["has_more"]:
        break
    cursor = data.get("next_cursor")
    if not cursor or cursor <= params.get("cursor", ""):
        raise RuntimeError("Incomplete historical response")
    params["cursor"] = cursor

for row in rows:
    filled = row["is_forward_filled"]
    print(row["date"], row["rates"]["EUR"], row["rates"]["GBP"], "filled" if filled else "")

Observaciones guardadas y valores trasladados

Las observaciones del rango tienen is_forward_filled false; una consulta fechada puede devolver el valor anterior y marcar true.

Un fin de semana no es una observación
El rango omite el sábado 2026-06-13. Una consulta directa puede devolver el valor anterior con is_forward_filled true.

Elige una fecha o un rango

Una fecha sirve para una consulta puntual. El rango sirve para gráficos, backfills y análisis masivo.

CampoFechaRango
SolicitudUna fechaUna solicitud y páginas
RespuestaUn díaArray data

Comprueba la cobertura

1.830 días es el límite, no una promesa de profundidad para cada pareja. Comprueba source, filas y data: [].

pandas

Carga las filas en pandas, ordénalas por fecha y excluye valores trasladados antes de calcular.

Python · pandascopy
import pandas as pd

# rows contains every page from the loop above
df = pd.json_normalize(rows)
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date").sort_index()

# keep only rows that were actually published that day
df = df[~df["is_forward_filled"]]

print(df[["rates.EUR", "rates.GBP"]].tail())

pandas es opcional; puedes procesar las mismas filas con otra herramienta.

Consultar una fecha en la herramienta histórica (en inglés)

ER
exchangerate.dev
Guías prácticas para integrar datos de FX

Sigue leyendo

TutorialObtener tipos de cambio en PythonLeer
ComparaciónFixer vs exchangerate.devComparaciónOpen Exchange Rates vs exchangerate.devComparaciónCurrencylayer vs exchangerate.devGuíaConversión de divisas en JavaScript y Node.jsGuíaCómo obtener tipos de cambio en PythonGuíaTipos de cambio en Next.js y TypeScriptTasa en vivoEUR/USDTasa en vivoGBP/USDTasa en vivoUSD/JPY