Tài Liệu API Giao Dịch
Tài liệu hướng dẫn tích hợp StockLab Trading API v1 cho bot và script.
Mẹo: Nhấn nút Copy Markdown cho AI ở trên để sao chép toàn bộ nội dung tài liệu này dưới định dạng Markdown, sau đó dán vào ChatGPT hoặc Claude để AI hỗ trợ bạn viết code tích hợp tự động!
Hỗ trợ kỹ thuật: Nếu bạn cần hỗ trợ tích hợp API, đăng ký giới hạn tần suất cao hơn, hoặc báo cáo lỗi, vui lòng liên hệ qua email: [email protected]
Trading API v1
Tài liệu hướng dẫn tích hợp StockLab Trading API v1 dành cho bot, thuật toán và ứng dụng bên thứ 3. Toàn bộ API đều yêu cầu xác thực bằng API Key và trả về định dạng JSON.
Tổng quan
Base URL: https://stocklab.io.vn/api/v1
Định dạng: JSON
Giao dịch: Mô phỏng (Paper Trading) — không ảnh hưởng tài sản thật
API cho phép bạn thao tác lấy thông tin tài khoản, tra cứu dữ liệu thị trường, và thực hiện đặt/hủy lệnh tự động bằng code.
Xác thực (Authentication)
Tất cả các endpoint đều yêu cầu gửi kèm API Key thông qua HTTP Header Authorization.
Format Header
Authorization: Bearer sl_live_...
- Token có tiền tố
sl_live_tiếp theo là chuỗi mã hóa an toàn (64 ký tự hex). - Hệ thống chỉ cung cấp mã này 1 lần duy nhất lúc bạn tạo Key trên giao diện Quản lý API Key.
- Bạn có thể tùy chọn phạm vi truy cập (Scope) cho từng API Key:
read: Chỉ được xem tài khoản, vị thế, lịch sử và dữ liệu.trade: Cho phép đặt lệnh, hủy lệnh (bao gồm cả quyềnread).
Giới hạn
- Mỗi tài khoản tối đa 5 API key hoạt động cùng lúc.
- Key bị thu hồi sẽ bị từ chối ngay lập tức (không khôi phục được).
Thông tin tài khoản
GET /v1/account
Xem thông tin tổng quan tài khoản (NAV, tiền mặt, lãi/lỗ).
Scope yêu cầu: read
Response:
{
"cash": 85000000,
"totalValue": 142500000,
"nav": 142500000,
"initialBalance": 150000000,
"realizedPnl": 3200000,
"unrealizedPnl": 4300000,
"totalPnl": 7500000,
"totalPnlPct": 5.26
}
| Trường | Kiểu | Mô tả |
|---|---|---|
cash | number | Tiền mặt hiện có (VNĐ) |
totalValue | number | Tổng giá trị tài sản (tiền + cổ phiếu) |
nav | number | Net Asset Value = totalValue |
initialBalance | number | Số dư ban đầu |
realizedPnl | number | Lãi/lỗ đã hiện thực hóa |
unrealizedPnl | number | Lãi/lỗ chưa hiện thực hóa |
totalPnl | number | Tổng lãi/lỗ |
totalPnlPct | number | % lãi/lỗ so với vốn ban đầu |
GET /v1/account/balance
Kiểm tra sức mua và tiền mặt khả dụng (đã trừ tiền treo ở các lệnh chưa khớp).
Scope yêu cầu: read
Response:
{
"cash": 85000000,
"buyingPower": 81800000,
"pendingBuyAmount": 3200000,
"availableCash": 81800000
}
| Trường | Kiểu | Mô tả |
|---|---|---|
cash | number | Tổng tiền mặt |
buyingPower | number | Sức mua khả dụng (= cash - pendingBuyAmount) |
pendingBuyAmount | number | Tiền đang khoá bởi lệnh mua chờ khớp |
availableCash | number | Tiền mặt khả dụng |
GET /v1/account/positions
Danh sách vị thế chứng khoán đang nắm giữ.
Query (Tùy chọn): ?symbol=VCB
Scope yêu cầu: read
Response:
{
"data": [
{
"symbol": "VCB",
"quantity": 1000,
"availableQty": 1000,
"pendingSellQty": 0,
"avgCost": 85.2,
"currentPrice": 89.5,
"value": 89500000,
"unrealizedPnl": 4300000,
"unrealizedPnlPct": 5.05,
"tSellable": true,
"tSellableDate": "2026-05-15T13:00:00+07:00",
"buyDate": "2026-05-13"
}
],
"total": 1
}
| Trường | Kiểu | Mô tả |
|---|---|---|
availableQty | number | Số lượng khả dụng (đã trừ T+ và lệnh bán chờ) |
pendingSellQty | number | Số lượng đang bị khoá bởi lệnh bán chờ |
tSellable | boolean | Có thể bán ngay không (đã qua T+) |
tSellableDate | string | Thời điểm sớm nhất có thể bán (RFC3339) |
buyDate | string | Ngày mua lot cũ nhất |
GET /v1/account/positions/{symbol}
Tra cứu chi tiết một vị thế theo mã chứng khoán (ví dụ: /v1/account/positions/VCB).
Scope yêu cầu: read
Giao dịch thị trường (Market Trade)
POST /v1/trades
Đặt lệnh mua/bán. Lệnh sẽ được đưa vào sổ lệnh chờ và khớp khi giá thị trường chạm tới giá đặt (tương tự lệnh Limit trên sàn thật).
Scope yêu cầu: trade
Request:
{
"type": "buy",
"symbol": "VCB",
"quantity": 100,
"clientPrice": 89.5
}
| Tham số | Bắt buộc | Ý nghĩa |
|---|---|---|
type | ✅ | "buy" hoặc "sell" |
symbol | ✅ | Mã chứng khoán |
quantity | ✅ | Số lượng (phải là bội số của 100) |
clientPrice | ✅ | Giá đặt lệnh (nghìn VNĐ/cp) |
Response:
{
"success": true,
"orderId": "89501130-c42c-43e7-9e9d-1e25d500bf13",
"status": "pending",
"message": "✅ Đặt lệnh BUY 100 CP VCB @ 89.50 nghìn đ thành công. Chờ khớp lệnh.",
"order": {
"side": "buy",
"symbol": "VCB",
"price": 89.5,
"quantity": 100,
"grossValue": 8950000,
"fee": 13425
}
}
Lưu ý: Lệnh sẽ bị từ chối nếu ngoài giờ giao dịch. Khi bán, hệ thống tự động enforce quy tắc T+ (thời gian thanh toán). Tiền/cổ phiếu sẽ bị khoá tạm thời cho đến khi lệnh được khớp hoặc hủy.
GET /v1/trades
Xem lịch sử giao dịch đã khớp. Hỗ trợ lọc và phân trang.
Query: ?symbol=VCB&type=sell&from=2026-01-01&to=2026-05-15&limit=50&offset=0
Scope yêu cầu: read
| Tham số | Mô tả |
|---|---|
symbol | Lọc theo mã CK |
type | "buy" hoặc "sell" |
from | Ngày bắt đầu (YYYY-MM-DD) |
to | Ngày kết thúc (YYYY-MM-DD) |
limit | Số kết quả tối đa (default: 50, max: 200) |
offset | Bỏ qua N kết quả đầu tiên |
Response:
{
"data": [
{
"id": "664f2a1b3c4d5e6f7a8b9c0d",
"type": "sell",
"symbol": "VCB",
"quantity": 500,
"price": 91.2,
"totalAmount": 45600000,
"fee": 427500,
"tax": 45600,
"netCash": 45126900,
"realizedPnl": 1250000,
"executedAt": "2026-05-14T14:22:00+07:00"
}
],
"total": 47,
"limit": 50,
"offset": 0
}
GET /v1/trades/{id}
Xem chi tiết một giao dịch cụ thể theo ID.
Scope yêu cầu: read
Lệnh chờ (Conditional Orders)
POST /v1/orders
Đặt các lệnh có điều kiện (Limit, Stop, OCO, Trailing).
Scope yêu cầu: trade
Request:
{
"side": "buy",
"symbol": "HPG",
"orderType": "limit",
"quantity": 500,
"price": 24.5,
"expiredAt": "2026-05-20"
}
| Tham số | Bắt buộc | Ý nghĩa |
|---|---|---|
side | ✅ | "buy" hoặc "sell" |
symbol | ✅ | Mã CK (VD: "HPG") |
orderType | ✅ | "limit", "stop", "oco", "trailing" |
quantity | ✅ | Số lượng (bội số 100) |
price | ✅ | Giá đặt lệnh (nghìn VNĐ) |
triggerPrice | ⚠️ | Giá kích hoạt (dùng cho stop/oco) |
triggerDirection | ⚠️ | Hướng kích hoạt: ">=" hoặc "<=" |
takeProfitPrice | ⚠️ | Giá chốt lời (dùng cho OCO) |
expiredAt | ✅ | Ngày hết hạn định dạng YYYY-MM-DD |
Response:
{
"success": true,
"orderId": "89501130-c42c-43e7-9e9d-1e25d500bf13",
"status": "pending",
"message": "✅ Đặt lệnh BUY 500 CP HPG @ 28.50 nghìn đ thành công.",
"order": {
"side": "buy",
"symbol": "HPG",
"price": 28.5,
"quantity": 500,
"grossValue": 14250000,
"fee": 21375
}
}
GET /v1/orders
Lấy danh sách lệnh chờ. Hỗ trợ lọc theo trạng thái.
Query: ?status=pending&symbol=HPG&limit=20&offset=0
Scope yêu cầu: read
Trạng thái (status) | Ý nghĩa |
|---|---|
pending | Đang chờ kích hoạt (mặc định) |
filled | Đã khớp |
cancelled | Đã huỷ |
expired | Hết hạn |
Response:
{
"data": [
{
"id": "664f3b2c4d5e6f7a8b9c1e2f",
"symbol": "HPG",
"side": "buy",
"orderType": "limit",
"quantity": 500,
"filledQty": 0,
"price": 24.5,
"triggerPrice": 0,
"status": "pending",
"fee": 21375,
"createdAt": "2026-05-15T09:15:00+07:00",
"expiredAt": "2026-05-20T00:00:00+07:00"
}
],
"total": 3,
"limit": 20,
"offset": 0
}
GET /v1/orders/{id}
Xem chi tiết một lệnh chờ theo ID.
Scope yêu cầu: read
DELETE /v1/orders/{id}
Hủy một lệnh chưa khớp.
Scope yêu cầu: trade
Response:
{
"success": true,
"message": "Lệnh đã được huỷ"
}
Dữ liệu thị trường (Market Data)
GET /v1/market/quote/{symbol}
Lấy giá theo thời gian thực (giá tham chiếu, trần, sàn, giá khớp gần nhất).
Scope yêu cầu: read
{
"symbol": "VCB",
"ref": 87.5,
"ceil": 93.6,
"floor": 81.4,
"match": 89.5,
"change": 2.0,
"changePct": 2.29,
"vol": 1523400,
"updatedAt": "2026-05-15T10:29:55+07:00"
}
| Trường | Kiểu | Mô tả |
|---|---|---|
ref | number | Giá tham chiếu |
ceil | number | Giá trần |
floor | number | Giá sàn |
match | number | Giá khớp gần nhất |
change | number | Chênh lệch so với tham chiếu |
changePct | number | % thay đổi |
vol | number | Khối lượng giao dịch |
GET /v1/market/ohlc
Lấy dữ liệu nến OHLC phục vụ phân tích kỹ thuật.
Query: ?symbol=VCB&range=1m
Scope yêu cầu: read
| Tham số | Giá trị | Mô tả |
|---|---|---|
symbol | Mã CK | Bắt buộc |
range | 1d, 5d, 1m, 3m, 6m, 1y | Khoảng thời gian |
Response:
{
"symbol": "VCB",
"range": "1m",
"data": [
{
"date": "2026-04-15",
"open": 86.2,
"high": 88.0,
"low": 85.5,
"close": 87.5,
"vol": 1200000
}
]
}
Xử lý lỗi
Khi có lỗi, API trả về HTTP Status Code tương ứng cùng JSON body có trường error và code (khi có).
{
"error": "Không đủ cổ phiếu khả dụng (T+ chưa đủ)",
"code": "INSUFFICIENT_AVAILABLE_QUANTITY"
}
| HTTP Status | Nguyên nhân | Error Code (nếu có) |
|---|---|---|
400 | Tham số đầu vào không hợp lệ | INVALID_PARAMS, INSUFFICIENT_FUNDS, INSUFFICIENT_AVAILABLE_QUANTITY |
401 | API Key bị sai, thiếu hoặc đã hết hạn | INVALID_API_KEY, EXPIRED_API_KEY |
403 | API Key không có Scope phù hợp | INSUFFICIENT_SCOPE |
404 | Không tìm thấy dữ liệu | — |
429 | Gửi quá nhiều request (Rate Limit) | RATE_LIMIT_EXCEEDED |
503 | Ngoài giờ giao dịch hoặc dữ liệu tạm thời không khả dụng | MARKET_CLOSED, SERVICE_UNAVAILABLE |
Giới hạn tần suất (Rate Limiting)
Hệ thống bảo vệ API bằng cơ chế giới hạn request trên từng API key.
| Loại API | Giới hạn | Endpoint áp dụng |
|---|---|---|
| Read | 300 req/phút | GET /v1/* |
| Trade | 30 req/phút | POST /v1/trades, POST/DELETE /v1/orders |
| Key Management | 10 req/phút | POST/DELETE /api/user/api-keys |
Headers theo dõi trong Response:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1715743260
Khi bị rate limit, API trả về HTTP 429 với body:
{
"error": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED"
}
Ví dụ tích hợp
Python
import requests
API_KEY = "sl_live_YOUR_API_KEY_HERE"
BASE_URL = "https://stocklab.io.vn/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Xem NAV
res = requests.get(f"{BASE_URL}/account", headers=HEADERS)
account = res.json()
print(f"NAV: {account['nav']:,.0f} VNĐ")
print(f"Lãi/lỗ: {account['totalPnlPct']:.2f}%")
# Xem vị thế
positions = requests.get(f"{BASE_URL}/account/positions", headers=HEADERS)
for pos in positions.json()["data"]:
print(f" {pos['symbol']}: {pos['quantity']} cp @ {pos['avgCost']}k")
print(f" P/L: {pos['unrealizedPnl']:,.0f} VNĐ ({pos['unrealizedPnlPct']:.2f}%)")
# Kiểm tra giá trước khi mua
quote = requests.get(f"{BASE_URL}/market/quote/VCB", headers=HEADERS)
price = quote.json()["match"]
print(f"VCB giá hiện tại: {price}k")
# Đặt lệnh Mua (Market Trade)
trade = requests.post(f"{BASE_URL}/trades", headers=HEADERS, json={
"type": "buy",
"symbol": "VCB",
"quantity": 100,
"clientPrice": price
})
result = trade.json()
if result.get("success"):
print(f"✅ Mua thành công {result['quantity']} cp {result['symbol']} @ {result['price']}k")
else:
print(f"❌ Lỗi: {result.get('error')}")
JavaScript (Node.js)
const API_KEY = process.env.STOCKLAB_API_KEY;
const BASE_URL = "https://stocklab.io.vn/api/v1";
const headers = {
Authorization: \`Bearer \${API_KEY}\`,
"Content-Type": "application/json",
};
// Xem tài khoản
const account = await fetch(\`\${BASE_URL}/account\`, { headers }).then((r) => r.json());
console.log(\`NAV: \${account.nav.toLocaleString()} VNĐ\`);
// Đặt lệnh limit mua
const order = await fetch(\`\${BASE_URL}/orders\`, {
method: "POST",
headers,
body: JSON.stringify({
side: "buy",
symbol: "HPG",
orderType: "limit",
quantity: 500,
price: 24.5,
expiredAt: "2026-05-20",
}),
}).then((r) => r.json());
if (order.success) {
console.log(\`✅ Đặt lệnh thành công: \${order.orderId}\`);
} else {
console.log(\`❌ Lỗi: \${order.error}\`);
}
cURL
# Xem tài khoản
curl https://stocklab.io.vn/api/v1/account \
-H "Authorization: Bearer sl_live_..."
# Đặt lệnh mua
curl -X POST https://stocklab.io.vn/api/v1/trades \
-H "Authorization: Bearer sl_live_..." \
-H "Content-Type: application/json" \
-d '{"type":"buy","symbol":"VCB","quantity":100,"clientPrice":87.0}'
# Xem lịch sử giao dịch
curl "https://stocklab.io.vn/api/v1/trades?symbol=VCB&limit=10" \
-H "Authorization: Bearer sl_live_..."
# Xem giá thị trường
curl https://stocklab.io.vn/api/v1/market/quote/VCB \
-H "Authorization: Bearer sl_live_..."
# Huỷ lệnh chờ
curl -X DELETE https://stocklab.io.vn/api/v1/orders/664f3b2c4d5e6f7a8b9c1e2f \
-H "Authorization: Bearer sl_live_..."