The Bot Ledger
ES

Inicio / Guías

Guía de la API de Kalshi: conecta un bot en 5 pasos

La API de Kalshi para un bot, en Python: peticiones firmadas, la forma del libro, enviar y cancelar órdenes, ejecuciones e historial gratuito de velas.

Server racks in a data center lit blue
Auth
API key id más una firma RSA sobre el timestamp, el método y la ruta, en cada petición.
Lectura
Una sola API REST para mercados, libros y velas; un websocket para ejecuciones y deltas del libro.
Trading
Órdenes limitadas en centavos o dólares por contrato; el libro está en contratos.
Comisión de taker
0.07 x contratos x p x (1-p), redondeada hacia arriba al centavo por orden. Los makers no pagan nada en casi todas las series.
Liquidación
Publicada por el exchange; los mercados de cripto liquidan sobre una media que el exchange transmite a medida que se acumula.
Geografía
Cuentas de Estados Unidos. Los programas de recompensas están cerrados a usuarios de fuera de Estados Unidos.
Docs
docs.kalshi.com

Cinco pasos, simplificados a propósito. Las rutas de los endpoints siguen la referencia pública en el momento de escribir esto; consulta la documentación antes de depender de ellas.

  1. Firma cada petición

    Genera una API key en los ajustes de la cuenta; recibes un key id y un archivo de clave privada. Cada petición lleva el id, un timestamp en milisegundos y una firma RSA-PSS sobre el timestamp, el método HTTP y la ruta.

    import time, base64, requests
    from cryptography.hazmat.primitives import hashes, serialization
    from cryptography.hazmat.primitives.asymmetric import padding
    
    BASE = "https://api.elections.kalshi.com/trade-api/v2"
    key = serialization.load_pem_private_key(open("kalshi.pem", "rb").read(), password=None)
    
    def headers(method, path):
        ts = str(int(time.time() * 1000))
        msg = (ts + method + "/trade-api/v2" + path).encode()
        sig = key.sign(msg, padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH), hashes.SHA256())
        return {"KALSHI-ACCESS-KEY": KEY_ID, "KALSHI-ACCESS-SIGNATURE": base64.b64encode(sig).decode(), "KALSHI-ACCESS-TIMESTAMP": ts}
  2. Lista los mercados de una serie

    r = requests.get(f"{BASE}/markets", params={"series_ticker": "KXBTC15M", "status": "open"}, headers=headers("GET", "/markets"))
    markets = r.json()["markets"]
    ticker = markets[0]["ticker"]
  3. Lee el libro de órdenes

    El endpoint del libro cambió de forma: la versión nueva lista el precio en dólares y el tamaño por nivel. Un parser escrito para los antiguos arrays en centavos devuelve profundidad cero sin ningún error.

    path = f"/markets/{ticker}/orderbook"
    ob = requests.get(BASE + path, headers=headers("GET", path)).json()["orderbook_fp"]
    yes_bids = ob["yes_dollars"]      # [[price_dollars, size], ...]
    no_bids  = ob["no_dollars"]
    best_yes_ask = 1 - float(no_bids[-1][0])   # un ask de YES es el espejo del mejor bid de NO

    La escalera puede estar cruzada (mejor bid de YES más mejor bid de NO por encima de 1.00) en una parte apreciable de las instantáneas. Protégete contra eso antes de cotizar.

  4. Envía y cancela una orden

    order = {"ticker": ticker, "action": "buy", "side": "yes", "type": "limit",
             "count": 20, "yes_price": 85, "client_order_id": "win-1757500800"}
    r = requests.post(f"{BASE}/portfolio/orders", json=order, headers=headers("POST", "/portfolio/orders"))
    order_id = r.json()["order"]["order_id"]
    
    requests.delete(f"{BASE}/portfolio/orders/{order_id}", headers=headers("DELETE", f"/portfolio/orders/{order_id}"))
  5. Lee ejecuciones y liquidaciones

    fills = requests.get(f"{BASE}/portfolio/fills", headers=headers("GET", "/portfolio/fills")).json()["fills"]
    settled = requests.get(f"{BASE}/portfolio/settlements", headers=headers("GET", "/portfolio/settlements")).json()

    Usa el websocket para las ejecuciones en un bot en vivo; consultar el endpoint de órdenes en bucle tiene límite de peticiones.

Historial gratuito del que nadie habla

El endpoint de candlesticks devuelve el historial de bid, ask y volumen de cualquier mercado en el intervalo que elijas, desde su listado. Para investigar, sustituye al logger que todavía no has escrito.

path = f"/series/KXBTC15M/markets/{ticker}/candlesticks"
c = requests.get(BASE + path, params={"start_ts": t0, "end_ts": t1, "period_interval": 1}, headers=headers("GET", path)).json()