QuestDB cho Giao dịch Thuật toán: Kiến trúc Nói ngôn ngữ của Thị trường
Phần 1 trong 3 — cũng có sẵn bằng RU · ZH
Tuyên bố miễn trừ trách nhiệm: Thông tin cung cấp trong bài viết này chỉ nhằm mục đích giáo dục và thông tin, không cấu thành tư vấn tài chính, đầu tư hay giao dịch. Giao dịch tiền điện tử tiềm ẩn rủi ro thua lỗ đáng kể.
Xin chào! Hôm nay chúng ta bắt đầu loạt ba bài phân tích chuyên sâu về QuestDB — một cơ sở dữ liệu chuỗi thời gian mã nguồn mở đang âm thầm trở thành xương sống của hạ tầng giao dịch hiện đại. Đây không phải bài "top 10 cơ sở dữ liệu" thông thường. Chúng ta sẽ đi sâu vào kỹ thuật, vì đó chính là điều mà giao dịch thuật toán đòi hỏi.
Nếu bạn đã từng vật lộn với giới hạn cardinality của InfluxDB, chiến đấu với overhead của TimescaleDB trên dữ liệu tick, hay thắc mắc tại sao PostgreSQL của mình không thể theo kịp một triệu lần chèn mỗi giây — loạt bài này dành cho bạn.
Tại sao Cơ sở dữ liệu Chuỗi thời gian quan trọng với Giao dịch
Mọi hệ thống giao dịch thuật toán — từ một bot grid đơn giản đến một engine HFT hoàn chỉnh — đều có cùng một phụ thuộc cơ bản: dữ liệu. Cụ thể là dữ liệu được sắp xếp theo thời gian, đến với tốc độ khổng lồ và cần được truy vấn theo thời gian thực.
Các cơ sở dữ liệu quan hệ truyền thống không được thiết kế cho điều này. Chúng xuất sắc trong các giao dịch ACID và các phép join phức tạp trên schema đã chuẩn hóa, nhưng lại bị nghẹt với các khối lượng công việc nặng về ghi, phân vùng theo thời gian — những đặc trưng định nghĩa thị trường tài chính. Bạn sẽ phải chống lại cơ sở dữ liệu thay vì để nó làm việc cho bạn.
Cơ sở dữ liệu chuỗi thời gian lật ngược mô hình này. Chúng giả định dữ liệu của bạn có timestamp, rằng nó đến theo thứ tự tương đối, và các truy vấn của bạn hầu như luôn liên quan đến phạm vi thời gian. QuestDB đi xa hơn khi được thiết kế đặc biệt hướng đến thị trường vốn — đội ngũ kỹ thuật đến từ các ngân hàng đầu tư Tier 1 (BoA, UBS, HSBC), và điều đó thể hiện rõ trong mọi quyết định thiết kế.
Tổng quan về QuestDB
QuestDB là cơ sở dữ liệu chuỗi thời gian mã nguồn mở (Apache 2.0) được viết bằng Java không có GC (zero-GC), C++, và Rust. Phần "zero-GC" rất quan trọng: engine lõi hoàn toàn tránh garbage collector của Java, quản lý bộ nhớ thủ công để loại bỏ các đột biến độ trễ không thể đoán trước vốn là bệnh dịch của hầu hết các hệ thống dựa trên JVM.
Các đặc điểm hiệu suất chính đáng chú ý:
- Thông lượng nhập liệu hàng triệu hàng mỗi giây trên một máy chủ đơn
- Độ trễ truy vấn dưới mili giây thông qua thực thi vector hóa với lệnh SIMD
- Timestamp độ chính xác nano giây gốc — thiết yếu cho dữ liệu tick
- Kiến trúc lưu trữ ba tầng được tối ưu cho cả dữ liệu nóng và lạnh
- Giao diện SQL với các phần mở rộng chuỗi thời gian mạnh mẽ
Nhưng các con số thô chỉ kể một phần câu chuyện. Điều làm QuestDB thực sự thú vị với các hệ thống giao dịch là cách nó lưu trữ và truy vấn dữ liệu.
Engine Lưu trữ Ba Tầng
Đây là nơi kiến trúc của QuestDB trở nên tinh tế. Dữ liệu chảy qua ba tầng riêng biệt, mỗi tầng được tối ưu cho một mẫu truy cập khác nhau:
Tầng 1: WAL (Write-Ahead Log)

Dữ liệu đến đầu tiên chạm vào Write-Ahead Log. Đây là tầng ghi thêm (append) với độ trễ cực thấp. Mỗi lần ghi được đảm bảo bền vững trước khi bất kỳ xử lý nào xảy ra — sống sót qua sự cố và mất điện mà không mất dữ liệu. WAL chỉ ghi tuần tự, nghĩa là nó hoạt động hoàn hảo với SSD và ổ NVMe hiện đại.
Đối với các hệ thống giao dịch, điều này có nghĩa là pipeline nhập dữ liệu thị trường của bạn có thể bơm dữ liệu vào QuestDB mà không lo về write amplification hay tranh chấp khóa. Dù bạn đang nhận cập nhật WebSocket từ 50 sàn crypto hay xử lý luồng tin nhắn FIX dồn dập, WAL đều hấp thụ tất cả.
WAL cũng được gửi không đồng bộ đến object storage, cho phép các bản sao mới bootstrap nhanh chóng và đọc cùng lịch sử — một thuộc tính quan trọng cho khôi phục thảm họa trong môi trường giao dịch sản xuất.
Tầng 2: Lưu trữ dạng Cột
Không đồng bộ, dữ liệu được sắp xếp theo thời gian, loại trùng lặp, và ghi vào định dạng cột gốc của QuestDB. Định dạng này được phân vùng theo thời gian (theo giờ, ngày, tuần hoặc tháng tùy thuộc vào khối lượng dữ liệu) và có thể truy vấn ngay lập tức.
Bố cục dạng cột chính là thứ cho phép hiệu suất truy vấn của QuestDB. Khi bạn yêu cầu giá trung bình của BTC-USD trong giờ qua, engine chỉ đọc cột price từ các phân vùng thời gian liên quan — không phải toàn bộ hàng. Kết hợp với thực thi SIMD-vector hóa trên nhiều lõi, điều này mang lại thời gian truy vấn dưới mili giây làm cho dashboard thời gian thực và tính toán chiến lược trực tiếp trở nên khả thi.
Mỗi bảng được lưu trữ dưới dạng các file riêng biệt theo cột, với các kiểu kích thước cố định có một file mỗi cột và các kiểu kích thước thay đổi (như VARCHAR) dùng hai file. Bố cục này được thiết kế đặc biệt cho các loại quét tuần tự chiếm ưu thế trong phân tích chuỗi thời gian.
Tầng 3: Object Storage (Parquet)
Đây là nơi quản lý chi phí gặp khả năng tương tác. Các phân vùng cũ hơn được tự động chuyển đổi sang định dạng Apache Parquet và gửi đến object storage (S3, Azure Blob, GCS). Nhưng — và đây là đổi mới chính — bạn vẫn có thể truy vấn chúng một cách minh bạch thông qua giao diện SQL của QuestDB. Trình lập kế hoạch truy vấn bao phủ cả ba tầng một cách liền mạch.
Đối với các nhà giao dịch thuật toán, điều này có nghĩa là bạn có thể giữ nhiều năm dữ liệu tick lịch sử có thể truy cập để backtesting mà không phải trả tiền cho terabyte lưu trữ SSD. Framework backtesting Python của bạn có thể đọc trực tiếp các file Parquet tương tự thông qua Polars, Pandas, hoặc Spark — không cần xuất cơ sở dữ liệu. Pipeline huấn luyện ML của bạn có thể truy cập cùng dữ liệu thông qua Arrow/ADBC để xử lý trong bộ nhớ. Không bị khóa vào nhà cung cấp.
Đây là một đề xuất hoàn toàn khác so với các định dạng cơ sở dữ liệu độc quyền khóa dữ liệu của bạn đằng sau một giao diện truy vấn duy nhất.
Thiết kế Schema cho Dữ liệu Giao dịch
Triết lý thiết kế schema của QuestDB xoay quanh một vài khái niệm quan trọng hoàn toàn phù hợp với dữ liệu giao dịch:
Designated Timestamp
Mỗi bảng chuỗi thời gian cần một cột timestamp được chỉ định. Đây không chỉ là metadata — nó xác định thứ tự lưu trữ vật lý và cho phép cắt tỉa phân vùng. Không có nó, bạn mất hầu hết lợi ích hiệu suất của QuestDB:
CREATE TABLE trades (
timestamp TIMESTAMP,
symbol SYMBOL,
side SYMBOL,
price DOUBLE,
quantity DOUBLE
) TIMESTAMP(timestamp) PARTITION BY DAY;
Kiểu SYMBOL

Kiểu SYMBOL là câu trả lời của QuestDB cho vấn đề chuỗi có cardinality cao. Các cặp giao dịch như "BTC-USD" hoặc "ETH-USDT" được lưu trữ dưới dạng mục từ điển được đánh chỉ số nguyên. Lọc và nhóm trên các cột SYMBOL nhanh hơn đáng kể so với VARCHAR — QuestDB giải quyết các phép so sánh chuỗi thành phép so sánh số nguyên tại thời gian biên dịch.
Nếu bạn đang nhập dữ liệu từ hơn 100 sàn với hàng ngàn cặp giao dịch, tối ưu hóa này một mình có thể là sự khác biệt giữa một truy vấn mất 5ms và 500ms.
Chiến lược Phân vùng
Kích thước phân vùng nên khớp với khối lượng dữ liệu của bạn. Dữ liệu tick tần số cao (hàng triệu hàng mỗi ngày mỗi symbol) nên dùng PARTITION BY HOUR. Dữ liệu end-of-day khối lượng thấp hơn hoạt động tốt với PARTITION BY MONTH. Mục tiêu là giữ các phân vùng riêng lẻ có thể quản lý trong khi cho phép cắt tỉa hiệu quả:
-- Dữ liệu tick khối lượng cao
CREATE TABLE ticks (...) TIMESTAMP(ts) PARTITION BY HOUR;
-- Giá hàng ngày khối lượng thấp hơn
CREATE TABLE eod_prices (...) TIMESTAMP(ts) PARTITION BY MONTH;
Loại bỏ Trùng lặp Dữ liệu
Trong các hệ thống giao dịch thực tế, dữ liệu trùng lặp là không thể tránh khỏi. Truyền lại qua mạng, kết nối sàn dự phòng để đảm bảo độ tin cậy, phát lại dữ liệu lịch sử trong quá trình phục hồi — tất cả đều tạo ra bản sao. QuestDB xử lý điều này một cách tự nhiên: khi được bật, loại trùng lặp thay thế các hàng khớp bằng phiên bản mới, và chỉ các hàng thực sự mới được chèn vào.
Tác động hiệu suất phụ thuộc vào mẫu dữ liệu của bạn. Nếu timestamp hầu hết là duy nhất giữa các hàng, overhead là tối thiểu. Trường hợp đòi hỏi nhất là khi nhiều hàng chia sẻ cùng timestamp và cần loại trùng lặp trên các cột bổ sung — phổ biến trong các snapshot order book nơi nhiều mức giá cập nhật đồng thời.
Các Cân nhắc Triển khai Sản xuất
Các khách hàng sản xuất của QuestDB bao gồm B3 (sàn chứng khoán lớn nhất Mỹ Latinh), One Trading (sàn crypto được quy định nhập tới 4 triệu hàng mỗi giây), Laser Digital (Nomura Group), và nhiều ngân hàng Tier 1 và quỹ hedge.
Một số ghi chú triển khai thực tế:
- QuestDB hỗ trợ giao thức wire PostgreSQL, vì vậy hầu hết thư viện client PG hoạt động ngay từ đầu
- Để nhập thông lượng cao, InfluxDB Line Protocol (ILP) qua HTTP hoặc TCP là con đường được khuyến nghị
- Protocol Version 2 (từ QuestDB 9.0+) thêm mã hóa nhị phân cho mảng và double, giảm đáng kể băng thông và overhead xử lý phía máy chủ
- Tạo schema tự động và thay đổi schema đồng thời cho phép bạn xử lý nhiều luồng dữ liệu với các sửa đổi nhanh chóng
Phiên bản Enterprise thêm RBAC (bao gồm quyền cấp cột), mã hóa TLS, sao chép và chuyển đổi dự phòng tự động, lưu trữ phân tầng đến cloud object store, và hỗ trợ chuyên dụng với SLA. Đối với môi trường được quy định, đây là những điều kiện cơ bản.
Những gì Sắp đến trong Phần 2 và 3
Trong Phần 2, chúng ta sẽ đi sâu vào các phần mở rộng SQL chuỗi thời gian của QuestDB — SAMPLE BY, ASOF JOIN, HORIZON JOIN, WINDOW JOIN, và LATEST ON — với các ví dụ giao dịch thực tế. Đây không phải là những cải tiến tăng dần so với SQL tiêu chuẩn; chúng là những công cụ hoàn toàn khác loại bỏ toàn bộ các loại truy vấn phức tạp.
Trong Phần 3, chúng ta sẽ đề cập đến các ứng dụng giao dịch thực tế: materialized view cho OHLC thời gian thực, mảng 2D cho phân tích order book, và kiến trúc đầy đủ của một nền tảng giao dịch thuật toán được vận hành bởi QuestDB.
Hãy theo dõi.
Trích dẫn
@software{soloviov2025questdb_algotrading_p1,
author = {Soloviov, Eugen},
title = {QuestDB for Algorithmic Trading: Architecture That Speaks the Language of Markets},
year = {2025},
url = {https://marketmaker.cc/vi/blog/post/questdb-algotrading-architecture},
version = {0.1.0},
description = {Phân tích chuyên sâu về kiến trúc lưu trữ ba tầng của QuestDB và thiết kế schema cho hệ thống giao dịch thuật toán.}
}
Tác Giả
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.