Diese Seite wurde maschinell übersetzt. Das englische Original ist maßgeblich. Auf Englisch lesen
Zum Hauptinhalt springen

WebSocket API

Echtzeit-Datenstreaming für den Hypercall-Optionshandel.

Interaktive Referenz

Sehen Sie sich die Interaktive WebSocket-API-Referenz für ein besseres Nutzungserlebnis mit Live-Beispielen und Schema-Details an.

Maschinenlesbare Spezifikation

Laden Sie die AsyncAPI-Spezifikation für die programmatische Nutzung herunter.

Verbindung

Verbinden Sie sich mit wss://HOST/ws:

Endpunkte:

  • Produktion: wss://api.hypercall.xyz/ws
  • Lokal: ws://localhost:3000/ws
Testnet-Status

Das Testnet ist vorübergehend deaktiviert, bis Hypercall mehr Testnet-HYPE erwirbt.

Wallet-Identifikation

Um Daten auf authentifizierten Kanälen (Orders, Fills, Portfolio) zu empfangen, identifizieren Sie Ihr Wallet nach dem Verbinden, indem Sie eine Authenticate-Nachricht senden:

{"type": "Authenticate", "wallet": "0x1234..."}

Der Server antwortet mit einer Bestätigung:

{"type": "Authenticated", "wallet": "0x1234..."}

Nach dem Empfang von Authenticated können Sie authentifizierte Kanäle abonnieren. Wenn die Wallet-Adresse ungültig ist, antwortet der Server mit einer Error-Nachricht und die Verbindung bleibt geöffnet.

Veraltet: Authentifizierung über Query-Parameter

Der ?wallet=-Query-Parameter wird aus Gründen der Abwärtskompatibilität weiterhin unterstützt, ist jedoch veraltet und wird in einer zukünftigen Version entfernt. Bevorzugen Sie den oben beschriebenen nachrichtenbasierten Ansatz.

Verbindungsaktivität

Der Server erzwingt einen WebSocket-Heartbeat:

  • Sendet alle 20 Sekunden einen Ping-Steuerframe
  • Erwartet einen passenden Pong innerhalb von 60 Sekunden
  • Schließt die Verbindung mit dem Schließcode 1008 und dem Grund pong timeout, wenn der Client nicht mehr antwortet

Browser-WebSocket-Implementierungen verarbeiten Ping/Pong automatisch. Viele Rust-WebSocket-Bibliotheken, darunter tungstenite und tokio-tungstenite, verarbeiten das Steuerframe-Ping/Pong ebenfalls für Sie. Prüfen Sie die Dokumentation der Bibliothek Ihres Clients, bevor Sie eine manuelle Pong-Behandlung hinzufügen. Benutzerdefinierte oder Raw-Socket-Implementierungen müssen auf Ping-Frames mit Pong antworten.

Slow-Consumer-Recovery

Der Server schließt eine /ws-Verbindung, die ausgehende Daten nicht innerhalb der konfigurierten Sicherheitsobergrenze für Nachrichten, kodierte Bytes, Warteschlangenalter oder Socket-Schreibvorgänge abbauen kann. Wenn die Verbindung noch einen Schließframe akzeptieren kann, verwendet der Server den Code 1008 und einen kompakten JSON-Grund:

{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}

Die Grund-Felder sind:

FeldBedeutung
classZustellungsklasse, deren Frame die Sicherheitsgrenze überschritten hat.
causemessage_limit, byte_limit, message_age oder write_timeout.
recoveryErforderliche nächste Aktion, wie etwa resubscribe, snapshot_resubscribe, portfolio_refetch oder rest_reconcile.

Nach jeder Trennung: verbinden Sie sich erneut, identifizieren Sie bei Bedarf das Wallet erneut, abonnieren Sie erneut und gleichen Sie den aktuellen Zustand ab, bevor Sie neue Ereignisse verarbeiten. Geordnete öffentliche Kanäle erfordern einen frischen Snapshot. Private Ereigniskanäle erfordern einen Abgleich über die maßgebliche REST-Schnittstelle, da ein Cursor-Replay noch nicht verfügbar ist. Eine vollständig blockierte Verbindung kann beendet werden, bevor sie den Schließgrund lesen kann, daher müssen Clients diesen Recovery-Ablauf auch bei einem unsauberen Schließen verwenden.

Verwenden Sie separate Verbindungen für öffentliche Marktdaten mit hoher Rate und für authentifizierte Befehle oder private Streams. Zustellungsklassen bestimmen die Metriken und das Recovery-Verhalten, aber Frames auf einer Verbindung teilen sich dennoch einen geordneten Socket-Schreibpfad. Ein blockierter öffentlicher Schreibvorgang kann daher spätere private Frames auf derselben Verbindung verzögern, bis die Schreib-Deadline sie schließt.

Kanäle abonnieren

Senden Sie eine JSON-Nachricht zum Abonnieren:

{"type": "Subscribe", "channel": "orderbook"}

Zum Abbestellen:

{"type": "Unsubscribe", "channel": "orderbook"}

Sie erhalten eine Bestätigung:

{"type": "Subscribed", "channel": "orderbook"}

Symbolfilterung

Die Kanäle order_updates und fills unterstützen einen optionalen symbols-Filter. Wenn er angegeben ist, sendet der Server nur Nachrichten, deren Basiswert einem der angegebenen Symbole entspricht.

{"type": "Subscribe", "channel": "order_updates", "symbols": ["BTC"]}

Sowohl reine Basiswerte ("BTC") als auch vollständige Instrumentennamen ("BTC-20260131-100000-C") werden akzeptiert. Um weitere Symbole hinzuzufügen, senden Sie ein weiteres Subscribe. Um bestimmte Symbole zu entfernen:

{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}

Wenn keine symbols angegeben sind, werden alle Updates für Ihr Wallet weitergeleitet.

Optionsketten-Filterung

Der options_chain-Kanal unterstützt die Filterung nach Basiswert-Symbolen, Verfallsdatum und Optionstyp:

{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
FilterWerteStandard
symbolsArray vollständiger Instrumentensymbole (z. B. ["BTC-20260131-100000-C"])Alle Instrumente
expiryDatumszeichenkette "YYYY-MM-DD"Alle Verfallstermine
option_type"call", "put" oder weglassen für beideBeide

Verfügbare Kanäle

KanalAuthentifizierung erforderlichBeschreibung
orderbookNeinL2-Orderbuch-Updates für alle Symbole
tradesNeinÖffentlicher Trade-Feed
market_updatesNeinÄnderungen an Marktlistungen (erstellt/gelöscht/verfallen)
options_chainNeinInkrementelle Optionsketten-Updates (filterbar nach Symbolen, Verfall, Optionstyp)
index_pricesNeinEchtzeit-Spot-/Indexpreise für alle Basiswerte
indicative_market_dataNeinQuote-Provider-Stream mit Allowlist. Noch nicht allgemein verfügbar
order_updatesJaÄnderungen an Ihrem Orderstatus (filterbar nach Symbol)
fillsJaIhre Trade-Fills (filterbar nach Symbol)
portfolioJaIhre Positions- und Guthaben-Updates
liquidationJaÄnderungen an Ihrem Liquidationszustand
competitionJaIhre Competition-GuV-Zusammenfassung, Rang und finale Statistiken
competition_engagementJaRangänderungen, Abstand zum nächsten Rang und Endstände
rfqJaRFQ-Quotes, Statusaktualisierungen und Fill-Benachrichtigungen

Nachrichtentypen

Order platzieren (authentifiziert)

Platzieren Sie eine Order über den WebSocket-Befehlspfad.

{
"type": "PlaceOrder",
"wallet": "0x1234...",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"size": "1",
"price": "100",
"tif": "gtc",
"route": "book_only",
"client_id": "my-order-1",
"nonce": 1000,
"signature": "0x..."
}
FeldTypBeschreibung
walletstringWallet-Adresse, die die Order besitzt
symbolstringOptionssymbol
sidestring"Buy" oder "Sell"
sizestringKontraktgröße, exakt übereinstimmend mit dem signierten Wert
pricestringLimitpreis, exakt übereinstimmend mit dem signierten Wert
tifstringOptionale Time-in-Force, Standardwert "gtc"
routestringOptionale Route. Verwenden Sie "book_only" für routenbewusste WebSocket-Orders. Eine weggelassene Route bleibt mindestens bis zum 4. Juli 2026 akzeptiert.
client_idstringOptionale Client-Order-ID
nonceintegerEindeutige Signier-Nonce
signaturestringEIP-712-PlaceOrder-Signatur

WebSocket-PlaceOrder leitet derzeit direkt an das Orderbuch weiter. route="best_execution" und route="rfq_only" werden über WebSocket abgelehnt, da dieser Pfad noch kein RPI/RFQ-Routing ausführt. Verwenden Sie POST /order für best_execution.

Orderbuch-Update

L2-Orderbuch-Snapshot/-Update für ein Symbol.

{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
FeldTypBeschreibung
symbolstringOptionssymbol
bidsarrayBid-Level als [price, size]-Tupel, size in menschenlesbaren Kontrakten
asksarrayAsk-Level als [price, size]-Tupel, size in menschenlesbaren Kontrakten
timestampintegerUnix-Zeitstempel (Millisekunden)

Trade

Öffentliches Trade-Ereignis.

{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "buy",
"timestamp": 1737331200000
}
FeldTypBeschreibung
symbolstringOptionssymbol
pricestringTrade-Preis in USD
sizestringTrade-Größe in Kontrakten
sidestringAggressor-Seite (buy oder sell)
timestampintegerUnix-Zeitstempel (Millisekunden)

Fill (authentifiziert)

Ihre Trade-Fill-Benachrichtigung.

{
"type": "Fill",
"order_id": 12345,
"fill_id": 67890,
"symbol": "BTC-20260131-100000-C",
"side": "buy",
"price": "0.0523",
"size": "5.0",
"timestamp": 1737331200000,
"wallet_address": "0x1234...abcd",
"fee": "0",
"trade_id": 99999,
"is_taker": true
}
FeldTypBeschreibung
order_idintegerIhre Order-ID
fill_idintegerFill-ID
symbolstringOptions-Symbol
sidestringHandelsseite (buy oder sell)
pricestringAusführungspreis in USD
sizestringAusführungsgröße in Kontrakten
timestampintegerUnix-Zeitstempel (Millisekunden)
wallet_addressstringIhre Wallet-Adresse
feestringErhobene Handelsgebühr. Gibt 0 zurück, solange die Gebühren des Launch-Venues deaktiviert sind
trade_idintegerEindeutige Trade-ID
is_takerbooleanOb Sie der Taker waren
builder_code_addressstring?Builder-Code-Wallet (falls vorhanden)
builder_code_feestring?Builder-Code-Gebühr. Gibt null zurück, solange die Gebühren des Launch-Venues deaktiviert sind

Portfolio-Update (authentifiziert)

Portfolio-Stream-Update für Positionen, Guthaben, Margin und Griechen.

Beispiel für ein Griechen-Update:

{
"type": "PortfolioUpdate",
"timestamp": 1737331200000,
"per_leg": [
{
"symbol": "BTC-20260131-100000-C",
"quantity": "2.0",
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
],
"aggregate": {
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
}

Bei leeren Portfolios verwenden Griechen-Updates:

  • per_leg: []
  • aggregate: null

Wettbewerbs-GuV-Zusammenfassung (authentifiziert)

Wettbewerbs-Stream-Update für die GuV-Anzeige in Kopf-/Fußzeile.

{
"type": "CompetitionPnlSummary",
"wallet_address": "0x1234...abcd",
"lifetime_realized_pnl": "1250.50",
"active_competition": {
"competition_id": 7,
"competition_name": "Spring Sprint",
"competition_state": "active",
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null
},
"timestamp": 1737331200000
}

Wenn kein aktiver Wettbewerb vorliegt, ist active_competition gleich null.

Order-Update (authentifiziert)

Benachrichtigung über eine Statusänderung der Order.

{
"type": "OrderUpdate",
"order_id": 12345,
"client_order_id": "my-order-1",
"status": "filled",
"filled_size": "10.0",
"remaining_size": "0",
"avg_fill_price": "0.0523"
}

Markt-Update

Änderungen bei Markt-Listings.

Markt erstellt:

{
"type": "MarketUpdate",
"action": "Created",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1737331200000
}

Markt verfallen:

{
"type": "MarketUpdate",
"action": "Expired",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1738281600000
}

Position verfallen (authentifiziert)

Benachrichtigung, wenn Ihre Position bei Verfall abgerechnet wird.

{
"type": "PositionExpired",
"wallet_address": "0x1234...abcd",
"symbol": "BTC-20260131-100000-C",
"position_size": "10.0",
"settlement_price": "105000",
"settlement_value": "500.0",
"timestamp": 1738281600000
}

Änderung des Liquidationsstatus (authentifiziert)

Änderung des Liquidationsstatus Ihres Kontos.

{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "Normal",
"new_state": "Warning",
"equity": "10000.0",
"mm_required": "9500.0",
"shortfall": "0",
"auction_id": null,
"timestamp": 1737331200000
}
StatusBeschreibung
NormalKonto ist gesund
WarningNähert sich einem Margin Call
LiquidatingLiquidationsauktion aktiv

Index-Preis-Update

Gebündelte Spot-/Index-Preise für alle Basiswerte.

{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50"},
{"underlying": "ETH", "price": "3200.00"},
{"underlying": "HYPE", "price": "28.50"}
],
"timestamp": 1737331200000
}
FeldTypBeschreibung
pricesarrayArray von {underlying, price}-Einträgen für jeden erfassten Basiswert
prices[].underlyingstringSymbol des Basiswerts (z. B. "BTC", "ETH")
prices[].pricestringAktueller Spot-/Index-Preis in USD
timestampintegerUnix-Zeitstempel (Millisekunden)

Indikative Marktdaten

Auf einer Allowlist basierender Quote-Provider-Stream mit aggregiertem bestem Bid/Ask von registrierten Quote-Providern. Dieser Kanal ist noch nicht allgemein verfügbar. Verwenden Sie REST-Marktdaten sowie die authentifizierten Order-/Fill-/Portfolio-Kanäle, sofern Hypercall das Quote-Provider-Streaming für Ihre Integration nicht aktiviert hat.

{
"type": "IndicativeMarketData",
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"indicative_bid_size": "50.0",
"indicative_ask_size": "25.0",
"num_providers": 3,
"timestamp": 1737331200000
}
FeldTypBeschreibung
instrumentstringOptions-Symbol
best_bidstringOptionaler bester aggregierter Bid-Preis
best_askstringOptionaler bester aggregierter Ask-Preis
bid_ivnumberOptionale implizite Volatilität des besten Bid
ask_ivnumberOptionale implizite Volatilität des besten Ask
indicative_bid_sizestringOptionale gesamte Bid-Größe über alle Provider
indicative_ask_sizestringOptionale gesamte Ask-Größe über alle Provider
num_providersintegerAnzahl der aktiven Quote-Provider
timestampintegerUnix-Zeitstempel (Millisekunden)

Änderung des Wettbewerbsrangs (authentifiziert)

Benachrichtigung, wenn sich Ihr Rang in einem aktiven Wettbewerb ändert.

{
"type": "CompetitionRankChange",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"from_rank": 15,
"to_rank": 12,
"delta_places": 3,
"pnl": "420.25",
"timestamp": 1737331200000
}

Wettbewerbs-Abstands-Update (authentifiziert)

Abstand zum nächsthöheren Rang über Ihnen.

{
"type": "CompetitionGapUpdate",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"next_rank": 11,
"gap_metric_value": "50.00",
"timestamp": 1737331200000
}

Endplatzierung im Wettbewerb (authentifiziert)

Wird gesendet, wenn ein Wettbewerb mit Ihren Endergebnissen endet.

{
"type": "CompetitionFinalStanding",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null,
"timestamp": 1737331200000
}

RFQ-Quotes (authentifiziert)

Quotes, die als Antwort auf Ihre RFQ-Einreichung empfangen wurden.

{
"type": "RfqQuotes",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"quotes": [
{
"quote_id": "660e8400-e29b-41d4-a716-446655440001",
"net_premium": "52.30",
"expires_at": 1737331225000
}
],
"status": "quoted",
"taker_wallet": "0x1234...abcd"
}

RFQ-Status-Update (authentifiziert)

Statusänderung für eine von Ihnen eingereichte RFQ.

{
"type": "RfqStatusUpdate",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "executed",
"taker_wallet": "0x1234...abcd"
}

Fehler

Server-Fehlermeldung.

{
"type": "Error",
"message": "Invalid channel: foobar"
}

Authentifizierung

Authentifizierte Kanäle erfordern nach dem Verbindungsaufbau eine Nachricht zur Wallet-Identifikation:

{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}

Nachrichten auf authentifizierten Kanälen werden gefiltert, sodass nur Daten für Ihr Wallet angezeigt werden. Für WebSocket-Verbindungen ist keine Signatur erforderlich.

Beispiel: Python-Client

import asyncio
import websockets
import json

async def main():
uri = "wss://api.hypercall.xyz/ws"

async with websockets.connect(uri) as ws:
# Identify the wallet before subscribing to authenticated channels.
await ws.send(json.dumps({
"type": "Authenticate",
"wallet": "0xYourWallet"
}))

# Subscribe to orderbook
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "orderbook"
}))

# Subscribe to fills for BTC only
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "fills",
"symbols": ["BTC"]
}))

# Listen for messages
async for message in ws:
data = json.loads(message)
print(f"Received: {data['type']}")

asyncio.run(main())

Beispiel: TypeScript-Client

const ws = new WebSocket("wss://api.hypercall.xyz/ws");

ws.onopen = () => {
ws.send(JSON.stringify({ type: "Authenticate", wallet: "0xYourWallet" }));

// Subscribe to channels
ws.send(JSON.stringify({ type: "Subscribe", channel: "orderbook" }));

// Subscribe to order updates filtered to BTC
ws.send(JSON.stringify({
type: "Subscribe",
channel: "order_updates",
symbols: ["BTC"],
}));
};

ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(`Received: ${msg.type}`);

if (msg.type === "OrderbookUpdate") {
console.log(`${msg.symbol}: ${msg.bids.length} bids, ${msg.asks.length} asks`);
}
};