Bài viết gần đây
-
Huỳnh Thị Ngọc Loan — Giảng Viên Yoga & Spa | HNDL
Tháng 8 6, 2026
Trang chủ → Bài Viết → Khóa Xây dựng IB Bot Auto Trading HP2 Buổi 15/24: Web Dashboard FastAPI phục vụ 100+ tài khoản
| Khóa Xây dựng IB Bot Auto Trading HP2 Buổi 15/24: Web Dashboard FastAPI phục vụ 100+ tài khoản
Được viết bởi Đặng Trí Thanh vào ngày 07/08/2026 lúc 11:48 | 11 lượt xem
Khóa Xây dựng IB Bot Auto Trading HP2 — Buổi 15/24: Web Dashboard FastAPI cho 100+ khách hàng
DNT Digital – Hướng Nghiệp Dữ Liệu (HNDL) tiếp tục chuỗi HP2 (High Performance 2) — khóa Xây dựng IB bằng Bot Auto Trading, nơi học viên xây hệ sinh thái bot MT5, quản lý nhiều tài khoản khách Introducing Broker (IB) và vận hành trên VPS. Buổi 15/24 chuyển từ logic EA/grid sang tầng hiển thị và vận hành: Web Dashboard viết bằng FastAPI, nhận snapshot trạng thái MT5, lưu SQLite/PostgreSQL, xác thực người dùng và thiết kế để scale hơn 100 tài khoản mà không sập dịch vụ trong giờ cao điểm.
Bài viết mang tính đào tạo kỹ thuật, tham chiếu pattern thực chiến từ hệ PyNhiQuaiBot (bot Nhị Quái / multi-cluster trên VPS HNDL) — không phải lời hứa lợi nhuận, không phải tư vấn đầu tư. Mục tiêu: bạn đọc xong có thể vẽ sơ đồ triển khai, chọn DB, và lên checklist bảo mật trước khi mở dashboard ra internet.
Mục tiêu Buổi 15
Sau buổi học, học viên có thể:
- Mô tả luồng dữ liệu: MT5 Terminal → Agent Python → API FastAPI → DB → Frontend.
- Thiết kế schema snapshot (balance, equity, margin, positions, clusters).
- Tạo project FastAPI với route REST cơ bản và OpenAPI
/docs. - So sánh SQLite vs Postgres cho giai đoạn MVP và 100+ account.
- Triển khai auth (API key / JWT) phân quyền IB admin vs khách xem.
- Nêu chiến lược scale: worker, queue, cache, connection pool.
- Liệt kê checklist VPS, firewall, HTTPS reverse proxy (Nginx/Caddy).
Bối cảnh IB và vì sao cần dashboard
IB vận hành bot cho nhiều khách: mỗi khách một login MT5, thường trên VPS riêng hoặc multi-terminal có kiểm soát. EA chạy 24/5; khách và team support cần một màn hình thấy: tài khoản còn trade được không, margin level, lệnh đang mở, P/L ngày, trạng thái grid/cluster — mà không Remote Desktop vào từng máy. Dashboard tập trung giảm thời gian support, nhưng tăng trách nhiệm bảo mật và độ tin cậy dữ liệu.
PyNhiQuaiBot pattern (tham chiếu nội bộ khóa): mỗi cụm bot trên VPS định kỳ đẩy snapshot lên API trung tâm; dashboard chỉ đọc DB và cache — không gọi MT5 trực tiếp từ web public, tránh treo terminal khi 100 người F5 cùng lúc.
Kiến trúc tổng quan
┌─────────────────┐ HTTPS POST/PUT ┌──────────────────┐
│ VPS Khách #N │ ───────────────────────►│ FastAPI (API) │
│ MT5 + Python │ /api/v1/snapshot │ + Auth middleware│
│ snapshot agent │ └────────┬─────────┘
└─────────────────┘ │
▼
┌──────────────────┐
│ PostgreSQL / │
│ SQLite (dev) │
└────────┬─────────┘
│
┌─────────────────┐ HTTPS GET │
│ Browser / App │ ◄─────────────────────────────────┘
│ Dashboard UI │ /api/v1/accounts/{id}
└─────────────────┘
Tách agent và API là nguyên tắc số một: agent chạy cùng user MT5 trên VPS, có quyền gọi MetaTrader5 package; API public chỉ nhận JSON đã chuẩn hóa.
Snapshot MT5: nội dung và tần suất
Snapshot là ảnh chụp tại thời điểm captured_at (UTC ISO), không thay thế tick stream.
Account level: login, server, balance, equity, margin, margin_free, margin_level, trade_allowed, currency.
Positions: ticket, symbol, type, volume, price_open, sl, tp, profit, magic, comment.
Optional (PyNhiQuaiBot): cluster_id, layer_count, lockdown flag, EA version.
Tần suất gợi ý đào tạo:
| Quy mô | Push snapshot | Ghi chú |
|---|---|---|
| Demo lớp | 30–60 giây | Giảm tải VPS học viên |
| 10–30 khách | 15–30 giây | Đủ mượt cho support |
| 100+ khách | 10–15 giây + batch | Cần queue/worker |
Agent mẫu (rút gọn):
import MetaTrader5 as mt5
from datetime import datetime, timezone
def capture_account_snapshot(login: int) -> dict:
if not mt5.initialize():
raise RuntimeError(mt5.last_error())
acc = mt5.account_info()
if acc is None or acc.login != login:
raise RuntimeError("Sai login hoặc chưa đăng nhập")
positions = mt5.positions_get() or []
return {
"captured_at": datetime.now(timezone.utc).isoformat(),
"account": acc._asdict(),
"positions": [p._asdict() for p in positions],
"agent_version": "hp2-buoi15-1.0",
}
Trên production, bọc _asdict() bằng serializer loại bỏ field không cần và chuyển datetime sang string.
FastAPI: skeleton dự án
from fastapi import FastAPI, Depends, HTTPException, Header
from pydantic import BaseModel, Field
from typing import List, Optional
app = FastAPI(title="HNDL IB Dashboard API", version="0.15.0")
class PositionSnapshot(BaseModel):
ticket: int
symbol: str
volume: float
profit: float
magic: int
class AccountSnapshotIn(BaseModel):
captured_at: str
login: int
balance: float
equity: float
margin_level: Optional[float] = None
trade_allowed: bool = True
positions: List[PositionSnapshot] = Field(default_factory=list)
def verify_agent_key(x_agent_key: str = Header(...)):
# Buổi 15: so khớp env hoặc DB keys — rotate định kỳ
if x_agent_key != "DEV_REPLACE_ME":
raise HTTPException(status_code=401, detail="Invalid agent key")
return x_agent_key
@app.post("/api/v1/snapshot")
def ingest_snapshot(body: AccountSnapshotIn, _: str = Depends(verify_agent_key)):
# persist to DB — xem phần schema bên dưới
return {"status": "ok", "login": body.login}
@app.get("/api/v1/health")
def health():
return {"ok": True}
Chạy local: uvicorn main:app --reload --port 8080. Truy cập /docs để test — thói quen quan trọng trước khi gắn frontend React/Vue hoặc template Jinja đơn giản.
Schema database: SQLite vs PostgreSQL
SQLite phù hợp MVP, một file, backup copy nhanh, học viên chạy trên laptop. Giới hạn: concurrent write kém, không lý tưởng khi 100 agent push liên tục.
PostgreSQL khuyến nghị từ ~30–50 account trở lên hoặc khi cần replication, read replica cho dashboard.
Bảng gợi ý (rút gọn):
CREATE TABLE accounts (
login BIGINT PRIMARY KEY,
server TEXT NOT NULL,
ib_client_id TEXT NOT NULL,
label TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE snapshots (
id BIGSERIAL PRIMARY KEY,
login BIGINT REFERENCES accounts(login),
captured_at TIMESTAMPTZ NOT NULL,
balance NUMERIC(18,2),
equity NUMERIC(18,2),
margin_level NUMERIC(10,2),
trade_allowed BOOLEAN,
payload JSONB
);
CREATE INDEX idx_snapshots_login_time ON snapshots(login, captured_at DESC);
Lưu payload JSONB giữ positions đầy đủ; các cột số phục vụ query nhanh trên dashboard (equity curve, cảnh báo margin).
ORM: SQLAlchemy 2 hoặc SQLModel (FastAPI-friendly). Buổi 15 demo SQLModel nếu lớp đã quen Pydantic từ buổi Python.
Auth: agent, admin, khách xem
Ba lớp identity:
- Agent key (header
X-Agent-Key): mỗi VPS một key, revoke khi đổi VPS. - Admin JWT: IB owner — xem mọi login, quản lý key, cấu hình cảnh báo.
- Client JWT (optional): khách chỉ xem login của mình — claim
loginhoặcclient_id.
Không dùng một password chung cho 100 khách. bcrypt hash password admin; JWT expiry ngắn (15–60 phút) + refresh token nếu cần.
Rate limit (slowapi hoặc Nginx): chống brute force /token và flood GET.
Scale 100+ tài khoản: thực tế không magic
100 account không có nghĩa 100 request/giây nếu snapshot 15 giây/lần — ~6–7 ingest/giây trung bình, burst khi VPS đồng bộ cùng phút. FastAPI async giúp I/O; bottleneck thường là DB write.
Chiến lược:
- Batch insert snapshot theo chunk nếu agent gom nhiều login (ít dùng với 1 login/VPS).
- Connection pool SQLAlchemy
pool_size=10,max_overflow=20— tune theo RAM API server. - Redis cache bản snapshot mới nhất per login — dashboard đọc cache, DB cho lịch sử.
- Celery/RQ worker tách ingest khỏi request nếu payload nặng hoặc cần ghi S3 archive.
- Read replica Postgres khi dashboard > 50 concurrent user.
Horizontal scale API: nhiều instance Uvicorn sau load balancer sticky không bắt buộc nếu stateless JWT + shared DB/Redis.
VPS và triển khai production
| Thành phần | Gợi ý tối thiểu (100 acc) |
|---|---|
| VPS Agent (mỗi khách) | 1–2 GB RAM, MT5 + Python agent |
| VPS API + DB | 4–8 GB RAM, SSD, Postgres |
| Reverse proxy | Nginx/Caddy + Let’s Encrypt |
| Firewall | Chỉ 443 public; SSH key; fail2ban |
Agent không lộ port MT5 ra ngoài. Chỉ outbound HTTPS tới API.
Systemd unit cho agent và api — auto restart khi OOM. Log journalctl + rotate.
Backup Postgres hàng ngày; test restore ít nhất tháng một lần — mất snapshot lịch sử làm khách mất niềm tin nhanh hơn downtime ngắn.
Frontend dashboard (phạm vi Buổi 15)

Buổi 15 ưu tiên API contract; UI có thể:
- Phase 1: HTML + HTMX poll
/api/v1/accounts/{login}/latest. - Phase 2: React/Vue SPA chart equity 24h từ bảng snapshots.
Widget tối thiểu IB support: bảng login, equity, margin level màu cảnh báo, số lệnh, thời gian snapshot cuối (stale nếu > 2× chu kỳ push).
PyNhiQuaiBot pattern: bài học vận hành
PyNhiQuaiBot (multi-cluster grid trên MT5) dạy tách cluster logic trong EA và mirror trạng thái ra Python agent. Dashboard không điều khiển mở lệnh trực tiếp từ web trong buổi 15 — tránh latency và rủi ro bảo mật. Nút “pause” trên web (nếu có ở buổi sau) phải đi qua hàng đợi lệnh xác thực, không POST thẳng OrderSend từ browser.
Mapping field magic và cluster_id giúp support biết cụm nào lockdown — snapshot JSON nên giữ nguyên convention EA học viên đã học ở buổi Grid/OOP.
Bảo mật và compliance nội bộ
- Không log plaintext password MT5 trên API server.
- Mã hóa disk VPS; hạn chế copy file
configagent. - GDPR/quyền riêng tư: khách biết dữ liệu balance được thu thập — policy trên website IB.
- Pen test cơ bản: OWASP top 10, đặc biệt broken auth và injection (dùng ORM parameterized).
Bài tập thực hành Buổi 15
- Dựng FastAPI ingest một snapshot giả (JSON file) vào SQLite.
- Viết query lấy snapshot mới nhất mỗi login.
- Thêm middleware đo thời gian xử lý request — log p95.
- Triển khai JWT login admin, route bảo vệ GET
/api/v1/accounts. - Docker Compose: api + postgres + redis (optional).
- Viết tài liệu OpenAPI mô tả error 401/422 cho agent.
FAQ
FastAPI vs Flask/Django? FastAPI + Pydantic + OpenAPI nhanh cho API thuần; Django khi cần admin CMS sẵn.
Có cần WebSocket? Poll 5–10s đủ nhiều case; WebSocket khi cần push alert sub-second.
100 VPS vs 1 VPS multi MT5? Kiến trúc agent giống nhau; multi-terminal phức tạp hóa snapshot — HP2 thường 1 login/VPS cho ổn định.
Làm sao phát hiện agent chết? captured_at stale + alert Telegram/email (buổi sau).
SQLite có đủ 100 acc? Có thể demo; production HNDL khuyến nghị Postgres.
HTTPS bắt buộc? Có, khi API qua internet; agent key lộ nếu HTTP.
Snapshot có chứa history deals? Tùy thiết kế; deals nặng — sync riêng đêm.
Liên quan Buổi Python cơ bản? Dict/datetime Buổi 6 = format payload snapshot.
Cam kết uptime? Không — bài học kỹ thuật; SLA do IB tự đặt với khách.
Tóm tắt
Buổi 15/24 HP2 đặt nền dashboard FastAPI cho mô hình IB bot: agent MT5 push snapshot, API xác thực và ghi DB, UI đọc cache/query. Scale 100+ account cần Postgres, pool, cache và tách worker — không chỉ “thêm RAM”. Pattern PyNhiQuaiBot nhắc bạn mirror trạng thái EA, không điều khiển nguy hiểm từ web.
Đăng ký và lộ trình đầy đủ: Xây dựng IB bằng Bot Auto Trading.
Luồng ingest chi tiết và idempotency
Khi agent push snapshot, mạng có thể retry cùng payload. API nên chấp nhận idempotency key (header X-Idempotency-Key = hash login + captured_at) hoặc dedupe trong DB unique (login, captured_at) nếu độ phân giải giây đủ. Nếu hai snapshot cùng giây, agent nên dùng millisecond trong ISO hoặc sequence tăng dần trong payload. FastAPI route ingest:
@app.post("/api/v1/snapshot")
async def ingest(body: AccountSnapshotIn, session=Depends(get_db)):
existing = session.exec(
select(Snapshot).where(
Snapshot.login == body.login,
Snapshot.captured_at == body.captured_at,
)
).first()
if existing:
return {"status": "duplicate", "login": body.login}
row = Snapshot.from_pydantic(body)
session.add(row)
session.commit()
await cache.set(f"latest:{body.login}", body.model_dump_json(), ex=120)
return {"status": "ok", "login": body.login}
Pattern trên minh họa DB + cache — phần cốt lõi Buổi 15 khi bàn 100 agent.
Observability: log, metric, alert
Dashboard IB không chỉ “có web là xong”. HNDL khuyến nghị structured log JSON từ API (request_id, login, latency_ms). Metric Prometheus: ingest_total, ingest_errors, snapshot_lag_seconds (now − captured_at). Alert khi snapshot_lag_seconds > 120 cho login VIP — gửi Telegram bot nội bộ (Buổi 16+ thường gắn notification). Agent log riêng trên VPS khách, không gộp vào API server để tránh lộ thông tin chéo khách hàng.
Multi-tenant: phân tách dữ liệu IB
Một server API phục vụ một IB owner với 100 login là phổ biến. Nếu sau này SaaS nhiều IB, thêm cột tenant_id mọi bảng và filter mọi query — JWT claim tenant_id. Không mix snapshot hai IB chung DB không partition. Buổi 15 giới thiệu concept để học viên không thiết kế schema chết-end sớm.
Contract API version và migration
Prefix /api/v1/ giữ tương thích khi đổi field snapshot (thêm clusters[]). Deprecation: header Sunset hoặc document LMS — agent cũ có 30 ngày upgrade. Pydantic model AccountSnapshotInV2 song song v1 trong giai đoạn chuyển tiếp. PyNhiQuaiBot field lockdown thêm vào v2 không phá v1 nếu optional default.
Agent deployment: systemd và môi trường ảo
Trên VPS Windows (phổ biến MT5), Task Scheduler chạy agent Python 5 giây sau khi MT5 login script hoàn tất. Linux không chạy MT5 native — bài học HP2 giả định Windows VPS. Virtualenv agent/.venv, pin MetaTrader5, httpx, pydantic. File .env (không commit git):
API_BASE=https://dashboard.example.com
AGENT_KEY=...
MT5_LOGIN=12345678
PUSH_INTERVAL_SEC=15
Script loop:
import time, httpx
while True:
try:
snap = capture_account_snapshot(int(os.environ["MT5_LOGIN"]))
httpx.post(
f'{os.environ["API_BASE"]}/api/v1/snapshot',
json=normalize(snap),
headers={"X-Agent-Key": os.environ["AGENT_KEY"]},
timeout=10.0,
).raise_for_status()
except Exception as e:
log.exception("push failed")
time.sleep(int(os.environ.get("PUSH_INTERVAL_SEC", "15")))
Reverse proxy Nginx (snippet tham khảo)
server {
listen 443 ssl http2;
server_name dashboard.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
TLS terminate tại Nginx; Uvicorn bind localhost only. Rate limit zone cho /api/v1/token.
Chi phí hạ tầng minh bạch (ước lượng giáo dục)
100 VPS khách × ~5–10 USD/tháng + 1 VPS API/DB ~20–40 USD — chi phí vận hành độc lập với phí học khóa HNDL. Dashboard không tự thu phí khách; IB tính phí dịch vụ bot/support riêng. Bài viết không khuyến nghị mức giá — chỉ để học viên không underestimat OPEX khi nhận 100 tài khoản.
So sánh poll vs WebSocket cho dashboard
| Tiêu chí | HTTP poll | WebSocket |
|---|---|---|
| Độ phức tạp | Thấp | Trung bình |
| Tải server 100 user | Chấp nhận với cache | Giữ nhiều kết nối mở |
| Phù hợp snapshot 15s | Có | Dư thừa |
| Push alert tức thì | Kém | Tốt |
Buổi 15 mặc định poll; WebSocket optional capstone.
Disaster recovery và runbook
Runbook một trang: (1) API down → restart systemd, check Postgres disk; (2) DB corrupt → restore backup; (3) agent key lộ → rotate key, deploy env mới tất cả VPS trong 4h; (4) MT5 terminal treo → script kill + relaunch (tham chiếu buổi VPS EA). Drill recovery một lần/học kỳ trên môi trường staging — học viên HP2 coi là bài tập nhóm.
Tích hợp PyNhiQuaiBot: snapshot cluster mở rộng
Payload mở rộng (minh họa):
{
"captured_at": "2026-08-07T09:00:00+00:00",
"login": 12345678,
"clusters": [
{"cluster_id": 1, "magic": 9001, "layers": 3, "lockdown": false},
{"cluster_id": 2, "magic": 9002, "layers": 0, "lockdown": true}
],
"positions": []
}
Dashboard hiển thị badge đỏ cluster lockdown — support gọi khách đúng cụm thay vò hỏi “EA sao không vào lệnh”. Logic lockdown nằm trong EA MQL5 đã học; web chỉ phản ánh.
Testing: pytest cho API
from fastapi.testclient import TestClient
def test_health(client: TestClient):
assert client.get("/api/v1/health").json()["ok"] is True
def test_ingest_requires_key(client: TestClient):
r = client.post("/api/v1/snapshot", json={})
assert r.status_code == 422 or r.status_code == 401
CI GitHub Actions chạy test mỗi push — thói quen professional IB tech.
Frontend bảo mật: CORS và cookie
Nếu SPA ở domain khác API, cấu hình CORS chặt allow_origins=[...]. JWT trong httpOnly cookie giảm XSS steal token so với localStorage — tradeoff phức tạp CSRF; Buổi 15 demo Bearer header cho đơn giản, ghi chú hardening buổi sau.
Roadmap sau Buổi 15 (HP2)
Buổi 16–18: alert Telegram, role RBAC chi tiết, export CSV báo cáo khách. Buổi 19–24: hardening production, onboarding agent tự động, tài liệu handover khách. Giữ repo monorepo ib-platform/ với folder agent/, api/, infra/ — dễ clone template cho dự án thực tế sau khóa.
FAQ mở rộng (vận hành)
Postgres trên cùng VPS API được không? Được cho 100 acc demo; tách khi CPU contended. Dùng Supabase/Neon? Được nếu latency Việt Nam chấp nhận; agent cần outbound 443 ổn định. Backup SQLite copy file? Có — nhưng lock write khi copy — dùng .backup() API. FastAPI async với SQLAlchemy sync? Dùng threadpool hoặc chuyển async engine — đừng block event loop ingest dài. 100 key agent quản lý thế nào? Bảng agent_keys hash, UI admin rotate. Khách đòi mobile app? PWA wrap dashboard responsive trước khi native app. Log snapshot có PII? Login là PII — mã hóa backup, policy retention 90 ngày gợi ý. Có cần Kubernetes? Không cho 100 acc điển hình; Docker Compose đủ. MT5 build 32-bit vs agent 64-bit Python? Cùng kiến trúc OS; kiểm tra doc MetaTrader5 package.
Workshop Buổi 15 (120 phút gợi ý)
Phút 0–20: kiến trúc + PyNhiQuaiBot snapshot. 20–50: live code FastAPI ingest SQLite. 50–70: JWT admin + protected route. 70–90: docker compose up, test /docs. 90–110: scale discussion + Q&A OPEX. 110–120: giao bài tập 6 + reading Nginx TLS.
Checklist go-live (IB tự ký)
- [ ] HTTPS valid, HSTS optional
- [ ] Agent key per VPS, không hardcode repo public
- [ ] Postgres backup automated
- [ ] Stale snapshot alert tested
- [ ] Disclaimer trên UI “dữ liệu trễ tối đa X giây”
- [ ] Runbook in incident channel
- [ ] Không cam kết lợi nhuận trên marketing dashboard
Mô hình dữ liệu đọc: từ snapshot đến equity curve
Dashboard không chỉ hiển thị số mới nhất. Khách IB thường hỏi: “Tuần này equity dao động thế nào?” — API cần endpoint /api/v1/accounts/{login}/equity-series?from=...&to=... query bảng snapshots theo captured_at, trả mảng [{t, equity}, ...]. Frontend vẽ line chart (Chart.js/ApexCharts). Downsample nếu > 2000 điểm (lấy mỗi N phút) để browser nhẹ. Index (login, captured_at DESC) đã đề xuất ở phần schema giúp query series không full scan.
Với 100 login, admin dashboard load overview: một query DISTINCT ON (login) hoặc materialized view latest_snapshots refresh mỗi phút — tradeoff freshness vs load. Buổi lab: học viên implement view SQL đơn giản trước khi optimize.
Phân quyền RBAC chi tiết (preview)
| Role | Quyền |
|---|---|
superadmin |
CRUD agent keys, xem mọi login |
support |
Read-only mọi login, không đổi key |
client |
Read login thuộc client_id |
agent |
Chỉ POST snapshot (key) |
Implement bằng dependency FastAPI:
def require_role(*roles):
def dep(user=Depends(get_current_user)):
if user.role not in roles:
raise HTTPException(403, "Forbidden")
return user
return dep
@app.get("/api/v1/accounts", dependencies=[Depends(require_role("superadmin", "support"))])
def list_accounts():
...
JWT claim role + allowed_logins[] cho client. PyNhiQuaiBot VPS chỉ mang role agent qua header key — không dùng JWT.
Latency và SLA nội bộ (minh họa)
Đặt mục tiêu nội bộ không cam kết khách: ingest p95 < 300 ms; GET latest p95 1s, kiểm tra disk Postgres, index thiếu, hoặc agent gửi payload quá lớn (ảnh base64 lỡ gắn vào JSON — cấm trong review code lớp).
Onboarding khách thứ 101: quy trình kỹ thuật
- Tạo bản ghi
accounts+ib_client_id. - Generate agent key, gửi qua kênh bảo mật (không kênh chat công khai).
- Gửi template
.envvà script agent Buổi 15. - Khách cài MT5 + EA PyNhiQuaiBot (hoặc bot riêng) trên VPS.
- Verify first snapshot trong dashboard admin.
- Bật alert stale sau 48h ổn định.
Quy trình giảm ticket “em không thấy tài khoản trên web” — phần lớn do agent chưa chạy hoặc sai AGENT_KEY.
Bảo mật agent key: rotation không downtime
Giữ hai key active trong DB trong cửa sổ 24h: agent gửi X-Agent-Key cũ vẫn pass; deploy env key mới từng VPS; revoke key cũ. FastAPI middleware check membership trong set keys valid. Rotation định kỳ 90 ngày hoặc khi nhân viên support nghỉ.
Tối ưu payload: không gửi thừa
Mỗi position _asdict() có thể chứa field thừa. Hàm normalize_position(p) chỉ giữ ticket, symbol, volume, profit, magic — giảm 30–50% bytes JSON khi 100 VPS × 20 lệnh. Bandwidth 100 agent × 2 KB × 4 push/phút ≈ 800 KB/phút — nhỏ, nhưng log DB lớn theo thời gian: retention policy xóa snapshot > 90 ngày hoặc archive cold storage.
Staging vs production
Môi trường staging-api nhận snapshot từ MT5 demo login — test release FastAPI trước khi deploy production IB. Data không mix: DB staging riêng. Học viên HP2 nên có một VPS demo luôn push staging để CI/CD không đụng khách thật.
Câu chuyện lớp: lỗi thật đã sửa
Lớp trước từng deploy SQLite trên cùng disk OS 100% full → ingest 500 im lặng. Bài học: monitor dung lượng disk, alert > 85%. Một team quên timezone captured_at naive vs aware → sort equity sai ngày; fix bằng bắt buộc ISO UTC end-to-end — liên hệ trực tiếp Buổi Python 6 datetime. Một IB expose /docs public không auth — scanner scrape; fix basic auth trên Nginx cho path /docs staging only.
Giải pháp thay thế (so sánh ngắn)
| Giải pháp | Ưu | Nhược |
|---|---|---|
| FastAPI tự build | Linh hoạt, học được | Tốn thời gian |
| Grafana + Prometheus exporter | Metric mạnh | Không thay UI khách |
| MetaTrader Manager API | Broker-native | Không phải lúc nào cũng có |
| Google Sheet + script | Nhanh MVP | Không scale 100, bảo mật kém |
HP2 chọn FastAPI vì khớp stack Python agent và skill học viên.
Bài tập nâng cao (tùy chọn)
- Materialized view
latest_snapshots+ refresh cron. - Endpoint export CSV tháng cho một login (admin).
- Load test 200 concurrent GET với Locust — ghi lại p95.
- Viết ADR (Architecture Decision Record) một trang giải thích chọn Postgres thay SQLite.
Thuật ngữ HP2 Buổi 15
Snapshot, Agent, Ingest, Stale, Tenant, JWT, Idempotency, Connection pool, Reverse proxy, Runbook, OPEX, RBAC, JSONB, Materialized view, PyNhiQuaiBot, Lockdown, Cluster — tra trong LMS glossary HP2.
Docker Compose gợi ý (api + postgres)
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: devpass
POSTGRES_DB: ibdash
volumes:
- pgdata:/var/lib/postgresql/data
api:
build: ./api
ports:
- "8080:8080"
environment:
DATABASE_URL: postgresql+psycopg://postgres:devpass@db:5432/ibdash
depends_on:
- db
volumes:
pgdata:
Học viên chạy docker compose up --build, mở localhost:8080/docs, ingest snapshot mẫu — mô phỏng một ngày vận hành thu nhỏ trước khi thuê VPS production. Nhớ đổi password trước khi expose ra internet; file compose trên chỉ cho lab local.
Kết nối Buổi 14 → 15 → 16
Buổi 14 HP2 thường củng cố VPS + EA ổn định; Buổi 15 gắn mắt nhìn lên hệ thống; Buổi 16 mở rộng cảnh báo khi margin thấp hoặc cluster lockdown. Nếu bỏ Buổi 15, IB vẫn trade được nhưng support mù trạng thái — chi phí nhân sự tăng ngầm. Lộ trình HNDL cố ý đặt dashboard sau khi bạn đã có agent Python đọc MT5 từ module Python cơ bản và EA grid ổn định.
Giao tiếp team: tài liệu API cho đối tác
Khi IB thuê dev ngoài vẽ mobile app, OpenAPI JSON export từ FastAPI (/openapi.json) là contract chính thức. Kèm ví dụ curl ingest và response lỗi 401/422. Mô tả rõ đơn vị: equity USD, volume lot MT5, thời gian UTC. Tránh “truyền miệng” field PyNhiQuaiBot — ghi vào wiki nội bộ ngay Buổi 15 để 100 khách không tạo 100 cách hiểu snapshot khác nhau.
Redis cache latest snapshot (pseudo-code)
# redis.asyncio
async def get_latest(login: int):
cached = await redis.get(f"latest:{login}")
if cached:
return json.loads(cached)
row = db.query(...).first()
if row:
await redis.set(f"latest:{login}", row.payload, ex=120)
return row
TTL 120 giây phù hợp chu kỳ push 15 giây — cache miss vẫn có DB. Buổi 15 không bắt buộc Redis, nhưng 100 user F5 dashboard là lý do thêm cache sớm thay vì đợi sập demo.
UI/UX tối thiểu cho khách IB (không overdesign)
Màn hình khách không cần dark mode hay animation — cần số liệu đúng, thời gian snapshot rõ, màu cảnh báo margin (ví dụ đỏ dưới 150%, vàng 150–300%). Hiển thị disclaimer “Dữ liệu chỉ phục vụ theo dõi, không phải khuyến nghị giao dịch” footer mọi trang. Nút refresh manual + auto poll 10 giây. Tab Positions sort theo profit; ẩn ticket nếu khách không cần — tùy policy IB. Admin view thêm cột VPS label và agent version để biết khách nào chưa update script.
Compliance log truy cập dashboard
Ghi audit: user_id, login xem, timestamp UTC, IP (cân nhắc GDPR). Retention audit 1 năm. Khi khách tranh chấp “ai đã xem tài khoản tôi”, IB có bằng chứng. FastAPI middleware ghi sau response thành công route GET nhạy cảm — không log body snapshot full tránh duplicate PII.
Tích hợp Telegram alert (preview Buổi 16)
Webhook nội bộ: khi ingest phát hiện margin_level < 120 lần đầu trong ngày, queue job gửi Telegram channel ops — không gửi trực tiếp cho 100 khách trừ khi product yêu cầu. PyNhiQuaiBot lockdown true → message template có cluster_id. Buổi 15 chỉ thiết kế hook on_snapshot_ingested(snapshot) để Buổi 16 gắn bot.
Checklist review code trước merge (học viên HP2)
- Route ingest có auth agent key
- Pydantic validate kiểu số (equity không phải string)
- Không commit
.env/ key thật - Exception handler trả JSON thống nhất, không stack trace ra client
- Migration DB có version (Alembic) nếu team > 1 dev
- Health check không lộ thông tin nội bộ
- Test pytest ít nhất health + 401 ingest
Review peer trên nhóm lớp trước khi coi dashboard “xong Buổi 15” — thói quen giúp IB tránh incident tuần đầu go-live với 30–50 khách pilot.
Khi mở rộng từ 50 lên 100 tài khoản, hãy lên lịch load test vào cuối tuần trước khi thông báo cho toàn bộ khách dùng dashboard — spike truy cập đầu tuần thường cao hơn dự đoán. Ghi lại kết quả test trong wiki nội bộ để lớp sau học từ con số thực tế, không chỉ lý thuyết slide. Nếu p95 vượt ngưỡng, ưu tiên cache và index DB trước khi mua thêm CPU — dashboard chậm làm khách lo lắng dù EA vẫn chạy bình thường trên VPS. Đặt mục tiêu hoàn thiện ít nhất một luồng end-to-end: agent demo push → API → DB → trang admin thấy login trong buổi lab tuần này.
Lời kết HP2 Buổi 15
Web dashboard là mặt tiền hệ thống IB bot: khách nhìn vào để tin tưởng vận hành, nhưng EA và risk mới quyết định rủi ro giao dịch — nằm ngoài phạm vi cam kết của khóa học. FastAPI + Postgres + agent snapshot là stack gọn, tuyển dụng được, cộng đồng Python lớn. Hãy hoàn thành bài tập Docker và JWT trước Buổi 16; mang câu hỏi thực tế từ VPS của bạn lên Q&A để giảng viên HNDL chỉnh schema sát PyNhiQuaiBot bạn đang chạy.
Disclaimer
Nội dung đào tạo xây dựng hệ thống phần mềm và vận hành kỹ thuật bot không phải tư vấn đầu tư, không cam kết lợi nhuận hay hiệu suất giao dịch. Giao dịch leveraged có rủi ro mất vốn. Triển khai dashboard lên internet đi kèm rủi ro bảo mật — tự đánh giá hoặc thuê chuyên gia. Ví dụ cấu hình mang tính minh họa.
Bài đồng bộ slide Buổi 15/24 HP2 — cập nhật 07/08/2026.
Weekly Digest — Nhận Bản Tin Hàng Tuần
Nhận các bài viết phân tích kỹ thuật chuyên sâu, thuật toán giao dịch tự động (Trading Bot) và các giải pháp công nghệ mới nhất từ Hướng Nghiệp Dữ Liệu.
Đặng Trí Thanh
Giám đốc Công nghệ · DNT Digital · Giảng viên HNDLĐặng Trí Thanh — Founder & CTO · Hướng Nghiệp Dữ Liệu - DNT Digital. Chuyên đào tạo và triển khai thực chiến Python, MT5 và hệ thống bot auto trading / IB cho học viên và doanh nghiệp.