API 레퍼런스
실시간 시그널을 자체 시스템에 연결하세요. API는 읽기 전용입니다: 시장 데이터만 제공하며 주문을 내거나 거래소 계정에 접근할 수 없습니다. VIP Quant에 포함됩니다. 터미널이 처음이신가요? 문서부터 시작하세요.
기본 URL:
https://api.arbitragex.io
인증
설정에서 키를 만드세요. 키는 한 번만 표시되고 해시로만 저장되므로 안전하게 보관하고 브라우저에 넣지 마세요. 분실한 키는 복구할 수 없습니다: 폐기하고 새로 만드세요. 사용자당 최대 5개. 웹소켓 업그레이드를 포함한 모든 요청에 X-API-Key 헤더로 보내세요.
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"]);
}폐기된 키는 몇 초 내에 작동을 멈추고, 열린 소켓도 곧 닫힙니다. 플랜이 종료되면 키도 멈추고, 플랜이 복구되면 다시 작동합니다.
요청 한도
키마다 별도의 한도가 있으며, 기본값은 분당 120회 요청(1분 단위 집계)과 열린 소켓 3개입니다. 모든 응답에 현재 상태가 표시됩니다:
X-RateLimit-Limit: 구간당 허용 요청 수.X-RateLimit-Remaining: 이번 구간의 남은 요청 수.X-RateLimit-Reset: 구간 종료까지 남은 초.
실시간 행에는 웹소켓을 권장합니다. 변경 사항을 즉시 푸시하며, 소켓은 열린 후에는 한도에 포함되지 않습니다.
오류
오류는 JSON 형식입니다: { "error": "Rate limit reached." }
- 401: 키가 잘못되었거나, 폐기되었거나, 플랜이 종료되었습니다.
- 405: API는 GET만 허용합니다.
- 429: 요청 한도 또는 소켓 한도에 도달했습니다.
Retry-After초만큼 기다리세요. - 503: 지금은 키를 확인할 수 없습니다. 잠시 후 다시 시도하세요.
OpenAPI
전체 API는 고정 주소에 있는 하나의 OpenAPI 3.1 문서에 기술되어 있습니다. Postman, Insomnia 또는 Swagger UI로 가져오거나, 이 문서에서 타입이 지정된 클라이언트를 생성하세요. 문서의 모든 엔드포인트에는 아래의 curl, Python, JavaScript 예제가 함께 있습니다.
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
엔드포인트 레퍼런스
OpenAPI 문서에서 생성한 모든 REST 엔드포인트입니다. 각 예제는 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, 필수: 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, 필수: 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, 필수: The market's venue.marketquery, 필수: 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, 필수: 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);기회
GET /v1/opportunities는 순수익이 높은 순으로 모든 실시간 행을 반환합니다.
{
"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
}펀딩비
GET /v1/funding은 모든 무기한 계약의 현재 펀딩비를 반환합니다.
{ "rows": [ { "coin": "BTC", "venue": "Binance", "symbol": "BTCUSDT", "ratePct": 0.01,
"hours": 8, "aprPct": 10.95, "nextFundingMs": 1793577600000 } ] }수수료
GET /v1/fees는 각 거래소의 공시 테이커 수수료를 체결당 bps로 반환합니다. 순수익 수치는 기본 요율을 사용합니다. 규모 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 / 10000스프레드
GET /v1/spread/:id는 경로의 순 스프레드를 반환하며, 열려 있는 동안은 실시간으로, 종료 후에는 저장된 값으로 제공합니다. id는 URL 인코딩하세요. 유닉스 밀리초 단위의 from 또는 to를 추가하면 해당 범위의 전체 저장 기록을 조회할 수 있습니다: 최대 2,000개 포인트, 오래된 순, 고점 유지.
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은 최소 30초 이상 지속된 종료된 기회를 최신순으로 반환합니다. limit는 최대 500입니다. 5분 이내에 다시 열린 경로는 마지막 행을 확장하므로, 행이 다시 맨 위로 이동할 수 있습니다.
from,to: 행이 종료된 시점 기준, 유닉스 밀리초.coin: 코인 하나.cursor: 이전 페이지의next값. 마지막 페이지에서next는 null입니다.
{ "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 }웹소켓
X-API-Key 헤더에 키를 넣어 wss://api.arbitragex.io/v1/stream에 연결하세요. 먼저 모든 행의 snapshot을 받은 후, 최대 250ms마다 배치를 받습니다. 약 4초 이상 뒤처진 클라이언트는 연결이 끊기며, 재연결 시 새 스냅샷을 받습니다.
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 }, 항상 첫 번째.upsert:{ type, rows }, 신규 또는 변경된 행, 배치당 최대 400개.remove:{ type, ids }, 사라진 행.health:{ type, venues, medianLatencyMs }, 5초마다.
타입
strategy:spot,spot_perp또는perp_perp.status:verified또는caution,reasons에 설명 포함.transfer:open,unknown또는not_needed.netUsd: 각 규모에서의 예상 수익.null은 호가창이 체결할 수 없다는 뜻입니다.netBps: $1,000 기준 비용 차감 후 값, $1,000에서 손실이면 가장 수익성 높은 규모 기준.- 시간은 유닉스 밀리초입니다. 가격은 코인 1개당 USDT입니다.
순수익 수치는 실제 체결이 아닌 추정치입니다. 순수익 계산 방법을 확인하세요. 자동화하는 모든 것에 대한 책임은 본인에게 있습니다.