Nguyên lý nền tảng
Sổ lệnh (order book) đang lưu điều gì?
Trước khi nói về tick hay gói tin, cần hiểu trạng thái mà hệ thống đang cố dựng lại.
Một lệnh giới hạn (limit order) cho biết có người muốn mua hoặc bán một khối lượng tại mức giá giới hạn. Các lệnh mua đang chờ tạo thành phía bid (mua); các lệnh bán đang chờ tạo thành phía ask (bán). Mức mua cao nhất là best bid (giá mua tốt nhất), mức bán thấp nhất là best ask (giá bán tốt nhất).
BID · người đang muốn mua
ASK · người đang muốn bán
Sổ lệnh là trạng thái hiện tại của các lệnh còn hiệu lực; dòng lịch sử giao dịch là những giao dịch đã xảy ra. Hai phần này có liên quan nhưng không giống nhau.
Bài kiểm tra xác nhậnLệnh còn hiệu lực khác giao dịch đã xảy ra như thế nào?Xem đáp án ↓Đóng ↑
Lệnh còn hiệu lực là ý định mua hoặc bán vẫn nằm trong sổ lệnh với một khối lượng còn lại. Giao dịch là lần khớp lệnh đã xảy ra trong quá khứ. Một lần khớp có thể làm giảm khối lượng của lệnh, nhưng bản ghi giao dịch không phải chính lệnh đó.
Mô hình tư duy
Tick không đồng nghĩa với giao dịch
Trong hệ thống dữ liệu thị trường, “tick” nên được hiểu rộng là một sự kiện mới từ luồng dữ liệu.
Sự kiện có thể là thêm, hủy hoặc khớp lệnh; bản ghi giao dịch; trạng thái phiên; tín hiệu duy trì kết nối (heartbeat) hoặc dữ liệu khôi phục. Vì mỗi loại phục vụ một thành phần khác nhau, đừng thiết kế một hàm book.apply(any_tick) rồi hy vọng mọi thứ tự đúng.
| Sự kiện | Sổ lệnh | Giao dịch / thống kê | Phiên / khôi phục |
|---|---|---|---|
| Thêm lệnh | ✓ | — | — |
| Khớp lệnh | ✓ | có thể ✓ | — |
| Giao dịch không hiển thị | — | ✓ | — |
| Dừng / mở lại | — | — | ✓ |
| Tín hiệu duy trì kết nối | — | — | ✓ |
using MarketEvent = std::variant<
AddOrder,
ReduceOrder,
DeleteOrder,
TradePrint,
TradingStatus
>;
std::visit(EventRouter{book, tape, session}, event);Bài kiểm tra xác nhậnVì sao trường khối lượng không có một ý nghĩa chung cho mọi thông điệp?Xem đáp án ↓Đóng ↑
Tùy thông điệp và luồng dữ liệu, khối lượng có thể là tổng tuyệt đối tại một mức giá, phần bị giảm, phần đã khớp hoặc tổng khối lượng mới. Cần đọc đặc tả trước khi quyết định dùng phép gán hay phép cộng hoặc trừ.
Dữ liệu mạng → đối tượng giá trị
Từ byte thành sự kiện an toàn
Dữ liệu mạng không phải đối tượng C++. Bộ phân tích là ranh giới kiểm tra đầu tiên của hệ thống.
Luồng dữ liệu nhị phân quy định chính xác thứ tự byte, độ rộng trường, hệ số, phần đệm và độ dài thông điệp. Nasdaq ITCH chẳng hạn dùng thứ tự byte lớn trước (big-endian), số nguyên có độ rộng cố định, trường ASCII và giá biểu diễn bằng số nguyên có hệ số (fixed-point). Ánh xạ thẳng vùng đệm bằng reinterpret_cast có thể sai do căn chỉnh, phần đệm, thứ tự byte hoặc dữ liệu đầu vào bị cắt ngắn.
Bản ghi thêm lệnh (Add) mô phỏng · 17 byte
big-endian · độ rộng cố định · đã kiểm tra giới hạn
std::uint64_t read_be(std::span<const std::byte> bytes) {
if (bytes.empty() || bytes.size() > 8) {
throw ParseError{"invalid integer width"};
}
std::uint64_t value = 0;
for (std::byte byte : bytes) {
value = (value << 8)
| std::to_integer<unsigned char>(byte);
}
return value;
}Giá trị thô 1.234.500 với hệ số 4 nghĩa là 123,4500. Giữ số nguyên làm giá trị chuẩn để việc làm tròn và phát lại luôn cho cùng kết quả.
Bản ghi thiếu một byte phải trả lỗi phân tích và không chuyển một sự kiện chưa đầy đủ xuống bộ dựng sổ lệnh.
string_view/span trỏ vào vùng đệm nhận chỉ hợp lệ khi quyền sở hữu bảo đảm vùng đệm tồn tại đủ lâu.
Khóa thường cần sở giao dịch, ngày giao dịch, kênh hoặc phân vùng và công cụ tài chính; một ID dạng số không phải định danh duy nhất toàn hệ thống.
Danh sách kiểm tra bộ phân tích
- 01Độ dài gói tin và bản ghi đã đủ chưa?
- 02Loại thông điệp có được hỗ trợ không?
- 03Thứ tự byte và hệ số đã được giải mã đúng chưa?
- 04Kiểu liệt kê (enum), phía mua/bán và cờ có hợp lệ không?
- 05Ngữ cảnh công cụ tài chính và phiên có đúng phạm vi không?
- 06Số thứ tự và dấu thời gian đã được gắn chưa?
Bài kiểm tra xác nhậnDấu thời gian có thể thay số thứ tự để sắp xếp sự kiện không?Xem đáp án ↓Đóng ↑
Không. Số thứ tự thể hiện tính liên tục và thứ tự theo giao thức; dấu thời gian thể hiện ý nghĩa của một đồng hồ. Nhiều sự kiện có thể cùng dấu thời gian, đồng hồ có thể lệch và việc sắp theo thời gian có thể làm đổi thứ tự của giao thức.
Trạng thái dẫn xuất
MBO, MBP và vòng đời lệnh
Phần này biến luồng sự kiện đã sắp thứ tự thành trạng thái mà nhà nghiên cứu hoặc chiến lược có thể đọc.
MBO · theo từng lệnh (Market-by-Order)
Giữ từng lệnh
- ◆ID lệnh và khối lượng còn lại
- ◆Phía mua/bán, giá và công cụ tài chính
- ◆Độ ưu tiên tại từng mức giá
- ◆Có thể tổng hợp thành MBP
MBP · theo mức giá (Market-by-Price)
Giữ mức giá tổng hợp
- ◆Giá → tổng khối lượng / số lệnh
- ◆Không biết đầy đủ định danh lệnh
- ◆Không suy ngược đầy đủ thứ tự ưu tiên
- ◆Nhẹ hơn cho nhiều thành phần sử dụng
Chỉ mục ID lệnh
42 → bid, 100.00, qty 50 ─┐
77 → bid, 100.00, qty 20 ─┼─→ level 100.00 = 70
91 → ask, 100.01, qty 30 ─┘
Độ ưu tiên theo giá
100.00 bid: [42, 77]Vòng đời phải bám đúng quy tắc của sở giao dịch
Với Nasdaq ITCH, Executed With Price vẫn giảm khối lượng tại giá hiển thị ban đầu; giá khớp lệnh phục vụ lịch sử và thống kê giao dịch. Thông điệp thay thế không gửi lại toàn bộ phía mua/bán, mã và thuộc tính, nên phải kế thừa chúng từ lệnh cũ.
Những điều bất biến cần bảo vệ
Ảnh chụp trạng thái và cập nhật tăng dần
Luồng MBP thường cần ảnh chụp trạng thái để khởi tạo, rồi nối với các cập nhật trực tiếp tăng dần. Ảnh chụp không tự chứng minh nó còn mới; cần ID cập nhật hoặc dữ liệu điểm chuyển để tạo một chuỗi liên tục.
Bài kiểm tra xác nhậnCó MBP rồi có dựng lại chính xác từng lệnh và thứ tự ưu tiên không?Xem đáp án ↓Đóng ↑
Không. MBP chỉ giữ tổng tại từng mức giá. Nhiều tập lệnh khác nhau có thể tạo cùng một tổng, nên định danh và vị trí trong hàng đợi đã mất không thể được suy ngược duy nhất.
Tính đúng đắn khi mất gói tin
Khoảng trống số thứ tự và khôi phục
UDP có thể làm mất, lặp hoặc đảo thứ tự gói tin. Sổ lệnh chỉ đáng tin khi tính liên tục đã được chứng minh.
Luồng A/B là hai đường truyền của cùng một luồng dữ liệu logic. Mục tiêu là nhận gói tin nhanh nhất nhưng chỉ áp dụng đúng một lần, không phải áp dụng cả hai “cho chắc”.
Gói tin 102 từ B lấp khoảng trống; 100/101/103 chỉ được áp dụng một lần.
seq < expectedBị lặp / đến muộnKhông áp dụng lại; có thể đối chiếu dấu vân tay để phát hiện dữ liệu khác nhau.
seq == expectedLiên tụcÁp dụng toàn bộ như một giao dịch duy nhất, rồi cập nhật số thứ tự mong đợi theo giao thức.
seq > expectedCó khoảng trốngGiữ tạm trong vùng đệm có giới hạn, đánh dấu kênh là đáng ngờ và bắt đầu khôi phục.
Cách tăng số thứ tự cũng không giống nhau ở mọi nơi: MoldUDP64 đánh số thông điệp nên số tiếp theo = số đầu + số thông điệp; CME MDP đánh số gói tin nên số tiếp theo = số gói tin + 1. Đừng đặt tên quá chung rồi vô tình dùng sai đơn vị.
Khôi phục từ ảnh chụp trạng thái theo đúng thứ tự
- 1Dừng xem trạng thái hiện tại là mới và giữ cập nhật trực tiếp trong hàng đợi có giới hạn.
- 2Dựng ảnh chụp trong trạng thái tạm, không ghi đè sổ lệnh mà bên đọc đang dùng.
- 3Đọc dữ liệu điểm chuyển để biết ảnh chụp đã chứa trạng thái đến số thứ tự nào.
- 4Bỏ cập nhật tạm cũ, rồi áp dụng liên tục phần còn lại theo số thứ tự.
- 5Kiểm tra các điều bất biến rồi công bố thế hệ trạng thái mới bằng thao tác nguyên tử.
Bài kiểm tra xác nhậnVùng đệm chờ đầy trước khi gói tin thiếu quay lại thì làm gì?Xem đáp án ↓Đóng ↑
Không bỏ ngẫu nhiên một gói tin rồi tiếp tục. Chuyển trạng thái sang dựng lại đầy đủ từ ảnh chụp, giữ bằng chứng và chỉ công bố lại sau khi tính liên tục cùng các điều bất biến đã được chứng minh.
Lịch sử giao dịch và đặc trưng theo khoảng
Lịch sử giao dịch, OHLCV và hiệu chỉnh
Thay đổi sổ lệnh và thống kê giao dịch là hai máy trạng thái có liên quan nhưng cần tách riêng.
Cờ cho phép công bố giúp tránh đếm hai lần một số khối lượng đấu giá hoặc giao dịch chéo, nhưng không phải mọi giao dịch có thể công bố đều được đưa vào mọi bộ dữ liệu. Điều kiện sử dụng còn phụ thuộc loại giao dịch, phiên, đấu giá và chính sách với dữ liệu không đúng thứ tự.
Khoảng trước khi hiệu chỉnh
O = 100.00 · H = 100.02
L = 100.00 · C = 100.02
V = 5 + 3 = 8
VWAP = (100×5 + 100.02×3) / 8
VWAP = 100.0075
Sau khi hủy giao dịch 100.02 × 3
O = H = L = C = 100.00
V = 5
VWAP = 100.00
revision = revision + 1
reason = trade_break
Để hoàn tác một giao dịch, bộ tổng hợp cần định danh có đúng phạm vi và giữ phần đóng góp cũ. Giá trị giao dịch chuẩn nên dùng phép tính trên số nguyên có hệ số và kiểm tra tràn. Khoảng thời gian cần có quy ước rõ như [bắt đầu, kết thúc); sự kiện đúng 10:01:00 thuộc khoảng sau.
Đừng nén mọi đồng hồ thành một dấu thời gian
Bài kiểm tra xác nhậnViệc hủy giao dịch có nên hoàn tác sổ lệnh hiện tại không?Xem đáp án ↓Đóng ↑
Mặc định là không. Trong các luồng như Nasdaq ITCH, Broken Trade sửa lịch sử và thống kê giao dịch nhưng không thay đổi sổ lệnh đang hiển thị. Sổ lệnh đã tiến theo vòng đời lệnh riêng.
Từ học đến trả lời
Khung trả lời phỏng vấn
Tình huống giao dịch thường rộng. Một thứ tự trả lời ổn định giúp bạn không nhảy thẳng vào cấu trúc lưu trữ hoặc kỹ thuật không khóa quá sớm.
Dự án tổng kết đề xuất
Bộ xử lý luồng dữ liệu mô phỏng, cho kết quả xác định
bộ phân tích → bộ xếp thứ tự → bộ định tuyến sự kiện
→ trạng thái MBO → khung nhìn MBP
→ trạng thái giao dịch/khoảng → công bố bất biến- ✓ Bản ghi không hợp lệ không đổi mã băm trạng thái.
- ✓ Dữ liệu lặp không được áp dụng hai lần.
- ✓ Khoảng trống khiến kết quả bị đánh dấu là không còn đáng tin cậy.
- ✓ Khôi phục lấp khoảng trống trước khi công bố.
- ✓ Hủy giao dịch làm tăng phiên bản của khoảng.
- ✓ Phát lại luôn cho cùng một tổng kiểm.
Bước tiếp theo
Giờ bạn đã có nền tảng để đọc 10 câu mới.
Mở từng câu, thử trả lời trước rồi mới xem đáp án và tiêu chí chấm.
Nguồn tham khảo chính
Nguồn dùng để kiểm chứng bài
Bài viết diễn giải lại cho người mới; khi triển khai luồng dữ liệu thật, đặc tả của sở giao dịch và phiên bản đang dùng mới là nguồn đáng tin cậy nhất.