| Kiến trúc 4 lớp PyNhiQuaiBot — Quant Buổi 1: từ script sang hệ thống quant Python hedging

Được viết bởi thanhdt vào ngày 18/07/2026 lúc 15:04 | 4 lượt xem

Nguồn: Day DataPass/.../Bot Nhi Quai Nang Cao/bot_nhi_quai_v6_pro.py · lộ trình 12 buổi PyNhiQuaiBot (QuantTrade)


Hầu hết lập trình viên bắt đầu bot trading bằng một file Python duy nhất: while True, đọc giá, nếu điều kiện thì order_send, rồi sleep. Cách này chạy được trên demo vài phút — nhưng khi reconnect API, khi có hàng chục vị thế Buy/Sell cùng lúc, hoặc khi equity giảm và bot vẫn cố mở lệnh mới, script đơn sẽ sụp đổ vì không có ranh giới trách nhiệm giữa dữ liệu, chiến thuật, kiểm soát rủi ro và thực thi.

Buổi 1 — Kiến trúc & chuẩn hóa bài toán trong khóa Lập trình Python nâng cao Hedging tự động hóa (dự án PyNhiQuaiBot, góc PR QuantTrade · Master Quantitative Trading) trả lời câu hỏi nền tảng: một bot hedging production cần được chia thành những lớp nào, và vòng lặp chính đi qua chúng theo thứ tự gì?

Bài viết bám trực tiếp mã nguồn bot_nhi_quai_v6_pro.py — bản Python port từ Bot Nhị Quái V6 Pro trên MQ5. Đây là tài liệu kỹ thuật và bài lab Buổi 1, không phải khuyến nghị đầu tư, không cam kết lợi nhuận. Grid, hedging và giao dịch tự động có thể gây drawdown lớn, margin call, trượt giá, phí và lỗi kết nối. Chỉ thực hành trên demo, đặt giới hạn rủi ro độc lập và tự chịu trách nhiệm triển khai.

1. Script một file vs hệ thống quant có trách nhiệm

Tiêu chí Script một file Hệ thống PyNhiQuaiBot
Trạng thái Biến global rời, mất khi restart GVStore JSON — persist + namespace theo symbol/account/magic
Quyết định mở lệnh if signal: buy() Grid Logic (process_cluster) tách khỏi Guard (handle_lockdown)
Side effect Gọi API trực tiếp trong logic order_send — adapter execution, chiến thuật không biết filling mode
Quan sát print(bid) draw_dashboard — equity, bias, P0, trạng thái Full Hedge
Thất bại Crash hoặc nhồi lệnh Spread guard, lockdown freeze, FSM STEP_BUSY (Buổi 8)

QuantTrade không bắt đầu bằng “tín hiệu thần kỳ”. Nó bắt đầu bằng cấu trúc có thể kiểm thử: mỗi lớp trả lời một câu hỏi riêng, và vòng lặp chính gọi chúng theo thứ tự cố định để tránh “sửa API làm hỏng chiến thuật” hoặc “sửa chiến thuật làm bỏ qua guard”.

2. Bốn phần kiến trúc — bản đồ cả khóa 12 buổi

Ảnh lộ trình: PyNhiQuaiBot_Lo_Trinh_4_Phan.png (Infrastructure → Grid Logic → Brain → UX).

Phần Buổi học (12 buổi chính) Module trong bot_nhi_quai_v6_pro.py Câu hỏi lớp trả lời
1 — Infrastructure B1–B4 Config, GVStore, rates, order_send, positions Dữ liệu đúng chưa? API giao tiếp thế nào? State lưu ở đâu?
2 — Grid Logic B5–B7 process_cluster, Step/X, Surplus/Hedge, cache Giá hiện tại = Step mấy? Có được mở lệnh tại Step này không?
3 — Brain B8–B10 get_fsm/set_fsm, handle_lockdown, check_basket_tp Hành động có được phép? Rủi ro vượt ngưỡng chưa?
4 — UX B11–B12 draw_dashboard, log, VPS, backtest hook Người vận hành nhìn thấy gì? Metric quant nào cần đo?

Buổi 1 không đi sâu Step/X hay FSM — mục tiêu là đọc được toàn cảnh trước khi zoom vào từng module ở các buổi sau. Nếu bạn đã đọc bài tổng quan PyNhiQuaiBot, bài này là lab Buổi 1: cùng chủ đề nhưng gắn trực tiếp vào file code và sơ đồ runtime.

graph TB
    subgraph UX["PHẦN 4 — UX"]
        DASH[draw_dashboard]
        LOG[logging]
    end
    subgraph BRAIN["PHẦN 3 — Brain"]
        LOCK[handle_lockdown]
        FSM[get_fsm / set_fsm]
        BASKET[check_basket_tp]
    end
    subgraph GRID["PHẦN 2 — Grid Logic"]
        CLUSTER[process_cluster]
        TP[tp_logic / check_x_profit]
    end
    subgraph INFRA["PHẦN 1 — Infrastructure"]
        CFG[Config dataclass]
        GV[GVStore JSON]
        API[rates · order_send · positions]
    end
    RUN[run → on_tick loop] --> INFRA
    INFRA --> BRAIN
    BRAIN --> GRID
    GRID --> UX
    UX --> GV

3. Khung dự án: Config — map 1-1 với input MQ5

Lớp Infrastructure bắt đầu bằng cấu hình tách biệt logic. Trong Python, @dataclass Config gom toàn bộ tham số mà trên MQ5 là input:

@dataclass
class Config:
    bot_name: str = "NHỊ QUÁI V6"
    storage_prefix: str = "NHỊ QUÁI V6"
    buy_magic: int = 6111
    sell_magic: int = 6112
    buy_step: float = 50.0
    buy_x: float = 60.0
    sell_step: float = 100.0
    sell_x: float = 120.0
    auto_lockdown: bool = True
    max_allowed_bias: float = 0.3
    tick_sleep: float = 0.25
    symbol: str = "BTCUSD"

Deliverable Buổi 1: liệt kê được mỗi nhóm field thuộc phần kiến trúc nào:

Nhóm Config Ví dụ Thuộc phần
Identity bot_name, storage_prefix, buy_magic, sell_magic Infrastructure — namespace
Grid buy_step, buy_x, sell_step, sell_x, buy_lot Grid Logic
Risk auto_lockdown, buy_min_equi2, max_allowed_bias Brain
Runtime tick_sleep, max_spread, symbol Infrastructure + UX

Hàm parse_args() cho phép override từ CLI (--symbol BTCUSD, --buy-step 50) mà không sửa class — pattern quant engineer: config ngoài code, dễ chạy trên VPS với tham số khác nhau.

4. GVStore — Global State thay GlobalVariable MT5

Trên MQ5, EA dùng GlobalVariableSet/Get. Port sang Python dùng file JSON:

class GVStore:
    def __init__(self, path: Path):
        self.path = path
        self.data: Dict[str, float] = {}
        self._load()

    def get(self, name: str, default: float = 0.0) -> float:
        return float(self.data.get(name, default))

    def set(self, name: str, value: float) -> None:
        self.data[name] = float(value)

    def save(self) -> None:
        self.path.write_text(json.dumps(self.data, ensure_ascii=False, indent=2), encoding="utf-8")

Mỗi tick kết thúc bằng self.gv.save() — state không chỉ nằm trong RAM. Key được namespace:

def gv_prefix(self, magic: int) -> str:
    return f"{self.cfg.storage_prefix}_{self.symbol}_{self._login}_{magic}"

Ví dụ key thực tế: NHỊ QUÁI V6_BTCUSD_12345678_6111_P0, ..._6111_LastStep, ..._6111_LOCKED.

Vì sao Buổi 1 dạy GVStore trước Grid? Vì mọi quyết định chiến thuật đều đọc/ghi state (P0, LastStep, MinStep, MaxStep, FSM keys). Không có store thống nhất, reconnect sẽ làm bot “quên” P0 và nhồi lệnh sai Step — pain mà bài Global State (Buổi 2) sẽ mở rộng thêm schema Pandas.

5. Class NhiQuaiV6 — composition thay vì God object một chiều

NhiQuaiV6 giữ:

  • self.cfg — cấu hình bất biến trong session
  • self.gv — store bền vững
  • Cache runtime: buy_cache, sell_cache (Buổi 7 — concurrency)
  • Throttle: last_action_buy, last_action_sell (2 giây giữa hai lần xử lý cụm)

Đây chưa phải OOP “sạch” kiểu microservice — nhưng đã phân tách method theo trách nhiệm:

Method Trách nhiệm
rates() Đọc Bid/Ask/spread — Infrastructure
order_send() / close_ticket() Execution adapter MT5
handle_lockdown() Brain — full hedge khi equity thấp
tp_logic() Grid — gặt X cục bộ
process_cluster() Grid — core rải lệnh theo Step
draw_dashboard() UX — quan sát bias, float, P0

Nguyên tắc Buổi 1: chiến thuật không gọi MT5 trực tiếp ngoài order_send/close_ticket. Mọi thay đổi filling mode, deviation, comment format chỉ sửa một chỗ.

6. Vòng đời: on_init → run → on_tick

6.1. Khởi tạo on_init

Trước vòng lặp, bot:

  1. Kiểm tra buy_magic != sell_magic (hai cụm không được trùng)
  2. mt5.symbol_select(symbol)
  3. Lấy account login → namespace GVStore
  4. Nếu cụm chưa có position → reset_cluster
  5. Khởi tạo P0StartTime cho từng magic nếu chưa có
  6. sync_traversed() — đồng bộ MinStep/MaxStep từ comment lệnh đang mở
def on_init(self) -> bool:
    if self.cfg.buy_magic == self.cfg.sell_magic:
        log.error("Buy/Sell magic trùng nhau!")
        return False
    ai = mt5.account_info()
    self._login = int(ai.login) if ai else 0
    for magic in (self.cfg.buy_magic, self.cfg.sell_magic):
        k = f"{self.gv_prefix(magic)}_P0"
        if not self.gv.check(k):
            bid, _, _ = self.rates()
            self.gv.set(k, bid)
    self.sync_traversed()
    self.gv.save()
    return True

Test Buổi 1 — init: chạy bot lần đầu trên demo → file .gv.json xuất hiện với key _P0 cho magic 6111 và 6112.

6.2. Vòng lặp chính run

def run(self) -> None:
    if not self.on_init():
        return
    try:
        while True:
            self.on_tick()
            time.sleep(self.cfg.tick_sleep)
    except KeyboardInterrupt:
        self.gv.save()

tick_sleep mặc định 0.25 giây — Python bot polling, không phải hook OnTick native như MQ5. Quant engineer cần hiểu: polling interval ảnh hưởng race window (Buổi 7) và tải CPU trên VPS (Buổi 12).

6.3. Một chu kỳ on_tick — flow đầy đủ

Đây là trái tim Buổi 1 — thứ tự gọi cố định:

def on_tick(self) -> None:
    bid, ask, spread = self.rates()
    if bid <= 0 or spread > self.cfg.max_spread:
        return
    if self.cfg.buy_enable:
        self.handle_lockdown(self.cfg.buy_magic)
        if not self.is_full_hedge_frozen(self.cfg.buy_magic):
            self.tp_logic(self.cfg.buy_magic)
            self.process_cluster(self.cfg.buy_magic)
    if self.cfg.sell_enable:
        self.handle_lockdown(self.cfg.sell_magic)
        if not self.is_full_hedge_frozen(self.cfg.sell_magic):
            self.tp_logic(self.cfg.sell_magic)
            self.process_cluster(self.cfg.sell_magic)
    self.draw_dashboard()
    self.gv.save()
sequenceDiagram
    participant Loop as run() while True
    participant Tick as on_tick()
    participant Rates as rates()
    participant Lock as handle_lockdown()
    participant TP as tp_logic()
    participant Grid as process_cluster()
    participant Dash as draw_dashboard()
    participant GV as GVStore.save()

    Loop->>Tick: mỗi tick_sleep
    Tick->>Rates: Bid, Ask, spread
    alt spread OK
        Tick->>Lock: magic 6111
        alt not frozen
            Tick->>TP: gặt X cụm BUY
            Tick->>Grid: rải lệnh cụm BUY
        end
        Tick->>Lock: magic 6112
        alt not frozen
            Tick->>TP: gặt X cụm SELL
            Tick->>Grid: rải lệnh cụm SELL
        end
        Tick->>Dash: in equity, bias, P0
        Tick->>GV: persist JSON
    else spread quá rộng
        Tick-->>Loop: return sớm
    end

Thứ tự có ý nghĩa:

  1. Spread guard trước — không trade khi thị trường mỏng
  2. Lockdown trước Grid — equity thấp → hedge ABS, đặt _LOCKED, bỏ qua process_cluster
  3. tp_logic trước process_cluster — chốt lệnh đã đủ X trước khi cân nhắc mở mới
  4. Cụm BUY trước SELL — quy ước code hiện tại (documented, không “đúng/sai” thị trường)
  5. Dashboard + save cuối — UX và durability

7. Execution layer — order_send tách khỏi chiến thuật

def order_send(self, magic: int, side: int, lot: float, comment: str) -> bool:
    tick = mt5.symbol_info_tick(self.symbol)
    order_type = mt5.ORDER_TYPE_BUY if side == POS_BUY else mt5.ORDER_TYPE_SELL
    price = tick.ask if side == POS_BUY else tick.bid
    req = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": self.symbol,
        "volume": float(lot),
        "type": order_type,
        "price": price,
        "deviation": int(self.cfg.slippage_allow),
        "magic": int(magic),
        "comment": comment[:31],
        "type_filling": filling,
    }
    r = mt5.order_send(req)
    return r is not None and r.retcode == mt5.TRADE_RETCODE_DONE

process_cluster chỉ gọi order_send — không biết Ask/Bid lấy từ đâu. Buổi 3 sẽ mở rộng thành adapter đa sàn (Binance, SSI, DNSE); Buổi 1 chỉ cần nhận ra interface execution đã tồn tại.

Comment format: NHỊ QUÁI V6_B_S12 (cụm BUY, Step 12) — Buổi 4 sẽ học Magic + Comment + lifecycle đầy đủ.

8. Hai cụm magic 6111 / 6112 — preview cho Buổi 4

Mỗi on_tick xử lý hai cluster độc lập:

Magic Tên cụm Step mặc định X mặc định
6111 Cụm BUY 50.0 60.0
6112 Cụm SELL 100.0 120.0

Mỗi cụm có P0 riêng, basket TP riêng, lockdown riêng. Tên “BUY cluster” không có nghĩa chỉ chứa lệnh Buy — cụm vẫn có cả Buy và Sell tại các Step (hedging). Chi tiết: Kiến trúc hai cụm 6111/6112 (Buổi 4).

9. Dashboard — UX không phải phần trang trí

def draw_dashboard(self) -> None:
    if self.tick_ms() - self.last_draw < 500:
        return
    lines = [
        "=== ROBOT NHI QUAI V6 (Python) ===",
        f"EQUITY: {equity:.2f} | FullHed: {hed}",
        f"CUM BUY | Float: {b_float:.2f} | P0: {p0_b:.2f}",
        f" > Buy: {b_bv:.2f} | Sell: {b_sv:.2f} | BIAS: {b_bv - b_sv:.2f}",
        f"BIAS TONG SYMBOL: {tot_b - tot_s:.2f} Lot",
    ]
    log.info("n".join(lines))

Quant engineer cần metric quan sát được trước khi tin bot chạy 24/7: equity, bias từng cụm, trạng thái Full Hedge. Buổi 11 sẽ nâng lên dashboard Pandas + backtest report (MDD, cost).

10. Ba kịch bản kiểm thử Buổi 1

Chạy trên tài khoản demo, symbol cố định (vd. BTCUSD), log level INFO.

Kịch bản A — Cold start (happy path)

  1. Xóa file bot_nhi_quai_v6_pro.gv.json
  2. python bot_nhi_quai_v6_pro.py --symbol BTCUSD
  3. Kỳ vọng: log Init OK, dashboard in equity, file GV có key _P0 cho 6111 và 6112
  4. Không kỳ vọng: lợi nhuận — chỉ xác nhận lifecycle

Kịch bản B — Restart giữa chừng

  1. Bot đang chạy, có ít nhất 1 position
  2. Ctrl+C → chạy lại cùng symbol/account
  3. Kỳ vọng: sync_traversed() khôi phục MinStep/MaxStep; không reset P0 nếu còn lệnh
  4. Red flag: P0 = 0 hoặc mở trùng S0

Kịch bản C — Spread guard

  1. Set max_spread rất thấp (vd. 0.01) trong Config test
  2. Kỳ vọng: on_tick return sớm, không gọi process_cluster
  3. Ý nghĩa: Infrastructure layer chặn trade khi điều kiện thị trường xấu

11. Checklist deliverable Buổi 1

Sinh viên hoàn thành Buổi 1 khi:

  • [ ] Vẽ được sơ đồ 4 phần và chỉ ra method tương ứng trong code
  • [ ] Giải thích thứ tự handle_lockdowntp_logicprocess_cluster trong on_tick
  • [ ] Đọc được file .gv.json và giải thích ý nghĩa key _P0, _LastStep
  • [ ] Chạy demo cold start + restart, ghi log quan sát dashboard
  • [ ] Phân biệt được Config (input) vs GVStore (state runtime) vs cache RAM (buy_cache)
  • [ ] Nêu được vì sao bot là hệ thống quant, không phải script signal

12. FAQ Buổi 1

PyNhiQuaiBot khác gì bot BUY/SELL đơn giản?
Bot quản lý cụm vị thế theo Step, có state persist, guard equity và FSM — không chỉ một lệnh một tín hiệu.

Buổi 1 có cần hiểu hết process_cluster?
Không. Buổi 1 chỉ cần biết đó là Grid Logic, được gọi sau lockdown/TP. Buổi 5–6 sẽ đi sâu Step, Surplus/Hedge.

GVStore JSON có thay được SQLite?
Có — Buổi 2 mở rộng schema. JSON đủ cho lab và port từ GlobalVariable MQ5.

QuantTrade và PyNhiQuaiBot có phải hai khóa?
Không. Cùng một khóa: PyNhiQuaiBot = dự án code; QuantTrade = góc PR Master Quantitative Trading.

Còn bao nhiêu ngày đến khai giảng?
KG 01/08/2026 — 12 buổi chính + 8 bài tập + 5 phụ đạo. FAQ: Lộ trình 12 buổi.

Có cam kết lợi nhuận không?
Không. Mọi ví dụ là tài liệu kỹ thuật; rủi ro thị trường vẫn tồn tại dù code đúng.

13. Buổi tiếp theo và liên kết nội bộ

Buổi Chủ đề Bài đọc thêm
Buổi 2 Global State, Pandas, schema Global State Pandas bot
Buổi 4 Magic 6111/6112, Comment, ID Kiến trúc hai cụm
Buổi 5 Step & X-Level Toán Step X-Level
Buổi 8 FSM STEP_BUSY 5s FSM chống nhồi lệnh

Tóm tắt Buổi 1: PyNhiQuaiBot không phải một vòng while nhồi lệnh — nó là bốn lớp (Infrastructure · Grid · Brain · UX) orchestrated bởi on_tick, với Config tách input, GVStore persist state, và execution adapter tách khỏi chiến thuật. Master Quantitative Trading bắt đầu từ chỗ đó: đo và kiểm soát rủi ro bằng cấu trúc code, không bằng lời hứa lợi nhuận.

Khóa học: Lập trình Python nâng cao Hedging tự động hóa · PyNhiQuaiBot · QuantTrade · KG 01/08/2026 · Hotline 0934 145 100

Khóa PyNhiQuaiBot · QuantTrade · Master Quantitative Trading: Lập trình Python Nâng cao Hedging & Tự động hóa

admin

admin

Biên tập viên, Hướng Nghiệp Dữ Liệu
769 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ệ.