1. Mô tả Liquidation HeatMap Strategy
Một bản đồ "độ nóng thanh khoản": chỉ báo tìm các đỉnh và đáy swing, đặt một dải ngang mỏng ngay phía ngoài mỗi điểm đó, rồi tô màu dải từ lime nhạt tới vàng rực tuỳ khối lượng giao dịch tại nến swing. Dải tồn tại cho tới khi giá cắt qua đường giữa của nó.
1.1 Concept của chỉ báo
Chỉ báo dựa trên một ý tưởng rất phổ biến của thị trường: lệnh dừng lỗ và các vị thế đòn bẩy thường dồn ngay phía ngoài những điểm swing dễ thấy. Người đang bán khống đặt lệnh cắt lỗ (thực chất là lệnh mua) ngay phía trên một đỉnh swing gần đây; người đang mua đặt lệnh cắt lỗ (thực chất là lệnh bán) ngay phía dưới một đáy swing gần đây. Vị thế đòn bẩy bị sàn thanh lý ("liquidation") cũng đi đúng chiều đó. Những cụm lệnh này được giới trader gọi là bể thanh khoản (liquidity pool), và giá thường bị hút về phía chúng vì đó là nơi dễ khớp lệnh lớn nhất.
Chỉ báo biến ý tưởng đó thành hình ảnh bằng ba nguyên liệu đơn giản:
- Ở ĐÂU: tại một điểm pivot. Mỗi đỉnh hoặc đáy swing (cây nến cao nhất hoặc thấp nhất trong 2 nến bên trái và 2 nến bên phải) được coi là nơi nhiều khả năng có lệnh dừng lỗ nằm sẵn.
- LỚN CỠ NÀO: dựa vào khối lượng giao dịch tại đúng nến pivot đó, so với khối lượng trung bình 500 nến gần nhất. Pivot hình thành với khối lượng lớn nghĩa là nhiều vị thế được mở ở đó, nên phía sau có thể ẩn nhiều lệnh dừng lỗ hơn. Điều này được thể hiện bằng màu: lime nhạt cho pivot bình thường, đậm dần tới vàng rực cho pivot sôi động nhất.
- SỐNG BAO LÂU: vùng tồn tại cho tới khi bị "quét", tức là một nến sau đó chạm tới đường giữa của dải. Đó là cách chỉ báo định nghĩa "thanh khoản đã bị lấy".
Một lưu ý trung thực: dù tên là "Liquidation", chỉ báo không đọc dữ liệu thanh lý thật nào từ sàn. Nó là một ước lượng dựng từ pivot giá và khối lượng. Chính phần mô tả của tác giả cũng nói như vậy: đây là công cụ vẽ các vùng nhiệt ngang nơi các lệnh thanh lý và cụm khối lượng có thể đang ẩn nấp. Hãy đọc các dải như "cụm lệnh dừng lỗ có khả năng xảy ra", đừng coi là sự thật.
1.2 Chức năng của chỉ báo
-
Hiển thị:
- Vùng PHÍA TRÊN giá (trên các đỉnh swing): một dải ngang mỏng có cạnh dưới nằm đúng tại đỉnh swing, cạnh trên cao hơn một "độ dày". Đây là bể lệnh mua dừng / thanh lý lệnh bán khống ước lượng.
- Vùng PHÍA DƯỚI giá (dưới các đáy swing): hình ảnh đối xứng: cạnh trên của dải nằm đúng tại đáy swing và dải kéo xuống dưới. Đây là bể lệnh bán dừng / thanh lý lệnh mua ước lượng.
- Màu nhiệt: mỗi dải được tô một màu nằm giữa lime (quan tâm thấp, gần như trong suốt) và vàng (quan tâm cao, đậm đặc). Cùng một bảng màu dùng cho cả phía trên lẫn phía dưới giá, nên màu chỉ cho biết "nóng cỡ nào", không cho biết "hướng nào"; hướng được xác định bởi vị trí dải so với giá.
- Hai loại dải trên màn hình: dải kéo dài tới tận nến mới nhất là dải còn nguyên ("còn sống"). Dải dừng lại giữa chừng là dải đã bị cắt qua tại nến mà nó dừng ("đã bị quét"). Cả hai giữ nguyên một màu, nên mép phải là cách duy nhất để phân biệt.
- Thang chú giải (giữa mép phải chart): một thanh màu dọc hẹp. Ô trên cùng ghi MAX cùng khối lượng lớn nhất trong 500 nến gần nhất (định dạng kiểu 142.375K); ô dưới cùng ghi MIN và số 0. Giữa hai đầu là 21 ô đổi màu dần từ vàng xuống lime gần như trong suốt.
- Alert: chỉ báo KHÔNG có lệnh alertcondition() nào và KHÔNG có đầu ra plot(). Nó thuần tuý trực quan: không có gì được phơi ra để script khác hay alert đọc.
1.3 Cách dùng chỉ báo
- Coi các dải như nam châm và mục tiêu. Dải phía trên giá là mức giá có thể bị hút lên; dải phía dưới là mức giá có thể bị hút xuống. Vàng càng đậm thì lực hút tác giả kỳ vọng càng mạnh. Các vùng vàng dày chính là chỗ tác giả khuyên tập trung nhìn.
- Tìm kiểu quét rồi bị đẩy ngược (sweep-and-reject). Cách giao dịch bể thanh khoản kinh điển là chờ giá đâm râu vào dải rồi đóng cửa quay ra khỏi dải. Lệnh dừng lỗ đã bị kích hoạt, nhiên liệu cạn, giá hay đảo chiều. Đây là điểm vào lệnh kiểu hồi về trung bình: bán sau khi dải phía trên bị quét hụt, mua sau khi dải phía dưới bị quét hụt.
- Dùng dải còn sống làm mục tiêu chốt lời. Nếu đang mua và phía trên giá có một dải vàng chưa bị chạm, đó là chỗ tự nhiên để chốt lời, vì lệnh của bạn nhiều khả năng gặp đúng đám lệnh dừng lỗ mà giá đang săn.
- Chỉ tin các dải chạm tới mép phải. Dải đã dừng trước nến cuối là dải đã dùng hết. Bỏ qua nó khi ra quyết định cho tương lai; nó chỉ hữu ích như lịch sử ("giá đã quét ở đây và phản ứng").
- Tìm các cụm dải. Nhiều dải chồng lên nhau ở cùng một vùng giá (đỉnh bằng nhau, đáy bằng nhau, mép biên đi ngang) báo hiệu bể thanh khoản lớn hơn bất kỳ dải đơn lẻ nào cho thấy.
- Kết hợp với xu hướng và cấu trúc. Dải cùng chiều xu hướng chính nhiều khả năng là mục tiêu để giá đi xuyên qua; dải ngược chiều xu hướng nhiều khả năng là điểm đảo chiều. Tác giả khuyên ghép với công cụ xu hướng hoặc cấu trúc, và trên khung nhỏ dùng để xác nhận điểm vào lệnh quanh các cú quét và lệch (deviation).
- Chỉnh bảng màu cho hợp chart. Chỉ có hai ô cài đặt (màu Max và Min). Hãy chọn màu nổi bật so với màu nến để các dải nóng nhất là thứ đập vào mắt đầu tiên.
1.4 Cách hoạt động của chỉ báo
Đầu vào & vai trò
- max_col (chọn màu, tiêu đề "Max", mặc định vàng, nhóm "Liquidation Color", chung một hàng với Min): màu của các dải nóng nhất, tức pivot có khối lượng nằm ở đỉnh phạm vi gần đây. Đây cũng là màu trên cùng của thang chú giải. Ví dụ: đổi sang đỏ thì các vùng sôi động nhất chuyển đỏ, vùng bình thường không đổi. Vì màu này được dùng nguyên trạng (code không làm mờ nó), chọn màu đặc thì dải nóng sẽ đặc.
- min_col (chọn màu, tiêu đề "Min", mặc định lime, cùng nhóm và cùng hàng): màu của các dải bình thường. Bên trong code nó bị làm mờ 90% trước khi dùng, nên dải yếu chỉ là một lớp phủ nhạt. Ví dụ: đổi sang xanh dương thì pivot trung bình hiện lớp phủ xanh dương nhạt. Vì đã mờ 90%, dù chọn màu chói thì kết quả vẫn kín đáo.
Đây là hai thiết lập duy nhất chỉnh được. Mọi thứ còn lại bị cố định trong code, liệt kê ngay dưới đây.
Hằng số cố định trong code (KHÔNG phải input)
- bars_amount = 500: dùng cho ba việc cùng lúc. Kích thước cửa sổ khối lượng trượt, số nến gần nhất được phép tạo và theo dõi vùng (nến cũ hơn không có gì), và kích thước ban đầu của mảng chứa vùng.
- index = 2: độ mạnh của pivot. Một pivot cần 2 nến bên trái và 2 nến bên phải để được xác nhận, nên pivot luôn được biết chậm 2 nến. Con số này cũng là độ lệch dùng để nhìn lại giá, khối lượng và ATR của nến pivot.
- ta.atr(200) × hệ số theo khung thời gian: độ dày của mọi dải. Hệ số theo khung: 0.2 cho mọi chart từ 60 phút trở lên (1H, 4H…) và cho khung Ngày; 0.25 cho chart từ 1 đến 59 phút; 0.4 cho phần còn lại (Tuần, Tháng, giây, tick).
- Các mốc của dải màu: độ mờ 90 cho đầu lime nhạt, và khối lượng trung bình 500 nến làm điểm giữa giữa "yếu" và "mạnh".
- Thang chú giải: 23 hàng (hàng 0 và 22 chứa chữ MAX / MIN, hàng 1 đến 21 là các ô màu), bảng đặt ở position.middle_right, chữ cỡ nhỏ.
- max_boxes_count = 500 và max_bars_back = 500: trần số hộp vẽ được và bộ nhớ lịch sử.
Các khối logic chính
📊 Luồng 1: Cửa sổ khối lượng trượt (hàm volume_data, mọi nến)
- Hàm giữ một danh sách (mảng: một dãy số có thứ tự) đúng 500 giá trị, mỗi giá trị ứng một nến gần đây. Mỗi nến mới, giá trị của nó được thêm vào cuối và giá trị cũ nhất bị bỏ khỏi đầu. Vậy danh sách luôn là "500 nến gần nhất".
- Giá trị được lưu: volume của nến. Có phương án dự phòng: nếu khối lượng cộng dồn nhỏ hơn hoặc bằng 1 (mã không có dữ liệu volume), nó lưu (high − low) × 100, tức kích thước nến phóng lớn lên. Nhờ vậy logic tô màu vẫn chạy được trên mã không có volume.
- Từ danh sách này, chỉ báo về sau đọc hai con số: trung bình và lớn nhất. Hai số này là thước đo để tô màu.
📍 Luồng 2: Tìm pivot và độ dày dải (phương thức detect_liquidity, mọi nến)
- ph = ta.pivothigh(2, 2) và pl = ta.pivotlow(2, 2): đỉnh swing là nến có high cao hơn high của 2 nến trước và 2 nến sau; đáy swing là điều tương tự ở phía low. Kết quả chỉ xuất hiện sau pivot 2 nến (khi các nến bên phải đã có) và chứa giá của pivot.
- atr = (ta.atr(200) × hệ số)[2]: biên độ nến trung bình trong 200 nến, nhân hệ số theo khung thời gian, rồi đọc giá trị của 2 nến trước để khớp với nến pivot. Ví dụ: chart XAUUSD 15 phút có ATR(200) = 4,00, hệ số là 0,25, nên mọi dải dày 1,00.
- vol_value = vol.last()[2]: khối lượng của nến pivot (phần tử cuối của danh sách, đọc lùi 2 nến).
🌈 Luồng 3: Chọn màu nhiệt
- Màu gồm hai đoạn, chia tại khối lượng trung bình của 500 nến. Bằng hoặc dưới trung bình: pha từ hoàn toàn trong suốt tới lime mờ 90%, nên pivot dưới trung bình gần như vô hình. Trên trung bình: pha từ lime mờ 90% tới trọn màu Max (vàng), đạt màu đầy đủ tại khối lượng lớn nhất của 500 nến.
- Ví dụ: khối lượng trung bình = 1.200, lớn nhất = 6.000. Nến pivot volume 600 → nằm nửa đường của đoạn đầu, gần như trong suốt. Volume 1.200 → lime nhạt. Volume 3.600 → đúng 50% quãng từ trung bình tới lớn nhất, nên là hỗn hợp 50/50 giữa lime nhạt và vàng. Volume 6.000 → vàng nguyên chất.
- Màu bị đóng băng ngay lúc dải được tạo. Nó không bao giờ được tính lại, dù thống kê 500 nến vẫn tiếp tục thay đổi.
🧱 Luồng 4: Tạo dải (chỉ trong 500 nến gần nhất)
- Điều kiện cổng: (last_bar_index − bar_index) < 500. Chỉ 500 nến gần nhất của chart mới chạy phần tạo và theo dõi. Nến cũ hơn không sinh ra gì, đó là lý do phần bên trái của chart dài bị trống.
- Vùng trên đỉnh swing: một hộp từ nến pivot (bar_index[2]) tới nến hiện tại, với đáy = đỉnh pivot và đỉnh = đỉnh pivot + atr. Không viền, tô màu nhiệt. Ví dụ: đỉnh pivot 2.650,00 và độ dày 1,00 → dải 2.650,00 tới 2.651,00.
- Vùng dưới đáy swing: một hộp với đỉnh = đáy pivot và đáy = đáy pivot − atr. Ví dụ: đáy pivot 2.630,00 → dải 2.629,00 tới 2.630,00.
- Điều kiện kích hoạt được viết là "ph bây giờ, HOẶC ph 1 nến trước, HOẶC ph 2 nến trước". Nghĩa là một pivot làm đoạn code tạo dải chạy ở ba nến liên tiếp, nên mỗi pivot sinh ra tới 3 dải chồng nhau thay vì một. Xem phần lưu ý bên dưới để biết hệ quả.
🔍 Luồng 5: Theo dõi và "quét" dải (mọi nến, trong cùng cổng)
- Mọi dải còn sống được giữ trong một danh sách thứ hai (liquid_zones). Mỗi nến, code duyệt qua danh sách này.
- Kéo dài: mép phải của mỗi dải được dời tới nến hiện tại, nên dải còn sống luôn chạy tới nến mới nhất.
- Kiểm tra đường giữa: mid = (đỉnh + đáy) / 2. Nếu nến hiện tại thoả high > mid VÀ low < mid (biên độ nến cắt qua đường giữa, tính cả râu), dải bị quét: nó bị gỡ khỏi danh sách. Vì không còn được kéo dài, mép phải của nó đứng yên tại nến đó, và hộp vẫn nằm trên chart.
- Ví dụ: dải 2.650,00 tới 2.651,00 có đường giữa ở 2.650,50. Một nến sau đó có high 2.652,00 và low 2.649,20 cắt qua 2.650,50 → dải bị quét, mép phải đóng băng tại đó. Một nến chỉ chạm tới 2.650,20 thì không quét được dải (chưa tới đường giữa).
📏 Luồng 6: Thang chú giải (hàm draw_scale, chỉ nến cuối)
- Chỉ chạy ở nến cuối cùng (barstate.islast) và dựng một bảng nhỏ ở giữa mép phải chart.
- Hàng 0 hiện khối lượng lớn nhất 500 nến kèm chữ MAX; hàng 22 hiện MIN và 0 (giá trị nhỏ nhất bị gán cứng bằng 0, không phải giá trị nhỏ nhất thật). Hàng 1 đến 21 là các ô màu pha đều từ lime nhạt tới màu Max.
Đầu ra & vai trò trong sử dụng
- Dải còn sống phía trên giá: bể lệnh mua dừng / thanh lý lệnh bán khống ước lượng, dùng làm nam châm phía trên, mục tiêu chốt lời cho lệnh mua, và vùng canh bán sau cú quét bị đẩy ngược.
- Dải còn sống phía dưới giá: bể lệnh bán dừng / thanh lý lệnh mua ước lượng, dùng làm nam châm phía dưới, mục tiêu chốt lời cho lệnh bán, và vùng canh mua sau cú quét bị đẩy ngược.
- Dải đã bị quét (mép phải đóng băng): bản ghi nơi giá đã quét thanh khoản và dải sống được bao lâu. Hữu ích làm bối cảnh, không phải mức giá nhìn về tương lai.
- Độ đậm của màu: tầm quan trọng tương đối của từng dải. Đọc đúng cần hiểu các lưu ý kỹ thuật bên dưới.
- Thang chú giải: chìa khoá nhanh cho biết "màu vàng" tương ứng khối lượng bao nhiêu trên chart hiện tại.
- Các vùng là ƯỚC LƯỢNG, không phải dữ liệu thanh lý thật. Không dòng code nào chạm tới dữ liệu thanh lý hay open interest của sàn. Một vùng chỉ là "pivot + một phần ATR + khối lượng của một nến". Hai pivot cùng khối lượng sẽ cùng màu, bất kể phía sau có lệnh dừng lỗ thật hay không.
- Mỗi pivot tạo TỚI BA dải, không phải một. Vì điều kiện là not na(ph) or not na(ph[1]) or not na(ph[2]), đoạn code tạo dải chạy ở nến xác nhận pivot và cả hai nến kế tiếp. Dải thứ 1 neo vào pivot thật. Dải thứ 2 và thứ 3 neo vào đỉnh (hoặc đáy) của hai nến ngay sau pivot, những nến này không phải pivot. Chúng rơi vào mức giá gần như y hệt, nên chồng lại thành thứ trông như một dải dày hơn một chút và đặc hơn một chút. Hệ quả: số hộp xấp xỉ gấp ba so với thiết kế mỗi pivot một dải, và bản sao thứ 2/3 dùng volume và ATR khác nên màu hơi lệch.
- Trần 500 hộp làm lịch sử hiển thị ngắn đi. Trên chuỗi giá bình thường cứ 5 nến thì có khoảng 2 nến là đỉnh hoặc đáy swing, nên với 3 hộp mỗi pivot, chart sinh ra cỡ một hộp mỗi nến. Trần 500 hộp vì thế chạm tới trước khi hết cửa sổ 500 nến (ước tính thô: khoảng 400 nến trở lại). Pine tự lặng lẽ xoá các hộp cũ nhất vượt trần, nên các vùng ngoài cùng bên trái tự biến mất.
- "Bị quét" nghĩa là một cái râu chạm tới đường GIỮA, không hơn. Không có phép kiểm tra theo giá đóng cửa. Một cái râu một tick cắt qua đường giữa vẫn quét dải dù giá lập tức quay lại, điều này khớp với ý tưởng quét thanh khoản nhưng cũng nghĩa là dải có thể biến mất vì nhiễu. Chiều ngược lại cũng đúng: nếu giá nhảy gap qua toàn bộ dải (low của nến đã nằm trên đường giữa), phép thử low < mid không thoả và dải không bị quét. Nó tiếp tục kéo dài sang phải trong khi giá nằm ở phía bên kia, và chỉ bị quét khi có một nến sau đó có biên độ vắt ngang đường giữa.
- Dải đã bị quét trông y hệt dải còn sống. Màu không bao giờ đổi sau khi tạo, và hộp không bị xoá khi bị quét. Manh mối trực quan duy nhất là chỗ mép phải dừng lại. Trên chart đông đúc rất dễ nhầm một dải cũ đã dùng hết với dải còn sống.
- Không có trí nhớ ngoài 500 nến gần nhất, và logic nằm trong một hàm. Danh sách các vùng còn sống (liquid_zones) được khai báo bên trong phương thức detect_liquidity, nên không phần nào khác của script đọc được nó. Điều này quan trọng cho Phase B: strategy không thể chỉ "đọc các vùng của chỉ báo". Nó phải tự tính lại một bộ pivot và vùng tương đương, dùng đúng các công thức đó. Chỉ báo cũng không phơi ra plot hay alert nào để móc vào.
- Màu mang tính tương đối, bị đóng băng, và chỉ dựa vào MỘT nến. Nó phản ánh khối lượng của nến pivot so với trung bình và lớn nhất của 500 nến tại thời điểm tạo. Một dải vàng từ 400 nến trước được chấm theo cửa sổ khác với dải vàng hôm nay, và không nên so màu giữa các mã hay các khung thời gian. Nó cũng không nói gì về tổng khối lượng đã giao dịch tại mức giá đó, chỉ nói về một nến, và không nói khối lượng đó là mua hay bán.
- Thang chú giải chỉ là xấp xỉ của cách tô màu. Thang pha đều từ lime nhạt tới vàng trong 21 bước. Màu dải thật dùng hai đoạn chia tại khối lượng trung bình, nên ô giữa của thang không phải "khối lượng trung bình". MIN của thang luôn bằng 0.
- Vùng xuất hiện chậm 2 nến, với mép trái lùi về quá khứ. Pivot cần 2 nến bên phải để được xác nhận. Dải được vẽ ở thời điểm xác nhận nhưng bắt đầu từ nến pivot, nên trên chart trực tiếp bạn không bao giờ hành động được với một dải trước khi nó đủ 2 nến tuổi. Đây không phải repaint: một khi đã vẽ, dải không bị dời.
- Độ dày phụ thuộc khung thời gian qua một bảng gán cứng. Chuyển giữa khung 45 phút và 60 phút làm hệ số đổi từ 0,25 sang 0,2, nên độ dày dải nhảy vì lý do không liên quan tới thị trường. Mọi thứ xây trên các vùng này đều thừa hưởng điểm lạ đó.
- Danh sách khởi đầu với 500 ô trống. Danh sách vùng được tạo với 500 phần tử rỗng (na) và không bao giờ bị gỡ, nên vòng lặp mỗi nến duyệt 500 phần tử trở lên dù chỉ có vài dải thật. Các ô trống không gây hại (phép kiểm tra đường giữa trên phần tử rỗng không bao giờ đúng), nhưng là công việc thừa.
- Vài điểm lạ nhỏ trong code, không ảnh hưởng kết quả. Dòng box_id.set_right(bar_index) bên trong phép kiểm tra đường giữa lặp lại việc vòng lặp đã làm. Bảng chú giải được tạo 100 hàng nhưng chỉ dùng 23. Các tham số của hàm tên min và max, trùng tên với hàm có sẵn của Pine bên trong draw_scale.
- Hai ô màu chung một hàng. Trong bảng Settings bạn thấy một hàng tiêu đề "Liquidation Color" với hai ô màu mang nhãn Max (đầu tiên) và Min (thứ hai).


