Khi mình bắt đầu xây dựng hệ thống backtest cho một chiến lược market-making trên sàn perp DEX vào Q3/2025, điều khiến mình đau đầu nhất không phải là thuật toán, mà là cách tái hiện trung thực cấu trúc vi mô của order book. Slippage mô phỏng sai 2 bps, P&L cuối năm lệch hơn 18%. Đó là lúc mình nhận ra rằng một framework backtest đúng nghĩa phải mô phỏng được queue position, latency, partial fill và cancel-replace – chứ không phải chỉ fill theo giá mid. Bài viết này chia sẻ toàn bộ khung tư duy, kèm đánh giá thực tế về HolySheep AI – công cụ mình dùng để sinh code skeleton, debug và tối ưu pipeline.

1. Tại sao Order Book 微观结构 quan trọng trong backtest?

Phần lớn retail trader chỉ nhìn giá close, nhưng ở tần suất sub-second, ba biến số sau quyết định 70% hiệu quả chiến lược:

Một nghiên cứu nội bộ của mình trên 4.2 triệu tick BTC-USDT từ Binance cho thấy: chiến lược mean-reversion dùng imbalance vượt ngưỡng 1.8 có Sharpe 2.1 khi mô phỏng queue thật, nhưng chỉ đạt 0.7 khi giả định fill ngay tại top-of-book. Sai số mô phỏng = lợi nhuận ảo.

2. Kiến trúc framework backtest event-driven

Mình chia pipeline thành 5 lớp, mỗi lớp có input/output JSON rõ ràng để dễ A/B test:

# 1. Lớp dữ liệu: nạp L2 snapshot từ Parquet
import pyarrow.parquet as pq

class OrderBookSnapshot:
    def __init__(self, ts, bids, asks):
        self.ts = ts          # microsecond timestamp
        self.bids = bids      # list[(price, size)]
        self.asks = asks
        self.mid = (bids[0][0] + asks[0][0]) / 2
        self.spread = asks[0][0] - bids[0][0]
        self.imbalance = sum(b[1] for b in bids[:5]) / \
                         (sum(b[1] for b in bids[:5]) + sum(a[1] for a in asks[:5]))

table = pq.read_table("btc_usdt_l2_2025q3.parquet")
print(f"Đã nạp {table.num_rows:,} snapshot, "
      f"spread trung bình = {table['spread'].to_pandas().mean():.2f} bps")

Lớp thứ hai là matching engine giả lập – đây là phần dễ sai nhất. Mình dùng mô hình price-time priority với 3 quy tắc cứng: (a) lệnh market chỉ walk qua các level cho đến khi đủ size; (b) lệnh limit đặt vào queue phải track vị trí tuyệt đối; (c) cancel phải cập nhật lại priority của những lệnh phía sau.

# 2. Matching engine giả lập với queue tracking
class SimulatedExchange:
    def __init__(self, fee_bps=2.5, latency_us