> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qfex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 定时推送订单簿

QFEX 通过 WebSocket 提供**每 500 毫秒推送一次**、深度最高为 20 档的订单簿数据流。

## 使用方式

连接公开 WebSocket：

* URL：`wss://mds.qfex.com`。

然后发送订阅消息：

```json theme={null}
{
  "type": "subscribe",
  "channels": ["level2"],
  "symbols": ["AAPL-USD", "US500-USD"]
}
```

也可使用通配符订阅**所有**交易品种：

```json theme={null}
{ "type": "subscribe", "channels": ["level2"], "symbols": ["*"] }
```

### 有效位数（可选）

可选择指定 `sig_figs`，以合并订单簿价位：

```json theme={null}
{
  "type": "subscribe",
  "channels": ["level2"],
  "symbols": ["AAPL-USD"],
  "sig_figs": [1]
}
```

* **默认值**：`0`，不合并。
* **有效值**：`0`、`1` 或 `2`。
* **用途**：从最小价格变动单位出发，按更高有效位合并各个价位。
  * 买价向下取整。
  * 卖价向上取整。
* **响应格式**：不变，与未提供 `sig_figs` 时相同。

## 示例代码

```python python theme={null}
# Python (websocket-client)
# pip install websocket-client
import json
import websocket

def on_open(ws):
    sub = {
        "type": "subscribe",
        "channels": ["level2"],
        "symbols": ["US500-USD"]  # or ["*"]
    }
    ws.send(json.dumps(sub))

def on_message(ws, message):
    data = json.loads(message)
    print("OrderBook update:", json.dumps(data, indent=2))

def on_error(ws, error):
    print("Error:", error)

def on_close(ws, close_status_code, close_msg):
    print("Closed:", close_status_code, close_msg)

if __name__ == "__main__":
    ws = websocket.WebSocketApp(
        "wss://mds.qfex.com",
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
    )
    ws.run_forever()
```

```javascript node theme={null}
// Node.js (ws)
// npm i ws
import WebSocket from "ws";

const ws = new WebSocket("wss://mds.qfex.com");

ws.on("open", () => {
  const sub = {
    type: "subscribe",
    channels: ["level2"],
    symbols: ["US500-USD"], // or ["*"]
  };
  ws.send(JSON.stringify(sub));
});

ws.on("message", (msg) => {
  try {
    const data = JSON.parse(msg.toString());
    console.log("OrderBook update:", data);
  } catch (e) {
    console.error("Parse error:", e);
  }
});

ws.on("error", (err) => console.error("WS error:", err));
ws.on("close", (code, reason) =>
  console.log("Closed:", code, reason?.toString()),
);
```

```go go theme={null}
// Go (gorilla/websocket)
// go get github.com/gorilla/websocket
package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"

	"github.com/gorilla/websocket"
)

func main() {
	c, _, err := websocket.DefaultDialer.Dial("wss://mds.qfex.com", nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close()

	sub := map[string]interface{}{
		"type":     "subscribe",
		"channels": []string{"level2"},
		"symbols":  []string{"US500-USD"}, // or []string{"*"}
	}
	if err := c.WriteJSON(sub); err != nil {
		log.Fatal("write:", err)
	}

	done := make(chan struct{})
	go func() {
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				return
			}
			fmt.Printf("OrderBook update: %s\n", message)
		}
	}()

	// keep running until Ctrl+C
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)
	<-interrupt
}
```

```java java theme={null}
// Java (OkHttp WebSocket)
// Gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0")
import java.util.concurrent.TimeUnit;
import okhttp3.*;

public class OrderBookWs {
  public static void main(String[] args) {
    OkHttpClient client = new OkHttpClient.Builder()
        .pingInterval(20, TimeUnit.SECONDS)
        .build();

    Request request = new Request.Builder()
        .url("wss://mds.qfex.com")
        .build();

    WebSocketListener listener = new WebSocketListener() {
      @Override public void onOpen(WebSocket webSocket, Response response) {
        String sub = "{\"type\":\"subscribe\",\"channels\":[\"level2\"],\"symbols\":[\"US500-USD\"]}";
        webSocket.send(sub);
      }
      @Override public void onMessage(WebSocket webSocket, String text) {
        System.out.println("OrderBook update: " + text);
      }
      @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        System.err.println("WS error: " + t.getMessage());
      }
    };

    client.newWebSocket(request, listener);

    // Keep JVM alive
    try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {}
  }
}
```

## 响应示例

```json theme={null}
{
  "type": "level2",
  "symbol": "AAPL-USD",
  "bid": [
    ["10101.10", "0.45054140"],
    ["10101.00", "0.55054140"]
  ],
  "ask": [
    ["10102.55", "0.57753524"],
    ["10102.65", "0.57753524"]
  ],
  "sequence": 30272539,
  "time": "2025-09-04T09:26:39.545268322Z"
}
```

### 取消订阅（可选）

```json theme={null}
{ "type": "unsubscribe", "channels": ["level2"], "symbols": ["US500-USD"] }
```

## 注意事项

* 每 500 毫秒定时推送。
* 深度最高为 20 档。
* `symbols` 接受通配符 `*`，用于获取全部交易品种。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.