閱讀時間 10 分鐘
概覽
Phoenix是一個基於Solana 的永續期貨(亦稱「perps」)Solana 公開 API 提供價格走勢、訂單簿深度、成交紀錄、K 線圖及資金費率歷史資料。本指南將向您展示如何運用該 API 建立即時儀表板Solana 用以檢視Solana 即時數據,並附有配套的 React 範例應用程式,您可以克隆、執行並擴充該應用程式。
- PhoenixSolana 的永續期貨交易平台,透過免費的唯讀公開 API 提供即時市場數據。
- 本指南將說明永續期貨、介紹 Phoenix,並帶您瀏覽其 REST 和 WebSocket API。
- 您將透過 REST 傳輸市場設定與歷史 K 線資料,接著透過單一 WebSocket 連線串流即時資料。
- 您將處理 Phoenix 的載荷特殊情況、乾淨俐落地重新連線,並在不丟失狀態的情況下切換圖表時間框架。
- 一個配套的 React 範例應用程式將所有內容整合成一個「perps」儀表板,您可以克隆、執行並擴充此儀表板。
您將負責的工作內容
- 了解 Perps 的概況,以及 Phoenix 如何在Solana 上提供相關功能。
- 複製並執行配套的範例儀表板應用程式。
- 訂閱所有六個 Phoenix WebSocket 頻道(
市場,訂單簿,交易,蠟燭,資金利率,交易所) 透過單一共用連線。 - 在單一邊界處處理 Phoenix 的載荷特殊情況(數值編碼、訂單簿形狀差異、時間單位混用)。
您需要準備的物品
- 若您計劃透過鏈上讀取功能擴充儀表板,請準備一個Quicknode (若使用唯讀的 Phoenix API,此步驟為可選)。
- Node.js 22 及以上版本
- 熟悉 React 和 TypeScript
- 了解如何建立Solana 訂閱
什麼是 Perps?
Perps 是一種追蹤標的資產價格且無到期日的衍生性金融商品。交易者可透過槓桿建立多頭或空頭部位,系統則透過多頭與空頭之間定期的資金結算,使該部位價格與現貨價格保持一致。此類產品無結算日,亦無展期機制。只要帳戶維持清償能力,部位即可無限期持有。
有四個因素驅動期貨市場:
- 標價是該程式針對該合約設定的參考價格。未實現損益、強制平倉及資金費率的結算均以此為基準。
- 預言機(或指數)價格是外部參考價格(通常為Pyth 等現貨交易平台的預言機聚合數據)。標價與預言機價格應保持緊密連動。若兩者持續出現背離,即為市場壓力或流動性不足的訊號。
- 資金費率是指多頭與空頭之間為使標價保持在預測價格附近而進行的定期支付。本指南及 Phoenix 的回應載荷中所採用的慣例是:正資金費率表示多頭向空頭支付,負資金費率則表示空頭向多頭支付。
- 未平倉合約是指所有未平倉部位的名義總值,即每筆未平倉多頭與空頭部位的槓桿規模之和,而非鎖定在協議中的抵押品(即 TVL)。這是衡量市場持倉強度的一項指標。
什麼是 Phoenix?
Phoenix 是一個Solana去中心化交易所。它最初以鏈上限價訂單簿的形式推出,用於現貨交易,其後又推出了永續期貨產品,而本指南的重點即在於此產品。配對過程完全在mainnet Solana 進行mainnet 鏈下配對引擎。
對於任何僅需讀取市場資料的應用程式(例如儀表板、價格資料饋送、分析工具),Phoenix 會將您所需的一切功能公開於 perp-api.phoenix.trade. 系統設有一個用於快照的 REST 主機,以及一個用於推送更新的 WebSocket 主機。公開讀取端點無需 API 金鑰、無需簽名標頭,也無需錢包。鏈上下單屬於另一項獨立的整合功能,需連接錢包,且超出本指南的範圍。
Phoenix WebSocket API
Phoenix 透過單一 WebSocketendpoint 提供即時市場數據: wss://perp-api.phoenix.trade/v1/ws. 您只需建立一個連線,並訂閱所需的任何頻道。本指南中的儀表板已訂閱全部六個頻道。
每項訂閱都遵循相同的模式:傳送一則包含 類型 的 訂閱, a 頻道 名稱,以及一個 符號:
{
"type": "subscribe",
"subscription":
{
"channel": "<channel>",
"symbol": "SOL"
}
}
儀表板所使用的六個頻道,以及每個頻道能為您提供什麼:
市場: 顯示核心市場數據:標價、預言機價格、中價、24 小時成交量、未平倉合約數量,以及當前資金費率。訂單簿: 每傳送一則訊息時,即提供訂單簿的完整 L2 快照,其中包含所有買入價與賣出價層級,並附有價格及數量。交易: 即時Streams 紀錄:價格、交易量、方向(買或賣)及時間戳記。蠟燭: 選定時間區間的Streams (OHLCV)K線資料(1m,5m,1h, 等)。資金利率: 每當當前資金費率發生變動時,便會推送該變動資訊。交易所: 描述交換機的整體運作狀態。在連線時傳送快照,隨後傳送增量更新。
Phoenix 還提供了一套完整的REST API,其中包含用於市場數據快照、交易者狀態、註冊、驗證以及交易建檔等功能的端點。
此配套範例應用程式是一個唯讀的 React 儀表板,它會與 Phoenix 建立單一 WebSocket 連線,訂閱所有六個頻道,並將資料渲染至五個面板中:
- 市場概覽: 標頭欄顯示標價、預言機價格、24 小時變動率、24 小時成交量、未平倉合約數量及當前資金費率。由
市場以及資金利率頻道。包含來自交易所頻道。 - 價格走勢圖: 附有時間框架切換器的蠟燭圖 (
1m,5m,15m,1h,4h,1d). 在載入時及重新連線時從 REST 取得初始資料,隨後從蠟燭頻道。 - 訂單簿: 前 15 大買入價與賣出價水準,附累計成交量及以基點為單位的價差。每日更新
訂單簿訊息。 - 交易動態: 最新交易的即時串流,依交易方以不同顏色標示。每筆交易更新一次
交易訊息。 - 市場資訊:顯示手續費、槓桿級別、保證金要求、報價單位及交易單位的靜態參考面板。

PhoenixProvider / usePhoenix() 在 src/ws/PhoenixWebSocket.tsx 負責管理單一共用 WebSocket、訂閱追蹤、訊息分發、重新連線邏輯、時間區間切換,以及對外公開的狀態物件。
請將其複製並在本地執行,以便跟著本指南的其餘步驟操作:
git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd solana/phoenix-dashboard
npm install
npm run dev
取得市場設定並點燃種燭
即使由 WebSocket 支援的儀表板,仍需仰賴 REST。WebSocket 會在資料流中途加入,並傳送下一次的更新,而非快照。在即時更新送達之前,必須先填入兩項狀態資料:靜態市場設定(WebSocket 絕不會推送此資料)以及歷史 K 線序列(以便圖表中顯示的 K 線數量超過一根)。
GET /exchange/market/{symbol} 回傳一個包含靜態市場參數的 JSON 物件。以下為經刪減的回應範例:
{
"symbol": "SOL",
"assetId": 1,
"marketStatus": "active",
"marketPubkey": "...",
"tickSize": 0.01,
"baseLotsDecimals": 3,
"takerFee": 0.0005,
"makerFee": 0.0001,
"fundingIntervalSeconds": 3600,
"fundingPeriodSeconds": 86400,
"maxFundingRatePerIntervalPercentage": 0.05,
"openInterestCapBaseLots": "100000000",
"maxLiquidationSizeBaseLots": "5000000",
"isolatedOnly": false,
"leverageTiers": [
{ "maxLeverage": 20, "maxSizeBaseLots": 1000000, "limitOrderRiskFactor": 0.05 },
{ "maxLeverage": 10, "maxSizeBaseLots": 5000000, "limitOrderRiskFactor": 0.1 }
],
"riskFactors": {
"maintenance": 0.03,
"backstop": 0.01,
"highRisk": 0.05,
"upnl": 0.5,
"upnlForWithdrawals": 0.25,
"cancelOrder": 0.001
}
}
儀表板將此資料用於「市場資訊」參考面板(最高槓桿、級別表、保證金要求、手續費、點值/手數)。這些欄位均未透過任何 WebSocket 通道推送,因此 REST 是唯一的資料來源。
GET /candles?symbol=SOL&timeframe=1m&limit=500 會傳回一個包含帶有毫秒級時間戳記的燭台物件陣列:
[
{
"time": 1747556400000,
"open": 170.21,
"high": 170.55,
"low": 170.14,
"close": 170.42,
"volume": 1284.5,
"volumeQuote": 218842.71,
"tradeCount": 42,
"markOpen": 170.20,
"markHigh": 170.54,
"markLow": 170.13,
"markClose": 170.41
}
]
訂閱 Phoenix WebSocket
const ws = new WebSocket('wss://perp-api.phoenix.trade/v1/ws');
const subscriptions = [
{ type: 'subscribe', subscription: { channel: 'market', symbol: 'SOL' } },
{ type: 'subscribe', subscription: { channel: 'orderbook', symbol: 'SOL' } },
{ type: 'subscribe', subscription: { channel: 'trades', symbol: 'SOL' } },
{ type: 'subscribe', subscription: { channel: 'candles', symbol: 'SOL', timeframe: '1m' } },
{ type: 'subscribe', subscription: { channel: 'fundingRate', symbol: 'SOL' } },
{ type: 'subscribe', subscription: { channel: 'exchange', encoding: 'json' } },
];
ws.onopen = () => {
for (const msg of subscriptions) ws.send(JSON.stringify(msg));
};
有兩點需要注意: 蠟燭 承載著 時間範圍,以及 交易所 承載 編碼:'json' (無符號)。
每個有效載荷都具有一個 頻道 或 a 類型 field。根據實際存在的情況進行分派:
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
const key = msg.channel ?? msg.type;
switch (key) {
case 'market': return onMarketStats(msg);
case 'orderbook': return onOrderbook(msg);
case 'trades': return onTrades(msg);
case 'candles': return onCandle(msg);
case 'fundingRate': return onFundingRate(msg);
case 'exchange': return onExchange(msg);
case 'subscriptionConfirmed': return;
case 'subscriptionError':
case 'error':
console.error('Phoenix error', msg);
return;
}
};
在連線建立且訂閱請求已傳送後,伺服器便開始推送訊息。以下是這六個頻道各自載荷的詳細說明:
市場
市場數據更新 推送標頭編號:
{
"channel": "market",
"markPx": 170.42,
"oraclePx": 170.41,
"midPx": 170.42,
"prevDayPx": 168.15,
"dayNtlVlm": 218842710.42,
"openInterest": 4521234.5,
"funding": 0.00012
}
替換記憶體中的 MarketStats 每則訊息的批發價格。計算自 markPx 以及 prevDayPx. 該儀表板採用 資金 包括頁首徽章,以及與圖表並列顯示的會話本地歷史記錄系列。
訂單簿
L2BookUpdate 這是一個完整的 L2 快照,而非增量快照。每收到一則訊息,便會替換記憶體中的區塊鏈。Phoenix 會以兩種形式傳送此載荷(參見 處理 Phoenix 的載荷怪癖). 若 市場數據更新 尚未抵達,推導 midPx 摘自書首: (最高買價 + 最高賣價) / 2.
{
"channel": "orderbook",
"symbol": "SOL",
"orderbook": {
"bids": [[170.41, 42.5], [170.40, 118.0], [170.38, 75.2]],
"asks": [[170.42, 30.1], [170.43, 95.0], [170.45, 210.3]],
"mid": 170.415
},
"bypassExecutionBand": false
}
交易
交易訊息 在傳輸過程中僅支援追加。儀表板會將資料追加至開頭,並限制為 100 行。關鍵欄位:
{
"channel": "trades",
"trades": [
{
"tradeSequenceNumber": 482113,
"slot": 281234567,
"slotIndex": 3,
"timestamp": "1747556421",
"time": 1747556421000,
"side": "b",
"price": 170.42,
"size": 12.5,
"notional": 2130.25,
"numFills": 1
}
]
}
蠟燭
CandleData streams 正在streams (隨其更新),並在時間區間結束時streams 已收盤的K線。此頻道的時間單位為秒(其餘為毫秒)。儀表板會透過以下方式進行「插入或更新」操作: 時間: 如果有一根蠟燭具有相同的 時間 若已存在,則予以取代;否則則追加。
{
"channel": "candles",
"symbol": "SOL",
"timeframe": "1m",
"candle": {
"time": 1747556460,
"open": 170.42,
"high": 170.50,
"low": 170.38,
"close": 170.45,
"volume": 92.1,
"volumeQuote": 15710.2
}
}
資金利率
資金利率更新 將取代目前的撥款比率。該儀表板還會推送一則 { timestamp: Date.now(), rate } 將資料寫入會話本地的陣列中,以便能將資金歷史紀錄與價格一併繪製成圖表。無需進行資料持久化。
{
"channel": "fundingRate",
"funding": 0.00012,
"fundingTime": 1747556400
}
交易所
該 交易所 此通道描述全球交易所的運作狀況。它會傳送一個 快照 在訂閱時執行一次,然後 delta 訊息。每個 delta 有一個 op; 這個儀表板僅會對以下項目做出反應: exchangeStatusChanged. 其他市場層級的 Delta 操作則被刻意忽略。
{
"channel": "exchange",
"type": "snapshot",
"active": true,
"gated": false
}
總結
現在,您已擁有一套完全基於推送機制、並完全由 Phoenix 公開 API 驅動的 SOL 永續合約終端。您已清楚該從哪些 REST 端點獲取初始資料、該訂閱哪六個 WebSocket 通道,以及如何在單一邊界處處理 Phoenix 資料負載的特殊性(數值編碼、訂單簿結構、時間單位),從而確保其餘程式碼保持簡潔。 重新連線、重新訂閱以及時間框架切換的邏輯均已預先設定,因此即使連線中斷,儀表板仍能持續更新而不致過時。在此基礎上,您可以將其指向任何 Phoenix 市場、透過Quicknode endpoint整合鏈上情境,或使用您偏好的任何框架重建使用者介面。
常見問題
Phoenix WebSocket 是否設有限流或需經過身份驗證?
本文所述的公開唯讀資訊流無需 API 金鑰、無需簽名標頭,也無需錢包。請查閱 Phoenix 文件以了解目前的速率限制,因為公開基礎設施的限制可能會有所變更。
標價與預言機價格之間有何區別?
標價是該協議針對永續合約設定的參考價格,用於結算未實現損益、強制平倉及資金費率。預言機(或指數)價格則為外部參考價格(通常為現貨交易平台的綜合價格)。這兩者應保持緊密連動;若出現持續性偏離,即為壓力訊號,儀表板會以圖表疊加方式顯示此狀況。
我能否將此功能應用於其他 Phoenix 市場,例如 BTC 或 ETH?
是的。Phoenix 的 REST 和 WebSocket 介面在各市場中完全一致。只需在整個服務提供者中對代碼進行參數化,將記憶體中的狀態提升為按代碼區分的映射,然後透過相同的六個通道傳輸儀表板所呈現的所有內容。
我可以在這個儀表板上進行交易嗎?
不。交易功能超出本指南的範圍。在 Phoenix 上下單屬於Solana 鏈Solana 互動,需要已連線的錢包及簽署過的交易,而本指南中使用的唯讀公開 API 介面並不支援這兩項功能。
