HNData Software - Trading Crypto, Forex, Chứng Khoán
Nghiên cứu ứng dụng công nghệ Blockchain, Tài sản mã hóa & Kinh tế số

Basket Banking TP trong PyNhiQuaiBot: từ lệnh riêng lẻ đến kết quả toàn cụm

Được viết bởi thanhdt vào ngày 12/07/2026 | 25 lượt xem

PyNhiQuaiBot banner

HNData Software

Phân tích realized, floating, StartTime, safety buffer và reset cluster trong engine Basket Banking TP của PyNhiQuaiBot Python Bot Auto Trading.

PyNhiQuaiBot lộ trình 4 phần
Lộ trình 4 phần PyNhiQuaiBot
Phân tích công nghệ bot (kiến trúc · rủi ro · thực thi). Không cam kết lợi nhuận.

Trong grid và hedge, đánh giá từng ticket riêng lẻ thường cho một bức tranh sai. Một số lệnh đã được gặt có lợi nhuận, vài vị thế còn mở đang âm, một số khác đang dương, commission và swap tiếp tục thay đổi. Nếu chỉ nhìn floating hiện tại, hệ thống quên phần kết quả đã ghi nhận. Nếu chỉ nhìn lịch sử, hệ thống bỏ qua rủi ro đang mở. PyNhiQuaiBot dùng Basket Banking TP để cộng hai thế giới đó thành kết quả của một cluster rồi quyết định khi nào kết thúc chu kỳ.

Đây là một module nền tảng của Python Bot Auto Trading. Nó không dự đoán hướng giá. Nó làm kế toán chiến lược: xác định deal nào thuộc cluster, tính realized từ mốc bắt đầu, cộng floating của position hiện tại, so với target và safety buffer, sau đó đóng toàn bộ Magic và reset state.

Nội dung thuộc Header Site HNDATA, dùng để đào tạo kỹ thuật. Basket TP không bảo đảm cluster sẽ đạt target. Trong trend kéo dài, gap, spread giãn hoặc thiếu margin, drawdown có thể lớn trước khi target xuất hiện. Không có cam kết lợi nhuận; hãy kiểm thử demo và dùng giới hạn rủi ro độc lập.

1. Vì sao take profit từng lệnh chưa đủ?

Flowchart PyNhiQuaiBot
Luồng kỹ thuật Python Bot Auto Trading

Một chiến lược lưới có thể chấp nhận một số lệnh âm trong khi các lệnh khác được thu hoạch. Mục tiêu của cluster không phải bắt mọi ticket đều xanh cùng lúc, mà là kết quả tổng từ đầu chu kỳ đạt mức định trước. Vì vậy:

cluster_total = realized_since_start + current_floating

Realized gồm profit, swap và commission của deal đã hoàn tất. Floating cũng gồm profit, swap và commission theo dữ liệu position. Khi cluster_total >= target, engine kích hoạt reset.

Ví dụ cluster đã gặt 180 đơn vị tiền, vị thế còn mở đang -35, tổng là 145. Nếu target cộng safety là 160, chưa đóng cụm. Khi floating cải thiện lên -15, tổng thành 165 và đạt điều kiện. Nếu dashboard chỉ hiển thị floating -15, người vận hành có thể tưởng cluster đang lỗ dù chu kỳ đã banking 180.

Ngược lại, realized 180 không có nghĩa đã an toàn nếu floating là -500. Kế toán hai phần là bắt buộc.

2. Hai sổ cái: realized và floating

Realized được lấy từ history_deals_get(StartTime, now). Bot lọc deal theo symbol và Magic rồi cộng:

deal.profit + deal.swap + deal.commission

Floating được tính từ positions_get(symbol) rồi lọc Magic:

position.profit + position.swap + position.commission

Việc lọc cả symbol lẫn Magic tránh lấy nhầm giao dịch của bot khác. StartTime giới hạn lịch sử vào chu kỳ hiện tại. Nếu thiếu StartTime, realized từ chu kỳ cũ có thể bị cộng lại và cluster chốt sai.

Trong MetaTrader5, cần hiểu deal, order và position không đồng nghĩa. Một order có thể tạo nhiều deal; một position có thể được partial close bằng nhiều deal. Kế toán nên dựa trên deal history nhưng phải kiểm thử cách broker ghi commission, swap và entry/exit. Có broker ghi commission ở deal mở, deal đóng hoặc cả hai.

3. Cache realized và cờ need_scan

Dual Cluster

Magic Buy/Sell tách state & basket.

Risk Guard

Lockdown equity + bias filter.

MT5 Python

order_send + FSM chống lệnh trùng.

Quét toàn bộ history ở mỗi tick tốn tài nguyên. PyNhiQuaiBot có biến buy_realized, sell_realizedneed_scan cho từng cluster. Khi cần, bot quét history rồi cache tổng. Khi basket reset, hai cờ được bật lại để vòng sau quét chu kỳ mới.

Cache tạo hiệu năng nhưng đặt ra câu hỏi freshness. Nếu trailing plow hoặc gặt X vừa đóng deal sau lần quét, realized cache phải được cập nhật hoặc quét lại. Kiến trúc production có ba cách:

  1. đặt need_scan = True sau mọi close thành công;
  2. cộng delta từ deal transaction rồi reconciliation định kỳ;
  3. quét một cửa sổ nhỏ từ deal cuối cùng.

Nếu cache không được làm mới đúng lúc, basket total có thể tạm thấp hơn thực tế. Điều này thường làm chốt muộn, nhưng vẫn là sai số cần xử lý. Test tích hợp phải tạo deal mới sau lần scan và xác minh total cập nhật.

4. Target, multiplier và safety buffer

Mỗi cluster có basket TP riêng:

buy_target = buy_basket_tp × buy_tp_mult + basket_safety
sell_target = sell_basket_tp × sell_tp_mult + basket_safety

Multiplier cho phép scale target mà không sửa giá trị cơ sở. Safety buffer cộng thêm một khoảng trước khi kích hoạt. Mục đích thường là bù biến động giữa lúc kiểm tra và lúc đóng nhiều position, nhưng nó không bảo đảm kết quả cuối vẫn trên target.

Khi đóng một basket gồm nhiều ticket, giá có thể đổi, spread có thể giãn và một số close có thể thất bại. Safety 10 không đủ hay quá lớn tùy lot, symbol, số position và thanh khoản. Nên ước lượng từ:

  • tổng commission dự kiến;
  • spread percentile;
  • slippage lịch sử;
  • số ticket;
  • thời gian đóng tuần tự;
  • tick value và gross volume.

Một safety tuyệt đối không tự scale. Sản phẩm nâng cao có thể dùng max(fixed_buffer, exposure_based_buffer).

5. Điều kiện chốt cụm

Engine chỉ chốt khi target dương và total đạt hoặc vượt target. Kiểm tra target dương ngăn cấu hình 0 vô tình đóng ngay. Khi đạt, bot log Magic, total và target rồi gọi reset_cluster.

Điểm quan trọng là điều kiện đọc “lớn hơn hoặc bằng”, không yêu cầu floating riêng dương. Một cluster có realized đủ lớn có thể chốt các vị thế còn lại đang âm mà tổng chu kỳ vẫn đạt mục tiêu kế toán tại thời điểm kiểm tra.

Tuy nhiên, số total là snapshot, không phải giá cam kết. Từ snapshot tới khi từng request close được broker xử lý, PnL có thể thay đổi. Dashboard và báo cáo phải phân biệt:

  • trigger total;
  • estimated total;
  • final realized after all closes.

Chỉ final realized từ history sau khi reset mới là kết quả kiểm toán.

6. Reset cluster là một transaction logic

Reset không chỉ đóng lệnh. PyNhiQuaiBot:

  1. gọi đóng mọi position thuộc Magic;
  2. tăng ResetCount;
  3. đặt StartTime mới;
  4. xóa LastStep, LastX, MinStep, MaxStep, HitXCount, P0, HadOrders và LOCKED;
  5. xóa các cờ X_CLOSED, PLOW_CLOSED, PLOW_STAGE và FSM;
  6. lưu JSON;
  7. đánh dấu cần quét realized.

Đây là ranh giới giữa chu kỳ cũ và mới. Nếu một phần reset thất bại, state có thể nguy hiểm. Ví dụ một ticket chưa đóng nhưng P0 đã bị xóa; tick sau bot coi vị thế cũ như thành phần chu kỳ mới.

Trong production, reset nên là state machine:

RUNNING -> CLOSE_REQUESTED -> VERIFY_EMPTY -> ARCHIVE -> RESET_STATE -> READY

Chỉ chuyển sang RESET_STATE khi xác minh không còn position thuộc Magic. Nếu close fail, giữ trạng thái CLOSING, retry có giới hạn và cảnh báo. Không nên xóa bối cảnh trước khi broker xác nhận basket đã trống.

7. Rủi ro đóng tuần tự

Hàm đóng toàn Magic lặp qua danh sách position. Đây là cách đơn giản và tương thích, nhưng không atomic. Ticket đầu có thể đóng, ticket sau thất bại. Trong thời gian đó, bias và floating thay đổi.

Các biện pháp giảm rủi ro:

  • snapshot ticket trước khi đóng;
  • ưu tiên phía có exposure ròng lớn;
  • kiểm tra market open và tick hợp lệ;
  • normalize volume;
  • log retcode từng ticket;
  • retry theo mã lỗi có thể phục hồi;
  • không retry lỗi cấu hình;
  • xác minh positions còn lại;
  • khóa mở lệnh mới trong trạng thái CLOSING;
  • tính final realized sau hoàn tất.

Không có “close all” thật sự atomic qua Python API cho mọi broker. Engine phải chấp nhận partial completion và có đường phục hồi.

8. StartTime và ranh giới chu kỳ

StartTime được lưu trong JSON theo namespace login, symbol, Magic. Khi reset, nó được đặt về thời điểm hiện tại cộng một khoảng nhỏ. Ý tưởng là loại các deal đóng của chu kỳ trước khỏi lần scan mới.

Ranh giới thời gian có các vấn đề:

  • độ phân giải timestamp;
  • timezone terminal và Python;
  • deal đến muộn;
  • clock VPS lệch;
  • khoảng +1 giây có thể bỏ deal đầu chu kỳ mới nếu mở quá nhanh;
  • restart giữa close và cập nhật StartTime.

Thiết kế chắc chắn hơn có thể lưu deal ticket cuối cùng hoặc archive cycle ID trong database. Tuy nhiên MetaTrader comment bị giới hạn độ dài, nên mapping cycle cần giữ ở state local và reconciliation.

Khi dùng timestamp, đồng bộ thời gian VPS bằng NTP, log UTC và kiểm thử broker history trên tài khoản thật/demo cùng server.

9. Banking theo Magic, không theo cảm xúc

Basket TP giúp tự động hóa một quyết định thường bị cảm xúc chi phối: cluster đã đạt mục tiêu tổng thì kết thúc chu kỳ. Nếu người dùng nhìn từng ticket đỏ và không muốn đóng, họ có thể bỏ lỡ tổng kết quả đã đạt. Nếu chỉ nhìn vài ticket xanh, họ có thể chốt quá sớm trong khi inventory còn lớn.

Engine dựa trên công thức và namespace. Nhưng target phải là quyết định quản trị rủi ro, không phải con số hứa hẹn thu nhập. Target quá cao có thể làm cluster tồn tại lâu và tích lũy exposure. Target quá thấp có thể tăng turnover và chi phí.

Các chỉ số đánh giá target:

  • thời gian trung vị của một cycle;
  • percentile 95 thời gian giữ;
  • gross exposure cực đại;
  • drawdown trong cycle;
  • số ticket lúc trigger;
  • chênh lệch trigger total và final realized;
  • turnover và commission;
  • số cycle bị lockdown;
  • cycle chưa hoàn tất khi kết thúc test.

Không loại các cluster “kẹt” khỏi báo cáo. Survivorship bias khiến kết quả banking trông tốt giả tạo.

10. Quan hệ với gặt X và trailing plow

X và plow tạo realized từng phần. Basket cộng các khoản đó vào ngân hàng của cycle. Có thể hình dung:

  • harvest là dòng tiền gửi nhỏ;
  • floating là giá trị tạm tính của inventory;
  • basket target là mức đóng sổ;
  • reset là kết thúc kỳ kế toán.

Nếu harvest quá tích cực, realized tăng nhanh nhưng các vị thế bất lợi có thể bị giữ lại, làm floating âm. Basket total mới cho biết hai phần có bù nhau hay không. Đây là lý do không quảng bá win rate của lệnh harvest như hiệu quả toàn hệ thống.

Cờ X/plow bị xóa khi reset vì step có thể được tái sử dụng trong cycle mới. Stage cũ không còn ý nghĩa khi P0 mới được tạo.

11. Quan hệ với bias và lockdown

Mỗi lần harvest hoặc close basket làm volume thay đổi. Khi basket trigger, cluster nên ngừng mở lệnh trước khi đóng để bias filter không tạo ticket mới giữa quá trình.

Lockdown lại đặt cluster vào trạng thái frozen khi equity thấp. Trong PyNhiQuaiBot, logic cluster chỉ tiếp tục TP/process nếu không frozen. Điều này có nghĩa basket check có thể không chạy trong nhánh frozen tùy luồng gọi. Chính sách cần được xác định rõ: khi full hedge, có tiếp tục theo dõi basket và cho phép close-all nếu total đạt không? Hay chỉ người vận hành unlock? Mỗi lựa chọn có trade-off.

Production nên hiển thị state precedence:

EMERGENCY > CLOSING > LOCKED > PAUSED > RUNNING

Mọi module đọc cùng state để tránh basket muốn close trong khi lockdown muốn giữ.

12. Dashboard cho Basket Banking

Một widget basket cần hiển thị riêng cho từng Magic:

  • cycle ID hoặc ResetCount;
  • StartTime và tuổi cycle;
  • realized;
  • floating;
  • total;
  • base target;
  • multiplier;
  • safety;
  • khoảng cách còn lại;
  • số position;
  • gross volume;
  • trạng thái RUNNING/CLOSING/LOCKED;
  • lần scan history cuối;
  • data freshness.

Thanh tiến độ chỉ có ý nghĩa khi total dương và target cố định. Nếu total âm sâu, nên hiển thị số thật thay vì ép phần trăm 0. Cảnh báo màu không được che dấu đơn vị tiền account.

Báo cáo cycle sau reset nên lưu trigger snapshot, final result, commission, duration, max exposure và lỗi execution. JSON state hiện tại phục vụ runtime; lịch sử phân tích nên vào SQLite, PostgreSQL hoặc log append-only, không ghi dồn vào file state.

13. Độ chính xác của commission, swap và currency

Không nên giả định mọi field luôn có cấu trúc giống nhau trên mọi broker. Kiểm tra:

  • currency của account;
  • profit currency của symbol;
  • terminal đã convert chưa;
  • commission âm hay dương;
  • swap ghi trên position hay deal;
  • partial close phân bổ commission ra sao;
  • history range có đủ deal mở và đóng không.

Một unit test mock API giúp kiểm tra công thức. Một integration test trên demo xác nhận broker-specific behavior. Đối chiếu tổng của engine với report MT5 sau cùng.

Nếu sai lệch vượt tolerance, bot nên cảnh báo và không tự reset dựa trên số không đáng tin, tùy chính sách rủi ro.

14. Hiệu năng quét history

History càng dài, truy vấn càng nặng. StartTime giới hạn phạm vi nhưng cluster kéo dài nhiều ngày vẫn có nhiều deal. Có thể tối ưu:

  • cache realized;
  • lưu last deal time/ticket;
  • quét incremental;
  • xử lý transaction event;
  • reconciliation toàn phần theo chu kỳ;
  • giới hạn tần suất scan;
  • tách dashboard polling khỏi trading loop.

Không tối ưu bằng cách bỏ commission hoặc chỉ cộng deal cuối. Đúng trước, nhanh sau. Vòng trading không nên bị dashboard hoặc truy vấn lịch sử chặn quá lâu.

15. Tình huống lỗi cần test

History API trả None

Engine phải dùng danh sách rỗng hoặc giữ cache cũ kèm cờ stale, không coi realized chắc chắn bằng 0 mà không cảnh báo.

Một close fail

Không reset state như basket đã trống. Chuyển CLOSING, giữ ticket còn lại và retry theo chính sách.

Process crash giữa reset

Journal state phải cho biết giai đoạn nào dang dở. Khi restart, reconcile positions trước.

Người dùng đóng lệnh thủ công

History vẫn phải được tính vào realized nếu Magic/symbol đúng. HadOrders phát hiện lưới trống và reset theo quy tắc.

Đổi Magic giữa cycle

Đây là migration nguy hiểm. Bot mới không nhìn thấy position cũ. Cần dừng, archive và xử lý thủ công có kế hoạch.

Spread giãn khi trigger

Final realized có thể thấp hơn trigger total. Đo slippage basket và điều chỉnh buffer dựa dữ liệu.

Clock thay đổi

StartTime query có thể bỏ hoặc lặp deal. Dùng UTC, NTP và kiểm tra monotonic logic cho timeout.

16. Backtest Basket Banking đúng cách

Backtest phải mô phỏng execution, không chỉ giá đóng nến. Basket có thể trigger giữa nến, nhiều lệnh đóng ở giá khác nhau. Dùng tick data nếu có, spread động, commission và swap.

Báo cáo theo cycle:

  1. thời gian bắt đầu/kết thúc;
  2. realized trước trigger;
  3. floating tại trigger;
  4. target và safety;
  5. final realized;
  6. max drawdown;
  7. max gross exposure;
  8. max position count;
  9. số harvest X/plow;
  10. số reject mô phỏng;
  11. trạng thái kết thúc dữ liệu.

Các cycle chưa đóng ở cuối test phải mark-to-market và xuất riêng. Không coi chúng là 0 hoặc bỏ đi.

Walk-forward giúp giảm overfitting. Chọn target trên giai đoạn train, đánh giá trên giai đoạn sau và lặp. Stress test target trong trend một chiều kéo dài, gap cuối tuần và spread cao.

17. Target theo tiền, lot hay equity?

Target tuyệt đối dễ hiểu nhưng không scale. Các mô hình khác:

  • tiền cố định mỗi cycle;
  • tiền trên mỗi 0,01 lot cơ sở;
  • phần trăm balance tại cycle start;
  • phần trăm equity;
  • target theo gross exposure;
  • target động theo volatility;
  • target có trần và sàn.

Target động phức tạp hơn và có nguy cơ “dời cột gôn”. Nếu target tăng trong lúc cluster gần đạt, bot có thể không bao giờ chốt. Cần freeze target tại cycle start và lưu vào state. Mọi thay đổi cấu hình chỉ áp dụng cycle sau, trừ khi có thao tác quản trị được audit.

18. An toàn dữ liệu và audit

State runtime cần atomic write: ghi file tạm, flush, rồi replace. Có checksum hoặc backup phiên gần nhất. Mỗi reset ghi event append-only với cycle ID. Log phải bao gồm:

  • timestamp UTC;
  • login, symbol, Magic;
  • cycle ID;
  • realized, floating, total;
  • target;
  • ticket close và retcode;
  • state transition;
  • config version.

Không log password MT5. Phân quyền file để user khác trên VPS không sửa state. Backup phải mã hóa nếu chứa thông tin nhạy cảm về tài khoản.

Audit trả lời được tại sao cluster đóng lúc đó và final khác trigger bao nhiêu. Nếu không có audit, tối ưu safety buffer chỉ là phỏng đoán.

19. Checklist triển khai

  • Magic từng cluster duy nhất;
  • StartTime được lưu bền;
  • history lọc symbol và Magic;
  • realized gồm profit, swap, commission;
  • floating dùng cùng quy ước;
  • cache được invalidated sau close;
  • target freeze theo cycle;
  • safety được đo từ dữ liệu;
  • basket trigger khóa mở mới;
  • close-all có verify empty;
  • partial failure có state CLOSING;
  • reset chỉ sau xác minh;
  • JSON atomic và có backup;
  • dashboard báo stale;
  • final realized được reconciliation;
  • test partial close;
  • test restart giữa reset;
  • test history None;
  • test spread giãn;
  • không quảng bá target như lợi nhuận bảo đảm.

20. Đối soát cuối ngày và báo cáo theo cycle

Basket engine chạy theo cycle, còn vận hành doanh nghiệp thường cần báo cáo theo ngày. Hai ranh giới không nên bị trộn. Một cycle có thể bắt đầu hôm trước và kết thúc hôm sau; một ngày có thể chứa nhiều cycle. Báo cáo cuối ngày vì thế phải lấy dữ liệu deal từ broker và liên kết với cycle ID, không tự coi thời điểm 0 giờ là reset chiến lược.

Quy trình đối soát nên xuất balance đầu ngày, realized theo từng Magic, commission, swap, deposit/withdrawal, floating cuối ngày và balance cuối ngày. Mọi chênh lệch giữa tổng event nội bộ với statement MT5 phải được điều tra. Các nguyên nhân thường gặp gồm deal thủ công, lệnh từ bot khác, timezone, partial close và commission ghi ở thời điểm khác dự kiến.

Cycle report phục vụ phân tích chiến lược; daily report phục vụ kiểm toán vận hành. Cả hai đều không nên sửa ngược state runtime. Nếu phát hiện sai, tạo adjustment record có lý do thay vì thay file JSON để làm số khớp.

21. Thiết kế target khi quy mô lot thay đổi

Khi lot cơ sở tăng, target cố định có thể đạt nhanh hơn nhưng exposure và drawdown cũng tăng. Không được suy luận rằng tăng lot chỉ làm rút ngắn cycle. Phân phối slippage, gross volume và margin đều thay đổi.

Một quy tắc quản trị là đóng băng bộ lot + target + limits thành profile được version hóa. Mỗi profile phải qua test riêng. Khi chuyển profile, chỉ áp dụng ở cycle mới và lưu version vào journal. Nhờ đó, báo cáo biết cycle dùng cấu hình nào và không so sánh hai giai đoạn khác quy mô như cùng điều kiện.

Nếu target được biểu diễn theo phần trăm equity, cần lưu equity tại cycle start. Không lấy equity live làm mẫu số liên tục vì target sẽ dịch chuyển theo floating, tạo feedback khó hiểu. Dù dùng công thức nào, luôn có hard cap về gross exposure và thời gian cycle để cảnh báo.

22. Câu hỏi thường gặp

Basket TP có giống đóng tất cả khi floating dương không?

Không. Nó cộng realized từ đầu cycle với floating hiện tại rồi so target. Floating riêng có thể âm tại thời điểm trigger.

Safety buffer có bảo đảm final đạt base target?

Không. Nó chỉ tạo khoảng đệm. Gap, slippage, reject và tốc độ đóng có thể làm final thấp hơn.

Vì sao cần StartTime?

Để không cộng lại deal của cycle trước. StartTime là ranh giới kế toán của cluster.

Hai cluster có chung basket không?

Trong kiến trúc này, mỗi Magic có realized, floating và target riêng. Muốn basket toàn account cần risk manager khác.

Có thể thay target khi bot đang chạy?

Về kỹ thuật có thể, nhưng nên freeze theo cycle và áp dụng thay đổi ở cycle sau để tránh hành vi khó kiểm toán.

Nếu đóng một ticket thất bại thì sao?

Engine production phải giữ trạng thái CLOSING, xác minh ticket còn lại, retry có giới hạn và cảnh báo. Không được xóa state như đã hoàn tất.

Basket Banking có bảo đảm thu nhập đều?

Không. Cycle có thể kéo dài, drawdown lớn hoặc không đạt target. Không có bảo đảm lợi nhuận.

23. Kết luận

Basket Banking TP biến PyNhiQuaiBot từ một tập lệnh đóng ticket thành hệ thống kế toán theo chu kỳ. Realized ghi nhận thành quả đã gặt; floating phản ánh inventory còn mở; target và safety tạo điều kiện kết thúc; reset cluster mở một sổ mới. Khi kết hợp với X, trailing plow, bias và JSON state, engine có thể giải thích hành vi ở cấp lệnh lẫn cấp cụm.

Muốn vận hành tin cậy, cần coi reset như transaction nhiều bước, xác minh broker đã đóng hết, làm mới cache realized và lưu audit. Target không phải cam kết; nó là điều kiện phần mềm trong một thị trường không chắc chắn.

Tìm hiểu giải pháp tại PyNhiQuaiBot HNDATA và trao đổi phạm vi triển khai tại Báo giá HNDATA.

Tuyên bố rủi ro: HNDATA không cam kết lợi nhuận, tỷ lệ thắng hoặc thời gian đạt Basket TP. Backtest và demo không bảo đảm kết quả tương lai. Người dùng chịu trách nhiệm về vốn, cấu hình, broker và vận hành.

Lockdown/Guard là lớp bảo vệ vận hành — không loại bỏ rủi ro thị trường.
Dual cluster · risk engine · MT5 Python · VPS

Xem Bot PyNhiQuaiBotNhận báo giá

Bước tiếp theo

Triển khai cùng HNData