WebSocket-API
Echtzeit-Datenstreaming für den Optionshandel auf Hypercall.
Nutzen Sie die interaktive WebSocket-API-Referenz für eine komfortablere Übersicht mit Live-Beispielen und Schemadetails.
Laden Sie die AsyncAPI-Spezifikation für die programmatische Nutzung herunter.
WebSocket-Nachrichtenobjekte können ohne Vorankündigung neue Felder erhalten. Clients müssen Felder ignorieren, die sie nicht kennen. Hypercall entfernt keine Felder aus einem bestehenden Nachrichtenschema.
Verbindung
Verbinden Sie sich mit wss://HOST/ws:
Endpunkte:
- Produktion:
wss://api.hypercall.xyz/ws - Lokal:
ws://localhost:3000/ws
Das Testnet ist vorübergehend deaktiviert, bis Hypercall weiteres Testnet-HYPE erhält.
Komprimierung
/ws unterstützt RFC 7692 permessage-deflate. Aktivieren Sie es in Ihrem Client, um die Bandbreite für Marktdaten zu senken: Bei aufgezeichnetem Produktionsverkehr sind einzeln komprimierte Frames etwa 45 % kleiner, Batches von Indexpreisen etwa 70 % kleiner.
- Ihr Client bietet die Erweiterung im Upgrade-Request an, zum Beispiel
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits. - Akzeptiert der Server, enthält die
101-AntwortSec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover. Jede Servernachricht wird dann einzeln komprimiert, ohne gemeinsames Sliding Window, und Nachrichten unter einigen hundert Bytes werden weiterhin unkomprimiert gesendet. Ihre Bibliothek dekomprimiert transparent. - Enthält die Antwort keinen
Sec-WebSocket-Extensions-Header, ist jeder Frame unkomprimiert. Die Komprimierung wird pro Umgebung aktiviert, daher müssen Clients beide Fälle behandeln; die JSON-Nachrichten sind in beiden Fällen identisch. Die Produktion akzeptiert die Erweiterung noch nicht, daher sind Produktions-Frames derzeit unkomprimiert. - Ihr Client darf gesendete Nachrichten komprimieren. Der Server dekomprimiert jede Client-Nachricht bis zu 256 KiB und schließt die Verbindung, wenn eine Nachricht diese Grenze überschreiten würde.
Browser handeln die Erweiterung automatisch aus. Die meisten Bibliotheken benötigen keine Änderung:
Python (websockets aktiviert die Komprimierung standardmäßig):
import websockets
async with websockets.connect("wss://api.hypercall.xyz/ws", compression="deflate") as ws:
...
Node.js (ws):
import WebSocket from "ws";
const ws = new WebSocket("wss://api.hypercall.xyz/ws", { perMessageDeflate: true });
Rust: Der WsClient aus hypercall-client handelt permessage-deflate standardmäßig aus (siehe Beispiel: Rust-Client). Reines tungstenite und tokio-tungstenite implementieren es noch nicht und verbinden sich daher unkomprimiert. Für Komprimierung mit Ihrem eigenen Socket verwenden Sie einen Client, der sie implementiert, etwa yawc:
let url = "wss://api.hypercall.xyz/ws".parse()?;
let mut ws = yawc::WebSocket::connect(url)
.with_options(yawc::Options::default().with_low_latency_compression())
.await?;
Wallet-Identifizierung
Um Daten auf authentifizierten Kanälen (Orders, Fills, Portfolio) zu empfangen, identifizieren Sie Ihre Wallet nach dem Verbindungsaufbau mit einer Authenticate-Nachricht:
{"type": "Authenticate", "wallet": "0x1234..."}
Der Server antwortet mit einer Bestätigung:
{"type": "Authenticated", "wallet": "0x1234..."}
Nach Erhalt von Authenticated können Sie authentifizierte Kanäle abonnieren. Ist die Wallet-Adresse ungültig, antwortet der Server mit einer Error-Nachricht, und die Verbindung bleibt offen.
Der Query-Parameter ?wallet= wird aus Gründen der Abwärtskompatibilität weiterhin unterstützt, ist aber veraltet und wird in einem künftigen Release entfernt. Verwenden Sie bevorzugt den oben beschriebenen nachrichtenbasierten Ansatz.
Verbindungs-Liveness
Der Server erzwingt einen WebSocket-Heartbeat:
- Sendet alle 20 Sekunden einen
Ping-Kontroll-Frame - Erwartet innerhalb von 60 Sekunden ein passendes
Pong - Schließt die Verbindung mit Close-Code
1008und Grundpong timeout, wenn der Client nicht mehr antwortet
WebSocket-Implementierungen im Browser verarbeiten Ping/Pong automatisch. Viele Rust-WebSocket-Bibliotheken, darunter tungstenite und tokio-tungstenite, übernehmen Ping/Pong auf Kontroll-Frame-Ebene ebenfalls für Sie. Prüfen Sie die Dokumentation Ihrer Client-Bibliothek, bevor Sie eine manuelle Pong-Behandlung hinzufügen. Eigene oder rohe Socket-Implementierungen müssen auf Ping-Frames mit Pong antworten.
Wiederherstellung bei langsamen Konsumenten
Der Server schließt eine /ws-Verbindung, die ausgehende Daten nicht innerhalb der konfigurierten Sicherheitsgrenzen für Nachrichtenanzahl, kodierte Bytes, Warteschlangenalter oder Socket-Schreibzeit abarbeiten kann. Kann die Verbindung noch einen Close-Frame annehmen, verwendet der Server den Code 1008 und einen kompakten JSON-Grund:
{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}
Die Felder des Grunds sind:
| Feld | Bedeutung |
|---|---|
class | Zustellklasse, deren Frame die Sicherheitsgrenze überschritten hat. |
cause | message_limit, byte_limit, message_age oder write_timeout. |
recovery | Erforderliche nächste Aktion, etwa resubscribe, snapshot_resubscribe, portfolio_refetch oder rest_reconcile. |
Nach jedem Verbindungsabbruch verbinden Sie sich neu, identifizieren die Wallet bei Bedarf erneut, abonnieren erneut und gleichen 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 Close-Grund lesen kann. Clients müssen diesen Wiederherstellungsablauf daher auch bei einem unsauberen Verbindungsende anwenden.
Verwenden Sie getrennte Verbindungen für öffentliche Marktdaten mit hoher Rate und für authentifizierte Befehle oder private Streams. Zustellklassen bestimmen Metriken und Wiederherstellungsverhalten, aber Frames auf einer Verbindung teilen sich weiterhin einen geordneten Socket-Schreibpfad. Ein blockierter öffentlicher Schreibvorgang kann daher nachfolgende private Frames auf derselben Verbindung verzögern, bis die Schreibfrist die Verbindung schließt.
Kanäle abonnieren
Senden Sie zum Abonnieren eine JSON-Nachricht:
{"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. Ist er angegeben, 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"]}
Sind keine symbols angegeben, werden alle Updates für Ihre Wallet weitergeleitet.
Die öffentlichen Kanäle orderbook, trades, indicative_market_data und indicative_market_data_v2 akzeptieren ebenfalls symbols. Der Abgleich erfolgt gegen exakte Instrumentensymbole (ohne Beachtung der Groß- und Kleinschreibung), nicht gegen Basiswerte:
{"type": "Subscribe", "channel": "orderbook", "symbols": ["BTC-20260131-100000-C"]}
Ohne symbols liefern diese Kanäle alle Instrumente.
Filterung der Optionskette
Der Kanal options_chain unterstützt die Filterung nach Instrumentensymbolen, Verfallsdatum und Optionstyp:
{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
| Filter | Werte | Standard |
|---|---|---|
symbols | Array vollständiger Instrumentensymbole (z. B. ["BTC-20260131-100000-C"]) | Alle Instrumente |
expiry | Datumsstring "YYYY-MM-DD", abgeglichen mit dem UTC-Kalenderdatum des Verfalls jedes Instruments | Alle Verfallstermine |
option_type | "call", "put", "both" oder weglassen für beide | Beide |
Gebündelte Zustellung
indicative_market_data_v2 überträgt dieselben Zeilen wie indicative_market_data, jedoch mehrere Zeilen pro Frame:
{"type": "Subscribe", "channel": "indicative_market_data_v2", "symbols": ["BTC-20260131-100000-C"]}
Der Server bestätigt mit einer Batch-Markierung:
{"type": "Subscribed", "channel": "indicative_market_data_v2", "batch": true}
Anschließend hält er jede Zeile höchstens ein Batch-Fenster lang zurück, standardmäßig 25 ms, und sendet die in diesem Fenster veröffentlichten Zeilen als einen IndicativeMarketDataBatch-Frame. Ein Batch wird außerdem vorzeitig gesendet, sobald er 256 Zeilen erreicht.
- Unterstützung erkennen: Nur eine Bestätigung mit
"batch": truebedeutet, dass der Server bündelt. Server, die vor diesem Kanal veröffentlicht wurden, bestätigen jeden Kanalnamen ohne die Markierung und senden dann nichts, und aktuelle Server beantworten einen unbekannten Kanal mit einemunknown_channel-Fehler. In beiden Fällen bestellen Sieindicative_market_data_v2ab und abonnierenindicative_market_dataauf derselben Verbindung. - Latenz: Eine Zeile kommt bis zu ein Fenster später an als auf
indicative_market_data. Bei Produktionsverkehr mit dem Standardfenster warteten Zeilen im Durchschnitt 12 ms und nie länger als 25 ms. Verwenden Sie den v1-Kanal, wenn Sie innerhalb von Millisekunden auf einzelne Quote-Updates reagieren. - Bandbreite: Bündelung allein spart etwa 7 % der Bytes. Die große Ersparnis ergibt sich mit
permessage-deflate: Komprimierte Batches sind bei einem ungefilterten Abonnement etwa 9,8-mal kleiner als unkomprimierte Ein-Zeilen-Frames und bei einer einzelnen Optionskette etwa 8,3-mal kleiner, gegenüber etwa 1,8-mal bei einzeln komprimierten Zeilen. - Reihenfolge: Zeilen in
updatesstehen in Veröffentlichungsreihenfolge, und Batches kommen in Reihenfolge an. Zeilen werden nicht zusammengefasst, sodass ein Instrument mehrmals in einem Batch vorkommen kann. Wenden Sie die Zeilen der Reihe nach an, erreichen Sie denselben Zustand wie auf dem v1-Kanal. - Snapshot: Der Snapshot beim Abonnieren kommt ebenfalls als Batch-Frames an.
- Filter:
symbolsfunktioniert wie beiindicative_market_data. Beim Einschränken des Filters oder beim Abbestellen werden zunächst alle unter dem alten Filter noch ausstehenden Zeilen gesendet, dann dieUnsubscribed-Bestätigung, sodass keine Zeile verloren geht oder doppelt ankommt. - Unabhängige Kanäle: Eine Verbindung kann beide Kanäle mit unterschiedlichen Filtern abonnieren.
indicative_market_datableibt unverändert.
Verfügbare Kanäle
| Kanal | Authentifizierung erforderlich | Beschreibung |
|---|---|---|
orderbook | Nein | L2-Orderbuch-Updates für alle Symbole |
trades | Nein | Öffentlicher Trade-Feed |
market_updates | Nein | Änderungen an Marktlistings (erstellt/gelöscht/verfallen) |
options_chain | Nein | Inkrementelle Updates der Optionskette (filterbar nach symbols, expiry, option_type) |
index_prices | Nein | Spot-/Indexpreise in Echtzeit für alle Basiswerte |
indicative_market_data | Nein | Stream für freigeschaltete Quote-Provider. Noch nicht allgemein verfügbar |
indicative_market_data_v2 | Nein | Derselbe Stream in Batch-Frames. Siehe Gebündelte Zustellung |
order_updates | Ja | Statusänderungen Ihrer Orders (filterbar nach Symbol) |
fills | Ja | Ihre Trade-Fills (filterbar nach Symbol) |
portfolio | Ja | Updates Ihrer Positionen und Salden |
liquidation | Ja | Änderungen Ihres Liquidationsstatus |
rfq | Ja | RFQ-Quotes, Status-Updates und Fill-Benachrichtigungen |
experimental_order_updates, experimental_combo_fills | Ja | Experimentelle Combo-Kanäle. Siehe Experimentelle Combo-API |
experimental_combo_trades | Nein | Experimentelle öffentliche Combo-Trades |
Wettbewerbs- und Leaderboard-Daten werden nicht von api.hypercall.xyz bereitgestellt, weder über WebSocket noch über REST. Das Abonnieren der eingestellten Kanäle competition oder competition_engagement liefert einen Error. Die Trading-App liest Wettbewerbe per HTTP vom Analytics-Dienst unter https://api-ui.hypercall.xyz, zum Beispiel GET /v2/competitions, GET /v2/competitions/{id}, GET /v2/competitions/leaderboard und GET /v2/competitions/all-time/leaderboard.
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": 1780000000000,
"signature": "0x..."
}
Die obige nonce dient nur zur Veranschaulichung. Erzeugen Sie für jede Order eine neue aus der aktuellen Unix-Zeit in Millisekunden, zum Beispiel Date.now() in JavaScript. Ein kopierter fester Wert liegt außerhalb des zulässigen Fensters und wird abgelehnt.
| Feld | Typ | Beschreibung |
|---|---|---|
wallet | string | Wallet-Adresse, der die Order gehört |
symbol | string | Optionssymbol |
side | string | "Buy" oder "Sell" |
size | string | Kontraktgröße, exakt identisch mit dem signierten Wert |
price | string | Limitpreis, exakt identisch mit dem signierten Wert |
tif | string | Optionale Time-in-Force, Standard ist "gtc" |
route | string | Verwenden Sie "book_only". Eine weggelassene Route wird weiterhin akzeptiert, ist aber veraltet, und ihr Abschaltdatum ist bereits verstrichen. |
client_id | string | Optionale Client-Order-ID |
reduce_only | boolean | Optional, Standard false. Eine Reduce-only-Order signiert PlaceOrderReduceOnly und erfordert eine explizite route |
mmp_enabled | boolean | Optional, Standard false |
builder_code_address | string | Optionale Builder-Code-Wallet |
nonce | integer | Erforderliche Signatur-Nonce: die aktuelle Unix-Zeit in Millisekunden. Sie muss zwischen zwei Tagen vor und einem Tag nach der aktuellen Zeit liegen. Jede Nonce wird pro Signer nur einmal akzeptiert, und REST- und WebSocket-Orders teilen sich denselben Nonce-Raum. Ein wiederholt gesendeter Frame wird abgelehnt. |
signature | string | EIP-712-PlaceOrder-Signatur |
Die Verbindung muss zuvor Authenticate gesendet haben; andernfalls antwortet der Server mit {"type": "Error", "message": "Not authenticated"}. Der Signer muss wallet oder ein dafür genehmigter Agent sein.
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.
Eine angenommene Order wird auf derselben Verbindung mit einem OrderResult beantwortet:
{
"type": "OrderResult",
"order_id": 12345,
"status": "ACKED",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "100",
"size": "1"
}
reason wird ergänzt, wenn die Order nicht angenommen wird. Validierungs-, Signatur- und Rate-Limit-Fehler werden als Error gesendet, dessen message mit Order placement failed: beginnt. Nachfolgende Statusänderungen kommen über order_updates.
Orderbuch-Update
L2-Orderbuch-Snapshot/-Update für ein Symbol.
{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"option_token_address": "0x...",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
| Feld | Typ | Beschreibung |
|---|---|---|
symbol | string | Optionssymbol |
option_token_address | string? | On-Chain-Adresse des Options-Tokens, sofern bekannt |
bids | array | Bid-Level als [price, size]-Tupel, die Größe ist in lesbaren Kontrakten angegeben |
asks | array | Ask-Level als [price, size]-Tupel, die Größe ist in lesbaren Kontrakten angegeben |
timestamp | integer | Unix-Zeitstempel (Millisekunden) |
Trade
Öffentliches Trade-Ereignis.
{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "Buy",
"timestamp": 1737331200000
}
| Feld | Typ | Beschreibung |
|---|---|---|
symbol | string | Optionssymbol |
price | string | Trade-Preis in USD |
size | string | Trade-Größe in Kontrakten |
side | string | Seite des Aggressors (Buy oder Sell) |
timestamp | integer | Unix-Zeitstempel (Millisekunden) |
Fill (authentifiziert)
Benachrichtigung über Ihren Trade-Fill.
{
"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,
"builder_code_address": null,
"builder_code_fee": null,
"instrument_type": "option"
}
| Feld | Typ | Beschreibung |
|---|---|---|
order_id | integer | Ihre Order-ID |
fill_id | integer | Fill-ID |
symbol | string | Optionssymbol |
side | string | Ihre Seite des Trades (Buy oder Sell) |
price | string | Fill-Preis in USD |
size | string | Fill-Größe in Kontrakten |
timestamp | integer | Unix-Zeitstempel (Millisekunden) |
wallet_address | string | Ihre Wallet-Adresse |
fee | string | Berechnete Handelsgebühr. Liefert 0, solange die Venue-Gebühren zum Launch deaktiviert sind |
trade_id | integer | Eindeutige Trade-ID |
is_taker | boolean | Ob Sie der Taker waren |
builder_code_address | string? | Builder-Code-Wallet (falls vorhanden) |
builder_code_fee | string? | Builder-Code-Gebühr. Liefert null, solange die Venue-Gebühren zum Launch deaktiviert sind |
instrument_type | string | "option" |
Portfolio-Update (authentifiziert)
Wird auf dem Kanal portfolio für Positionen, Salden, Margin und Greeks gesendet. Beim Abonnieren sendet der Server einen Initial-Snapshot, danach inkrementelle Updates.
Das type jedes Frames ist seine Update-Art:
| Update-Art | Felder neben timestamp |
|---|---|
Initial | positions |
PositionUpdate | position |
BalanceUpdate | total_margin_used |
MarginUpdate | span_margin, margin_summary, margin_mode, total_margin_used, available_balance |
GreeksUpdate | per_leg, aggregate |
timestamp ist bei portfolio-Frames in Unix-Sekunden angegeben, anders als die Millisekunden-Zeitstempel auf anderen Kanälen.
Beispiel für ein Greeks-Update:
{
"type": "GreeksUpdate",
"timestamp": 1737331200,
"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 Greeks-Updates:
per_leg: []aggregate: null
Order-Update (authentifiziert)
Benachrichtigung über eine Statusänderung einer Order. PARTIALLY_FILLED-Updates sind enthalten.
filled_size ist die kumulierte ausgeführte Menge über alle Ausführungen der Order,
nicht die Menge des letzten Fills.
{
"type": "OrderUpdate",
"order_id": 12345,
"client_id": "my-order-1",
"request": {
"price": "0.0523",
"size": "10.0",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"tif": "gtc"
},
"status": "PARTIALLY_FILLED",
"filled_size": "0.75",
"timestamp": 1767225600000,
"reason": null,
"wallet_address": "0x0000000000000000000000000000000000000001",
"instrument_type": "option"
}
status ist einer der Werte ACKED, OPEN, PARTIALLY_FILLED, FILLED, CANCELED oder REJECTED. client_id wird weggelassen, wenn die Order keine hat. instrument_type ist "option" oder "perp".
Markt-Update
Änderungen an Marktlistings.
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
}
action ist Created, Expired, Deleted (enthält nur symbol und timestamp) oder ComboCreated (siehe Experimentelle Combo-API).
Optionsketten-Update
Wird auf options_chain gesendet, wenn sich ein Listing oder dessen Top of Book ändert. action ist Upsert oder Remove.
{
"type": "OptionsChainUpdate",
"action": "Upsert",
"currency": "BTC",
"expiry": 1769846400,
"row": {
"strike": 100000.0,
"call": {
"symbol": "BTC-20260131-100000-C",
"bid_price_usd": 1520.0,
"ask_price_usd": 1580.0
}
},
"timestamp": 1737331200000
}
Eine Upsert-Zeile enthält ein Leg (call oder put) mit den Leg-Feldern des Optionsketten-Snapshots: symbol, option_token_address, Bid- und Ask-Preis, IV, Größe in Kontrakten und USD-Nominalwert, greeks_abs und greeks_cash (das obige Beispiel ist gekürzt). Nicht verfügbare Werte sind null; das Leg, das nicht Teil des Updates ist, wird weggelassen. Ein Remove enthält currency, expiry, strike, option_type, symbol und timestamp, wenn ein Instrument gelöscht wird, verfällt oder in das ausstehende Settlement übergeht. expiry ist in Unix-Sekunden angegeben.
Position verfallen (authentifiziert)
Wird auf dem Kanal portfolio gesendet, wenn Ihre Position beim 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",
"settlement_entry_price": "100.0",
"cost_basis": "1000.0",
"net_pnl": "-500.0",
"timestamp": 1738281600000
}
settlement_entry_price, cost_basis und net_pnl sind null, wenn sie nicht verfügbar sind.
Änderung des Liquidationsstatus (authentifiziert)
Wird auf dem Kanal liquidation gesendet, wenn sich der Liquidationsstatus Ihres Kontos ändert.
{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "healthy",
"new_state": "pre_liquidation",
"liquidation_mode": "partial",
"margin_mode": "standard",
"equity": "10000.0",
"mm_required": "10500.0",
"maintenance_margin": "-500.0",
"shortfall": "500.0",
"partial_liquidation": { "...": "..." },
"full_liquidation": null,
"timestamp": 1737331200000
}
| Feld | Beschreibung |
|---|---|
previous_state, new_state | healthy, pre_liquidation, in_liquidation oder liquidated |
liquidation_mode | partial, full oder null, wenn kein Liquidationsablauf aktiv ist |
margin_mode | standard oder portfolio |
equity | Kontoeigenkapital |
mm_required | Maintenance-Margin-Anforderung |
maintenance_margin | Eigenkapital abzüglich der Maintenance-Margin-Anforderung |
shortfall | Betrag, um den das Konto unter der Maintenance Margin liegt |
partial_liquidation | Fortschritt der Teilliquidation (Eintrittszeit, Ziel-Eigenkapital, Eskalationsfrist, aktive Liquidationsorders, Bonus) oder null |
full_liquidation | Details der Auktion bei vollständiger Liquidation (Auktions-ID, Startzeit, benötigte Margin und nach Abschluss der Gewinner, Bonus und die Auflösungstransaktion) oder null |
Unter Liquidation erfahren Sie, was jeder Status bedeutet.
Indexpreis-Update
Gebündelte Spot-/Indexpreise für alle Basiswerte.
{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50", "timestamp": 1737331200000},
{"underlying": "ETH", "price": "3200.00", "timestamp": 1737331199980},
{"underlying": "NVDA", "price": "182.40", "timestamp": 1737331199950}
],
"timestamp": 1737331199950
}
| Feld | Typ | Beschreibung |
|---|---|---|
prices | array | Array von {underlying, price, timestamp}-Einträgen für jeden erfassten Basiswert |
prices[].underlying | string | Symbol des Basiswerts (z. B. "BTC", "ETH") |
prices[].price | string | Aktueller Spot-/Indexpreis in USD |
prices[].timestamp | integer | Beobachtungszeit der Quelle für diesen Basiswert, in Unix-Millisekunden |
timestamp | integer | Älteste in prices enthaltene Beobachtungszeit der Quelle, in Unix-Millisekunden |
Indikative Marktdaten
Stream für freigeschaltete Quote-Provider mit aggregiertem besten Bid/Ask registrierter Quote-Provider. Dieser Kanal ist noch nicht allgemein verfügbar. Verwenden Sie REST-Marktdaten und 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,
"published_at": 1737331200004,
"timestamp": 1737331200000
}
| Feld | Typ | Beschreibung |
|---|---|---|
instrument | string | Optionssymbol |
best_bid | string | Optional, bester aggregierter Bid-Preis |
best_ask | string | Optional, bester aggregierter Ask-Preis |
bid_iv | number | Optional, implizite Volatilität des besten Bids |
ask_iv | number | Optional, implizite Volatilität des besten Asks |
indicative_bid_size | string | Optional, gesamte Bid-Größe über alle Provider |
indicative_ask_size | string | Optional, gesamte Ask-Größe über alle Provider |
num_providers | integer | Anzahl aktiver Quote-Provider |
rfq_provider_quotes | array | Optional, Quotes pro Provider: wallet, bid_price, ask_price, max_bid_size, max_ask_size, updated_at |
published_at | integer | Zeitpunkt der Veröffentlichung dieser Zeile laut API-Uhr, in Unix-Millisekunden. Messen Sie das Alter von rfq_provider_quotes daran, nicht an Ihrer lokalen Uhr |
timestamp | integer | Zeitpunkt des letzten Provider-Quotes, in Unix-Millisekunden |
Indikative Marktdaten im Batch
Wird auf dem Kanal indicative_market_data_v2 gesendet (siehe Gebündelte Zustellung). Jedes Element von updates hat dieselben Felder wie eine IndicativeMarketData-Nachricht, ohne type.
{
"type": "IndicativeMarketDataBatch",
"flushed_at": 1737331200025,
"updates": [
{
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
},
{
"instrument": "BTC-20260131-105000-C",
"best_bid": "0.0310",
"best_ask": "0.0322",
"num_providers": 2,
"published_at": 1737331200004,
"timestamp": 1737331200001
}
]
}
| Feld | Typ | Beschreibung |
|---|---|---|
flushed_at | integer | Zeitpunkt des Versands des Batches laut API-Uhr, in Unix-Millisekunden. flushed_at - published_at ist die Bündelungsverzögerung einer Zeile |
updates | array | Im Fenster veröffentlichte Zeilen, älteste zuerst |
RFQ-Quotes (authentifiziert)
Quotes, die als Antwort auf Ihre RFQ-Anfrage eingehen.
{
"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"
}
Uhrensynchronisation
Senden Sie ClockSync mit einem beliebigen nonce-String, um auf derselben Verbindung eine Stichprobe der API-Uhr zu erhalten, zum Beispiel um die Übertragungsverzögerung einzugrenzen:
{"type": "ClockSync", "nonce": "abc"}
{"type": "ClockSynced", "nonce": "abc", "server_at": 1737331200000}
server_at ist in Unix-Millisekunden angegeben. Eine Authentifizierung ist nicht erforderlich.
Fehler
Fehlermeldung des Servers. Werten Sie code aus, sofern vorhanden, nicht message.
{
"type": "Error",
"message": "Unknown channel 'foobar'",
"code": "unknown_channel",
"channel": "foobar"
}
| Feld | Typ | Beschreibung |
|---|---|---|
message | string | Lesbare Beschreibung |
code | string | Optionaler stabiler Grund. unknown_channel: Ein Subscribe nannte einen Kanal, der nicht existiert |
channel | string | Optional. Der Kanal, den ein abgelehntes Subscribe nannte |
Ein Subscribe auf einen Kanal, der nicht unter Verfügbare Kanäle aufgeführt ist, wird mit dem Fehler unknown_channel beantwortet, und es wird kein Abonnement angelegt. Frühere Server bestätigten jeden Namen und sendeten dann nichts.
Andere Fehler enthalten nur message. Beispiele: Authentication required for this channel, wenn Sie einen authentifizierten Kanal vor Authenticate abonnieren, Not authenticated für PlaceOrder vor Authenticate sowie Invalid wallet address: ....
Authentifizierung
Authentifizierte Kanäle erfordern nach dem Verbindungsaufbau eine Nachricht zur Wallet-Identifizierung:
{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}
Nachrichten auf authentifizierten Kanälen werden so gefiltert, dass nur Daten Ihrer 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`);
}
};
Beispiel: Rust-Client
Der WsClient des Crates hypercall-client identifiziert die Wallet, stellt Abonnements nach einem Reconnect wieder her und beantwortet Server-Pings für Sie. Er bietet standardmäßig permessage-deflate-Komprimierung an und fällt auf unkomprimierte Frames zurück, wenn der Server sie nicht akzeptiert, mit denselben JSON-Nachrichten in beiden Fällen. Rufen Sie with_permessage_deflate(false) auf, um das Angebot abzuschalten.
use hypercall_client::WsClient;
#[tokio::main]
async fn main() -> hypercall_client::Result<()> {
let ws = WsClient::new();
ws.connect("https://api.hypercall.xyz", None).await?;
ws.subscribe(vec!["orderbook", "index_prices"]).await?;
if let Some(msg) = ws.wait_for_message(|_| true, 5_000).await {
println!("Received: {msg:?}");
}
Ok(())
}