Nội dung này phục vụ mục đích giáo dục, không phải lời khuyên đầu tư hoặc tín hiệu giao dịch.

Trả lời ngắn: Rủi ro API, sàn và thực thi là khả năng lệnh thật khác ý định vì kết nối, giới hạn dịch vụ, trạng thái sàn hoặc cách khớp lệnh. Nguy hiểm nhất là trạng thái UNKNOWN: bot không biết lệnh đã vào sàn chưa. Khi đó phải dừng gửi mới, truy vấn và đối chiếu trước khi retry.

Đọc xong, bạn sẽ hiểu:

  • Vì sao model đúng vẫn có thể tạo vị thế sai.
  • Timeout, stale feed và partial fill cần xử lý khác nhau thế nào.
  • Cách dùng state machine và Incident Card để ngăn retry trùng lệnh.

1. Ba lớp rủi ro sau khi model tạo tín hiệu

a. API là đường giao tiếp, không phải sàn

API là bộ quy tắc để phần mềm gửi yêu cầu và nhận dữ liệu từ dịch vụ khác. Bot có thể dùng REST API để đặt hoặc hỏi trạng thái lệnh, còn WebSocket để nhận dữ liệu liên tục. API trả lỗi chỉ chứng minh đường giao tiếp có vấn đề; chưa chắc matching engine của sàn đã từ chối lệnh.

Hãy nghĩ tới chuyển khoản ngân hàng. Bạn bấm gửi, màn hình quay rồi báo timeout. Có ba khả năng: lệnh chưa rời điện thoại, ngân hàng đã nhận nhưng phản hồi thất lạc, hoặc tiền đã chuyển xong. Chuyển lại ngay có thể trả hai lần. Với order cũng vậy.

b. Sàn là hệ thống trạng thái riêng

Sàn hay venue giữ order book, balance, order và fill. Nó có thể bảo trì, rate-limit, chậm phản hồi hoặc trả dữ liệu từ nguồn có độ trễ khác nhau. Local bot chỉ giữ bản sao. Nếu bản sao đó lệch sàn, mọi quyết định tiếp theo đều dựa trên vị thế tưởng tượng.

c. Execution là kết quả từ ý định tới fill

Execution là toàn bộ quá trình biến ý định thành lệnh và giao dịch khớp. Nó bao gồm giá gửi, thời điểm, khối lượng, loại lệnh, trạng thái, lượng đã fill, phí và giá trung bình. Model dự đoán hướng chỉ là đầu vào; execution mới quyết định vị thế thật.

Ví dụ model muốn exposure 0,010 BTC. Lệnh chỉ fill 0,004 BTC rồi đứng. Nếu bot ghi “đã mua 0,010” thì hedge sai; nếu ghi “chưa mua” rồi gửi lại đủ 0,010 thì tổng có thể thành 0,014. Hai lỗi đều không nằm trong model.

2. State machine: SENT không đồng nghĩa FAILED

a. Mỗi ý định cần một định danh

Intent là ý định hành động đã được risk control phê duyệt, chẳng hạn “đưa exposure từ 0 lên 0,010 BTC bằng limit order”. Gắn cho nó một client order ID duy nhất. ID này giúp query cùng một ý định sau khi phản hồi bị mất và ngăn hệ thống vô tình coi retry là order mới.

Acknowledgment hay ACK là xác nhận sàn đã nhận yêu cầu. ACK chưa phải fill. Sau SENT, bot có thể nhận REJECTED, OPEN, PARTIAL_FILL, FILLED hoặc không nhận được câu trả lời.

b. UNKNOWN là trạng thái thật

Nếu request timeout, đừng ép nó vào FAILED. UNKNOWN nghĩa bot chưa có đủ bằng chứng về kết quả. Binance ghi rõ timeout từ matching engine không luôn có nghĩa request thất bại và khuyên kiểm User Data Stream hoặc query status; tài liệu cũng cảnh báo 5XX có execution status UNKNOWN (Binance Spot REST API).

Từ UNKNOWN, hành động an toàn là:

  1. Đóng van gửi order mới cho cùng intent.
  2. Query bằng client order ID hoặc order ID nếu đã có.
  3. Đối chiếu order, fills và balance.
  4. Chỉ chuyển sang trạng thái xác định khi có bằng chứng.
  5. Escalate nếu quá thời hạn reconcile.

Hình 1 — Timeout đưa lệnh vào UNKNOWN; đường đúng là reconcile, không vòng ngược về SENT bằng một retry mù.

c. Reconciliation là đối chiếu hai cuốn sổ

Reconciliation là so sánh local state với nguồn sự thật của sàn rồi sửa chênh lệch có kiểm soát. Nó giống đối chiếu sổ chi tiêu gia đình với sao kê ngân hàng. Không được chọn cuốn sổ mình thích; phải ghi rõ nguồn, timestamp và quy tắc xử lý xung đột.

3. Ví dụ thực tế: timeout rồi partial fill

Giả sử lúc 10:15:02, bot gửi limit order mua 0,010 BTC với client ID BTC-15M-042. Sau 10 giây, HTTP timeout. Bot chuyển intent sang UNKNOWN và freeze order mới.

Lúc 10:15:15, query theo client ID thấy order OPEN; vậy request cũ đã tới sàn. Lúc 10:15:20, user stream báo fill 0,004 BTC với giá trung bình giả lập 60.050 USD. Partial fill là order chỉ khớp một phần. Residual là lượng còn lại: 0,010 - 0,004 = 0,006 BTC.

Bot phải cập nhật ba thứ riêng:

  • Filled quantity: 0,004 BTC.
  • Leaves/residual quantity: 0,006 BTC.
  • Exposure thực: tính từ fills, không tính từ lượng request ban đầu.

Coinbase WebSocket order fields cũng tách cumulative quantity, leaves quantity, số fills và giá trung bình — minh họa rằng một order không chỉ có hai trạng thái “xong/chưa xong” (Coinbase WebSocket Channels).

Slippage là chênh lệch giữa mức giá kỳ vọng và giá thực thi. Nếu bot dự kiến 60.000 nhưng fill trung bình 60.050, slippage là 50 USD/BTC trước khi quy đổi theo khối lượng. Slippage có thể tới từ spread, thanh khoản, độ trễ hoặc market impact; không nên gán hết cho “API chậm”.

Sau khi reconcile, quyết định giữ, hủy residual hay giảm exposure phải quay lại policy/risk owner. Bài này không đưa ra quyết định mua bán. Điểm kỹ thuật là mọi hành động tiếp theo dùng filled state thật, không dùng request ban đầu.

4. Sai lầm, giới hạn và rủi ro thường gặp

a. Retry mọi lỗi theo một công thức

Retry là gửi lại request. Nó phù hợp với một số read request tạm lỗi, nhưng nguy hiểm với write request có side effect như đặt order. AWS lưu ý timeout không chứng minh side effect chưa xảy ra; API có tính idempotency mới cho phép lặp lại an toàn theo cùng một định danh (AWS Builders' Library).

Khi retry được phép, dùng backoff — tăng thời gian chờ giữa các lần — và jitter — thêm độ ngẫu nhiên để nhiều client không cùng dội request trở lại. Retry vô hạn chỉ biến lỗi nhỏ thành bão tải.

b. Còn kết nối nên tưởng dữ liệu còn live

Stale feed là luồng dữ liệu vẫn hiện hữu nhưng bản tin đã cũ. WebSocket chưa đóng không đảm bảo giá mới đang tới. Cần heartbeat để biết kết nối còn sống, sequence number để phát hiện mất hoặc đảo thứ tự bản tin, cùng timestamp từ sàn và timestamp nhận local.

Nếu last market event đã 8 giây trong chiến lược cần dữ liệu 1 giây, feed là stale dù màn hình còn xanh. Khi đó phải chặn signal/execution theo data freshness contract, không tự điền giá cũ.

Hình 2 — Market feed, API response và exchange state có đồng hồ khác nhau; reconciliation kéo local state về đúng nguồn sự thật.

c. Bỏ qua rate limit và clock skew

Rate limit là giới hạn số hoặc trọng số request trong một khoảng thời gian. Binance dùng HTTP 429 khi vượt hạn mức và có thể auto-ban IP nếu tiếp tục spam; Retry-After cho biết thời gian chờ (Binance Spot REST API). Query dồn dập để “chắc ăn” có thể làm mất luôn đường reconcile.

Clock skew là chênh lệch đồng hồ giữa máy bot và sàn. Request ký theo timestamp có thể bị từ chối dù logic đúng. Vì vậy cần đồng bộ thời gian, log cả exchange time/local time và cảnh báo khi drift quá ngưỡng.

Giới hạn cần nói thẳng: không có state machine nào loại hết venue risk. Sàn có thể outage, trả dữ liệu chậm hoặc thay contract. Mục tiêu là fail-safe, giới hạn blast radius và giữ đủ evidence để phục hồi.

5. Checklist vận hành trước khi cho bot đặt lệnh

  1. Identity: mỗi intent có client order ID duy nhất, không chứa secret.
  2. Preflight: kiểm symbol, tick size, step size, min notional, balance và permission.
  3. Freshness: market data, account state và clock đều còn trong ngưỡng.
  4. Timeout policy: connection timeout và request timeout tách riêng.
  5. Retry matrix: quy định lỗi nào retry được; write UNKNOWN không retry mù.
  6. Rate budget: theo dõi quota, 429, Retry-After và backoff+jitter.
  7. Order state: ACK, OPEN, PARTIAL, FILLED, CANCELLED, REJECTED, UNKNOWN.
  8. Reconciliation: query order, fills, balance và residual theo lịch.
  9. Circuit breaker: khi lỗi dồn, mở cầu dao để dừng request mới.
  10. Kill/escalate: có owner, deadline và cách xử lý manual.

Circuit breaker là cơ chế tạm ngừng gọi dịch vụ khi tỷ lệ lỗi hoặc timeout vượt ngưỡng. Nó không sửa sàn; nó ngăn bot tự khuếch đại sự cố. Đứng ngoài khi không có client ID, feed stale, local exposure không khớp balance, hoặc hệ thống không query được order/fills.

Điểm dừng bắt buộc: nếu UNKNOWN kéo dài hơn SLA nội bộ, freeze chiến lược liên quan và chuyển human review. Không lấy “có lẽ order chưa vào” làm bằng chứng.

6. Bài tập 15 phút: Execution Incident Card

Dùng Google Sheets hoặc giấy, không cần API key. Điền sự cố giả: intent mua 0,010 BTC; gửi 10:15:02; timeout; query thấy OPEN; đã fill 0,004; residual 0,006. Chưa dùng tiền thật.

Mẫu đối chiếu đã điền

Trường Giá trị demo Ý nghĩa
Intent ID BTC-15M-042 Khóa truy vết duy nhất
Sent at 10:15:02 Local send timestamp
Response TIMEOUT Chưa biết execution status
Query FOUND OPEN Request cũ đã tới sàn
Filled 0,004 / 0,010 BTC Exposure thật hiện tại
Residual 0,006 BTC Lượng chưa khớp
Action FREEZE + REVIEW Không gửi lại tự động

Hình 3 — Incident Card giữ fact, evidence và action trên cùng một hàng truy vết, không ghi API secret.

Trong 5 phút cuối, viết hai câu. Câu đoán: “Timeout nên lệnh thất bại.” Câu đúng điều kiện: “Timeout làm trạng thái UNKNOWN; query theo client ID cho thấy order OPEN và fill 0,004 BTC.” Kết quả mong đợi là bạn biết dừng ở evidence, không tự lấp khoảng trống bằng phỏng đoán.

7. Tổng kết

a. Năm ý chính

  • API error không luôn đồng nghĩa order thất bại.
  • UNKNOWN là trạng thái thật và phải dẫn tới reconciliation.
  • Exposure lấy từ fills, không lấy từ requested quantity.
  • Feed còn kết nối vẫn có thể stale; phải kiểm heartbeat, sequence và freshness.
  • Retry cần idempotency, backoff, jitter, rate budget và circuit breaker.

b. Câu hỏi tự kiểm tra

  • Vì sao timeout không được tự đổi thành FAILED?
  • Partial fill 0,004 trên request 0,010 để lại residual bao nhiêu?
  • WebSocket còn mở có đủ chứng minh feed đang live không?
  • Khi nào phải freeze và human review?

c. Gợi ý đáp án

Xem gợi ý câu 1

Request có thể đã tới matching engine dù phản hồi mất; phải query/reconcile. → xem mục 2.

Xem gợi ý câu 2

Residual là 0,006 BTC; exposure hiện tại dựa trên fill 0,004. → xem mục 3.

Xem gợi ý câu 3

Không. Cần freshness, heartbeat và sequence; kết nối sống vẫn có thể stale. → xem mục 4.

Xem gợi ý câu 4

Khi UNKNOWN quá SLA, không query được hoặc local state lệch sàn. → xem mục 5.

d. Thuật ngữ cần nhớ

Thuật ngữ Giải thích ngắn
Timeout Client ngừng chờ sau thời hạn, chưa khẳng định server thất bại.
Client order ID Định danh do client tạo để truy vết intent.
UNKNOWN Chưa đủ bằng chứng xác định trạng thái order.
Reconciliation Đối chiếu local state với order, fills và balance trên sàn.
Partial fill Order chỉ khớp một phần khối lượng.
Residual Khối lượng còn lại chưa khớp.
Stale feed Luồng dữ liệu còn kết nối nhưng bản tin đã cũ.
Idempotency Lặp cùng request không tạo thêm side effect.
Circuit breaker Tạm dừng request khi lỗi vượt ngưỡng.

e. Nguồn tham khảo

Bài trước: Black-box AI và khả năng giải thích #27
Bài tiếp theo: Human-in-the-loop và Kill Switch #29

Chọn đúng bài trong lộ trình

Bài này tập trung vào rủi ro API và thực thi lệnh — timeout, retry, trạng thái lệnh và reconciliation. Nếu bạn cần bức tranh chung trước khi đi sâu, hãy bắt đầu từ AI Trading là gì? Hướng dẫn từ nền tảng đến kiểm định. Các bước liên quan trực tiếp là Kiến trúc dữ liệu thời gian thực cho AI Trading, Risk Management trong AI TradingHuman-in-the-loop và Kill Switch.

Nội dung này phục vụ mục đích giáo dục, không phải lời khuyên đầu tư hoặc tín hiệu giao dịch. Mọi thị trường đều có rủi ro mất vốn.