Khi mình bắt đầu tìm hiểu về giao dịch định lượng trên Binance, mình gặp một khái niệm nghe rất "pro": Order Flow Imbalance (OFI). Ban đầu mình tưởng nó phức tạp lắm, nhưng sau hai ngày cuối tuần ngồi debug, mình nhận ra: nó chỉ là "đo xem phe nào đang đặt lệnh mạnh hơn" trên sổ lệnh. Bài viết này là kinh nghiệm thực chiến của mình, mình sẽ dẫn bạn đi từ con số 0 đến khi chạy được một backtest hoàn chỉnh trên hợp đồng vĩnh cửu (perpetual) của Binance.

Nếu bạn chưa từng gọi API bao giờ, đừng lo. Mình sẽ gợi ý từng ảnh chụp màn hình và giải thích mọi dòng lệnh theo ngôn ngữ đời thường.

⚠️ Lưu ý: Toàn bộ ví dụ trong bài dùng Binance Testnet (môi trường thử nghiệm, không dùng tiền thật). Bài viết chỉ phục vụ mục đích học tập, không phải lời khuyên đầu tư.

1. OFI là gì, hiểu trong 2 phút

Tưởng tượng bạn đứng trước một quán phở lúc 7 giờ sáng. Nếu khách xếp hàng dài bên trái (phe mua) và bên phải vắng tanh (phe bán), bạn biết ngay phở đang "hot". OFI làm điều tương tự trên sổ lệnh:

Trong backtest, OFI được tính trên dữ liệu lịch sử của hợp đồng vĩnh cửu Binance để xem chiến lược có sinh lời trong quá khứ hay không.

2. Chuẩn bị những thứ bạn cần

Mẹo nhỏ từ kinh nghiệm của mình: bạn đăng ký tại đây để nhận tín dụng miễn phí, dùng cho các bước phân tích phía sau.

3. Bước 1 — Kéo dữ liệu sổ lệnh từ Binance

Mình dùng thư viện requests để gọi endpoint /fapi/v1/depth. Bạn copy đoạn dưới, dán vào file fetch_depth.py và chạy bằng lệnh python fetch_depth.py.

import requests
import json

BASE = "https://testnet.binancefuture.com"
SYMBOL = "BTCUSDT"

def get_depth(symbol: str, limit: int = 20):
    """Lấy snapshot sổ lệnh hiện tại."""
    url = f"{BASE}/fapi/v1/depth"
    params = {"symbol": symbol, "limit": limit}
    r = requests.get(url, params=params, timeout=10)
    r.raise_for_status()
    return r.json()

if __name__ == "__main__":
    data = get_depth(SYMBOL, 50)
    print(json.dumps(data, indent=2)[:500])

4. Bước 2 — Tính chỉ số OFI theo công thức Cont

Công thức OFI phổ biến (theo Cont 2023) tính trên top N cấp giá:

def compute_ofi(prev: dict, curr: dict, levels: int = 10) -> float:
    """So sánh hai snapshot liên tiếp, trả về giá trị OFI."""
    prev_bids = {float(p): float(q) for p, q in prev["bids"][:levels]}
    curr_bids = {float(p): float(q) for p, q in curr["bids"][:levels]}
    prev_asks = {float(p): float(q) for p, q in prev["asks"][:levels]}
    curr_asks = {float(p): float(q) for p, q in curr["asks"][:levels]}

    ofi = 0.0
    # Cộng delta phe mua
    for price in set(prev_bids) | set(curr_bids):
        ofi += curr_bids.get(price, 0.0) - prev_bids.get(price, 0.0)

    # Trừ delta phe bán
    for price in set(prev_asks) | set(curr_asks):
        ofi -= curr_asks.get(price, 0.0) - prev_asks.get(price, 0.0)

    return ofi

5. Bước 3 — Backtest đơn giản với pandas

Mình không dùng framework nặng như backtrader để bạn dễ theo dõi. Thay vào đó, mình gom OFI của nhiều snapshot liên tiếp, rồi đưa ra tín hiệu LONG/SHORT, cuối cùng tính lũy kế PnL.

import pandas as pd
import numpy as np

def backtest(ofi_series: pd.Series, threshold: float = 50.0):
    """OFI > threshold → LONG, OFI < -threshold → SHORT."""
    signal = np.where(ofi_series > threshold, 1,
              np.where(ofi_series < -threshold, -1, 0))
    ret = signal[:-1] * ofi_series.diff().fillna(0).to_numpy()[1:]
    pnl = pd.Series(ret).cumsum()
    return signal, pnl

Ví dụ chạy thử

ofi_series = pd.Series([12, 80, -30, 120, -90, 5, 200, -150, 0, 60]) signal, pnl = backtest(ofi_series, threshold=50) print("Tín hiệu:", signal) print("Lũy kế PnL:", pnl.tolist())

6. Bước 4 — Nhờ HolySheep AI phân tích kết quả backtest

Sau khi có chuỗi PnL, mình hay dùng HolySheep AI để giải thích vì sao chiến lược lời/lỗ ở một số giai đoạn. Cách gọi cực đơn giản