| Buổi 15 IB Bot — Web Dashboard FastAPI 100+ Khách & Cảnh Báo DD

Được viết bởi thanhdt vào ngày 20/07/2026 lúc 07:57 | 35 lượt xem


Buổi 15 — Web Dashboard FastAPI — 100+ khách

Phần 5 — Telegram, Copy Trading & Web Dashboard, buổi thứ ba và cũng là buổi kết Phần 5. Buổi 13 đã đưa Telegram vào vòng vận hành — khách Investor Pass nhìn PnL, alert Drawdown, phễu trial. Buổi 14 đã có engine copy Master → Client dưới 100ms với Guard ngắt lệnh khi mất mạng hoặc vượt DD riêng từng khách. Buổi 15 trả lời câu hỏi IB vận hành thực tế: khi có 10, 50, 100+ tài khoản client, ai nhìn tập trung Balance, Equity, Max DD và Volume — và báo đỏ trước khi khách panic trên group Zalo?

Bài này ghi lại nội dung lớp Buổi 15 (Syllabus) để học viên ôn và làm bài tập trước Buổi 16 (Partner Area — IB vs Affiliate).

Buổi này làm gì — và không làm gì

Làm Không làm
Web Dashboard FastAPI (hoặc Streamlit prototype) giám sát tập trung Partner Area Silver/Gold (Buổi 16)
Hiển thị Balance, Equity, Max DD, Volume một màn hình Funnel onboarding trial → active (Buổi 17)
Thiết kế cho 100+ accounts — pagination, filter Lab pilot 10 khách thật (Buổi 18)
Cảnh báo đỏ trên dashboard + push Telegram khi DD nguy hiểm Autorebates backcom (Buổi 21)
Agent thu thập số liệu từ MT5 / copy engine Buổi 14 Landing page mới (Buổi 19)
Deliverable: web monitor chạy demo với ≥5 tài khoản giả Cam kết lợi nhuận cho khách

Deliverable cuối buổi: dashboard web (FastAPI + giao diện HTML/Streamlit) hiển thị được ít nhất 5 client giả với cột Balance, Equity, Max DD (%), Volume tháng, trạng thái copy (RUNNING | HALTED | LOCKDOWN); một hàng đỏ khi max_dd_pct >= ngưỡng; một alert Telegram gửi ops khi DD vượt ngưỡng (tích hợp contract Buổi 13); screenshot + URL local hoặc VPS demo.

1. Vì sao IB cần dashboard web sau Telegram và Copy

Telegram Buổi 13 phù hợp push tóm tắt — PnL master, alert DD, CTA link IB. Copy Buổi 14 xử lý hành động — đồng bộ lệnh, Guard từng client. Nhưng IB vận hành OPC không thể mở 100 chat Telegram hoặc 100 terminal MT5 mỗi sáng để trả lời «tài khoản em sao rồi?».

Pain point khi scale Telegram alone Dashboard Buổi 15
So sánh DD 20 khách Scroll chat — mất thứ tự Sort cột Max DD — thấy ngay top 5
Client copy HALTED qua đêm Alert lẫn trong hội thoại Badge đỏ + filter state=HALTED
Volume tháng cho backcom Không có trong message PnL Cột volume — nền cho Buổi 16–21
Ops 2 phút buổi sáng Mở 10 app Một tab browser

Dashboard không thay Telegram cho khách cuối — khách vẫn nhận alert cá nhân. Dashboard là màn hình nội bộ IB (và tuỳ chọn Investor Pass read-only sau này).

2. Kiến trúc FastAPI — tách thu thập và hiển thị

2.1. Ba lớp gợi ý

[Collector]  MT5 EA / Python agent / copy log → POST /api/v1/snapshot
[API Core]     FastAPI — validate, lưu SQLite/PostgreSQL, rule alert
[UI]           Streamlit prototype HOẶC HTML+HTMX/Jinja — bảng 100+ dòng

FastAPI làm API core vì: typing Pydantic, async, OpenAPI docs tự sinh, dễ gắn auth sau. Streamlit dùng nhanh trên lớp để demo — production có thể tách frontend riêng.

Buổi 15 không yêu cầu microservice phức tạp — một process FastAPI + SQLite đủ deliverable lab.

2.2. Luồng dữ liệu (tóm tắt)

Mỗi 30–60s / mỗi sự kiện copy:
  Client EA hoặc agent Python đọc AccountInfoDouble(BALANCE|EQUITY)
  → Tính max_dd từ peak_equity lưu DB
  → POST JSON snapshot
FastAPI:
  → Upsert row client_id
  → Evaluate alert rules
  → Nếu DD >= threshold → queue Telegram (Buổi 13)
UI poll GET /api/v1/clients?sort=max_dd_desc&limit=100

Copy engine Buổi 14 đã có COPY_STATE_* — dashboard đọc state đó, không điều khiển copy trực tiếp trên Buổi 15 (tránh scope creep).

2.3. Contract snapshot (JSON minh hoạ)

{
  "schema": 1,
  "client_id": "CLI-0042",
  "account_login_masked": "****7890",
  "balance": 4820.50,
  "equity": 4612.30,
  "peak_equity": 5100.00,
  "max_dd_usd": 487.70,
  "max_dd_pct": 9.56,
  "volume_month_lot": 14.2,
  "copy_state": "RUNNING",
  "latency_p95_ms": 78,
  "ts_ms": 1721452800123
}
Trường Nguồn Ghi chú
max_dd_pct (peak - equity) / peak × 100 Peak reset theo policy (ngày/tuần)
volume_month_lot History MT5 magic client Phục vụ Partner Area Buổi 16
copy_state Global Variable IB_COPY_State client Đồng bộ với Buổi 14

3. Balance, Equity, Max DD — định nghĩa thống nhất

Mọi kênh (Telegram, dashboard, fanpage) phải cùng công thức — tránh khách thấy DD 8% trên Telegram mà dashboard 12%.

3.1. Balance vs Equity

Chỉ số Ý nghĩa trên dashboard
Balance Số dư không gồm floating P/L
Equity Balance + floating — dùng tính DD realtime
Peak equity Max equity trong window (ví dụ rolling 30 ngày)

3.2. Max DD — hai cách hiển thị

max_dd_usd  = peak_equity - current_equity
max_dd_pct  = max_dd_usd / peak_equity × 100

Dashboard nên hiển thị cả USD và % — khách vốn nhỏ quan tâm %; IB ops quan tâm USD tổng book.

3.3. Volume một màn hình

Cột Volume tháng (lot round-turn) tách biệt PnL:

  • PnL = kết quả trading — rủi ro khách
  • Volume = cơ sở backcom IB — Buổi 16–21

Không dùng volume để suy PnL. Không dùng PnL Telegram để tính backcom.

4. FastAPI — endpoint và model Pydantic

4.1. Endpoint tối thiểu

Method Path Mục đích
POST /api/v1/snapshot Agent đẩy số liệu
GET /api/v1/clients List + filter + sort + pagination
GET /api/v1/clients/{id} Chi tiết một khách
GET /api/v1/alerts/active Danh sách cảnh báo đỏ chưa ack
POST /api/v1/alerts/{id}/ack Ops xác nhận đã xử lý

4.2. Model Pydantic (rút gọn)

from pydantic import BaseModel, Field
from enum import Enum

class CopyState(str, Enum):
    RUNNING = "RUNNING"
    HALTED = "HALTED"
    LOCKDOWN = "LOCKDOWN"

class ClientSnapshot(BaseModel):
    schema_version: int = Field(1, alias="schema")
    client_id: str
    balance: float
    equity: float
    peak_equity: float
    max_dd_pct: float
    volume_month_lot: float = 0.0
    copy_state: CopyState
    ts_ms: int

Validate equity <= peak_equity (hoặc cho phép peak update) — reject snapshot lỗi clock.

4.3. Lưu trữ — SQLite đủ lab

Bảng clients_current (1 row/client) + snapshots_history (append-only) cho sparkline sau. Buổi 15 chỉ bắt buộc current + export CSV.

5. Giao diện — một màn hình 100+ khách

5.1. Cột bảng gợi ý

Cột Sort Filter
client_id search
balance
equity
max_dd_pct ✓ default desc >= 8
volume_month
copy_state RUNNING/HALTED/LOCKDOWN
last_update stale > 5 phút

5.2. Pagination và performance

100+ accounts bắt buộc pagination server-side:

GET /api/v1/clients?page=1&page_size=25&sort=max_dd_pct&order=desc

UI: 25 dòng/trang — ops xem top DD trước. Không load 500 row DOM một lần.

5.3. Streamlit vs HTML

Tuỳ chọn Ưu Nhược
Streamlit Code ít — phù hợp lớp 3h Khó custom theme production
Jinja + HTMX Nhẹ, deploy static Viết nhiều hơn

Deliverable chấp nhận Streamlit gọi FastAPI hoặc FastAPI serve template HTML.

5.4. Cảnh báo đỏ dashboard

Rule minh hoạ:

RED if max_dd_pct >= dd_red_threshold (ví dụ 10%)
     OR copy_state == LOCKDOWN
     OR last_update stale > 300s
AMBER if max_dd_pct >= dd_amber_threshold (ví dụ 7%)

Hàng đỏ CSS background: #fee — không chỉ icon nhỏ. Ops mở dashboard buổi sáng phải thấy ngay ai cần gọi.

6. Scale 100+ accounts — pattern vận hành

6.1. Agent per VPS vs central collector

Pattern Mô tả Khi nào
Push per client Mỗi VPS client POST snapshot Client rải nhiều datacenter
Central scraper Một service đọc DB/file từ copy hub Nhiều client cùng VPS cluster
Batch file EA ghi CSV → cron Python upload Lab đơn giản

Buổi 15 lab: 5 client giả push snapshot bằng script Python — mô phỏng 100 bằng seed data + pagination.

6.2. Stale detection

Nếu now - ts_ms > 300_000 → badge STALE màu xám. Copy có thể RUNNING nhưng agent chết — nguy hiểm hơn HALTED rõ ràng.

6.3. Idempotent snapshot

client_id + ts_ms unique — hoặc upsert chỉ giữ latest. Tránh duplicate row khi agent retry POST.

7. Telegram khi DD nguy hiểm — nối Buổi 13

Dashboard không thay Telegram — bổ sung rule tập trung.

7.1. Alert pipeline

FastAPI evaluate rules after upsert
  → if RED and not alerted in last 15 min:
       POST Telegram sendMessage (ops channel)
       INSERT alert_log

Message ops gợi ý:

[IB OPS] DD RED — CLI-0042 max_dd=10.2% equity=4612 copy=RUNNING
Dashboard: https://monitor.example.com/clients/CLI-0042

7.2. Tránh spam

Cơ chế Mục đích
Cooldown 15 phút / client / rule Không 60 message/giờ khi DD dao động
Ack trên dashboard Ops bấm «đã xử lý» — reset cooldown
Tách channel ops vs khách Khách vẫn nhận alert cá nhân policy Buổi 13

Field copy_state trong message — tránh đọc PnL master trong lúc client LOCKDOWN (nhất quán Buổi 14).

7.3. WebRequest vs Python middleware

Buổi 13 EA có thể gọi Telegram trực tiếp. Buổi 15 nên gom alert qua FastAPI — một nơi rule DD, stale, volume bất thường.

8. Bảo mật và phân quyền (tối thiểu)

Dashboard chứa equity khách — không public internet không auth.

Mức lab Biện pháp
Demo lớp Basic auth / API key header trên POST snapshot
VPS production HTTPS + JWT ops + IP allowlist agent
Khách xem Subset read-only sau — Investor Pass style

Không lộ full account login trên UI — mask ****7890. Token Telegram Buổi 13 không commit Git.

9. Gắn Copy Engine và Guard (Buổi 14)

Signal từ Buổi 14 Hiển thị dashboard
COPY_STATE_HALTED Badge vàng + filter
COPY_STATE_LOCKDOWN Hàng đỏ
latency_p95_ms Cột phụ — phát hiện copier chậm
Guard DD client max_dd_pct khớp ngưỡng Guard

Khi master disconnect → client HALTED → dashboard đỏ trước khi khách nhắn Zalo.

10. Gắn FSM và Global Variables (Phần 1)

Agent đọc GV prefix IB_COPY_*IB_BOT_* — cùng convention Buổi 2–3:

IB_DASH_LastPushMs
IB_DASH_AlertCountToday

Sau reconnect VPS, agent push snapshot ngay — dashboard bỏ STALE.

11. FastAPI skeleton — code lab trên lớp

11.1. File main.py (rút gọn — đủ chạy demo)

from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
from enum import Enum
import sqlite3, time

app = FastAPI(title="IB Monitor Buoi 15")

class CopyState(str, Enum):
    RUNNING = "RUNNING"
    HALTED = "HALTED"
    LOCKDOWN = "LOCKDOWN"

class Snapshot(BaseModel):
    schema_version: int = 1
    client_id: str
    balance: float
    equity: float
    peak_equity: float
    max_dd_pct: float
    volume_month_lot: float = 0.0
    copy_state: CopyState
    ts_ms: int

def upsert(row: Snapshot) -> None:
    con = sqlite3.connect("ib_monitor.db")
    con.execute(
        """INSERT INTO clients VALUES (?,?,?,?,?,?,?,?)
           ON CONFLICT(client_id) DO UPDATE SET
           balance=excluded.balance, equity=excluded.equity,
           peak_equity=excluded.peak_equity, max_dd_pct=excluded.max_dd_pct,
           volume_month_lot=excluded.volume_month_lot,
           copy_state=excluded.copy_state, ts_ms=excluded.ts_ms""",
        (row.client_id, row.balance, row.equity, row.peak_equity,
         row.max_dd_pct, row.volume_month_lot, row.copy_state.value, row.ts_ms),
    )
    con.commit()
    con.close()

@app.on_event("startup")
def init_db() -> None:
    con = sqlite3.connect("ib_monitor.db")
    con.execute(
        """CREATE TABLE IF NOT EXISTS clients (
           client_id TEXT PRIMARY KEY, balance REAL, equity REAL,
           peak_equity REAL, max_dd_pct REAL, volume_month_lot REAL,
           copy_state TEXT, ts_ms INTEGER)"""
    )
    con.commit()
    con.close()

@app.post("/api/v1/snapshot")
def post_snapshot(
    row: Snapshot,
    x_api_key: str | None = Header(default=None),
) -> dict:
    if x_api_key != "lab-key-buoi15":
        raise HTTPException(401, "Invalid API key")
    upsert(row)
    return {"ok": True, "client_id": row.client_id}

@app.get("/api/v1/clients")
def list_clients(
    page: int = 1,
    page_size: int = 25,
    sort: str = "max_dd_pct",
) -> dict:
    allowed = {"max_dd_pct", "equity", "balance", "volume_month_lot"}
    col = sort if sort in allowed else "max_dd_pct"
    off = (page - 1) * page_size
    con = sqlite3.connect("ib_monitor.db")
    rows = con.execute(
        f"SELECT * FROM clients ORDER BY {col} DESC LIMIT ? OFFSET ?",
        (page_size, off),
    ).fetchall()
    total = con.execute("SELECT COUNT(*) FROM clients").fetchone()[0]
    con.close()
    return {"page": page, "page_size": page_size, "total": total, "rows": rows}

Học viên chạy uvicorn main:app --reload — mở /docs xem OpenAPI. Deliverable không bắt buộc copy y nguyên — nhưng phải có POST snapshot + GET list pagination.

11.2. Script agent giả push_demo.py

import requests, random, time
BASE = "http://127.0.0.1:8000"
HDR = {"X-Api-Key": "lab-key-buoi15"}

for i in range(1, 31):
    cid = f"CLI-{i:04d}"
    peak = 10000 + random.random() * 5000
    dd = random.random() * 12
    eq = peak * (1 - dd / 100)
    requests.post(f"{BASE}/api/v1/snapshot", headers=HDR, json={
        "client_id": cid,
        "balance": eq * 0.98,
        "equity": eq,
        "peak_equity": peak,
        "max_dd_pct": round(dd, 2),
        "volume_month_lot": round(random.random() * 40, 1),
        "copy_state": "LOCKDOWN" if dd > 10 else "RUNNING",
        "ts_ms": int(time.time() * 1000),
    }, timeout=5)

30 client giả → kiểm tra pagination 25/trang. Một client dd > 10 → hàng đỏ trên UI.

12. Deploy dashboard trên VPS — gợi ý production-lite

Lab chạy localhost; OPC deploy trên cùng VPS monitor hoặc VPS riêng — HTTPS bắt buộc nếu mở ngoài LAN.

Bước Việc
1 systemd unit uvicorn main:app --host 127.0.0.1 --port 8000
2 Nginx reverse proxy monitor.ib.example.com127.0.0.1:8000
3 Cert Let’s Encrypt — không gửi equity qua HTTP thuần
4 Basic auth Nginx cho ops — tách API key agent POST
5 Firewall: chỉ IP agent được POST snapshot

Không expose SQLite file ra ngoài. Backup ib_monitor.db hàng tuần — lịch sử DD phục vụ tranh chấp «tuần trước em DD bao nhiêu».

Streamlit deploy riêng port 8501 — gọi FastAPI nội bộ; ops bookmark một URL duy nhất sau Nginx path /dashboard/.

13. Lịch sử snapshot — sparkline và audit

Buổi 15 tối thiểu lưu current row. Mở rộng khuyến khích:

CREATE TABLE snapshots_history (
  id INTEGER PRIMARY KEY,
  client_id TEXT,
  equity REAL,
  max_dd_pct REAL,
  ts_ms INTEGER
);

Append mỗi POST — UI chi tiết client vẽ sparkline 24h. Lợi ích:

  • Ops thấy DD leo dần hay spike — xử lý khác nhau
  • Đối chiếu Telegram alert «DD 8% lúc 14h» với DB — nhất quán Buổi 13
  • Nền audit trước Autorebates Buổi 21 — không thay CSV volume broker

Retention policy: giữ 90 ngày raw — export CSV trước khi purge.

14. Multi-broker và suffix symbol

Copy Buổi 14 đã nhắc map XAUUSD vs XAUUSDc. Dashboard aggregate theo client_id, không theo symbol — nhưng agent nên gửi thêm field tuỳ chọn:

"broker": "exness",
"symbol_suffix": "c",
"account_currency": "USD"

Filter UI: «chỉ client USD» — tránh cộng equity EUR và USD không convert (Buổi 15 không dạy FX convert — chỉ cảnh báo không cộng mù).

15. Quy trình buổi sáng ops — 5 phút

08:00 — Mở dashboard, sort max_dd_pct desc
     — Kiểm tra hàng STALE (agent chết qua đêm)
     — Ack alert đỏ hôm qua chưa xử lý
08:02 — Filter copy_state=LOCKDOWN → gọi/kh nhắn template
08:04 — So sánh top 3 DD với Telegram master (Buổi 13)
08:05 — Ghi log ops (sheet hoặc comment alert ack)

Dashboard giảm thời gian trả lời Zeno «tài khoản em sao» — không thay chăm sóc khách. Funnel Buổi 17 bổ sung message tự động; Buổi 15 là radar nội bộ.

16. Tích hợp volume — cầu nối Partner Area Buổi 16

Cột volume_month_lot trên dashboard preview số Partner Area — IB không mở portal 100 lần/ngày.

Nguồn volume Tần suất cập nhật
Agent đọc MT5 history magic client Mỗi 1h hoặc end-of-day
Cron import CSV Partner Area 1 lần/ngày — source of truth payout
Snapshot POST realtime Chỉ equity/DD — volume có thể lag 1h

Ghi chú trên UI: «Volume T-1 từ broker» — tránh khách so sánh realtime với CSV tháng.

17. Thực hành lab — deliverable web monitor

17.1. Setup tối thiểu

Bước Việc
1 uvicorn main:app --host 0.0.0.0 --port 8000
2 Tạo 5 client_id giả — script push snapshot mỗi 10s
3 UI bảng sort max_dd_pct desc
4 Set 1 client max_dd_pct=11 → hàng đỏ
5 Trigger Telegram ops (token Buổi 13)
6 Screenshot + ghi URL

17.2. Kịch bản kiểm thử

  1. Happy path: 5 client RUNNING — không đỏ
  2. DD red: Tăng max_dd_pct → đỏ + Telegram (cooldown)
  3. LOCKDOWN: copy_state=LOCKDOWN → đỏ dù DD thấp
  4. Stale: Ngừng push 6 phút → badge STALE
  5. Pagination: Seed 30 client giả — 2 trang, sort ổn

Ghi file dashboard_lab_YYYYMMDD.csv export từ GET /api/v1/clients.

18. Checklist thực hành trên lớp

  1. [ ] Sơ đồ 3 lớp Collector — API — UI
  2. [ ] Pydantic model + POST snapshot hoạt động
  3. [ ] Bảng 5 client — cột Balance, Equity, Max DD, Volume, copy_state
  4. [ ] Sort max_dd + pagination 25/trang
  5. [ ] Rule RED + hàng CSS đỏ
  6. [ ] Telegram ops 1 alert DD (cooldown)
  7. [ ] Mask login — không lộ full số TK
  8. [ ] Ghi chú công thức DD khớp Telegram Buổi 13

13. Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
DD dashboard ≠ Telegram Khác peak window Document cùng peak_rolling_days
100 row treo browser Không pagination Server-side page_size
Telegram spam Không cooldown 15 phút + ack
Snapshot 401 Thiếu API key agent Header X-Api-Key
Volume = 0 mãi Chưa đọc history Job đêm aggregate MT5
STALE không hiện Không check ts_ms Rule stale > 300s

14. FAQ

Dashboard có cho khách đăng nhập xem không?
Buổi 15 tập trung ops IB. Read-only cho khách có thể mở rộng sau — pattern Investor Pass Buổi 13.

Bắt buộc FastAPI hay Streamlit?
FastAPI cho API là chuẩn deliverable; Streamlit tuỳ chọn UI nhanh.

100+ khách có cần PostgreSQL không?
SQLite đủ đến vài trăm client với snapshot 60s. Scale lớn hơn → PostgreSQL + index client_id, ts_ms.

Dashboard có điều khiển copy không?
Buổi 15 chỉ giám sát. Điều khiển copy là scope engine Buổi 14 — tránh nút «pause all» nguy hiểm trên web chưa auth đủ.

Buổi 16 thêm gì?
Partner Area — IB vs Affiliate, backcom recurring vs CPA, tier Silver/Gold — dòng tiền tách khỏi PnL dashboard.

15. Nối Buổi 13, 14 và 16

  • Buổi 13: khách nhìn qua Telegram / Investor Pass
  • Buổi 14: khách nhận lệnh copy — Guard từng tài khoản
  • Buổi 15: IB nhìn tập trung 100+ client — DD đỏ, volume, copy state
  • Buổi 16: IB hiểu doanh thu Partner Area — backcom ≠ PnL trên dashboard

Thiếu dashboard Buổi 15, scale 10 khách (Buổi 18) dễ thành «trả lời Zalo từng người» — không OPC.

16. Đăng ký / xem lộ trình khóa

Trang khóa: Xây dựng IB bằng Bot Auto Trading
Lịch khai giảng: Lịch khai giảng
Hotline 0934 145 100 · Zalo 039 791 9841

17. Disclaimer

Nội dung buổi học phục vụ đào tạo kỹ thuật xây dashboard giám sát IB và copy trading. Không phải tư vấn đầu tư; không cam kết lợi nhuận. Số liệu Balance, Equity, DD minh hoạ vận hành — không phải cam kết hiệu suất bot. Giao dịch có rủi ro. Tuân thủ điều khoản broker và quy định pháp luật khi vận hành IB.

Lộ trình khóa IB: Xây dựng IB bằng Bot Auto Trading

admin

admin

Biên tập viên, Hướng Nghiệp Dữ Liệu
778 Bài viết
15.4k Người theo dõi
120k+ Lượt đọc

Biên tập viên nội dung tại Hướng Nghiệp Dữ Liệu, phụ trách tổng hợp và biên soạn các bài viết về lập trình Python, dữ liệu và công nghệ.