🐍 Ngày 42 - Python hằng ngày 365 ngày - Khám phá Order Book với API Binance
Hôm nay, chúng ta sẽ cùng tìm hiểu Order Book là gì và cách lấy dữ liệu Order Book từ API Binance bằng Python.
📚 Order Book là gì?
Order Book (Sổ Lệnh) là nơi lưu trữ tất cả các lệnh mua và lệnh bán của một tài sản (ví dụ Bitcoin) trên sàn giao dịch, được sắp xếp theo thứ tự giá.
🔹 Cấu trúc:
- Lệnh mua (Bid): Người mua đề nghị mua tài sản với một mức giá cụ thể.
- Lệnh bán (Ask): Người bán đề nghị bán tài sản với một mức giá cụ thể.
✅ Khi giá mua cao nhất khớp với giá bán thấp nhất, giao dịch sẽ được thực hiện.
📈 Ví dụ Order Book BTC/USDT:
| Giá mua (Bid) | Khối lượng (BTC) | Giá bán (Ask) | Khối lượng (BTC) |
|---|---|---|---|
| 93,000 | 0.5 | 63,100 | 0.3 |
| 92,900 | 1.0 | 63,200 | 0.4 |
| 92,800 | 2.0 | 63,300 | 0.6 |
🛠 Bài tập thực hành
Bước 1: Cài đặt thư viện
pip install python-binance
Bước 2: Kết nối API Binance và lấy Order Book
from binance import Client
# Thay bằng API Key và Secret Key của bạn
api_key = 'YOUR_API_KEY'
api_secret = 'YOUR_API_SECRET'
client = Client(api_key, api_secret)
# Lấy Order Book cho cặp BTCUSDT
order_book = client.get_order_book(symbol='BTCUSDT')
# In ra top 5 lệnh mua và bán
print("Top 5 lệnh mua (Bids):")
for bid in order_book['bids'][:5]:
price, quantity = bid
print(f"Giá: {price}, Khối lượng: {quantity}")
print("\nTop 5 lệnh bán (Asks):")
for ask in order_book['asks'][:5]:
price, quantity = ask
print(f"Giá: {price}, Khối lượng: {quantity}")
Video hướng dẫn Docusaurus
Đây là video hướng dẫn chi tiết:
📊 Đọc và phân tích order book thực tế
import urllib.request
import json
import pandas as pd
def lay_order_book(symbol: str = "BTCUSDT", gioi_han: int = 20) -> tuple[pd.DataFrame, pd.DataFrame]:
"""Lấy order book, trả về (bids, asks) dưới dạng DataFrame."""
url = ("https://api.binance.com/api/v3/depth"
f"?symbol={symbol}&limit={gioi_han}")
with urllib.request.urlopen(url, timeout=15) as r:
du_lieu = json.loads(r.read().decode())
bids = pd.DataFrame(du_lieu["bids"], columns=["gia", "khoi_luong"], dtype=float)
asks = pd.DataFrame(du_lieu["asks"], columns=["gia", "khoi_luong"], dtype=float)
# Tính giá trị từng mức (USDT)
for df in (bids, asks):
df["gia_tri"] = df["gia"] * df["khoi_luong"]
return bids, asks
bids, asks = lay_order_book("BTCUSDT", 20)
best_bid = bids["gia"].iloc[0]
best_ask = asks["gia"].iloc[0]
spread = best_ask - best_bid
spread_pct = spread / best_bid * 100
print(f"Best bid: {best_bid:,.2f}")
print(f"Best ask: {best_ask:,.2f}")
print(f"Spread: {spread:,.2f} ({spread_pct:.4f}%)")
print(f"\nTổng khối lượng mua (20 mức đầu): {bids['khoi_luong'].sum():,.4f} BTC")
print(f"Tổng khối lượng bán (20 mức đầu): {asks['khoi_luong'].sum():,.4f} BTC")
⚖️ Mất cân bằng sổ lệnh — chỉ báo quan trọng nhất từ order book
Order book imbalance đo lực mua so với lực bán. Đây là thông tin mà biểu đồ giá không cho bạn biết.
import numpy as np
def mat_can_bang(bids: pd.DataFrame, asks: pd.DataFrame) -> dict:
"""Tính các chỉ số mất cân bằng của sổ lệnh."""
khoi_luong_mua = bids["khoi_luong"].sum()
khoi_luong_ban = asks["khoi_luong"].sum()
tong = khoi_luong_mua + khoi_luong_ban
if tong == 0:
return {"loi": "Sổ lệnh rỗng"}
return {
"ty_le_mua": round(khoi_luong_mua / tong * 100, 2),
"ty_le_ban": round(khoi_luong_ban / tong * 100, 2),
"chenh_lech": round((khoi_luong_mua - khoi_luong_ban) / tong * 100, 2),
"gia_tri_mua_usdt": round(bids["gia_tri"].sum(), 2),
"gia_tri_ban_usdt": round(asks["gia_tri"].sum(), 2),
}
tt = mat_can_bang(bids, asks)
for k, v in tt.items():
print(f"{k:<22} {v}")
chenh = tt["chenh_lech"]
if chenh > 20:
print("\n🟢 Áp lực MUA chiếm ư ưu thế rõ rệt")
elif chenh < -20:
print("\n🔴 Áp lực BÁN chiếm ưu thế rõ rệt")
else:
print("\n➖ Cân bằng — không có bên nào chiếm ưu thế")
| Chỉ số | Ý nghĩa |
|---|---|
| Chênh lệch > +20% | Áp lực mua mạnh — hỗ trợ bên dưới dày |
| Chênh lệch < −20% | Áp lực bán mạnh — kháng cự bên trên dày |
| Chênh lệch ≈ 0 | Thị trường cân bằng, chờ tín hiệu khác |
| Spread rộng | Thanh khoản kém — cẩn thận trượt giá |
⚠️ Giới hạn quan trọng: tường mua/bán trong order book có thể là lệnh ảo — được đặt rồi huỷ ngay trước khi giá chạm tới (spoofing). Đừng bao giờ vào lệnh chỉ dựa vào imbalance. Hãy dùng nó như một yếu tố phụ.
🧱 Phát hiện tường mua/bán (walls)
import pandas as pd
def tim_tuong(df: pd.DataFrame, so_lan_tb: float = 3.0) -> pd.DataFrame:
"""Tìm các mức giá có khối lượng lớn bất thường."""
nguong = df["khoi_luong"].mean() * so_lan_tb
tuong = df[df["khoi_luong"] > nguong].copy()
tuong["gap_so_lan"] = (tuong["khoi_luong"] / df["khoi_luong"].mean()).round(1)
return tuong.sort_values("khoi_luong", ascending=False)
tuong_mua = tim_tuong(bids)
tuong_ban = tim_tuong(asks)
print("🧱 Tường MUA (hỗ trợ tiềm năng):")
for _, r in tuong_mua.head(3).iterrows():
print(f" {r['gia']:>12,.2f} {r['khoi_luong']:>10,.3f} BTC (gấp {r['gap_so_lan']}x)")
print("\n🧱 Tường BÁN (kháng cự tiềm năng):")
for _, r in asks.nlargest(3, "khoi_luong").iterrows():
print(f" {r['gia']:>12,.2f} {r['khoi_luong']:>10,.3f} BTC")
🔴 WebSocket — theo dõi order book theo thời gian thực
REST API chỉ cho bạn ảnh chụp tại một thời điểm. WebSocket cho bạn dòng dữ liệu liên tục.
# pip install websocket-client
import json
import websocket
def theo_doi_order_book(symbol: str = "btcusdt", so_cap_nhat: int = 10):
"""Theo dõi order book realtime qua WebSocket Binance."""
url = f"wss://stream.binance.com:9443/ws/{symbol}@depth20@100ms"
dem = 0
def khi_nhan(ws, thong_diep):
nonlocal dem
du_lieu = json.loads(thong_diep)
bids = [(float(p), float(q)) for p, q in du_lieu.get("bids", [])]
asks = [(float(p), float(q)) for p, q in du_lieu.get("asks", [])]
if not bids or not asks:
return
kl_mua = sum(q for _, q in bids)
kl_ban = sum(q for _, q in asks)
chenh = (kl_mua - kl_ban) / (kl_mua + kl_ban) * 100
dem += 1
print(f"[{dem:>3}] Bid {bids[0][0]:,.2f} | Ask {asks[0][0]:,.2f} | "
f"Imbalance {chenh:+.1f}%")
if dem >= so_cap_nhat:
ws.close()
websocket.WebSocketApp(url, on_message=khi_nhan).run_forever()
# theo_doi_order_book()
| Tiêu chí | REST API | WebSocket |
|---|---|---|
| Cách hoạt động | Gọi → nhận → kết thúc | Kết nối mở liên tục |
| Độ trễ | 100–500ms | 10–100ms |
| Số request | Mỗi lần gọi là 1 request | 1 kết nối cho hàng nghìn cập nhật |
| Rate limit | Có | Hầu như không |
| Phù hợp | Kiểm tra định kỳ | Bot realtime |
📝 Bài tập mở rộng
Bài 1: So sánh imbalance giữa các cặp
Lấy order book của BTC, ETH, SOL và so sánh chỉ số imbalance. Cặp nào đang có áp lực mua mạnh nhất?
Bài 2: Cảnh báo spread rộng
Viết script kiểm tra spread mỗi 10 giây, in cảnh báo khi spread > 0,1%.
Bài 3: Vẽ biểu đồ sổ lệnh
Dùng matplotlib vẽ biểu đồ cột ngang thể hiện khối lượng ở mỗi mức giá (bids một màu, asks màu khác).
Bài 4: Theo dõi imbalance theo thời gian
Dùng WebSocket ghi lại imbalance mỗi 5 giây trong 2 phút, vẽ biểu đồ đường.
🎯 Tóm tắt ngày 42
✅ Lấy và chuẩn hoá order book thành DataFrame ✅ Tính spread, tổng khối lượng, và imbalance ✅ Phát hiện tường mua/bán bất thường ✅ Hiểu giới hạn: tường có thể là lệnh ảo (spoofing) ✅ Biết khi nào dùng REST API vs WebSocket
🎯 Ghi chú
- Dữ liệu Order Book có thể cập nhật cực kỳ nhanh theo thời gian thực.
- Bạn có thể dùng WebSocket để theo dõi biến động trực tiếp của Order Book nếu muốn nâng cao.