Isolated Scroll Container

1. Mô Tả Statistical Order Blocks Strategy

Phát hiện Order Block (OB) theo displacement chuẩn ICT/SMC, đồng thời chạy một bộ máy tự-backtest không lookahead ngay trong chỉ báo để dán trực tiếp Win Rate, P(Touch), Expected Value, R:R lên nhãn của mỗi vùng OB mới hình thành.

1.1 Khái Niệm Chỉ Báo

Chỉ báo này dựa trên khái niệm Order Block (OB) kinh điển của trường phái ICT/Smart Money Concepts: cây nến ngược màu CUỐI CÙNG trước một cú "dịch chuyển" (displacement) đủ mạnh ra khỏi nó được xem là nơi để lại lệnh tổ chức chưa khớp hết - một vùng giá có xu hướng "hút" giá quay lại phản ứng trong tương lai.

Điểm khác biệt cốt lõi của chỉ báo này: nó không chỉ vẽ vùng OB, mà còn chạy song song một bộ máy tự-backtest chạy ngay bên trong chính chỉ báo, không có lookahead. Mỗi nến đã đóng cửa, chỉ báo nhìn lùi lại đúng "Max Bars to Simulate Outcome" nến - đủ xa để biết chắc chắn kết quả đã ngã ngũ - "phát hiện lại" MỘT cơ hội OB lịch sử vừa được xác định xong kết quả (nếu đúng lúc đó có 1 pivot), rồi cộng dồn kết quả thật của nó (có bị chạm không? thắng hay thua? mất bao nhiêu nến?) vào một bộ đếm chạy riêng cho phe tăng và phe giảm.

  • Mỗi vùng OB MỚI được vẽ đều mang theo "hồ sơ thành tích": nhãn thông tin trên mỗi OB hiện Win Rate, Xác Suất Bị Chạm (P(Touch)), Kỳ Vọng (EV theo đơn vị ATR), R:R, số nến trung bình để thắng/thua, và cỡ mẫu (n) - tất cả tính từ TOÀN BỘ lịch sử các OB cùng phía đã thực sự ngã ngũ trên chính biểu đồ và cài đặt hiện tại, KHÔNG phải một con số chung chung có sẵn.
  • Mọi mục tiêu/dừng lỗ đều tính theo ATR, không phải pip cố định, nên cùng một logic có thể áp dụng nhất quán hơn giữa các cặp/khung thời gian khác nhau mà không cần chỉnh tay nhiều.
  • Chiều cao vùng OB có thể chuẩn hoá về một bội số ATR cố định thay vì dùng đúng range thật của nến gốc - thuần tuý cho mục đích hiển thị nhất quán giữa các vùng có kích thước rất khác nhau.

1.2 Chức Năng Chỉ Báo

  • Vùng OB Tăng/Giảm: box màu theo phía tăng/giảm, mép trái neo tại đúng nến gốc, mép phải tự động kéo dài về tương lai khi vùng còn "sống" (chưa bị vô hiệu hoá).
  • Nhãn Thống Kê: chuỗi text 1 dòng hiện đầy đủ WR / (Wins/Losses) / P(Touch) / EV / R:R / AvgW / AvgL / kích thước vùng (pip) / cỡ mẫu n - luôn "bám" theo giá, liên tục dịch chuyển tới vị trí 5 nến phía trước mỗi khi có nến mới, thay vì đứng yên tại nơi vùng hình thành.
  • Vòng đời theo Mitigation: một vùng OB biến mất (hoặc chuyển sang "lịch sử") ngay khi giá đóng cửa xuyên qua nó - kiểm tra này chạy trên MỌI tick, không chỉ nến đã đóng, nên phản ứng gần như tức thời.
  • OB Lịch Sử (tuỳ chọn): sau khi bị vô hiệu hoá, vùng có thể được giữ lại trên biểu đồ dưới dạng vùng mờ (không nhãn) thay vì xoá hẳn - tooltip gốc cảnh báo tính năng này "có thể chậm trên lịch sử rất dài".
  • Giới hạn FIFO 2 tầng: số vùng OB đang hoạt động mỗi phía bị chặn bởi "Max Active OBs Per Side"; số vùng lịch sử (mờ) mỗi phía bị chặn ở gấp 3 lần con số đó.
  • Tuỳ biến đầy đủ: màu nền/viền riêng cho tăng/giảm, cỡ chữ nhãn, bật/tắt độc lập từng phía và từng loại hiển thị (vùng đang hoạt động / vùng lịch sử / nhãn).

1.3 Cách Dùng Chỉ Báo

  • Đọc nhãn thống kê TRƯỚC khi tin một OB mới: một phía có Win Rate thấp hoặc EV âm trên chính biểu đồ/cài đặt hiện tại là cảnh báo thực sự, không chỉ là trang trí - đây là kết quả tự-backtest ngay trên dữ liệu bạn đang xem.
  • Hiểu đúng ý nghĩa "P(Touch)": đây là xác suất một OB dạng này TỪNG được giá quay lại chạm tới, không phải xác suất thắng. P(Touch) thấp nghĩa là phần lớn vùng loại này không bao giờ được test lại - chờ entry kiểu "retest" trên biểu đồ này có thể đồng nghĩa với bỏ lỡ phần lớn cơ hội.
  • Tự tính TP/SL nếu cần dùng cho vào lệnh: chỉ báo tính sẵn tp_price/sl_price cho mỗi vùng (mid ± ATR×"Take Profit", mép xa ± ATR×"Stop Loss") nhưng KHÔNG vẽ 2 mức này lên biểu đồ hay đưa vào nhãn - phải tự tính lại bằng đúng công thức nếu muốn thấy trực quan.
  • R:R hiển thị luôn cố định = "Take Profit"/"Stop Loss" (mặc định 3.0/6.0 = 1:2), giống nhau cho MỌI vùng OB bất kể range thật của nó - vì cả TP lẫn SL đều định nghĩa thuần theo bội số ATR.
  • Tắt "Show Historical OBs" trên khung thời gian nhỏ/lịch sử rất dài nếu chỉ báo bắt đầu chậm - đây là cảnh báo hiệu năng có sẵn từ tooltip gốc, không phải suy đoán.
  • Tăng "OB Candle Lookback" / "Displacement Multiplier" để chỉ giữ lại các OB có cú dịch chuyển thật mạnh, dứt khoát (ít vùng hơn nhưng chất lượng cao hơn); giảm để bắt nhiều vùng hơn.
  • Cân nhắc "Max Bars to Simulate Outcome": giá trị nhỏ khiến bộ máy thống kê "bỏ cuộc" sớm với các setup di chuyển chậm (có thể đánh giá thấp Win Rate thật); giá trị lớn làm chậm tốc độ cập nhật thống kê mới (vì một mẫu chỉ được tính xong sau đúng ngần ấy nến kể từ khi OB hình thành).

1.4 Cách Hoạt Động Của Chỉ Báo

Đầu vào & vai trò

  • swing_len ("Swing Detection Length", Số nguyên, mặc định: 9, khoảng 3-30): số nến 2 bên để xác nhận pivot. Tăng → chỉ bắt đỉnh/đáy lớn, quan trọng hơn. Giảm → nhiều pivot hơn, dễ nhiễu hơn.
  • lookback_bars ("OB Candle Lookback", Số nguyên, mặc định: 20, khoảng 5-50): số nến trước pivot được quét để tìm nến gốc của OB.
  • disp_mult ("Displacement Multiplier (ATR)", Số thập phân, mặc định: 1.5): cú dịch chuyển từ nến OB ra tới pivot phải ≥ số ATR này mới được công nhận là OB hợp lệ. Ví dụ: ATR=0.0050, disp_mult=1.5 → cú dịch chuyển phải ≥ 0.0075 mới đạt.
  • normalize_zones ("Normalize All Zone Heights", Boolean, mặc định: true) / norm_atr_mult ("Zone Height (ATR Multiplier)", Số thập phân, mặc định: 0.75): khi bật, MỌI vùng OB bị ép về cùng 1 chiều cao = ATR hiện tại × norm_atr_mult (không dùng range thật của nến gốc), tâm vùng giữ nguyên ở trung điểm ban đầu.
  • tp_atr_mult ("Take Profit (ATR Multiplier)", Số thập phân, mặc định: 3.0): mục tiêu TP = trung điểm vùng ± ATR×tp_atr_mult.
  • sl_atr_mult ("Stop Loss (ATR Multiplier)", Số thập phân, mặc định: 6.0): SL = mép xa của vùng ± ATR×sl_atr_mult. Với mặc định 3.0/6.0, R:R luôn cố định ở 1:2 cho mọi vùng.
  • max_sim_bars ("Max Bars to Simulate Outcome", Số nguyên, mặc định: 100, khoảng 20-300): đồng thời là (a) số nến tối đa bộ máy thống kê chờ một OB lịch sử ngã ngũ trước khi bỏ cuộc (không tính là thắng/thua), VÀ (b) độ trễ cố định giữa lúc một OB hình thành và lúc kết quả của nó được cộng vào thống kê.
  • max_obs_per_side ("Max Active OBs Per Side", Số nguyên, mặc định: 7): số vùng đang hoạt động tối đa mỗi phía; vùng CŨ NHẤT bị loại theo FIFO khi vượt ngưỡng, bất kể còn hợp lệ về giá hay không.
  • zone_extend ("Zone Extension (bars)", Số nguyên, mặc định: 200): số nến vùng box kéo dài về phía tương lai trong khi còn hoạt động.
  • show_bull / bull_bg / bull_border, show_bear / bear_bg / bear_border: bật/tắt và màu nền/viền riêng cho từng phía.
  • show_hist ("Show Historical OBs", Boolean, mặc định: true): giữ lại vùng đã vô hiệu hoá dưới dạng mờ thay vì xoá hẳn.
  • show_labels ("Show Statistical Labels", Boolean, mặc định: true) / lbl_txt_size ("Label Text Size", mặc định: "Large"): bật/tắt và cỡ chữ nhãn thống kê.
💡 Lưu ý về phương pháp thống kê: vì Pine Script tính toán lại TOÀN BỘ lịch sử mỗi khi một input thay đổi, việc chỉnh tp_atr_mult hoặc sl_atr_mult sẽ tính lại NGAY LẬP TỨC toàn bộ hồ sơ thắng/thua/chạm của MỌI OB lịch sử, không chỉ ảnh hưởng các OB mới - đây là hành vi đúng và mong muốn (đảm bảo so sánh "táo với táo" cùng 1 bộ tham số), không phải lỗi, nhưng cần hiểu để không nhầm lẫn khi thấy thống kê thay đổi đột ngột sau khi chỉnh 2 input này.

Các Khối Logic Chính

🎯 Luồng 1: Tái Hiện Thống Kê Lịch Sử - Phe Tăng

  • Mỗi nến đã đóng cửa: kiểm tra xem đúng max_sim_bars nến trước có một pivot low đã xác nhận không (ta.pivotlow(...)[check_offset]). Nếu có: quét về phía trước pivot đó (dùng đúng logic swing_len/lookback_bars/disp_mult như khi vẽ OB sống) để tìm nến giảm hợp lệ làm "nến OB lịch sử".
  • Nếu tìm thấy: hist_bull_total += 1, tính tp_h/sl_h từ ATR tại thời điểm đó và tp_atr_mult/sl_atr_mult HIỆN TẠI. Sau đó đi TỚI TRƯỚC (từ pivot hướng về hiện tại) từng nến một: lần đầu tiên giá chạm lại vùng → hist_bull_touches += 1; sau khi đã chạm, nến nào chạm tp_h trước → tính thắng (cộng số nến vào hist_bull_win_bars), chạm sl_h trước → tính thua. Nếu hết max_sim_bars nến mà chưa ngã ngũ → không tính thắng hay thua (vẫn tính vào n=total).
  • Ví dụ: max_sim_bars=100. Tại bar hiện tại, kiểm tra bar (hiện tại-100) có pivot low không - có → tìm được nến OB giảm tại (hiện tại-112). tp_h=mid+ATR×3.0, sl_h=đáy-ATR×6.0. Đi từ (hiện tại-99) tới (hiện tại-1): nến nào chạm vùng trước → touches+=1; sau đó nến nào đạt tp_h/sl_h trước → cộng vào wins/losses tương ứng.

🎯 Luồng 2: Tái Hiện Thống Kê Lịch Sử - Phe Giảm

  • Đối xứng hoàn toàn với Luồng 1, dùng pivot high, tìm nến tăng làm "nến OB lịch sử", tp_h nằm DƯỚI trung điểm, sl_h nằm TRÊN đỉnh - cộng dồn vào hist_bear_*.

🧮 Luồng 3: Tính Thống Kê Tổng Hợp

  • compute_stats() chạy cho cả 2 phía ngay sau khi 2 luồng trên vừa cập nhật xong bộ đếm: Win Rate = wins/(wins+losses), P(Touch) = touches/total, EV = tỷ lệ thắng×tp_atr_mult - tỷ lệ thua×sl_atr_mult (dùng 50% làm giá trị mặc định nếu chưa có mẫu nào ngã ngũ, để EV không bị NA ngay từ đầu), R:R = tp_atr_mult/sl_atr_mult (cố định, không phụ thuộc mẫu thống kê).

🖊️ Luồng 4: Phát Hiện & Vẽ OB Giảm (sống)

  • Khi có pivot high MỚI vừa xác nhận (không offset, thời gian thực): quét từ swing_len+1 tới swing_len+lookback_bars nến TRƯỚC pivot, tìm nến tăng ĐẦU TIÊN (gần pivot nhất) có displacement (từ đỉnh nến đó xuống đáy tại pivot) ≥ ATR×disp_mult.
  • Nếu tìm thấy: áp dụng normalize_zone() (dùng ATR HIỆN TẠI, không phải ATR tại thời điểm nến OB hình thành), tính tp_price/sl_price cho riêng vùng này (lưu vào struct nhưng KHÔNG vẽ lên biểu đồ), vẽ box màu giảm từ nến gốc tới bar_index+zone_extend, kèm nhãn thống kê (nếu bật) dùng đúng bear_wr/bear_pt/... vừa tính ở Luồng 3. Đẩy vào mảng bear_obs.
  • Ví dụ: pivot high xác nhận, quét ngược tìm được nến tăng tại i=14 với high=1.2650, low=1.2620. normalize_zones=true, ATR hiện tại=0.0050, norm_atr_mult=0.75 → half_h=0.0050×0.75/2=0.001875, mid=1.2635 → norm_top=1.265375, norm_bot=1.261625 (chiều cao vùng cố định ~0.00375 bất kể range thật của nến gốc là 0.0030). tp_price=1.2635-0.0050×3.0=1.2485, sl_price=1.265375+0.0050×6.0=1.295375 (2 giá trị này chỉ lưu nội bộ, không hiện trên biểu đồ).

🖊️ Luồng 5: Phát Hiện & Vẽ OB Tăng (sống)

  • Đối xứng hoàn toàn với Luồng 4, dùng pivot low, tìm nến giảm làm nến OB, tp_price nằm TRÊN trung điểm, sl_price nằm DƯỚI đáy vùng. Đẩy vào mảng bull_obs.

🗑️ Luồng 6: Kiểm Tra Vô Hiệu Hoá (Mitigation) - chạy mọi tick

  • Khác với các luồng trên (chỉ chạy khi nến đã đóng), luồng này chạy trên MỌI tick. Vùng tăng bị vô hiệu hoá khi close < ob.bot; vùng giảm khi close > ob.top.
  • Nếu show_hist bật: chuyển vùng sang mảng lịch sử (hist_bull_obs/hist_bear_obs) - cố định mép phải tại bar hiện tại, huỷ auto-extend, đổi màu sang phiên bản mờ (nền 95% trong suốt, viền 90%), XOÁ NỘI DUNG CHỮ của nhãn (đặt về rỗng, KHÔNG xoá đối tượng nhãn). Nếu show_hist tắt: xoá hẳn box + nhãn, chỉ gỡ khỏi mảng đang hoạt động.
  • Ví dụ: vùng tăng có ob.bot=1.2616. Giá đóng cửa 1.2610 (<1.2616) → vô hiệu hoá. Nếu show_hist bật: box đóng băng tại vị trí hiện tại, chuyển màu mờ, nhãn trống chữ nhưng vẫn tồn tại; nếu tắt: box và nhãn bị xoá hoàn toàn.

📦 Luồng 7: Giới Hạn FIFO Cho Vùng Đang Hoạt Động

  • Nếu bull_obs.size() > max_obs_per_side (hoặc tương tự cho bear_obs): xoá vùng CŨ NHẤT theo thứ tự tạo (không xét còn hợp lệ về giá hay không) - độc lập hoàn toàn với việc mitigation ở Luồng 6.

🔄 Luồng 8: Làm Mới Hình Vẽ Mỗi Nến (vùng còn sống)

  • Với mỗi vùng CHƯA bị vô hiệu hoá: kéo dài mép phải box tới bar_index+zone_extend, VÀ nếu đang hiện nhãn, di chuyển nhãn tới toạ độ (bar_index+5, trung điểm vùng) - nhãn liên tục "đuổi theo" nến hiện tại, luôn nổi 5 nến phía trước giá, trong khi mép trái của box vẫn neo cố định tại nến gốc.

📦 Luồng 9: Giới Hạn FIFO Cho Vùng Lịch Sử (mờ)

  • Nếu số vùng trong hist_bull_obs/hist_bear_obs vượt quá max_obs_per_side × 3: xoá vùng cũ nhất - giới hạn số lượng box tích luỹ trên các biểu đồ có lịch sử rất dài, đúng như cảnh báo hiệu năng trong tooltip của show_hist.

Đầu ra & vai trò trong sử dụng

  • Vùng OB (đang hoạt động): vùng hỗ trợ/kháng cự động, neo tại nến gốc thật, tự kéo dài về tương lai cho đến khi bị vô hiệu hoá.
  • Vùng OB lịch sử (mờ, tuỳ chọn): dấu vết trực quan các vùng đã "hết hiệu lực" trong quá khứ, hữu ích để nhìn mật độ vùng mà không làm rối biểu đồ bằng nhãn đầy đủ.
  • Nhãn thống kê: hồ sơ thành tích không-lookahead, cập nhật liên tục, in mới lên MỖI vùng vừa hình thành - nên đọc như "logic phát hiện này đã hoạt động ra sao trên biểu đồ/cài đặt hiện tại tính đến giờ", không phải lời đảm bảo cho riêng vùng mới này.
  • tp_price/sl_price lưu trữ (không hiển thị): mức chốt lời/dừng lỗ theo ATR đã tính sẵn cho từng vùng cụ thể, sẵn sàng để nối vào logic đặt lệnh thật ở Phase B dù bản chỉ báo hiện tại chưa bao giờ vẽ chúng ra.
💡 Lưu ý khác: cẩn thận phân biệt 2 khái niệm cùng dùng tiền tố "hist_": mảng hist_bull_obs/hist_bear_obs là các VÙNG ĐÃ VẼ được giữ lại dưới dạng mờ sau khi vô hiệu hoá (chỉ tồn tại nếu show_hist bật), còn các biến hist_bull_wins/losses/touches/total... là BỘ ĐẾM THỐNG KÊ chạy ngầm nuôi Luồng 1-3 (LUÔN chạy, không phụ thuộc show_hist) - đây là 2 cơ chế hoàn toàn khác nhau, chỉ tình cờ trùng tiền tố đặt tên trong code gốc. Ngoài ra, trường tp_price/sl_price trên mỗi OrderBlock được tính và lưu đầy đủ nhưng KHÔNG được đọc lại ở bất kỳ đâu khác trong code - không nên bịa ra rằng chỉ báo có vẽ 2 mức này.
Zoom/Pan Layered Image
Background Overlay
− +

Chỉ báo trên vừa hoá thành BOT TRADE — chỉ 1 click AI

📊Chỉ báo gốc
→
🤖AI convert 1-click
→
⚙️Bot tự trade 24/7