| Basket TP Buy/Sell trong PyNhiQuaiBot: chốt cụm bằng realized + floating và BasketSafety

Được viết bởi thanhdt vào ngày 12/07/2026 lúc 17:49 | 5 lượt xem

Trong một bot quản lý nhiều vị thế, chốt lời từng ticket chưa nói lên kết quả của cả chiến dịch. Một số lệnh đã đóng có thể tạo lãi thực nhận, trong khi các lệnh còn mở vẫn âm; hoặc ngược lại, floating đang dương nhưng phí khi đóng khiến kết quả cuối thấp hơn mục tiêu. Basket TP Python Bot giải quyết bài toán bằng cách xem toàn bộ cụm Buy hoặc Sell như một “rổ” thống nhất: cộng lợi nhuận đã thực hiện từ đầu chu kỳ với lãi/lỗ thả nổi hiện tại, so sánh với mục tiêu có vùng an toàn rồi đóng và reset cả cụm.

Trong PyNhiQuaiBot, Basket TP không chỉ là một phép cộng. Module phải xác định đúng phạm vi theo symbol, Magic Number và thời điểm bắt đầu; phải phân biệt realized với floating; phải tránh cộng trùng lịch sử; phải đóng được nhiều position trong điều kiện giá thay đổi; và phải reset state sao cho vòng mới không kế thừa dữ liệu cũ. Đây là ví dụ điển hình cho việc một quy tắc giao dịch ngắn gọn trở thành bài toán kiến trúc khi triển khai bằng Python Bot Auto Trading.

Bài viết phân tích thiết kế hiện tại của Nhi Quái V6, các giả định cần kiểm chứng và hướng nâng cấp an toàn. Nội dung phục vụ giáo dục kỹ thuật, không phải tín hiệu mua bán, không bảo đảm lợi nhuận và không loại bỏ rủi ro thị trường.

1. Basket TP khác take profit từng lệnh như thế nào?

Take profit truyền thống gắn mục tiêu vào một position. Khi giá chạm mức, position đó được đóng. Cách này rõ ràng với chiến lược một lệnh, nhưng chưa đủ cho grid hoặc hedge nhiều tầng vì mỗi ticket đóng một vai trò khác nhau.

Basket TP gắn mục tiêu vào kết quả kinh tế của cả cụm. Cụm có thể chứa:

  • lệnh Buy và Sell tại nhiều Step;
  • ticket đã chốt bằng X-Level;
  • ticket đã thu quân bằng trailing plow;
  • position hedge còn mở;
  • commission, swap và các deal đóng một phần;
  • trạng thái P0, MinStep, MaxStep và các cờ đã chốt.

Khi tổng giá trị ròng của chiến dịch đạt mục tiêu, hệ thống đóng phần còn lại rồi khởi tạo chu kỳ mới. Cách nhìn này cho phép một lệnh đã bank lợi nhuận bù cho floating loss có kiểm soát của các lệnh khác. Nhưng nó cũng tạo nguy cơ nếu cách tính history sai: chỉ cần cộng thiếu phí hoặc lấy nhầm deal của chu kỳ trước, bot có thể chốt quá sớm.

Công thức cốt lõi

Trong mã Nhi Quái V6:

total_net = realized_since_start + floating_current

target = basket_tp * tp_mult + basket_safety

if total_net >= target and target > 0:
    reset_cluster()

Cụm Buy dùng buy_basket_tpbuy_tp_mult. Cụm Sell dùng sell_basket_tpsell_tp_mult. basket_safety được cộng vào mục tiêu của cả hai.

Ví dụ minh họa:

BuyBasketTP = 150
BuyTPMult   = 1,0
BasketSafety = 10
target       = 160

realized = 210
floating = -42
total_net = 168

Điều kiện đạt vì 168 lớn hơn hoặc bằng 160. Bot yêu cầu reset cụm. Đây chỉ là mô phỏng công thức, không phải mức lợi nhuận kỳ vọng hoặc cấu hình khuyến nghị.

2. Tại sao phải cộng realized và floating?

Nếu chỉ nhìn floating, bot bỏ quên phần lợi nhuận đã “bank” từ các ticket chốt trước. Một cụm có floating -30 nhưng đã realized +200 thực chất đang có tổng +170 trong phạm vi chu kỳ. Ngược lại, floating +100 chưa chắc đủ bù realized -150 nếu trước đó có các deal lỗ.

Phân biệt:

  • Realized P/L: kết quả từ các deal đã đóng, không còn thay đổi theo giá nhưng có thể bị ghi nhận sai nếu phạm vi history sai.
  • Floating P/L: kết quả của position đang mở, thay đổi từng tick và chỉ là ước lượng trước khi đóng thực tế.
  • Total net của basket: tổng hai phần sau khi tính profit, swap và commission theo cách nhất quán.

Ở bản Python, history được đọc bằng mt5.history_deals_get(start, time.time()). Mỗi deal đúng symbol và Magic được cộng:

deal.profit + deal.swap + deal.commission

Floating của positions hiện tại cũng cộng:

position.profit + position.swap + position.commission

Việc dùng cùng ba thành phần giúp định nghĩa net nhất quán hơn so với chỉ lấy profit. Tuy nhiên, tùy broker và package, commission có thể nằm ở entry deal, exit deal hoặc trường position không phản ánh đầy đủ phí cuối cùng. Người phát triển phải kiểm tra dữ liệu thực tế của tài khoản, không mặc định mọi broker ghi giống nhau.

Realized là “bank”, nhưng không phải tiền tách biệt

Dashboard có thể gọi realized là “Lãi Bank”. Tên này giúp hình dung phần đã đóng, nhưng số tiền vẫn thuộc equity chung của tài khoản. Nếu tài khoản có strategy khác cùng lúc, equity tổng có thể bị ảnh hưởng. Basket TP chỉ lọc history theo Magic và symbol; nó không cô lập tiền trong một ví riêng.

Vì vậy, cần tránh diễn giải “bank” như một khoản chắc chắn dành riêng cho cụm. Nó là số liệu kế toán nội bộ của chiến dịch, dựa trên tag và thời gian.

3. Ranh giới cụm: symbol, Magic và StartTime

Một Basket TP đúng phải trả lời ba câu hỏi:

  1. Deal thuộc symbol nào?
  2. Deal thuộc cụm nào?
  3. Deal thuộc chu kỳ nào?

PyNhiQuaiBot lọc symbol hiện tại và Magic Number. Magic Buy và Sell khác nhau nên history của hai cụm không trộn vào nhau. StartTime đánh dấu đầu chu kỳ để các deal trước lần reset gần nhất không bị cộng lại.

Key lưu trữ có dạng prefix theo bot, symbol, account login và Magic, nối _StartTime. Khi reset, bot đặt StartTime thành thời gian hiện tại cộng một giây. Ý đồ là bỏ qua deal đóng phát sinh trong quá trình reset khỏi chu kỳ kế tiếp.

Tại sao cộng một giây?

Trong lúc reset_cluster() đóng positions, các deal exit được ghi vào lịch sử. Nếu StartTime mới trùng đúng timestamp của các deal đó và API chọn biên thời gian bao gồm cả hai đầu, lần scan sau có thể cộng kết quả của vòng vừa kết thúc vào vòng mới. Dịch StartTime thêm một giây là cách đơn giản để tạo ranh giới.

Nhưng cách này phụ thuộc độ phân giải timestamp và clock. Một thiết kế chắc chắn hơn nên lưu last_deal_ticket, millisecond timestamp hoặc cycle ID; khi scan, chỉ nhận các deal có ID lớn hơn watermark. Thời gian vẫn hữu ích để truy vấn, nhưng không nên là khóa duy nhất nếu API có thể trả nhiều deal cùng giây.

Magic không bảo vệ khỏi mọi nhầm lẫn

Nếu hai instance vô tình dùng cùng Magic, cùng symbol và cùng account, history sẽ bị trộn. Nếu người vận hành đổi Magic giữa chu kỳ, bot mất liên kết với deal cũ. Nếu broker hoặc thao tác thủ công tạo deal không mang Magic mong đợi, kết quả không được tính.

Do đó, khởi tạo phải kiểm tra tính duy nhất của namespace và log đầy đủ login/symbol/magic/cycle_start. Một hệ thống lớn nên cấp strategy instance ID rõ ràng thay vì để người dùng tự nhập số ngẫu nhiên.

4. Cơ chế cache realized trong PyNhiQuaiBot

Quét toàn bộ history trên mỗi tick là tốn tài nguyên. Bản Python dùng:

  • buy_realizedsell_realized để giữ tổng hiện tại;
  • need_scan_buyneed_scan_sell để quyết định có quét lại lịch sử hay không.

Lần đầu check_basket_tp(magic) chạy với need_scan = True, bot đọc deals và tính realized. Sau đó cờ chuyển false, các tick kế tiếp chỉ tính floating từ positions. Khi reset cụm, hai cờ được đặt true để lần sau tải lại.

Trong MQ5, OnTradeTransaction đặt cả hai cờ scan về true mỗi khi có deal mới. Đây là điểm event-driven quan trọng: realized thay đổi khi phát sinh deal, không phải khi giá chỉ chạy mà chưa đóng lệnh. Bản Python không có callback MT5 giống EA, nên cần cơ chế tương đương trong vòng lặp.

Khoảng trống cần chú ý trong bản Python

Ở mã port hiện tại, need_scan được bật lại chủ yếu khi reset. Nếu tp_logic() hoặc trailing plow đóng một ticket, realized thực tế thay đổi nhưng cờ cache có thể vẫn false. Floating giảm vì position biến mất, trong khi phần realized mới chưa được cộng vào buy_realized hoặc sell_realized. Tổng basket tạm thời bị thấp hơn thực tế cho đến khi một sự kiện khác buộc scan.

Đây là bài học quan trọng khi port event-driven EA sang Python polling: không thể chỉ dịch từng hàm; phải thay thế luôn cơ chế phát hiện event. Sau bất kỳ close_ticket() thành công nào, nên:

  • đánh dấu need_scan cho đúng Magic;
  • hoặc cập nhật realized từ deal xác nhận;
  • hoặc dùng watermark để ingest deal mới theo từng vòng.

Nếu không, Basket TP có thể phản ứng trễ. Phản ứng trễ không nhất thiết luôn gây lỗ, nhưng nó làm hành vi khác với đặc tả.

5. BasketSafety thực sự làm gì?

BasketSafety được cộng vào mục tiêu:

target = base_target + safety

Nếu mục tiêu cơ sở là 150 và safety là 10, hệ thống chỉ bắt đầu reset khi total net đạt 160. Khoảng thêm này nhằm hấp thụ một phần chi phí và biến động giữa lúc kiểm tra với lúc đóng xong toàn bộ positions.

Tên “Safety” không có nghĩa 10 USD chắc chắn đủ. Chi phí thực tế phụ thuộc:

  • số lượng positions cần đóng;
  • spread tại thời điểm reset;
  • slippage và thanh khoản;
  • commission exit chưa phản ánh trong floating;
  • swap mới cập nhật;
  • tốc độ vòng lặp;
  • giá biến động trong thời gian đóng tuần tự;
  • partial fill hoặc requote.

Vì vậy, BasketSafety là buffer vận hành, không phải bảo hiểm lợi nhuận. Buffer cố định có thể phù hợp lúc cụm nhỏ nhưng thiếu khi có 100 position. Thiết kế nâng cao có thể tính động:

estimated_exit_cost =
    spread_cost_by_position
  + expected_commission
  + slippage_allowance
  + uncertainty_buffer

target = base_target + estimated_exit_cost

Ước lượng vẫn có sai số. Mục tiêu là minh bạch giả định, không tuyên bố bảo đảm.

6. Buy Basket và Sell Basket độc lập nhưng dùng chung tài khoản

Nhi Quái V6 có buy_basket_tp, buy_tp_mult, sell_basket_tp, sell_tp_mult. Cách tách này cho phép Step, X và mục tiêu khác nhau theo cụm. Mỗi cụm chỉ cộng positions mang Magic của mình.

Tuy nhiên, cả hai vẫn:

  • giao dịch cùng symbol;
  • dùng equity và margin chung;
  • chịu spread chung;
  • có thể giữ vị thế đối ứng;
  • ảnh hưởng lẫn nhau về free margin;
  • được xử lý tuần tự trong cùng vòng tick.

Nếu cụm Buy đạt Basket TP và reset, việc đóng các position của nó có thể làm gross/net exposure tổng symbol thay đổi ngay trước khi cụm Sell được xử lý. Snapshot được lấy ở thời điểm khác nhau, nên thứ tự gọi hàm có ý nghĩa.

Một kiến trúc production có thể tạo account snapshot duy nhất cho mỗi cycle, sau đó lập kế hoạch action cho cả hai cụm, kiểm tra xung đột và thực thi theo priority. Nếu chỉ gọi từng cụm độc lập, cần ít nhất log rõ thứ tự và reconcile sau mỗi batch đóng.

7. Điều gì xảy ra khi đạt target?

Khi total >= target, check_basket_tp() gọi reset_cluster(magic). Hàm reset:

  1. duyệt toàn bộ position đúng Magic và đóng;
  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 key theo tầng như X_CLOSED, PLOW_CLOSED, PLOW_STAGE và FSM;
  6. lưu GVStore.

Đây là một transaction nghiệp vụ nhiều bước, nhưng mã hiện tại không có transaction nguyên tử. Nếu một position đóng thất bại, hàm vẫn có thể tiếp tục xóa state. Cụm còn sót position nhưng P0 và dấu tầng bị mất, tạo điều kiện cho vòng mới hiểu sai.

Reset không nên đồng nghĩa “đã đóng hết”

Một reset an toàn cần ít nhất hai pha:

RESET_REQUESTED
  -> CLOSING_POSITIONS
  -> VERIFY_EMPTY
  -> CLEAR_STATE
  -> NEW_CYCLE

Chỉ sau khi positions(magic) rỗng mới xóa state chiến dịch. Nếu còn ticket:

  • retry theo chính sách;
  • giữ state cũ;
  • dừng mở mới;
  • cảnh báo danh sách ticket và mã lỗi;
  • không đặt StartTime vòng mới.

Nếu process chết giữa chừng, startup reconcile phải nhận ra state CLOSING_POSITIONS và tiếp tục đóng hoặc chờ người vận hành. Đây là chỗ state machine đem lại giá trị rõ rệt.

8. Race condition khi chốt cụm

Trong vòng loop, Basket TP được kiểm tra trước core grid. Nhưng nếu hệ thống có nhiều thread hoặc nhiều instance, một worker có thể đang gửi lệnh mới đúng lúc worker khác reset. Kết quả là position mới xuất hiện sau khi danh sách đóng đã được chụp.

Giải pháp gồm:

  • khóa cụm ở trạng thái RESETTING trước khi gửi close;
  • mọi đường order_send phải kiểm tra guard này;
  • sử dụng mutex/process lock cho một strategy instance;
  • gắn cycle ID vào intent;
  • sau khi đóng, quét lại broker cho đến khi rỗng hoặc timeout;
  • không cho loop tiếp theo mở mới trước NEW_CYCLE.

FSM 5 giây theo Step giúp chống nhồi lệnh tại tầng, nhưng không thay thế cluster-level lock. Hai loại khóa có phạm vi khác nhau.

Snapshot floating có thể cũ ngay lập tức

Floating được tính từ position snapshot. Sau đó giá thay đổi trước khi các close order khớp. Total 161 tại thời điểm kiểm tra có thể trở thành 149 sau khi đóng xong dù safety là 10. Không có cách loại bỏ hoàn toàn market risk trong khoảng thời gian này.

Có thể giảm rủi ro bằng:

  • đóng song song có kiểm soát nếu API và broker cho phép;
  • ưu tiên position rủi ro cao;
  • dùng market snapshot và slippage cap;
  • tạm dừng nếu spread vượt giới hạn;
  • điều chỉnh safety theo volatility và số ticket;
  • đo actual_cycle_pnl sau khi hoàn tất.

Điều quan trọng là báo cáo kết quả thực, không chỉ log giá trị trigger.

9. Cách tính history đúng cho deal vào và deal ra

MT5 history chứa deal entry, exit, in/out và các loại balance/commission khác nhau. Lọc chỉ symbol và Magic có thể vẫn nhận cả deal mở lệnh. Deal mở thường có profit bằng 0 nhưng commission có thể âm. Điều này có thể đúng nếu mục tiêu là tổng net toàn chu kỳ: commission entry phải được tính.

Khi close một phần, nhiều deal chia sẻ cùng position ID. Bot không nên giả định một ticket position tương ứng đúng một deal. Tổng theo deal là hợp lý hơn tổng theo order, nhưng cần:

  • bỏ các deal không phải trading nếu API trả lẫn;
  • xác định cách broker ghi commission;
  • không cộng deposit/withdrawal;
  • dùng timezone và timestamp đúng;
  • lưu watermark để không bỏ deal;
  • xử lý deal sửa hoặc dữ liệu đến trễ nếu có.

Một bài test tốt lấy history thật từ demo, xuất từng trường ticket, order, position_id, entry, type, profit, swap, commission, rồi đối chiếu với statement MT5. Không nên viết parser theo trí nhớ.

10. Tối ưu quét history trong Python Bot Auto Trading

Ba chiến lược phổ biến:

Quét lại toàn chu kỳ khi có thay đổi

Đây là cách đơn giản và dễ kiểm chứng. Mỗi khi phát hiện số position thay đổi hoặc close thành công, quét từ StartTime. Phù hợp cụm nhỏ, chu kỳ ngắn. Nhược điểm là chi phí tăng theo số deals.

Ingest gia tăng theo watermark

Lưu last_deal_time_msclast_deal_ticket. Mỗi cycle hỏi history từ watermark trừ một khoảng overlap nhỏ, loại trùng bằng ticket, rồi cộng deals mới. Cách này nhanh nhưng cần xử lý boundary và persistence cẩn thận.

Event journal nội bộ

Mọi lệnh gửi và deal xác nhận được ghi vào journal append-only. Realized được dựng từ journal, đồng thời định kỳ reconcile với MT5 history. Đây là hướng mạnh cho audit nhưng phức tạp hơn.

Dù chọn cách nào, số cache phải có as_of timestamp. Dashboard hiển thị realized 200 nhưng dữ liệu đã cũ 10 phút là gây hiểu lầm. Observability phải nói rõ độ tươi.

11. Kiểm thử Basket TP bằng các kịch bản số

Chưa đạt mục tiêu

realized = 100
floating = 45
base = 150
safety = 10
total = 145
target = 160

Không reset. Xác minh không có close order và state không đổi.

Đạt đúng biên

realized = 130
floating = 30
target = 160

Điều kiện >= đúng. Hệ thống chuyển RESET_REQUESTED.

Realized dương, floating âm

realized = 230
floating = -65
total = 165

Vẫn đạt target 160. Đây là tình huống thể hiện mục đích của basket.

Realized âm, floating dương

realized = -40
floating = 205
total = 165

Điều kiện đạt ở snapshot, nhưng floating chiếm tỷ trọng lớn nên execution risk cao. Test cần mô phỏng giá xấu đi giữa các close.

Target bằng hoặc nhỏ hơn zero

Mã kiểm tra target > 0. Nếu base target bằng 0 nhưng safety dương, target vẫn dương và module có thể hoạt động. Cần định nghĩa rõ “0 là disable” áp dụng cho base hay target cuối. Nếu muốn 0 tắt Basket TP, phải kiểm tra base trước khi cộng safety.

Phí ở entry và exit

Tạo deals có profit 170, commission entry -5, commission exit -5, floating 0. Total phải là 160. Nếu parser chỉ lấy exit profit, kết quả sai 10.

Hai Magic cùng symbol

Lịch sử trộn 6111 và 6112. Xác minh mỗi cụm chỉ nhận đúng deals của mình.

Reset đóng thất bại một ticket

Ba position; hai close thành công, một bị reject. Hệ thống phải giữ RESETTING, không xóa P0 và không mở vòng mới. Đây là invariant quan trọng hơn việc hàm return nhanh.

12. Các invariant nên viết thành test

Invariant là điều luôn phải đúng:

  • realized chỉ gồm deals đúng account, symbol, Magic và cycle;
  • floating chỉ gồm positions đúng symbol và Magic;
  • không reset nếu target không hợp lệ;
  • khi cluster đang RESETTING, không được mở lệnh mới;
  • chỉ clear state sau khi broker xác nhận cụm rỗng;
  • StartTime mới không bao gồm deals của vòng cũ;
  • mỗi deal chỉ được tính một lần;
  • cache stale phải bị phát hiện;
  • actual cycle P/L được lưu sau reset;
  • lỗi close không bị biến thành reset thành công.

Property-based testing có thể tạo ngẫu nhiên danh sách deals/positions rồi so sánh hàm tổng với oracle đơn giản. Với tiền, cân nhắc Decimal hoặc làm tròn theo currency precision thay vì so float tuyệt đối.

13. Basket TP và tương tác với trailing plow, X-Level

X-Level và trailing plow đóng ticket riêng lẻ, tạo realized cho basket. Basket TP là lớp tổng hợp quyết định khi nào dọn toàn cụm. Ba module phải dùng chung định nghĩa net P/L.

Chu trình thường là:

  1. bot mở position theo Step;
  2. một số ticket đạt X hoặc trailing condition và được đóng;
  3. realized của những deal đó tích lũy;
  4. các position còn lại tạo floating;
  5. khi realized + floating đạt target có safety, reset cụm.

Nếu một module tính commission còn module khác không tính, dashboard và trigger mâu thuẫn. Nên tạo một hàm duy nhất:

def net_pnl(item):
    return item.profit + item.swap + item.commission

Sau đó kiểm thử với data của broker. Việc chuẩn hóa không chỉ giảm lặp code mà còn bảo đảm cùng ngôn ngữ kế toán.

Thứ tự action cũng cần xác định. Trong một tick, nếu Basket TP đã đạt, không cần trailing đóng riêng một ticket rồi mới reset. Cluster state nên chuyển sang RESETTING và vô hiệu hóa các exit strategy khác để tránh hai lệnh close cùng ticket.

14. Basket TP và full hedge lockdown

Trong on_tick() của bản Python, nếu cụm frozen bởi auto lockdown, bot không gọi process_cluster(), do đó Basket TP bên trong core cũng không được đánh giá. Điều này phản ánh ưu tiên: khi full hedge đang khóa, hệ thống giữ nguyên cấu trúc thay vì tự đóng cả cụm.

Nhưng total net có thể đạt target trong thời gian frozen do thay đổi swap, deal khác hoặc sai lệch hedge. Chính sách cần trả lời:

  • Basket TP có được phép override lockdown không?
  • Nếu có, ai tháo lock và đóng positions?
  • Nếu không, dashboard có hiển thị “target reached but frozen” không?
  • reset có đóng luôn LOCKDOWN_ABS không?

Mã hiện tại thiên về không chạy action khi frozen. Đây là lựa chọn bảo thủ, nhưng phải được tài liệu hóa để người vận hành không chờ một Basket TP sẽ không xảy ra.

15. Observability cho chốt cụm

Một dashboard hữu ích nên hiển thị cho từng Magic:

  • Cycle ID và StartTime;
  • realized net và thời điểm scan gần nhất;
  • floating net và thời điểm snapshot;
  • total net;
  • base target, multiplier, safety và target cuối;
  • khoảng cách tới target;
  • số positions, gross Buy/Sell và bias;
  • trạng thái NORMAL/RESETTING/ERROR;
  • số ticket đã đóng, còn lại và lỗi gần nhất;
  • actual P/L của chu kỳ vừa hoàn tất.

Khi trigger, log có cấu trúc:

event=BASKET_TP_TRIGGERED
magic=6111
cycle=...
realized=...
floating=...
target=...
position_count=...

Sau khi đóng xong, phát event khác với actual realized theo statement. Không dùng số trigger làm số “lợi nhuận đã đạt” vì execution có thể làm kết quả khác.

16. Quy trình reset cụm có khả năng phục hồi

Một thiết kế đề xuất:

Pha 1: đóng quyền mở mới

Ghi bền cluster_state = RESETTING, cycle ID và snapshot trigger. Mọi hàm mở lệnh kiểm tra state này.

Pha 2: lập danh sách position

Đọc positions từ MT5, lưu ticket mục tiêu. Không dựa vào cache cũ. Gắn correlation ID cho batch.

Pha 3: đóng và xác nhận

Gửi close có giới hạn tốc độ. Với mỗi response, ghi retcode. Sau batch, đọc lại positions. Retry lỗi tạm thời theo backoff; lỗi quyền, margin mode hoặc market closed phải cảnh báo.

Pha 4: quyết toán

Khi không còn position, chờ history cập nhật, quét deals của cycle và tính actual net. Lưu báo cáo bất biến.

Pha 5: clear state và mở cycle mới

Xóa cờ theo tầng, đặt P0 mới khi giá hợp lệ, StartTime/watermark mới, chuyển NORMAL. Nếu bất kỳ pha nào thất bại, restart tiếp tục từ state lưu bền.

Quy trình này dài hơn một hàm close_all_magic, nhưng giảm tình trạng nửa cũ nửa mới.

17. Checklist triển khai Basket TP

Trước khi sử dụng, kiểm tra:

  • Magic Buy/Sell duy nhất;
  • StartTime và timezone đúng;
  • history bao gồm đúng profit, swap, commission;
  • entry commission không bị bỏ;
  • realized cache được invalidate sau mọi deal;
  • floating lấy từ snapshot mới;
  • base target và multiplier hợp lệ;
  • ý nghĩa giá trị 0 đã định nghĩa;
  • BasketSafety dựa trên chi phí quan sát được;
  • cluster lock chặn lệnh mới trong reset;
  • close result được kiểm tra từng ticket;
  • state chỉ clear sau verify empty;
  • restart tiếp tục được reset dang dở;
  • target trigger và actual P/L được ghi riêng;
  • interaction với lockdown được định nghĩa;
  • test demo bao gồm spread cao, reject và partial close.

Nếu một mục chưa có câu trả lời, tốt hơn nên giữ module ở chế độ quan sát hoặc paper trading.

18. Bài học kiến trúc từ Basket TP

Basket TP cho thấy “lãi của bot” không phải một trường duy nhất từ API. Đó là phép tổng hợp có phạm vi, thời gian và định nghĩa phí. Sai một trong ba yếu tố có thể làm decision sai dù code không báo exception.

Bài học thứ hai là cache phải gắn với event invalidation. Port từ MQ5 sang Python mà bỏ OnTradeTransaction sẽ làm dữ liệu stale. Kiến trúc polling phải chủ động phát hiện deal mới.

Bài học thứ ba là reset là workflow, không phải thao tác xóa biến. Một Python Bot Auto Trading có thể đóng 99/100 tickets; nếu vẫn tuyên bố reset thành công, state đã mất tính nhất quán.

Bài học thứ tư là con số safety không bảo đảm kết quả. Nó chỉ là biên nhằm hấp thụ chi phí dự kiến. Báo cáo đúng phải dựa trên deals sau execution.

Kết luận

Basket TP trong PyNhiQuaiBot quản lý mục tiêu theo cụm Buy/Sell bằng công thức realized + floating, sau đó so với BasketTP * multiplier + BasketSafety. Khi đạt, bot đóng positions và reset state. Logic này phù hợp để học cách kết nối kế toán deal, state persistence, execution và vòng đời chiến dịch.

Phần khó không nằm ở phép cộng mà ở ranh giới history, cache invalidation, chi phí exit, race condition và reset không nguyên tử. Một triển khai đáng tin phải đối soát broker, xác nhận từng close, giữ cluster lock và báo cáo actual P/L sau execution. Không có thiết kế Basket TP nào cam kết lợi nhuận; chiến lược vẫn có thể thua và buffer vẫn có thể không đủ trong biến động mạnh.

Nếu muốn thực hành sâu hơn về Basket TP, trailing plow, FSM, Global State và kiến trúc PyNhiQuaiBot, bạn có thể tham khảo khóa Lập trình Python nâng cao Hedging tự động hóa tại Hướng Nghiệp Dữ Liệu. Mục tiêu là xây tư duy kỹ thuật và quản trị rủi ro cho Python Bot Auto Trading, không cung cấp tín hiệu hay lời hứa lợi nhuận.


📌 Khóa Lập trình Python nâng cao Hedging (PyNhiQuaiBot)
Xem lộ trình & đăng ký · Zalo 0934.145.100 · Hướng Nghiệp Dữ Liệu

admin

admin

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