Referencia de la API
Conecta señales en vivo a tus propios sistemas. La API es de solo lectura: sirve datos de mercado y nunca puede colocar una orden ni tocar una cuenta de exchange. Incluida en VIP Quant. ¿Eres nuevo en la terminal? Empieza por la documentación.
URL base:
https://api.arbitragex.io
Autenticación
Crea una clave en Ajustes. Se muestra una vez y solo se guarda como hash, así que guárdala bien y nunca la pongas en un navegador. Las claves perdidas no se pueden recuperar: revócala y crea otra. Hasta 5 claves por usuario. Envíala en la cabecera X-API-Key en cada petición, incluida la actualización a websocket.
curl -H "X-API-Key: $ARBITRAGEX_KEY" https://api.arbitragex.io/v1/opportunities
import os, requests
rows = requests.get(
"https://api.arbitragex.io/v1/opportunities",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=5,
).json()["rows"]
for row in rows[:5]:
print(row["coin"], row["buy"]["venue"], row["sell"]["venue"], row["netUsd"]["1000"])const res = await fetch("https://api.arbitragex.io/v1/opportunities", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
const { rows } = await res.json();
for (const row of rows.slice(0, 5)) {
console.log(row.coin, row.buy.venue, row.sell.venue, row.netUsd["1000"]);
}Una clave revocada deja de funcionar en segundos, y los sockets abiertos se cierran poco después. Una clave se detiene cuando lo hace su plan y vuelve a funcionar si el plan regresa.
Límites de peticiones
Cada clave tiene su propio límite, 120 peticiones por minuto por defecto, contadas en ventanas de un minuto, más 3 sockets abiertos. Cada respuesta te indica dónde estás:
X-RateLimit-Limit: peticiones permitidas por ventana.X-RateLimit-Remaining: peticiones restantes en esta ventana.X-RateLimit-Reset: segundos hasta que termina la ventana.
Usa preferiblemente el websocket para filas en vivo. Envía los cambios en cuanto ocurren, y un socket no cuenta contra el límite una vez abierto.
Errores
Los errores son JSON: { "error": "Rate limit reached." }
- 401: la clave es incorrecta, está revocada o su plan ha terminado.
- 405: la API solo acepta GET.
- 429: se alcanzó el límite de peticiones o de sockets. Espera los segundos de
Retry-After. - 503: las claves no se pueden comprobar ahora. Reintenta en breve.
OpenAPI
Toda la API se describe en un único documento OpenAPI 3.1 en una dirección estable. Impórtalo en Postman, Insomnia o Swagger UI, o genera un cliente tipado a partir de él. Cada endpoint incluye los ejemplos en curl, Python y JavaScript de abajo.
https://arbitragex.io/openapi.json
# A typed client, for example: npx openapi-typescript https://arbitragex.io/openapi.json -o arbitragex.d.ts openapi-python-client generate --url https://arbitragex.io/openapi.json
Referencia de endpoints
Cada endpoint REST, generado a partir del documento OpenAPI. Cada ejemplo lee tu clave de la variable de entorno ARBITRAGEX_KEY.
- /v1/opportunities Live opportunities
- /v1/listings New listings
- /v1/notices Exchange notices
- /v1/funding Funding rates
- /v1/funding/history Funding history
- /v1/premiums Regional premiums
- /v1/markets Volume and open interest
- /v1/fees Taker fees
- /v1/reliability Venue reliability
- /v1/spread/{id} A route's spread over time
- /v1/proof Proof Log
- /v1/events Prediction market routes
- /v1/events/proof Prediction market Proof Log
- /v1/events/markets Prediction market browser
- /v1/events/history A market's odds over time
- /v1/events/holders A Polymarket market's holders and big bets
get/v1/opportunitiesLive opportunities
Every route on the feed right now, as the plan sees it. Reading it often is fine; the stream is better past a few times a minute.
strategyquery: `all`, the default, or one trade type.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/opportunities"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/opportunities",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["coin"], row["buy"]["venue"], row["sell"]["venue"], row["netBps"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/opportunities", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.coin, row.buy.venue, row.sell.venue, row.netBps);get/v1/listingsNew listings
Markets first seen in the last 72 hours, newest first, and listings exchanges have announced but don't list yet.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/listings"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/listings",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"]:
print(row["venue"], row["kind"], row["coin"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/listings", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows) console.log(row.venue, row.kind, row.coin);get/v1/noticesExchange notices
Delistings, deposit and withdrawal suspensions, maintenance and announced listings still in effect, newest first. The same for every plan.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/notices"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/notices",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"]:
print(row["venue"], row["kind"], row["coins"], row["title"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/notices", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows) console.log(row.venue, row.kind, row.coins, row.title);get/v1/fundingFunding rates
Every perp's current funding rate, per interval and annualised.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/funding"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/funding",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
top = sorted(data["rows"], key=lambda r: -abs(r["aprPct"]))[:5]
for row in top:
print(row["coin"], row["venue"], row["aprPct"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/funding", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
const top = [...data.rows].sort((a, b) => Math.abs(b.aprPct) - Math.abs(a.aprPct)).slice(0, 5);
for (const row of top) console.log(row.coin, row.venue, row.aprPct);get/v1/funding/historyFunding history
One coin's funding settlements over the last 30 days, oldest first. A gap is never filled in.
coinquery, obligatorio: The coin, in any case.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/funding/history?coin=BTC"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/funding/history?coin=BTC",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"]:
print(row["venue"], len(row["points"]), "settlements")JavaScript
const res = await fetch("https://api.arbitragex.io/v1/funding/history?coin=BTC", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows) console.log(row.venue, row.points.length, "settlements");get/v1/premiumsRegional premiums
Each coin's premium in each local currency over the middle USDT price on order book venues, priced through each venue's own USDT book, with each currency's index and its 24 hours of 5-minute means. With coin, that coin's rows only, each with its own 24 hours.
coinquery: One coin, in any case.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/premiums"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/premiums",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["coin"], row["fiat"], row["premiumBps"], row["verified"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/premiums", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.coin, row.fiat, row.premiumBps, row.verified);get/v1/marketsVolume and open interest
One row per market, busiest first, as arrays: [venue, kind, coin, symbol, volumeUsd, oiUsd]. Null where the venue publishes no figure.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/markets"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/markets",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for venue, kind, coin, symbol, volume, oi in data["rows"][:5]:
print(venue, kind, symbol, volume, oi)JavaScript
const res = await fetch("https://api.arbitragex.io/v1/markets", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const [venue, kind, , symbol, volume, oi] of data.rows.slice(0, 5)) console.log(venue, kind, symbol, volume, oi);get/v1/feesTaker fees
Each venue's published base taker fee, the rate net figures are priced at. Re-price a route at your own fees with the formula on /docs/api#fees.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/fees"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/fees",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"]:
print(row["venue"], row["spotTakerBps"], row["perpTakerBps"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/fees", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows) console.log(row.venue, row.spotTakerBps, row.perpTakerBps);get/v1/reliabilityVenue reliability
Each venue's track record over the last 7 and 30 UTC days, from watched time only: uptime, outages, how fresh its prices were, the share of its routes that lasted 30 seconds, and wallet list changes. A figure with too little behind it is null, never a guess.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/reliability"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/reliability",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["venue"], row["online"], row["uptime7d"], row["heldShare30d"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/reliability", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.venue, row.online, row.uptime7d, row.heldShare30d);get/v1/spread/{id}A route's spread over time
Net bps over time for one route. Without a range, the latest row, up to 72 points. With `from` or `to`, every row in that stretch, at most 2,000 points, keeping the peaks.
idpath, obligatorio: A route id, URL-encoded.fromquery: Earliest point, unix ms.toquery: Latest point, unix ms.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/spread/BTC%7CBinance%3Aspot%7COKX%3Aperp"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/spread/BTC%7CBinance%3Aspot%7COKX%3Aperp",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
print(len(data["points"]), "points, peak", max((p["netBps"] for p in data["points"]), default=None))JavaScript
const res = await fetch("https://api.arbitragex.io/v1/spread/BTC%7CBinance%3Aspot%7COKX%3Aperp", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
console.log(data.points.length, "points, peak", Math.max(...data.points.map((p) => p.netBps)));get/v1/proofProof Log
Closed opportunities that lasted at least 30 seconds, newest first, with a cursor for the next page.
limitquery: Rows per page, 50 by default, at most 500.fromquery: Earliest close, unix ms.toquery: Latest close, unix ms.coinquery: One coin, exact in any case.cursorquery: `next` from the previous page.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/proof?limit=100"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/proof?limit=100",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["coin"], row["buyVenue"], row["sellVenue"], row["peakNetBps"])
print("next page:", data["next"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/proof?limit=100", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.coin, row.buyVenue, row.sellVenue, row.peakNetBps);
console.log("next page:", data.next);get/v1/eventsPrediction market routes
Sets of contracts on Polymarket, Polymarket US and Kalshi that cost less after fees than the $1 they pay at settlement, best net first, as the plan sees them. Every `cross` route is Caution: each exchange settles by its own rules, attached in `rules`.
kindquery: `all`, the default, or one route kind.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/events"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/events",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["kind"], row["title"], row["netBps"], row["days"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/events", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.kind, row.title, row.netBps, row.days);get/v1/events/proofPrediction market Proof Log
Prediction market routes that ended after lasting at least 30 seconds, newest first, with a cursor for the next page. Kept a year.
limitquery: Rows per page, 50 by default, at most 500.fromquery: Earliest close, unix ms.toquery: Latest close, unix ms.kindquery: `all`, the default, or one route kind.cursorquery: `next` from the previous page.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/events/proof?limit=100"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/events/proof?limit=100",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["kind"], row["title"], row["venues"], row["peakNetBps"])
print("next page:", data["next"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/events/proof?limit=100", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.kind, row.title, row.venues, row.peakNetBps);
console.log("next page:", data.next);get/v1/events/marketsPrediction market browser
Every open market on Polymarket, Polymarket US and Kalshi, routes or not, joined into events so each venue's odds for the same outcome stand side by side. Odds are YES's probability, 0 to 1. With `group`, one event whole; with `markets`, the events holding those markets. Live on every plan.
qquery: Every word in the title, outcomes or questions. At most 100 characters.categoryquery: One category.venuequery: Events on this venue.daysquery: An outcome resolving within this many days.sortquery: `volume`, the default, `closing` or `movers`.limitquery: Rows per page, 25 by default, at most 50.cursorquery: `next` from the previous page.groupquery: One event's id, for all its outcomes.marketsquery: Up to 50 `<venue>|<market id>`, comma separated.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/events/markets?category=crypto&sort=closing"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/events/markets?category=crypto&sort=closing",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for row in data["rows"][:5]:
print(row["title"], [(q["venue"], q["prob"]) for q in row["lines"][0]["quotes"]])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/events/markets?category=crypto&sort=closing", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const row of data.rows.slice(0, 5)) console.log(row.title, row.lines[0].quotes.map((q) => [q.venue, q.prob]));get/v1/events/historyA market's odds over time
YES's probability over a day, week or month, oldest first: from the venue where it keeps a history, else sampled by us.
venuequery, obligatorio: The market's venue.marketquery, obligatorio: The market id, as in a quote's `marketId`.rangequery: `1d`, `1w` or `1m`.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/events/history"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/events/history",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
print(len(data["points"]), "points from", data["source"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/events/history", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
console.log(data.points.length, "points from", data.source);get/v1/events/holdersA Polymarket market's holders and big bets
The top 10 holders of each outcome and the latest 20 bets of $1,000 or more, as Polymarket's public data states them.
marketquery, obligatorio: Polymarket's condition id.
curl
curl -s -H "X-API-Key: $ARBITRAGEX_KEY" "https://api.arbitragex.io/v1/events/holders"
Python
import os
import requests
res = requests.get(
"https://api.arbitragex.io/v1/events/holders",
headers={"X-API-Key": os.environ["ARBITRAGEX_KEY"]},
timeout=10,
)
res.raise_for_status()
data = res.json()
for h in data["holders"][:5]:
print(h["side"], h["name"] or h["address"], h["shares"])JavaScript
const res = await fetch("https://api.arbitragex.io/v1/events/holders", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();
for (const h of data.holders.slice(0, 5)) console.log(h.side, h.name ?? h.address, h.shares);Oportunidades
GET /v1/opportunities devuelve cada fila en vivo, de mayor a menor neto.
{
"rows": [
{
"id": "BTC|Binance:spot|OKX:perp",
"coin": "BTC",
"strategy": "spot_perp",
"buy": { "venue": "Binance", "kind": "spot", "symbol": "BTCUSDT", "price": 68250.1,
"sizeUsd": 41200, "ageMs": 120, "fundingBps8h": null, "url": "https://..." },
"sell": { "venue": "OKX", "kind": "perp", "symbol": "BTC-USDT-SWAP", "price": 68310.4,
"sizeUsd": 38900, "ageMs": 240, "fundingBps8h": 1.2, "url": "https://..." },
"grossBps": 8.8,
"netBps": 2.1,
"netUsd": { "100": 0.2, "1000": 2.1, "10000": 19.4, "100000": null, "1000000": null },
"maxSizeUsd": 21400,
"exitBps": 6.2,
"transfer": "not_needed",
"network": null,
"status": "verified",
"reasons": [],
"firstSeenMs": 1793570209670,
"updatedMs": 1793570229670,
"spark": [2.0, 2.1]
}
],
"delayedMs": 0
}Financiación
GET /v1/funding devuelve la tasa de financiación actual de cada perp.
{ "rows": [ { "coin": "BTC", "venue": "Binance", "symbol": "BTCUSDT", "ratePct": 0.01,
"hours": 8, "aprPct": 10.95, "nextFundingMs": 1793577600000 } ] }Comisiones
GET /v1/fees devuelve las comisiones taker publicadas de cada exchange en bps, por ejecución. Las cifras netas usan la tarifa base. Para calcular el neto con tu propia comisión sobre un tamaño S:
{ "rows": [ { "venue": "Binance", "spotTakerBps": 10, "perpTakerBps": 5 } ] }
fills = 1 if strategy == "spot" else 2 # a hedged route pays again to close
shift = fills * ((paid_buy - mine) + (paid_sell - mine) * (1 + grossBps / 10000))
net = netUsd[S] + S * shift / 10000Spread
GET /v1/spread/:id devuelve el spread neto de una ruta, en vivo mientras está abierta y tal como se guardó tras cerrarse. Codifica el id para URL. Añade from o to, en milisegundos unix, para leer la ruta en todo su historial guardado en ese rango: como máximo 2000 puntos, del más antiguo al más reciente, conservando los picos.
curl -H "X-API-Key: $ARBITRAGEX_KEY" \
"https://api.arbitragex.io/v1/spread/BTC%7CBinance%3Aspot%7COKX%3Aperp"
{ "points": [ { "t": 1793570209670, "netBps": 2.1 } ], "historyFromMs": 0 }Proof Log
GET /v1/proof?limit=50 devuelve oportunidades cerradas que duraron al menos 30 segundos, de la más reciente a la más antigua. limit es como máximo 500. Una ruta que vuelve en menos de 5 minutos amplía su última fila, así que una fila puede volver arriba.
from,to: milisegundos unix, según el cierre de la fila.coin: una moneda.cursor: el valornextde la página anterior.nextes null en la última página.
{ "rows": [ { "id": "BTC|Binance:spot|OKX:perp", "coin": "BTC", "strategy": "spot_perp",
"buyVenue": "Binance", "sellVenue": "OKX", "peakNetBps": 4.2, "maxSizeUsd": 21400,
"openNetBps": 3.8, "openSizeUsd": 18200, "closeNetBps": 1.1, "closeSizeUsd": 9600,
"status": "verified", "openedMs": 1793570209670, "closedMs": 1793570389670 } ],
"next": "1793570389670:48121", "historyFromMs": 0 }Websocket
Conéctate a wss://api.arbitragex.io/v1/stream con la clave en la cabecera X-API-Key. Recibes un snapshot de todas las filas y luego lotes como mucho cada 250 ms. Un cliente que se queda unos 4 segundos atrás se desconecta, y recibe un snapshot nuevo al reconectarse.
import WebSocket from "ws";
const rows = new Map();
function connect() {
const socket = new WebSocket("wss://api.arbitragex.io/v1/stream", {
headers: { "X-API-Key": process.env.ARBITRAGEX_KEY },
});
socket.on("message", (data) => {
const message = JSON.parse(data);
if (message.type === "snapshot") {
rows.clear();
for (const row of message.rows) rows.set(row.id, row);
}
if (message.type === "upsert") for (const row of message.rows) rows.set(row.id, row);
if (message.type === "remove") for (const id of message.ids) rows.delete(id);
});
socket.on("close", () => setTimeout(connect, 1000));
}
connect();snapshot:{ type, rows, delayedMs }, siempre primero.upsert:{ type, rows }, filas nuevas o modificadas, como máximo 400 por lote.remove:{ type, ids }, filas que han desaparecido.health:{ type, venues, medianLatencyMs }, cada 5 segundos.
Tipos
strategy:spot,spot_perpoperp_perp.status:verifiedocaution, con texto sencillo enreasons.transfer:open,unknownonot_needed.netUsd: ganancia estimada en cada tamaño.nullsignifica que los libros no pueden ejecutarlo.netBps: tras costes con 1000 $, o al tamaño más rentable si con 1000 $ se pierde.- Los tiempos son milisegundos unix. Los precios son USDT por moneda entera.
Las cifras netas son estimaciones, no ejecuciones. Consulta cómo se calcula el neto. Eres responsable de todo lo que automatices.