1. Mô Tả Chỉ Báo Elliott Wave Scanner (MarkitTick)
Quét các điểm xoay (pivot) đã xác nhận để tìm một sóng đẩy (Impulse) 5 sóng hoàn chỉnh (1-2-3-4-5) hoặc một sóng điều chỉnh (Correction) 3 sóng hoàn chỉnh (A-B-C), kiểm tra mẫu hình ứng viên đó theo các quy tắc cấu trúc của lý thuyết Elliott và các tỷ lệ Fibonacci, vẽ đếm sóng kèm kế hoạch giao dịch dựa trên Fibonacci (điểm vào, cắt lỗ, mục tiêu, Vùng Đảo Chiều Tiềm Năng), và báo cáo chất lượng mẫu hình trên một dashboard chấm điểm trực tiếp
1.1 Khái Niệm Chỉ Báo
Lý thuyết sóng Elliott cho rằng giá không di chuyển ngẫu nhiên mà theo các chu kỳ lặp lại gồm một sóng "đẩy" (impulse) 5 sóng (theo hướng xu hướng lớn) rồi tiếp theo là một sóng "điều chỉnh" (corrective) 3 sóng (ngược hướng xu hướng). Chỉ báo này không cố dự đoán đếm sóng trong thời gian thực khi nó đang hình thành - thay vào đó nó làm việc ngược lại từ các điểm xoay (pivot) đã được xác nhận. Mỗi khi có đủ pivot đã xác nhận, chỉ báo kiểm tra 6 pivot gần nhất (3 đỉnh + 3 đáy) theo các quy tắc mà một sóng đẩy 5 sóng thật sự phải tuân theo, và riêng biệt kiểm tra 3 pivot gần nhất (2 pivot một loại + 1 pivot loại kia) theo tỷ lệ mà một sóng điều chỉnh A-B-C thật sự phải tuân theo. Chỉ khi một ứng viên vượt qua mọi quy tắc và mọi bộ lọc đã bật thì nó mới trở thành một mẫu hình được xác nhận - lúc đó chỉ báo dùng chính hình học của mẫu hình (độ dài các chặng đã hoàn thành) để tính ra điểm vào, điểm cắt lỗ, và một hoặc nhiều mục tiêu dựa trên Fibonacci, cùng với một khung "Vùng Đảo Chiều Tiềm Năng" (PRZ - Potential Reversal Zone) đánh dấu nơi khả năng cao giá sẽ đảo chiều tiếp theo.
- Mẫu hình được xác nhận sau khi đã hoàn thành, không dự đoán khi đang hình thành: một mẫu hình chỉ xuất hiện sau khi pivot cuối cùng của nó (sóng 5, hoặc sóng C) đã được xác nhận qua piv_right nến - chỉ báo đánh dấu một cấu trúc đã hoàn thành và đề xuất một ý tưởng giao dịch cho tương lai từ đó, chứ không dự báo sóng 3 trong khi sóng 2 còn đang hình thành.
- Hai quy tắc luôn bật, ba quy tắc có thể tắt: kiểm tra hồi giá (retracement) của Sóng 2 (38.2%-78.6% của Sóng 1) và Sóng 4 (23.6%-50.0% của Sóng 3) luôn được áp dụng vô điều kiện cho mọi ứng viên sóng đẩy, trong khi "Sóng 3 không phải sóng ngắn nhất", "Sóng 4 không chồng lấn Sóng 1", và "Sóng 3 mở rộng hơn Sóng 1" đều có thể tắt riêng biệt trong nhóm Elliott Rules.
- Mỗi nến chỉ có thể xác nhận một mẫu hình, theo thứ tự ưu tiên cố định: Impulse Bull được thử trước, sau đó Impulse Bear, rồi Correction Bull, rồi Correction Bear - nếu một ứng viên đứng trước trong thứ tự này đủ điều kiện, các ứng viên sau trên cùng nến đó đơn giản không bao giờ được vẽ, dù chúng cũng vượt qua các quy tắc riêng.
- Một Impulse luôn có ưu thế hơn một Correction trùng vùng nến: một mẫu hình 5 sóng vừa được xác nhận sẽ chủ động xoá bất kỳ mẫu hình A-B-C đã vẽ trước đó có vùng nến chồng lấn với nó, trong khi một Correction bị chặn hoàn toàn không được vẽ nếu nó sẽ chồng lấn với một Impulse đã có trên biểu đồ - mối quan hệ này chỉ theo một chiều.
1.2 Tính Năng Chỉ Báo
- Quét Pivot Tự Động: xác nhận đỉnh/đáy swing bằng một số nến trái/phải có thể cấu hình, độc lập với logic mẫu hình.
- Nhận Diện Sóng Đẩy 5 Sóng (1-2-3-4-5): kiểm tra 6 pivot gần nhất theo các quy tắc cốt lõi của sóng đẩy Elliott và các khoảng hồi giá Fibonacci, riêng biệt cho cấu trúc tăng và giảm.
- Nhận Diện Sóng Điều Chỉnh 3 Sóng (A-B-C): kiểm tra 3 pivot gần nhất theo một khoảng mở rộng Fibonacci cho chặng C, riêng biệt cho cấu trúc tăng và giảm, và gán nhãn kết quả là "Flat" hoặc "Exp Flat" tuỳ theo C đi xa bao nhiêu.
- Đường Mở Rộng Fibonacci (chỉ cho Sóng Đẩy): ba đường chiếu nét chấm (1.0x / 1.618x / 2.618x độ dài Sóng 1) vẽ về phía trước từ điểm kết thúc của một sóng đẩy đã xác nhận.
- Vùng Đảo Chiều Tiềm Năng (PRZ): một khung tô bóng đánh dấu dải giá Fibonacci nơi dự kiến mẫu hình sẽ đảo chiều tiếp theo, được vẽ cho cả mẫu hình Sóng Đẩy và Sóng Điều Chỉnh.
- Đường Mục Tiêu Giao Dịch: các đường nét đứt Entry (Vào lệnh) / Stop (Cắt lỗ) / Target (Mục tiêu) kèm nhãn giá và tỷ lệ Risk:Reward (Rủi ro:Lợi nhuận) trực tiếp; mẫu hình Sóng Điều Chỉnh có thêm đường TP1 và TP3.
- Dashboard Chấm Điểm Trực Tiếp: một bảng 22 dòng báo cáo xu hướng (bias), tên/loại mẫu hình, entry/stop/target, độ dài và tỷ lệ các sóng, chất lượng Risk:Reward, số lượng pivot, và số lượng mẫu hình - tất cả dưới dạng điểm số "thanh khối" trực quan.
- Bộ Lọc Xu Hướng Tuỳ Chọn: bộ lọc xu hướng khung thời gian lớn hơn (Higher- Timeframe), bộ lọc điểm giữa cấu trúc thị trường (Market-Structure), và xác nhận khối lượng (Volume, chỉ cho Sóng Đẩy) - mỗi cái đều có thể bật/tắt độc lập.
- Quản Lý Lịch Sử Mẫu Hình: chỉ giữ lại N mẫu hình gần nhất trên biểu đồ, tự động xoá hình vẽ của mẫu hình cũ nhất một khi vượt giới hạn.
- Cảnh Báo (Alert): điều kiện cảnh báo riêng cho một Sóng Đẩy mới và một Sóng Điều Chỉnh mới, kích hoạt tối đa một lần mỗi khi nến đóng, với entry/stop/target của mẫu hình được đưa thẳng vào nội dung tin nhắn.
1.3 Cách Sử Dụng Chỉ Báo
- Đọc thanh điểm "R:R Quality" trên dashboard như một lối tắt đánh giá chất lượng lệnh - nó chuyển tỷ lệ khoảng cách Target/Stop thô thành điểm số 0-10 kèm màu sắc, giúp bạn đánh giá một setup chỉ bằng cái nhìn thoáng qua mà không cần tự tính Risk:Reward.
- Xem khung PRZ như một vùng phản ứng, không phải một mức giá đảo chiều chắc chắn - đây là một dải giá suy ra từ Fibonacci, không phải một đường đơn lẻ; giá có thể xuyên vào một phần trong đó trước khi thực sự đảo chiều.
- Nhớ rằng Entry/Stop/Target của một Sóng Đẩy là một ý tưởng tiếp diễn xu hướng, không phải một lệnh đảo chiều - Target nằm xa hơn theo cùng hướng với Sóng 5 (được tính bằng 0.618 độ dài Sóng 3), và Stop nằm ngay ngoài Sóng 4 - vì vậy đây là một setup tiếp diễn xu hướng được vào lệnh ngay tại điểm kết thúc của chuỗi 5 sóng vừa được đánh dấu, không phải một cược rằng giá sẽ đảo chiều khi đếm sóng hoàn tất.
- Dùng ba mục tiêu (TP1/TP2/TP3) của một mẫu hình Sóng Điều Chỉnh để chốt lời từng phần - chúng được tính ở 1.0x / 1.618x / 2.618x độ dài chặng A-đến-B, tính từ pivot C trở đi, tạo ra ba mục tiêu tiếp diễn xu hướng với mức độ tham vọng tăng dần sau khi điều chỉnh hoàn tất.
- Tăng Pattern Cooldown nếu cùng một swing cứ liên tục kích hoạt lại - vì mỗi khi có nến mới hình thành, cửa sổ pivot dịch đi một bước, nên cùng một cấu trúc có thể bị xác nhận và vẽ lại lặp đi lặp lại nếu không có cơ chế này.
- Bật các bộ lọc tuỳ chọn (HTF Bias, Market Structure, Volume) để giảm bớt tín hiệu ngược xu hướng hoặc thiếu thuyết phục - cả ba đều tắt theo mặc định, nên chỉ báo cơ bản sẽ đánh dấu một mẫu hình hợp lệ bất kể xu hướng lớn hơn hay mức độ tham gia thị trường, trừ khi bạn tự bật chúng.
1.4 Cách Chỉ Báo Hoạt Động
Các Input & Vai Trò
- piv_left / piv_right ("Pivot Left" - Số Nến Trái Pivot / "Pivot Right" - Số Nến Phải Pivot, mặc định: 5 / 5, khoảng 2-50): số nến cần có ở mỗi bên của một đỉnh/đáy để xác nhận nó là một pivot. Một pivot chỉ xuất hiện piv_right nến sau khi nó thực sự xảy ra - tăng một trong hai giá trị làm pivot hiếm hơn và quan trọng hơn, nhưng trễ xác nhận hơn; ví dụ ở mặc định 5, một pivot sóng 5 chỉ được xác nhận 5 nến sau đỉnh/đáy thực tế của nó.
- max_piv ("Max Pivots" - Số Pivot Tối Đa, mặc định: 500, khoảng 10-1000): số lượng pivot lịch sử tối đa được lưu trong bộ nhớ cho mỗi loại (đỉnh/đáy); không ảnh hưởng đến logic mẫu hình, chỉ ảnh hưởng đến mảng dữ liệu có thể lùi về xa đến đâu.
- cooldown ("Pattern Cooldown" - Thời Gian Nghỉ Giữa Các Mẫu Hình, mặc định: 5, khoảng 1-50): khoảng cách tối thiểu (theo chỉ số nến) mà pivot bắt đầu của ứng viên mới phải cách pivot bắt đầu của mẫu hình được chấp nhận gần nhất trước khi một mẫu hình mới được chấp nhận - nếu không có cơ chế này, một cửa sổ pivot dịch chuyển chậm có thể xác nhận lại gần như cùng một đếm sóng ở các nến liên tiếp.
- max_patterns ("Max Patterns on Chart" - Số Mẫu Hình Tối Đa Trên Biểu Đồ, mặc định: 3, khoảng 1-20): có bao nhiêu mẫu hình đã hoàn thành được vẽ cùng lúc; một khi vượt quá, đường/nhãn/khung của mẫu hình cũ nhất bị xoá trước.
- fib_tol ("Fib Tolerance (%)" - Dung Sai Fibonacci (%), mặc định: 10.0%, khoảng 1-30%, được lưu nội bộ dưới dạng số thập phân 0.01-0.30): một dung sai duy nhất áp dụng cho mọi kiểm tra tỷ lệ Fibonacci trong kịch bản (hồi giá Sóng 2/4, tỷ lệ Sóng 5, mở rộng chặng C của điều chỉnh). Tăng giá trị này sẽ nới rộng mọi cửa sổ tỷ lệ - ví dụ cửa sổ hồi giá Sóng 2 là 38.2%-78.6% sẽ nới rộng thành khoảng 34.4%-86.5% ở dung sai mặc định 10%, nên nhiều ứng viên (lỏng lẻo hơn) sẽ đạt; giảm giá trị này làm bộ quét khắt khe hơn nhiều và ít mẫu hình xuất hiện hơn.
- min_size_atr ("Min Size (ATR x)" - Kích Thước Tối Thiểu (bội số ATR), mặc định: 0.8, khoảng 0.1-10.0): độ dài tối thiểu mà một chặng sóng phải có, tính theo bội số của ATR chu kỳ 14, trước khi được xem là đủ lớn để đáng kể. Ở mặc định 0.8, trên một mã có ATR = 10, bất kỳ chặng nào trong Sóng 1/3/5 (sóng đẩy) hoặc chặng A/C (điều chỉnh) ngắn hơn 8 đơn vị giá sẽ bị loại bỏ hoàn toàn vì coi là nhiễu.
- req_w3_ext ("W3 Must Extend W1" - Sóng 3 Phải Mở Rộng Hơn Sóng 1, mặc định: true): yêu cầu độ dài Sóng 3 phải vượt độ dài Sóng 1. Tắt đi cho phép một sóng đẩy hợp lệ mà Sóng 3 ngắn hơn hoặc bằng Sóng 1 - một cách đọc lỏng hơn của xu hướng cổ điển "Sóng 3 thường là dài nhất".
- req_w4_no_ol ("W4 No Overlap W1" - Sóng 4 Không Chồng Lấn Sóng 1, mặc định: true): yêu cầu đáy (tăng) hoặc đỉnh (giảm) của Sóng 4 phải nằm ngoài vùng giá của Sóng 1 - một trong ba quy tắc không thể phá vỡ của lý thuyết Elliott cổ điển. Tắt đi cho phép Sóng 4 hồi lại vào vùng Sóng 1, điều mà thông thường được xem là làm mất hiệu lực đếm sóng đẩy.
- req_w3_not_short ("W3 Not Shortest" - Sóng 3 Không Phải Ngắn Nhất, mặc định: true): yêu cầu độ dài Sóng 3 phải ít nhất bằng cả Sóng 1 và Sóng 5 - quy tắc cổ điển rằng Sóng 3 (trong ba sóng 1, 3, 5) không bao giờ là sóng ngắn nhất. Tắt đi cho phép Sóng 3 là sóng ngắn nhất trong ba chặng sóng đẩy.
- req_w5_fib ("W5 Fib Ratio (61.8%-161.8% W1)" - Tỷ Lệ Fib Sóng 5, mặc định: false): khi bật, yêu cầu thêm rằng độ dài Sóng 5 phải nằm trong khoảng 61.8%-161.8% độ dài Sóng 1 (trong phạm vi dung sai). Tắt theo mặc định, nên Sóng 5 có thể dài bao nhiêu tuỳ ý miễn là vượt qua bộ lọc kích thước ATR.
- req_b_fib ("ABC: B Retracement Filter" - Bộ Lọc Hồi Giá Sóng B, mặc định: false): một tuỳ chọn nhằm ràng buộc mức hồi giá của chặng B trong mẫu hình Sóng Điều Chỉnh - xem ghi chú triển khai bên dưới, vì bộ lọc này thực tế không ảnh hưởng đến việc mẫu hình nào được chấp nhận.
- show_impulse / show_correction (mặc định: true / true): bật/tắt độc lập việc phát hiện và vẽ mỗi nhóm mẫu hình; tắt một trong hai sẽ loại bỏ hoàn toàn nhóm đó khỏi thứ tự ưu tiên, nên nhóm còn lại là nhóm duy nhất có thể được xác nhận.
- show_labels (mặc định: true): bật/tắt các nhãn sóng đẩy "1"/"2"/"3"/"4" và nhãn sóng điều chỉnh "A"/"B"/"C" (nhãn tên mẫu hình ở giữa vẫn được vẽ bất kể cài đặt này).
- show_fib_lines (mặc định: true): bật/tắt ba đường mở rộng Fibonacci nét chấm (chỉ dành cho mẫu hình Sóng Đẩy).
- show_prz (mặc định: true) / prz_transp ("PRZ Transparency" - Độ Trong Suốt PRZ, mặc định: 88, khoảng 50-99): bật/tắt khung Vùng Đảo Chiều Tiềm Năng và đặt độ trong suốt của nó - giá trị càng cao càng trong suốt/mờ hơn.
- show_targets (mặc định: true) / stop_atr_buf ("SL ATR Buffer" - Vùng Đệm Cắt Lỗ (ATR), mặc định: 0.5): bật/tắt các đường Entry/Stop/ Target, và đặt khoảng cách (theo bội số ATR) mà điểm cắt lỗ được đặt vượt ra ngoài pivot neo của nó - ví dụ ở ATR = 10 và mặc định 0.5, điểm cắt lỗ nằm cách 5 đơn vị giá ngoài đáy Sóng 4 (sóng đẩy) hoặc ngoài pivot C (điều chỉnh).
- min_rr ("Min R:R" - Tỷ Lệ R:R Tối Thiểu, mặc định: 1.5, tối thiểu 0.1): tỷ lệ Reward:Risk (Lợi Nhuận:Rủi Ro) tối thiểu mà giao dịch dự kiến của một ứng viên phải đạt được (Target so với khoảng cách Entry/Stop cho Sóng Đẩy; TP2 so với khoảng cách Entry/Stop cho Sóng Điều Chỉnh) - các ứng viên không đạt kiểm tra này bị loại bỏ hoàn toàn, kể cả khi đã vượt qua mọi quy tắc sóng/Fibonacci khác.
- use_htf_bias (mặc định: false) / htf_tf ("HTF TF" - Khung Thời Gian Lớn Hơn, mặc định: "240" = 4 giờ): khi bật, chỉ cho phép mẫu hình tăng nếu giá đóng cửa khung thời gian lớn hơn nằm trên SMA 50 kỳ của nó (và chỉ cho phép mẫu hình giảm nếu nằm dưới) - cả hai đều lấy dữ liệu lùi lại một nến HTF để tránh nhìn trước tương lai (look-ahead).
- use_ms_filter (mặc định: false) / ms_len ("MS Length" - Độ Dài Cấu Trúc Thị Trường, mặc định: 20, khoảng 5-100): khi bật, chỉ cho phép mẫu hình tăng nếu giá đóng cửa nằm trên điểm giữa của biên độ đỉnh/đáy trong ms_len nến gần nhất (và chỉ cho phép mẫu hình giảm nếu nằm dưới điểm giữa đó).
- use_vol_confirm (mặc định: false) / vol_len ("Vol SMA Len" - Độ Dài SMA Khối Lượng, mặc định: 20): khi bật, yêu cầu khối lượng của nến hiện tại phải vượt mức trung bình vol_len kỳ của nó - chỉ được kiểm tra bên trong logic nhận diện Sóng Đẩy, không bao giờ áp dụng cho Sóng Điều Chỉnh.
- col_impulse / col_imp_bear / col_correction (mặc định: xanh cyan / đỏ / cam): các chủ đề màu của sóng - lưu ý mẫu hình Sóng Điều Chỉnh dùng chung một màu cho cả cấu trúc tăng và giảm, khác với mẫu hình Sóng Đẩy có hai màu riêng biệt cho tăng/giảm.
- col_entry / col_stop / col_target / col_fib (mặc định: vàng / hồng / xanh lá / tím): các màu cố định cho đường mục tiêu giao dịch và đường mở rộng Fibonacci, áp dụng như nhau bất kể hướng của mẫu hình.
- alert_impulse / alert_correction (mặc định: true / true): bật/tắt độc lập cảnh báo "tối đa một lần mỗi khi nến đóng" được kích hoạt khi một mẫu hình mới thuộc nhóm đó được chấp nhận.
Các Luồng Logic Chính
🎯 Flow 1: Những Gì Bạn Nhìn Thấy
- Một đường zigzag 5 chặng tô màu (Sóng Đẩy) hoặc zigzag 2 chặng (Sóng Điều Chỉnh A-B-C) nối các pivot liên quan, các nhãn số/chữ sóng, một nhãn tên mẫu hình, một khung PRZ tô bóng tuỳ chọn, các đường Entry/Stop/Target nét đứt kèm nhãn giá + Risk:Reward, và một bảng dashboard ở góc trên bên phải tóm tắt mẫu hình mới nhất cùng thống kê quét trực tiếp.
🔍 Flow 2: Phát Hiện Pivot
- Mỗi nến, một hàm kiểm tra pivot cao/thấp tự viết (f_pivotHigh / f_pivotLow) nhìn lùi piv_left nến và nhìn tới piv_right nến từ một nến ứng viên; nếu mọi nến xung quanh đó đều kém cực trị hơn một cách chặt chẽ, ứng viên được xác nhận là một pivot và được chèn vào đầu một danh sách đang chạy (giới hạn ở max_piv mục cho mỗi loại, cái cũ nhất bị loại bỏ trước).
📈 Flow 3: Kiểm Tra Mẫu Hình Sóng Đẩy
- Một khi có ít nhất 3 đỉnh và 3 đáy, 6 pivot xen kẽ gần nhất được lấy làm các điểm ứng viên Sóng 0-1-2-3-4-5. Ứng viên trước tiên phải vượt qua kiểm tra thứ tự thời gian và hướng nghiêm ngặt, sau đó: Sóng 2 phải hồi lại 38.2%-78.6% Sóng 1 (luôn bật); Sóng 4 phải hồi lại 23.6%-50.0% Sóng 3 (luôn bật); Sóng 4 không được chồng lấn vùng giá Sóng 1 (có thể tắt); Sóng 3 không được là chặng ngắn nhất trong Sóng 1/3/5 (có thể tắt); Sóng 3 phải vượt độ dài Sóng 1 (có thể tắt); Sóng 5 có thể cần nằm trong khoảng 61.8%-161.8% Sóng 1 (tuỳ chọn); và Sóng 1, 3, 5 mỗi cái đều phải tự vượt qua bộ lọc kích thước ATR. Nếu Volume Confirmation được bật, khối lượng của nến hiện tại cũng phải vượt SMA của nó.
🔄 Flow 4: Kiểm Tra Mẫu Hình Điều Chỉnh (A-B-C)
- Một khi có ít nhất 2 đỉnh và 2 đáy, 3 pivot xen kẽ gần nhất trở thành các điểm ứng viên A-B-C (ví dụ với cách đọc tăng: A = đáy cũ hơn, B = đỉnh ở giữa, C = đáy gần nhất). Cả chặng A-đến-B và chặng B-đến-C đều phải vượt qua bộ lọc kích thước ATR, C phải mở rộng 61.8%-161.8% độ dài chặng A-đến-B tính từ B, và C phải nằm vượt qua A theo hướng tiếp diễn (bằng hoặc thấp hơn A với cách đọc tăng). Sau đó điều chỉnh được gán nhãn "Flat" hoặc "Exp Flat" tuỳ theo tỷ lệ mở rộng C đó lớn hơn hay nhỏ hơn 1.0 (xem ghi chú triển khai bên dưới về bộ lọc chặng B và nhãn "Zigzag" không bao giờ đạt tới).
🧭 Flow 5: Bộ Lọc Xu Hướng Tuỳ Chọn
- Một ứng viên đã vượt qua các quy tắc sóng riêng sau đó được kiểm tra thêm, nếu được bật, theo xu hướng khung thời gian lớn hơn (giá đóng cửa HTF so với SMA 50 của HTF, lùi một nến) và bộ lọc điểm giữa cấu trúc thị trường (giá đóng cửa hiện tại so với điểm giữa biên độ ms_len nến gần nhất) - ứng viên tăng cần kết quả tăng trên mọi bộ lọc đã bật, ứng viên giảm cần kết quả giảm trên mọi bộ lọc đã bật. Cuối cùng, tỷ lệ Reward:Risk của giao dịch dự kiến được tính và phải đạt min_rr.
🏁 Flow 6: Cổng Ưu Tiên, Kiểm Tra Chồng Lấn & Cooldown
- Việc phát hiện chỉ chạy sau một điểm khởi động (bar_index vượt quá hai lần cửa sổ pivot trái+phải). Trong số tối đa 4 ứng viên được tính trên nến này (Impulse Bull, Impulse Bear, Correction Bull, Correction Bear), chỉ ứng viên đầu tiên theo thứ tự ưu tiên cố định đó, đã được bật và hợp lệ, được giữ lại - các ứng viên sau trên cùng nến bị loại bỏ dù chúng có hợp lệ. Một ứng viên Correction còn bị loại bỏ thêm nếu vùng nến của nó chồng lấn với một mẫu hình Impulse đã có trên biểu đồ. Ứng viên còn sót lại chỉ thực sự được chấp nhận khi nến đã đóng xác nhận, và chỉ khi chưa có mẫu hình nào được chấp nhận trước đó hoặc pivot bắt đầu của ứng viên mới cách pivot bắt đầu của mẫu hình được chấp nhận gần nhất hơn cooldown nến.
✏️ Flow 7: Vẽ Mẫu Hình
- Với một Sóng Đẩy được chấp nhận: 5 đường nối được vẽ (Sóng 1, 3, 5 dùng màu đầy đủ; Sóng 2, 4 nhạt/mờ hơn), các nhãn "1"-"4" được đặt tại pivot tương ứng của chúng (pivot của chính Sóng 5 không được gắn nhãn riêng), một nhãn tên mẫu hình ở giữa được thêm vào, và - nếu được bật - bất kỳ mẫu hình Sóng Điều Chỉnh nào có vùng nến chồng lấn với Sóng Đẩy mới này sẽ bị xoá. Nếu đường mở rộng Fibonacci được bật, ba đường nét chấm (ở 1.0x / 1.618x / 2.618x độ dài Sóng 1 tính từ Sóng 4) được chiếu 50 nến về phía trước kèm nhãn tương ứng. Với một Sóng Điều Chỉnh được chấp nhận: 2 đường nối (A-đến-B màu đầy đủ, B- đến-C nhạt hơn) được vẽ, các nhãn "A"/"B"/"C" được đặt, và một nhãn ở giữa hiển thị tên mẫu hình cộng với phân loại Flat/Exp Flat của nó trong ngoặc vuông.
🎯 Flow 8: Khung PRZ & Đường Mục Tiêu Giao Dịch
- Nếu được bật, một khung Vùng Đảo Chiều Tiềm Năng tô bóng được vẽ trải dài trên dải đảo chiều được chiếu theo Fibonacci của chính mẫu hình, kèm một nhãn "PRZ". Nếu mục tiêu giao dịch được bật và hợp lệ, các đường Entry/Stop/Target nét đứt được vẽ kéo dài 50 nến về phía trước kèm nhãn giá (nhãn Target cũng hiển thị tỷ lệ Risk:Reward trực tiếp); riêng với mẫu hình Sóng Điều Chỉnh, hai đường nét đứt bổ sung (TP1 ở 1.0x, TP3 ở 2.618x độ dài chặng A-đến-B tính từ Entry) được thêm vào bên cạnh đường Target chính (chính nó đại diện cho TP2 ở 1.618x).
🗑️ Flow 9: Quản Lý Lịch Sử Mẫu Hình
- Hình vẽ của mỗi mẫu hình vừa được chấp nhận được đẩy vào một danh sách lịch sử đang chạy; một khi danh sách đó vượt quá max_patterns, đường/nhãn/ khung của mẫu hình cũ nhất bị xoá hoàn toàn khỏi biểu đồ (chứ không chỉ ẩn đi) để giữ số lượng hình vẽ trong giới hạn.
🔔 Flow 10: Cảnh Báo
- Trên cùng nến đã đóng xác nhận mà một mẫu hình được chấp nhận, nếu công tắc cảnh báo tương ứng (alert_impulse hoặc alert_correction) đang bật, một cảnh báo được kích hoạt (tối đa một lần mỗi khi nến đóng) với tên mẫu hình, entry, stop, và target được định dạng vào nội dung tin nhắn.
📋 Flow 11: Dashboard
- Mỗi nến, bảng dashboard làm mới: xu hướng (Bull/Bear), tên và loại của mẫu hình mới nhất, Entry/Stop/Target của nó, điểm số "thanh khối" Risk:Reward (0-10, phân màu theo mức), độ dài Sóng 1/3/5 và tỷ lệ của chúng so với Sóng 1, loại điều chỉnh (nếu có), một điểm số "thanh khối" tổng số pivot, số nến đã trôi qua kể từ mẫu hình gần nhất, ATR(14) hiện tại, các bộ đếm mẫu hình Sóng Đẩy + Sóng Điều Chỉnh đang chạy, và (nếu được bật) kết quả xu hướng HTF.
Đầu Ra & Vai Trò Sử Dụng
- Hình vẽ đếm sóng (zigzag + nhãn): một bản ghi trực quan chính xác về việc chỉ báo đã dùng những pivot nào để biện minh cho mẫu hình, cho phép bạn tự kiểm tra đếm sóng so với cách đọc biểu đồ của riêng bạn.
- Đường mở rộng Fibonacci (Sóng Đẩy): các mức tham chiếu chiếu về phía trước (1.0x/1.618x/2.618x Sóng 1) để ước lượng một đợt tiếp diễn xu hướng có thể hợp lý mở rộng đến đâu.
- Khung PRZ: một dải giá suy ra từ Fibonacci đánh dấu nơi cấu trúc của mẫu hình gợi ý khả năng cao sẽ xảy ra đảo chiều tiếp theo.
- Đường Entry/Stop/Target (+ TP1/TP3 cho Sóng Điều Chỉnh): một kế hoạch giao dịch dựa trên Fibonacci đã dựng sẵn, neo vào mẫu hình vừa được xác nhận, kèm tỷ lệ Risk:Reward trực tiếp.
- Dashboard: một bản tóm tắt chất lượng và bối cảnh chỉ cần nhìn thoáng qua - xu hướng, danh tính mẫu hình, các mức giao dịch, tỷ lệ các sóng, và lượng lịch sử mà lần quét đã tích luỹ được - mà không cần kiểm tra từng hình vẽ trên biểu đồ.
- Cảnh báo: thông báo đẩy ngay khi một Sóng Đẩy hoặc Sóng Điều Chỉnh mới được xác nhận, mang theo đúng entry/stop/target mà biểu đồ vừa vẽ.
// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
// https://creativecommons.org/licenses/by-nc-sa/4.0/
// © MarkitTick
//@version=6
indicator("Elliott Wave Scanner [MarkitTick]", overlay=true, max_lines_count=500, max_labels_count=500, max_boxes_count=200, max_bars_back=1000)
// Inputs (Đã Việt hóa)
string GRP_GEN = "⚙️ Chung"
string GRP_PIV = "📍 Pivot"
string GRP_EW = "🌊 Quy Tắc Elliott"
string GRP_COR = "🔄 Điều Chỉnh"
string GRP_FLT = "🧭 Bộ Lọc"
string GRP_VIS = "🎨 Hiển Thị"
string GRP_DASH = "📊 Dashboard"
string GRP_ALT = "🔔 Cảnh Báo"
piv_left = input.int(5, "Độ Dài Trái Pivot", minval=2, maxval=50, group=GRP_PIV, tooltip="Số nến bên trái một đỉnh/đáy để xác nhận nó là pivot. Tăng giá trị = pivot xác nhận chậm hơn nhưng chỉ bắt được swing lớn hơn.")
piv_right = input.int(5, "Độ Dài Phải Pivot", minval=2, maxval=50, group=GRP_PIV, tooltip="Số nến bên phải một đỉnh/đáy để xác nhận nó là pivot. Một pivot chỉ xuất hiện sau đúng số nến này kể từ khi nó thực sự xảy ra.")
max_piv = input.int(500, "Số Pivot Tối Đa", minval=10, maxval=1000,group=GRP_PIV, tooltip="Số lượng pivot lịch sử tối đa được lưu trong bộ nhớ cho mỗi loại (đỉnh/đáy). Không ảnh hưởng logic mẫu hình, chỉ ảnh hưởng phạm vi dữ liệu có thể lùi về.")
cooldown = input.int(5, "Thời Gian Nghỉ Mẫu Hình", minval=1, maxval=50, group=GRP_GEN, tooltip="Số nến tối thiểu giữa pivot bắt đầu của mẫu hình mới và mẫu hình được chấp nhận gần nhất. Tăng lên nếu cùng một swing cứ bị xác nhận lặp lại.")
max_patterns = input.int(3, "Số Mẫu Hình Tối Đa Trên Biểu Đồ",minval=1, maxval=20, group=GRP_GEN, tooltip="Số mẫu hình đã hoàn thành được vẽ cùng lúc. Mẫu hình cũ nhất sẽ tự động bị xoá khi vượt quá giới hạn này.")
fib_tol = input.float(10.0,"Dung Sai Fibonacci (%)", minval=1.0,maxval=30.0,step=0.5,group=GRP_EW, tooltip="Dung sai áp dụng cho MỌI tỷ lệ Fibonacci trong chỉ báo (hồi giá Sóng 2/4, tỷ lệ Sóng 5, mở rộng chặng C). Tăng giá trị = bộ quét lỏng hơn, nhiều mẫu hình xuất hiện hơn.") / 100.0
min_size_atr = input.float(0.8, "Kích Thước Tối Thiểu (ATR×)", minval=0.1,maxval=10.0,step=0.1,group=GRP_EW, tooltip="Độ dài tối thiểu của một chặng sóng, tính theo bội số ATR(14), để không bị coi là nhiễu. VD: ATR=10, giá trị 0.8 → chặng phải dài hơn 8 đơn vị giá.")
req_w3_ext = input.bool(true, "Sóng 3 Phải Mở Rộng Hơn Sóng 1", group=GRP_EW, tooltip="Bắt buộc độ dài Sóng 3 phải vượt Sóng 1. Tắt để cho phép Sóng 3 ngắn hơn hoặc bằng Sóng 1.")
req_w4_no_ol = input.bool(true, "Sóng 4 Không Chồng Lấn Sóng 1", group=GRP_EW, tooltip="Bắt buộc Sóng 4 không được hồi vào vùng giá Sóng 1 - một quy tắc bất di bất dịch của lý thuyết Elliott cổ điển.")
req_w3_not_short= input.bool(true, "Sóng 3 Không Phải Ngắn Nhất", group=GRP_EW, tooltip="Bắt buộc Sóng 3 không phải là chặng ngắn nhất trong ba sóng 1/3/5.")
req_w5_fib = input.bool(false, "Tỷ Lệ Fib Sóng 5 (61.8%–161.8% Sóng 1)",group=GRP_EW, tooltip="Khi bật, yêu cầu thêm Sóng 5 phải dài bằng 61.8%-161.8% Sóng 1 (trong phạm vi dung sai).")
req_b_fib = input.bool(false, "ABC: Bộ Lọc Hồi Giá Sóng B", group=GRP_EW, tooltip="Dự kiến ràng buộc mức hồi giá của chặng B trong mẫu hình ABC. LƯU Ý: do cách tính hiện tại, bộ lọc này luôn đúng và không loại bỏ ứng viên nào.")
show_impulse = input.bool(true, "Hiện Sóng Đẩy (12345)", group=GRP_VIS, tooltip="Bật/tắt việc phát hiện và vẽ mẫu hình Sóng Đẩy 5 sóng.")
show_correction = input.bool(true, "Hiện Sóng Điều Chỉnh (ABC)", group=GRP_VIS, tooltip="Bật/tắt việc phát hiện và vẽ mẫu hình Sóng Điều Chỉnh A-B-C.")
show_labels = input.bool(true, "Hiện Nhãn Sóng", group=GRP_VIS, tooltip="Bật/tắt nhãn số 1-4 (sóng đẩy) và chữ A/B/C (sóng điều chỉnh). Nhãn tên mẫu hình ở giữa vẫn hiện bất kể cài đặt này.")
show_fib_lines = input.bool(true, "Hiện Đường Mở Rộng Fib", group=GRP_VIS, tooltip="Bật/tắt ba đường mở rộng Fibonacci nét chấm (1.0x/1.618x/2.618x Sóng 1), chỉ áp dụng cho Sóng Đẩy.")
show_prz = input.bool(true, "Hiện Vùng PRZ", group=GRP_VIS, tooltip="Bật/tắt khung Vùng Đảo Chiều Tiềm Năng (PRZ).")
prz_transp = input.int(88, "Độ Trong Suốt PRZ", minval=50,maxval=99, group=GRP_VIS, tooltip="Độ trong suốt của khung PRZ. Giá trị càng cao càng trong suốt/mờ.")
show_targets = input.bool(true, "Hiện Mục Tiêu Giao Dịch", group=GRP_VIS, tooltip="Bật/tắt các đường Entry/Stop/Target.")
stop_atr_buf = input.float(0.5, "Vùng Đệm Cắt Lỗ (ATR)", minval=0.0,step=0.1, group=GRP_VIS, tooltip="Khoảng đệm đặt Stop, tính theo bội số ATR(14), ngoài pivot neo (Sóng 4 hoặc pivot C). VD: ATR=10, giá trị 0.5 → Stop cách pivot neo 5 đơn vị giá.")
min_rr = input.float(1.5, "Tỷ Lệ R:R Tối Thiểu", minval=0.1,step=0.1, group=GRP_FLT, tooltip="Tỷ lệ Reward:Risk tối thiểu của giao dịch dự kiến. Ứng viên không đạt tỷ lệ này bị loại bỏ dù đã qua mọi quy tắc sóng.")
use_htf_bias = input.bool(false, "Bộ Lọc Xu Hướng Khung Lớn (HTF)", group=GRP_FLT, tooltip="Chỉ cho phép mẫu hình tăng khi khung thời gian lớn hơn đang tăng (và ngược lại), dựa trên giá đóng cửa so với SMA 50.")
htf_tf = input.timeframe("240","Khung Thời Gian HTF", group=GRP_FLT, tooltip="Khung thời gian lớn hơn dùng để xác định xu hướng khi Bộ Lọc Xu Hướng HTF được bật. Mặc định 240 phút (4 giờ).")
use_ms_filter = input.bool(false, "Bộ Lọc Cấu Trúc Thị Trường", group=GRP_FLT, tooltip="Chỉ cho phép mẫu hình tăng khi giá đóng cửa nằm trên điểm giữa biên độ N nến gần nhất (và ngược lại cho mẫu hình giảm).")
ms_len = input.int(20, "Độ Dài Cấu Trúc Thị Trường", minval=5,maxval=100, group=GRP_FLT, tooltip="Số nến dùng để tính biên độ cao/thấp cho Bộ Lọc Cấu Trúc Thị Trường.")
use_vol_confirm = input.bool(false, "Xác Nhận Khối Lượng (Sóng 3)", group=GRP_FLT, tooltip="Yêu cầu khối lượng nến hiện tại phải vượt mức trung bình. Chỉ áp dụng cho mẫu hình Sóng Đẩy, không áp dụng cho Sóng Điều Chỉnh.")
vol_len = input.int(20, "Độ Dài SMA Khối Lượng", group=GRP_FLT, tooltip="Số nến dùng để tính khối lượng trung bình (SMA) khi Xác Nhận Khối Lượng được bật.")
col_impulse = input.color(color.rgb(0, 200, 255, 0), "Màu Sóng Đẩy Tăng", group=GRP_VIS, tooltip="Màu dùng để vẽ mẫu hình Sóng Đẩy theo hướng tăng.")
col_imp_bear = input.color(color.rgb(255, 80, 80, 0), "Màu Sóng Đẩy Giảm", group=GRP_VIS, tooltip="Màu dùng để vẽ mẫu hình Sóng Đẩy theo hướng giảm.")
col_correction = input.color(color.rgb(255, 160, 0, 0), "Màu Sóng Điều Chỉnh", group=GRP_VIS, tooltip="Màu dùng để vẽ mẫu hình Sóng Điều Chỉnh - dùng chung cho cả hướng tăng và giảm.")
col_entry = input.color(color.rgb(255, 220, 0, 0), "Màu Vào Lệnh", group=GRP_VIS, tooltip="Màu của đường Entry (Vào Lệnh), áp dụng như nhau bất kể hướng mẫu hình.")
col_stop = input.color(color.rgb(255, 50, 130, 0), "Màu Cắt Lỗ", group=GRP_VIS, tooltip="Màu của đường Stop (Cắt Lỗ), áp dụng như nhau bất kể hướng mẫu hình.")
col_target = input.color(color.rgb(0, 255, 160, 0), "Màu Mục Tiêu", group=GRP_VIS, tooltip="Màu của các đường Target/TP1/TP2/TP3, áp dụng như nhau bất kể hướng mẫu hình.")
col_fib = input.color(color.rgb(180, 100, 255, 0), "Màu Đường Fib", group=GRP_VIS, tooltip="Màu của ba đường mở rộng Fibonacci nét chấm (chỉ Sóng Đẩy).")
color dash_bg_color = input.color(color.rgb(10, 10, 18, 5), "Nền", group=GRP_DASH, tooltip="Màu nền của bảng dashboard.")
color dash_txt_color = input.color(color.rgb(220, 220, 235, 0), "Chữ", group=GRP_DASH, tooltip="Màu chữ mặc định của bảng dashboard.")
bool alert_impulse = input.bool(true, "Cảnh Báo: Phát Hiện Sóng Đẩy", group=GRP_ALT, tooltip="Kích hoạt cảnh báo (tối đa 1 lần/nến đóng) khi một mẫu hình Sóng Đẩy mới được chấp nhận.")
bool alert_correction = input.bool(true, "Cảnh Báo: Phát Hiện Sóng Điều Chỉnh", group=GRP_ALT, tooltip="Kích hoạt cảnh báo (tối đa 1 lần/nến đóng) khi một mẫu hình Sóng Điều Chỉnh mới được chấp nhận.")
// Types
type Pivot
float p
int i
type WaveResult
bool detected
string name
bool isBullish
float w1_lo
float w1_hi
int w1_lo_i
int w1_hi_i
float w2_p
int w2_i
float w3_p
int w3_i
float w4_p
int w4_i
float w5_p
int w5_i
float wa_p
int wa_i
float wb_p
int wb_i
float wc_p
int wc_i
float entry_p
float stop_p
float target_p
float tp2_p
float tp3_p
float prz_lo
float prz_hi
int start_i
int end_i
float w1_len
float w3_len
float w5_len
int pattern_type
string corr_type
type WaveDrawings
line[] lns
label[] lbls
box[] bxs
int pattern_type
int start_i
int end_i
// State
var WaveResult EMPTY_W = WaveResult.new(false, "", false, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, na, 0, "")
var array pivotHighs = array.new()
var array pivotLows = array.new()
var array pat_history = array.new()
var string dash_name = "—"
var bool dash_bull = false
var int dash_last_bar = 0
var float dash_entry = na
var float dash_stop = na
var float dash_target = na
var float dash_w1_len = na
var float dash_w3_len = na
var float dash_w5_len = na
var float dash_w3_ratio = na
var float dash_w5_ratio = na
var float dash_fib_a = na
var float dash_fib_b = na
var float dash_fib_c = na
var int dash_pattern_type= 0
var string dash_corr_type = "—"
var float dash_tp2 = na
var float dash_tp3 = na
var int frozen_idx = na
var int impulse_count = 0
var int correction_count = 0
// Calculations
string clean_ticker = syminfo.prefix + ":" + syminfo.ticker
float atr_val = ta.atr(14)
float vol_sma = use_vol_confirm ? ta.sma(volume, math.max(1, math.min(vol_len, bar_index + 1))) : na
[htf_close, htf_ema] = if use_htf_bias
request.security(syminfo.tickerid, htf_tf, [close[1], ta.sma(close, 50)[1]], lookahead=barmerge.lookahead_on)
else
[na, na]
bool htf_bull = use_htf_bias ? htf_close > htf_ema : true
bool htf_bear = use_htf_bias ? htf_close < htf_ema : true
float ms_hi = use_ms_filter ? ta.highest(high, ms_len) : na
float ms_lo = use_ms_filter ? ta.lowest(low, ms_len) : na
float ms_mid = (ms_hi + ms_lo) * 0.5
bool ms_bull = use_ms_filter and close > ms_mid
bool ms_bear = use_ms_filter and close < ms_mid
int dash_bars_since = bar_index - dash_last_bar
float dash_rr_raw = not na(dash_entry) and not na(dash_stop) and not na(dash_target) and math.abs(dash_entry - dash_stop) > 1e-10 ? math.abs(dash_target - dash_entry) / math.abs(dash_entry - dash_stop) : 0.0
f_blockBar(float score) =>
int n = math.min(math.max(math.round(score), 0), 10)
string s = ""
for i = 1 to 10
s += i <= n ? "█" : "░"
s + " " + str.tostring(math.round(score / 10.0 * 100.0), "##0") + "%"
f_blockColor(float score) =>
score >= 7.0 ? color.rgb(0, 255, 120) : score >= 4.0 ? color.rgb(80, 255, 0) : score >= 1.5 ? color.rgb(200, 200, 0) : color.rgb(110, 110, 110)
f_pivotHigh(series float src, simple int llen, simple int rlen) =>
float candidate = src[rlen]
bool isValid = true
for i = 1 to llen + rlen
if i != rlen and src[i] >= candidate
isValid := false
isValid ? candidate : na
f_pivotLow(series float src, simple int llen, simple int rlen) =>
float candidate = src[rlen]
bool isValid = true
for i = 1 to llen + rlen
if i != rlen and src[i] <= candidate
isValid := false
isValid ? candidate : na
f_inRange(float ratio, float lo, float hi, float tol) =>
ratio >= lo * (1.0 - tol) and ratio <= hi * (1.0 + tol)
f_fibRatio(float leg1, float leg2) =>
math.abs(leg1) > 1e-10 ? math.abs(leg2) / math.abs(leg1) : na
f_isValidSize(float h) =>
h > atr_val * min_size_atr
f_sl(float anchor, bool isBull) =>
isBull ? anchor - atr_val * stop_atr_buf : anchor + atr_val * stop_atr_buf
f_validate_rr(float entry_p, float stop_p, float target_p) =>
float risk = math.abs(entry_p - stop_p)
float reward = math.abs(target_p - entry_p)
risk > 1e-10 and reward / risk >= min_rr
f_ms_bias(bool isBull) => not use_ms_filter or (isBull ? ms_bull : ms_bear)
f_htf_bias(bool isBull) => not use_htf_bias or (isBull ? htf_bull : htf_bear)
f_manage_drawings(int max_items) =>
while array.size(pat_history) > max_items
WaveDrawings old = array.shift(pat_history)
int _ls = array.size(old.lns)
if _ls > 0
for i = 0 to _ls - 1
line _l = array.get(old.lns, i)
if not na(_l)
line.delete(_l)
int _lb = array.size(old.lbls)
if _lb > 0
for i = 0 to _lb - 1
label _l = array.get(old.lbls, i)
if not na(_l)
label.delete(_l)
int _bx = array.size(old.bxs)
if _bx > 0
for i = 0 to _bx - 1
box _b = array.get(old.bxs, i)
if not na(_b)
box.delete(_b)
f_deleteDrawing(WaveDrawings d) =>
int _ls = array.size(d.lns)
if _ls > 0
for i = 0 to _ls - 1
line _l = array.get(d.lns, i)
if not na(_l)
line.delete(_l)
int _lb = array.size(d.lbls)
if _lb > 0
for i = 0 to _lb - 1
label _l = array.get(d.lbls, i)
if not na(_l)
label.delete(_l)
int _bx = array.size(d.bxs)
if _bx > 0
for i = 0 to _bx - 1
box _b = array.get(d.bxs, i)
if not na(_b)
box.delete(_b)
f_purgeOverlappingCorrections(int newStart, int newEnd) =>
int _n = array.size(pat_history)
if _n > 0
array _toRemove = array.new()
for i = 0 to _n - 1
WaveDrawings _d = array.get(pat_history, i)
bool _isCorrection = _d.pattern_type == 2
bool _overlap = _d.start_i <= newEnd and _d.end_i >= newStart
if _isCorrection and _overlap
array.push(_toRemove, i)
int _rn = array.size(_toRemove)
if _rn > 0
for j = _rn - 1 to 0
int _ri = array.get(_toRemove, j)
WaveDrawings _dd = array.get(pat_history, _ri)
f_deleteDrawing(_dd)
array.remove(pat_history, _ri)
f_overlapsExistingImpulse(int newStart, int newEnd) =>
bool _found = false
int _n = array.size(pat_history)
if _n > 0
for i = 0 to _n - 1
WaveDrawings _d = array.get(pat_history, i)
bool _isImpulse = _d.pattern_type == 1
bool _overlap = _d.start_i <= newEnd and _d.end_i >= newStart
if _isImpulse and _overlap
_found := true
_found
// Signals
detectImpulseBull(array highs, array lows) =>
res = EMPTY_W
bool _has = highs.size() >= 3 and lows.size() >= 3
if not _has
res
else
_p0 = lows.get(2)
_p1 = highs.get(2)
_p2 = lows.get(1)
_p3 = highs.get(1)
_p4 = lows.get(0)
_p5 = highs.get(0)
bool _seq = _p0.i < _p1.i and _p1.i < _p2.i and _p2.i < _p3.i and _p3.i < _p4.i and _p4.i < _p5.i
bool _dir = _p1.p > _p0.p and _p2.p > _p0.p and _p3.p > _p1.p
bool _w2 = _p2.p > _p0.p
float _w1_len = _p1.p - _p0.p
float _w2_ret = _p1.p > _p0.p ? (_p1.p - _p2.p) / _w1_len : na
float _w3_len = _p3.p - _p2.p
float _w4_ret = _p3.p > _p2.p ? (_p3.p - _p4.p) / _w3_len : na
float _w5_len = _p5.p - _p4.p
bool _w4_no_ol = not req_w4_no_ol or (_p4.p > _p1.p)
bool _w3_not_s = not req_w3_not_short or (_w3_len >= _w1_len and _w3_len >= _w5_len)
bool _w3_ext = not req_w3_ext or (_w3_len > _w1_len)
float _w5_rat = _w1_len > 1e-10 ? _w5_len / _w1_len : na
bool _w5_fib = not req_w5_fib or (not na(_w5_rat) and f_inRange(_w5_rat, 0.618, 1.618, fib_tol))
bool _w2_fib = not na(_w2_ret) and f_inRange(_w2_ret, 0.382, 0.786, fib_tol)
bool _w4_fib = not na(_w4_ret) and f_inRange(_w4_ret, 0.236, 0.500, fib_tol)
bool _w5_valid = f_isValidSize(_w5_len) and f_isValidSize(_w1_len) and f_isValidSize(_w3_len)
bool _vol_ok = not use_vol_confirm or (not na(vol_sma) and volume > vol_sma)
if _seq and _dir and _w2 and _w2_fib and _w4_fib and _w4_no_ol and _w3_not_s and _w3_ext and _w5_fib and _w5_valid and _vol_ok
if f_ms_bias(true) and f_htf_bias(true)
float _w5_proj_161 = _p4.p + _w1_len * 1.618
float _w5_proj_100 = _p4.p + _w1_len * 1.000
float _prz_lo = math.min(_w5_proj_100, _p5.p)
float _prz_hi = math.max(_w5_proj_161, _p5.p)
float _entry_p = _p5.p
float _stop_p = f_sl(_p4.p, true)
float _target_p = _p5.p + _w3_len * 0.618
bool _rr_ok = f_validate_rr(_entry_p, _stop_p, _target_p)
if _rr_ok
res := WaveResult.new(true, "Sóng Đẩy Tăng", true, _p0.p, _p1.p, _p0.i, _p1.i, _p2.p, _p2.i, _p3.p, _p3.i, _p4.p, _p4.i, _p5.p, _p5.i, na, na, na, na, na, na, _entry_p, _stop_p, _target_p, na, na, _prz_lo, _prz_hi, _p0.i, _p5.i, _w1_len, _w3_len, _w5_len, 1, "")
res
detectImpulseBear(array highs, array lows) =>
res = EMPTY_W
bool _has = highs.size() >= 3 and lows.size() >= 3
if not _has
res
else
_p0 = highs.get(2)
_p1 = lows.get(2)
_p2 = highs.get(1)
_p3 = lows.get(1)
_p4 = highs.get(0)
_p5 = lows.get(0)
bool _seq = _p0.i < _p1.i and _p1.i < _p2.i and _p2.i < _p3.i and _p3.i < _p4.i and _p4.i < _p5.i
bool _dir = _p1.p < _p0.p and _p2.p < _p0.p and _p3.p < _p1.p
bool _w2 = _p2.p < _p0.p
float _w1_len = _p0.p - _p1.p
float _w2_ret = _p0.p > _p1.p ? (_p2.p - _p1.p) / _w1_len : na
float _w3_len = _p2.p - _p3.p
float _w4_ret = _p2.p > _p3.p ? (_p4.p - _p3.p) / _w3_len : na
float _w5_len = _p4.p - _p5.p
bool _w4_no_ol = not req_w4_no_ol or (_p4.p < _p1.p)
bool _w3_not_s = not req_w3_not_short or (_w3_len >= _w1_len and _w3_len >= _w5_len)
bool _w3_ext = not req_w3_ext or (_w3_len > _w1_len)
float _w5_rat = _w1_len > 1e-10 ? _w5_len / _w1_len : na
bool _w5_fib = not req_w5_fib or (not na(_w5_rat) and f_inRange(_w5_rat, 0.618, 1.618, fib_tol))
bool _w2_fib = not na(_w2_ret) and f_inRange(_w2_ret, 0.382, 0.786, fib_tol)
bool _w4_fib = not na(_w4_ret) and f_inRange(_w4_ret, 0.236, 0.500, fib_tol)
bool _w5_valid = f_isValidSize(_w5_len) and f_isValidSize(_w1_len) and f_isValidSize(_w3_len)
bool _vol_ok = not use_vol_confirm or (not na(vol_sma) and volume > vol_sma)
if _seq and _dir and _w2 and _w2_fib and _w4_fib and _w4_no_ol and _w3_not_s and _w3_ext and _w5_fib and _w5_valid and _vol_ok
if f_ms_bias(false) and f_htf_bias(false)
float _w5_proj_161 = _p4.p - _w1_len * 1.618
float _w5_proj_100 = _p4.p - _w1_len * 1.000
float _prz_lo = math.min(_w5_proj_161, _p5.p)
float _prz_hi = math.max(_w5_proj_100, _p5.p)
float _entry_p = _p5.p
float _stop_p = f_sl(_p4.p, false)
float _target_p = _p5.p - _w3_len * 0.618
bool _rr_ok = f_validate_rr(_entry_p, _stop_p, _target_p)
if _rr_ok
res := WaveResult.new(true, "Sóng Đẩy Giảm", false, _p1.p, _p0.p, _p1.i, _p0.i, _p2.p, _p2.i, _p3.p, _p3.i, _p4.p, _p4.i, _p5.p, _p5.i, na, na, na, na, na, na, _entry_p, _stop_p, _target_p, na, na, _prz_lo, _prz_hi, _p0.i, _p5.i, _w1_len, _w3_len, _w5_len, 1, "")
res
detectCorrectionBull(array highs, array lows) =>
res = EMPTY_W
bool _has = highs.size() >= 2 and lows.size() >= 2
if not _has
res
else
_wa = lows.get(1)
_wb = highs.get(1)
_wc = lows.get(0)
bool _seq = _wa.i < _wb.i and _wb.i < _wc.i
float _a_len = _wb.p - _wa.p
float _b_ret = _a_len > 1e-10 ? (_wb.p - _wc.p) / _a_len : na
float _c_drop = _wb.p - _wc.p
float _c_ext = _a_len > 1e-10 ? _c_drop / _a_len : na
float _b_ret_ab = _a_len > 1e-10 ? (_wb.p - _wa.p - (_wb.p - _wc.p)) / _a_len : na
float _b_from_a = _a_len > 1e-10 ? (_wb.p - _wc.p) / _a_len : na
bool _abc_ok = f_isValidSize(_a_len) and f_isValidSize(_c_drop)
bool _c_ok = not na(_c_ext) and f_inRange(_c_ext, 0.618, 1.618, fib_tol)
bool _c_below_a = _wc.p <= _wa.p
float _b_wave_ret = _a_len > 1e-10 ? (_wb.p - _wa.p) / _a_len : na
bool _b_ok = not req_b_fib or (not na(_b_wave_ret) and _b_wave_ret >= 0.382 * (1.0 - fib_tol) and _b_wave_ret <= 1.382 * (1.0 + fib_tol))
string _ctype = "Zigzag"
if not na(_b_wave_ret) and not na(_c_ext)
if _b_wave_ret >= 0.9 * (1.0 - fib_tol) and _b_wave_ret <= 1.05 * (1.0 + fib_tol)
_ctype := _c_ext > 1.0 ? "Exp Flat" : "Flat"
else
_ctype := "Zigzag"
if _seq and _abc_ok and _c_ok and _c_below_a and _b_ok
if f_ms_bias(true) and f_htf_bias(true)
float _prz_lo = _wb.p - _a_len * 1.618 * (1.0 + fib_tol)
float _prz_hi = _wb.p - _a_len * 0.618 * (1.0 - fib_tol)
float _entry_p = _wc.p
float _stop_p = f_sl(_wc.p, true)
float _tp1 = _wc.p + _a_len * 1.000
float _tp2 = _wc.p + _a_len * 1.618
float _tp3 = _wc.p + _a_len * 2.618
bool _rr_ok = f_validate_rr(_entry_p, _stop_p, _tp2)
if _rr_ok
res := WaveResult.new(true, "ABC Tăng", true, na, na, na, na, na, na, na, na, na, na, na, na, _wa.p, _wa.i, _wb.p, _wb.i, _wc.p, _wc.i, _entry_p, _stop_p, _tp2, _tp2, _tp3, _prz_lo, _prz_hi, _wa.i, _wc.i, _a_len, na, na, 2, _ctype)
res
detectCorrectionBear(array highs, array lows) =>
res = EMPTY_W
bool _has = highs.size() >= 2 and lows.size() >= 2
if not _has
res
else
_wa = highs.get(1)
_wb = lows.get(1)
_wc = highs.get(0)
bool _seq = _wa.i < _wb.i and _wb.i < _wc.i
float _a_len = _wa.p - _wb.p
float _c_rise = _wc.p - _wb.p
float _c_ext = _a_len > 1e-10 ? _c_rise / _a_len : na
bool _abc_ok = f_isValidSize(_a_len) and f_isValidSize(_c_rise)
bool _c_ok = not na(_c_ext) and f_inRange(_c_ext, 0.618, 1.618, fib_tol)
bool _c_above_a = _wc.p >= _wa.p
float _b_wave_ret = _a_len > 1e-10 ? (_wa.p - _wb.p) / _a_len : na
bool _b_ok = not req_b_fib or (not na(_b_wave_ret) and _b_wave_ret >= 0.382 * (1.0 - fib_tol) and _b_wave_ret <= 1.382 * (1.0 + fib_tol))
string _ctype = "Zigzag"
if not na(_b_wave_ret) and not na(_c_ext)
if _b_wave_ret >= 0.9 * (1.0 - fib_tol) and _b_wave_ret <= 1.05 * (1.0 + fib_tol)
_ctype := _c_ext > 1.0 ? "Exp Flat" : "Flat"
else
_ctype := "Zigzag"
if _seq and _abc_ok and _c_ok and _c_above_a and _b_ok
if f_ms_bias(false) and f_htf_bias(false)
float _prz_lo = _wb.p + _a_len * 0.618 * (1.0 - fib_tol)
float _prz_hi = _wb.p + _a_len * 1.618 * (1.0 + fib_tol)
float _entry_p = _wc.p
float _stop_p = f_sl(_wc.p, false)
float _tp1 = _wc.p - _a_len * 1.000
float _tp2 = _wc.p - _a_len * 1.618
float _tp3 = _wc.p - _a_len * 2.618
bool _rr_ok = f_validate_rr(_entry_p, _stop_p, _tp2)
if _rr_ok
res := WaveResult.new(true, "ABC Giảm", false, na, na, na, na, na, na, na, na, na, na, na, na, _wa.p, _wa.i, _wb.p, _wb.i, _wc.p, _wc.i, _entry_p, _stop_p, _tp2, _tp2, _tp3, _prz_lo, _prz_hi, _wa.i, _wc.i, _a_len, na, na, 2, _ctype)
res
float ph = f_pivotHigh(high, piv_left, piv_right)
float pl = f_pivotLow(low, piv_left, piv_right)
if not na(ph)
pivotHighs.unshift(Pivot.new(ph, bar_index - piv_right))
if pivotHighs.size() > max_piv
pivotHighs.pop()
if not na(pl)
pivotLows.unshift(Pivot.new(pl, bar_index - piv_right))
if pivotLows.size() > max_piv
pivotLows.pop()
bool has_imp = pivotHighs.size() >= 3 and pivotLows.size() >= 3
bool has_cor = pivotHighs.size() >= 2 and pivotLows.size() >= 2
WaveResult _r_imp_bull = has_imp ? detectImpulseBull(pivotHighs, pivotLows) : EMPTY_W
WaveResult _r_imp_bear = has_imp ? detectImpulseBear(pivotHighs, pivotLows) : EMPTY_W
WaveResult _r_cor_bull = has_cor ? detectCorrectionBull(pivotHighs, pivotLows) : EMPTY_W
WaveResult _r_cor_bear = has_cor ? detectCorrectionBear(pivotHighs, pivotLows) : EMPTY_W
WaveResult res_w = EMPTY_W
bool _gate = bar_index > (piv_left + piv_right) * 2
if _gate
if show_impulse and not res_w.detected and _r_imp_bull.detected
res_w := _r_imp_bull
if show_impulse and not res_w.detected and _r_imp_bear.detected
res_w := _r_imp_bear
bool _cor_bull_clear = show_correction and not res_w.detected and _r_cor_bull.detected and not f_overlapsExistingImpulse(_r_cor_bull.start_i, _r_cor_bull.end_i)
bool _cor_bear_clear = show_correction and not res_w.detected and _r_cor_bear.detected and not f_overlapsExistingImpulse(_r_cor_bear.start_i, _r_cor_bear.end_i)
if _cor_bull_clear
res_w := _r_cor_bull
if not res_w.detected and _cor_bear_clear
res_w := _r_cor_bear
bool _is_new = res_w.detected and barstate.isconfirmed and (na(frozen_idx) or math.abs(res_w.start_i - frozen_idx) > cooldown)
if _is_new
WaveDrawings cur = WaveDrawings.new(array.new_line(), array.new_label(), array.new_box(), res_w.pattern_type, res_w.start_i, res_w.end_i)
frozen_idx := res_w.start_i
dash_name := res_w.name
dash_bull := res_w.isBullish
dash_last_bar := bar_index
dash_entry := res_w.entry_p
dash_stop := res_w.stop_p
dash_target := res_w.target_p
dash_w1_len := res_w.w1_len
dash_w3_len := res_w.w3_len
dash_w5_len := res_w.w5_len
dash_pattern_type:= res_w.pattern_type
dash_corr_type := res_w.corr_type
dash_tp2 := res_w.tp2_p
dash_tp3 := res_w.tp3_p
dash_w5_ratio := not na(res_w.w1_len) and res_w.w1_len > 1e-10 and not na(res_w.w5_len) ? res_w.w5_len / res_w.w1_len : na
if res_w.pattern_type == 1
impulse_count := impulse_count + 1
else
correction_count := correction_count + 1
color _col = res_w.pattern_type == 1 ? (res_w.isBullish ? col_impulse : col_imp_bear) : col_correction
bool _is_impulse = res_w.pattern_type == 1
if _is_impulse
f_purgeOverlappingCorrections(res_w.start_i, res_w.end_i)
if _is_impulse and not na(res_w.w1_lo_i) and not na(res_w.w5_i)
int _x0 = res_w.isBullish ? res_w.w1_lo_i : res_w.w1_hi_i
float _y0 = res_w.isBullish ? res_w.w1_lo : res_w.w1_hi
int _x1 = res_w.isBullish ? res_w.w1_hi_i : res_w.w1_lo_i
float _y1 = res_w.isBullish ? res_w.w1_hi : res_w.w1_lo
int _x2 = res_w.w2_i
float _y2 = res_w.w2_p
int _x3 = res_w.w3_i
float _y3 = res_w.w3_p
int _x4 = res_w.w4_i
float _y4 = res_w.w4_p
int _x5 = res_w.w5_i
float _y5 = res_w.w5_p
line _l01 = line.new(_x0, _y0, _x1, _y1, color=_col, width=3)
line _l12 = line.new(_x1, _y1, _x2, _y2, color=color.new(_col, 40), width=3)
line _l23 = line.new(_x2, _y2, _x3, _y3, color=_col, width=3)
line _l34 = line.new(_x3, _y3, _x4, _y4, color=color.new(_col, 40), width=3)
line _l45 = line.new(_x4, _y4, _x5, _y5, color=_col, width=3)
array.push(cur.lns, _l01)
array.push(cur.lns, _l12)
array.push(cur.lns, _l23)
array.push(cur.lns, _l34)
array.push(cur.lns, _l45)
if show_fib_lines and not na(res_w.w1_len) and res_w.w1_len > 1e-10
float _fib_161 = res_w.isBullish ? _y4 + res_w.w1_len * 1.618 : _y4 - res_w.w1_len * 1.618
float _fib_100 = res_w.isBullish ? _y4 + res_w.w1_len * 1.000 : _y4 - res_w.w1_len * 1.000
float _fib_262 = res_w.isBullish ? _y4 + res_w.w1_len * 2.618 : _y4 - res_w.w1_len * 2.618
int _fx1 = res_w.end_i
int _fx2 = res_w.end_i + 50
int _flx = _fx2 + 1
line _lf1 = line.new(_fx1, _fib_100, _fx2, _fib_100, color=color.new(col_fib, 60), style=line.style_dotted, width=2)
line _lf2 = line.new(_fx1, _fib_161, _fx2, _fib_161, color=color.new(col_fib, 40), style=line.style_dotted, width=2)
line _lf3 = line.new(_fx1, _fib_262, _fx2, _fib_262, color=color.new(col_fib, 70), style=line.style_dotted, width=2)
label _lf1l = label.new(_flx, _fib_100, "Sóng 5 ×1.0", color=color.new(col_fib, 80), textcolor=col_fib, style=label.style_label_left, size=size.small)
label _lf2l = label.new(_flx, _fib_161, "Sóng 5 ×1.618", color=color.new(col_fib, 80), textcolor=col_fib, style=label.style_label_left, size=size.small)
label _lf3l = label.new(_flx, _fib_262, "Sóng 5 ×2.618", color=color.new(col_fib, 80), textcolor=col_fib, style=label.style_label_left, size=size.small)
array.push(cur.lns, _lf1)
array.push(cur.lns, _lf2)
array.push(cur.lns, _lf3)
array.push(cur.lbls, _lf1l)
array.push(cur.lbls, _lf2l)
array.push(cur.lbls, _lf3l)
if show_labels
label _lb0 = label.new(_x1, _y1, "1", color=color.new(_col, 100), textcolor=_col, style=res_w.isBullish ? label.style_label_down : label.style_label_up, size=size.small)
label _lb1 = label.new(_x2, _y2, "2", color=color.new(_col, 100), textcolor=_col, style=res_w.isBullish ? label.style_label_up : label.style_label_down, size=size.small)
label _lb2 = label.new(_x3, _y3, "3", color=color.new(_col, 100), textcolor=_col, style=res_w.isBullish ? label.style_label_down : label.style_label_up, size=size.small)
label _lb3 = label.new(_x4, _y4, "4", color=color.new(_col, 100), textcolor=_col, style=res_w.isBullish ? label.style_label_up : label.style_label_down, size=size.small)
array.push(cur.lbls, _lb0)
array.push(cur.lbls, _lb1)
array.push(cur.lbls, _lb2)
array.push(cur.lbls, _lb3)
int _cx = (res_w.start_i + res_w.end_i) / 2
float _cy = res_w.isBullish ? (nz(res_w.w3_p) + nz(res_w.w1_lo)) * 0.5 : (nz(res_w.w3_p) + nz(res_w.w1_hi)) * 0.5
label _lbl_name = label.new(_cx, _cy, res_w.name, color=color.rgb(0, 0, 0, 0), textcolor=_col, style=label.style_label_center, size=size.small)
array.push(cur.lbls, _lbl_name)
if not _is_impulse and not na(res_w.wa_i) and not na(res_w.wc_i)
line _la = line.new(res_w.wa_i, res_w.wa_p, res_w.wb_i, res_w.wb_p, color=_col, width=2)
line _lb2 = line.new(res_w.wb_i, res_w.wb_p, res_w.wc_i, res_w.wc_p, color=color.new(_col, 30), width=1)
array.push(cur.lns, _la)
array.push(cur.lns, _lb2)
if show_labels
label _lwa = label.new(res_w.wa_i, res_w.wa_p, "A", color=color.new(_col, 20), textcolor=color.white, style=res_w.isBullish ? label.style_label_down : label.style_label_up, size=size.small)
label _lwb = label.new(res_w.wb_i, res_w.wb_p, "B", color=color.new(_col, 20), textcolor=color.white, style=res_w.isBullish ? label.style_label_up : label.style_label_down, size=size.small)
label _lwc = label.new(res_w.wc_i, res_w.wc_p, "C", color=color.new(_col, 20), textcolor=color.white, style=res_w.isBullish ? label.style_label_down : label.style_label_up, size=size.small)
array.push(cur.lbls, _lwa)
array.push(cur.lbls, _lwb)
array.push(cur.lbls, _lwc)
int _cx2 = (res_w.wa_i + res_w.wc_i) / 2
float _cy2 = (res_w.wa_p + res_w.wc_p) * 0.5
string _abc_lbl_txt = res_w.name + (res_w.corr_type != "" ? " [" + res_w.corr_type + "]" : "")
label _lbl_n2 = label.new(_cx2, _cy2, _abc_lbl_txt, color=color.rgb(0, 0, 0, 0), textcolor=color.white, style=label.style_label_center, size=size.small)
array.push(cur.lbls, _lbl_n2)
if show_prz and not na(res_w.prz_lo) and not na(res_w.prz_hi)
int _prz_end = res_w.end_i
int _prz_x1 = _prz_end - 3
int _prz_x2 = _prz_end + 40
box _prz = box.new(_prz_x1, res_w.prz_hi, _prz_x2, res_w.prz_lo, bgcolor=color.new(_col, prz_transp), border_color=color.new(_col, 40), border_width=1)
array.push(cur.bxs, _prz)
label _prz_lbl = label.new(_prz_x2, (res_w.prz_hi + res_w.prz_lo) * 0.5, "PRZ", style=label.style_label_left, color=color.new(_col, 50), textcolor=_col, size=size.small)
array.push(cur.lbls, _prz_lbl)
if show_targets and not na(res_w.entry_p) and not na(res_w.stop_p) and not na(res_w.target_p)
int _x1 = res_w.end_i
int _x2 = res_w.end_i + 50
int _lx = _x2 + 1
float _ep = res_w.entry_p
float risk_v = math.abs(_ep - res_w.stop_p)
float reward_v = math.abs(res_w.target_p - _ep)
float rr_v = risk_v > 1e-10 ? reward_v / risk_v : 0.0
string _ep_s = str.tostring(_ep, format.mintick)
string _sp_s = str.tostring(res_w.stop_p, format.mintick)
string _tp_s = str.tostring(res_w.target_p, format.mintick)
string _rr_s = str.tostring(rr_v, "#.##")
line ln_e = line.new(_x1, _ep, _x2, _ep, color=col_entry, style=line.style_dashed, width=1)
line ln_s = line.new(_x1, res_w.stop_p, _x2, res_w.stop_p, color=col_stop, style=line.style_dashed, width=1)
line ln_t = line.new(_x1, res_w.target_p,_x2, res_w.target_p,color=col_target, style=line.style_dashed, width=1)
label lb_e = label.new(_lx, _ep, "▶ Vào Lệnh " + _ep_s, style=label.style_label_left, color=color.new(col_entry, 70), textcolor=col_entry, size=size.small)
label lb_s = label.new(_lx, res_w.stop_p, "▶ Cắt Lỗ " + _sp_s, style=label.style_label_left, color=color.new(col_stop, 70), textcolor=col_stop, size=size.small)
label lb_t = label.new(_lx, res_w.target_p, "▶ Mục Tiêu " + _tp_s + " R:R " + _rr_s, style=label.style_label_left, color=color.new(col_target, 70), textcolor=col_target, size=size.small)
array.push(cur.lns, ln_e)
array.push(cur.lns, ln_s)
array.push(cur.lns, ln_t)
array.push(cur.lbls, lb_e)
array.push(cur.lbls, lb_s)
array.push(cur.lbls, lb_t)
if not _is_impulse and not na(res_w.tp2_p) and not na(res_w.tp3_p)
float _a_base = res_w.w1_len
float _tp1_p = res_w.isBullish ? res_w.entry_p + _a_base * 1.000 : res_w.entry_p - _a_base * 1.000
line ln_t1 = line.new(_x1, _tp1_p, _x2, _tp1_p, color=color.new(col_target, 60), style=line.style_dashed, width=1)
line ln_t3 = line.new(_x1, res_w.tp3_p, _x2, res_w.tp3_p, color=color.new(col_target, 20), style=line.style_dashed, width=1)
label lb_t1 = label.new(_lx, _tp1_p, "▶ TP1 A×1.0 " + str.tostring(_tp1_p, format.mintick), style=label.style_label_left, color=color.new(col_target, 70), textcolor=color.new(col_target, 30), size=size.small)
label lb_t3 = label.new(_lx, res_w.tp3_p, "▶ TP3 A×2.618 " + str.tostring(res_w.tp3_p, format.mintick), style=label.style_label_left, color=color.new(col_target, 70), textcolor=color.new(col_target, 10), size=size.small)
array.push(cur.lns, ln_t1)
array.push(cur.lns, ln_t3)
array.push(cur.lbls, lb_t1)
array.push(cur.lbls, lb_t3)
array.push(pat_history, cur)
f_manage_drawings(max_patterns)
if alert_impulse and res_w.pattern_type == 1 and barstate.isconfirmed
alert(str.format("Elliott {0} — Vào lệnh: {1} Cắt lỗ: {2} Mục tiêu: {3}", res_w.name, str.tostring(res_w.entry_p, format.mintick), str.tostring(res_w.stop_p, format.mintick), str.tostring(res_w.target_p, format.mintick)), alert.freq_once_per_bar_close)
if alert_correction and res_w.pattern_type == 2 and barstate.isconfirmed
alert(str.format("Elliott {0} — Vào lệnh: {1} Cắt lỗ: {2} Mục tiêu: {3}", res_w.name, str.tostring(res_w.entry_p, format.mintick), str.tostring(res_w.stop_p, format.mintick), str.tostring(res_w.target_p, format.mintick)), alert.freq_once_per_bar_close)
// Dashboard
int dash_piv_total = array.size(pivotHighs) + array.size(pivotLows)
float dash_rr_score = math.min(dash_rr_raw * 2.0, 10.0)
float dash_piv_score = math.min(dash_piv_total * 0.005 * 10.0, 10.0)
string dash_rr_str = f_blockBar(dash_rr_score)
string dash_piv_str = f_blockBar(dash_piv_score)
color dash_rr_col = f_blockColor(dash_rr_score)
color dash_piv_col = f_blockColor(dash_piv_score)
color _bull_c = color.rgb(0, 255, 120)
color _bear_c = color.rgb(255, 60, 80)
color dash_bias_col = dash_bull ? _bull_c : _bear_c
color dash_name_col = dash_bull ? _bull_c : _bear_c
string dash_bias_str = dash_bull ? "▲ Tăng" : "▼ Giảm"
string dash_type_str = dash_pattern_type == 1 ? "📈 Sóng Đẩy (12345)" : dash_pattern_type == 2 ? "🔄 Sóng Điều Chỉnh (ABC)" : "—"
color dash_type_col = dash_pattern_type == 1 ? col_impulse : dash_pattern_type == 2 ? col_correction : color.rgb(110, 110, 110)
string dash_w1_str = not na(dash_w1_len) ? str.tostring(dash_w1_len, format.mintick) : "—"
string dash_w3_str = not na(dash_w3_len) ? str.tostring(dash_w3_len, format.mintick) : "—"
string dash_w5_str = not na(dash_w5_len) ? str.tostring(dash_w5_len, format.mintick) : "—"
string dash_ratio_str = not na(dash_w1_len) and not na(dash_w3_len) and dash_w1_len > 1e-10 ? str.tostring(math.round(dash_w3_len / dash_w1_len, 3)) + "× Sóng 1" : "—"
string dash_w5r_str = not na(dash_w5_ratio) ? str.tostring(math.round(dash_w5_ratio, 3)) + "× Sóng 1" : "—"
string dash_ctype_str = dash_corr_type != "" and dash_corr_type != "—" ? dash_corr_type : "—"
string dash_entry_str = not na(dash_entry) ? str.tostring(dash_entry, format.mintick) : "—"
string dash_stop_str = not na(dash_stop) ? str.tostring(dash_stop, format.mintick) : "—"
string dash_target_str= not na(dash_target) ? str.tostring(dash_target, format.mintick) : "—"
string dash_atr_str = str.tostring(atr_val, format.mintick)
string dash_since_str = "⏳ " + str.tostring(dash_bars_since) + " Nến"
string dash_cnt_str = "📈 " + str.tostring(impulse_count) + " 🔄 " + str.tostring(correction_count)
color hdrBg = color.rgb(30, 30, 45, 10)
color altBg = color.rgb(20, 20, 25, 10)
color oddBg = dash_bg_color
var table dash = table.new(position.top_right, 2, 22,
border_width=1, border_color=color.rgb(50, 50, 70, 20),
frame_width=1, frame_color=color.rgb(60, 60, 90, 10))
table.cell(dash, 0, 0, " Elliott Wave Scanner", bgcolor=hdrBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 0, clean_ticker + " · " + timeframe.period, bgcolor=hdrBg, text_color=dash_txt_color, text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 1, " Xu Hướng", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 1, dash_bias_str, bgcolor=altBg, text_color=dash_bias_col, text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 2, " Mẫu Hình", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 2, dash_name, bgcolor=oddBg, text_color=dash_name_col, text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 3, " Loại", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 3, dash_type_str, bgcolor=altBg, text_color=dash_type_col, text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 4, " Vào Lệnh", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 4, dash_entry_str, bgcolor=oddBg, text_color=color.rgb(255, 220, 0), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 5, " Cắt Lỗ", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 5, dash_stop_str, bgcolor=altBg, text_color=color.rgb(255, 60, 80), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 6, " Mục Tiêu", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 6, dash_target_str, bgcolor=oddBg, text_color=color.rgb(0, 255, 160), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 7, " Chất Lượng R:R", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 7, dash_rr_str, bgcolor=altBg, text_color=dash_rr_col, text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 8, " ─── Sóng Đẩy ───", bgcolor=hdrBg, text_color=color.new(col_impulse, 30), text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 8, "Sóng 1·2·3·4·5", bgcolor=hdrBg, text_color=color.new(col_impulse, 30), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 9, " Độ Dài W1", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 9, dash_w1_str, bgcolor=oddBg, text_color=color.rgb(100, 200, 255), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 10, " Độ Dài W3", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 10, dash_w3_str, bgcolor=altBg, text_color=color.rgb(100, 200, 255), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 11, " Độ Dài W5", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 11, dash_w5_str, bgcolor=oddBg, text_color=color.rgb(100, 200, 255), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 12, " Tỷ Lệ W3/W1", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 12, dash_ratio_str, bgcolor=altBg, text_color=color.rgb(180, 255, 80), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 13, " Tỷ Lệ W5/W1", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 13, dash_w5r_str, bgcolor=oddBg, text_color=color.rgb(100, 200, 255), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 14, " Loại Điều Chỉnh", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 14, dash_ctype_str, bgcolor=altBg, text_color=dash_pattern_type == 2 ? col_correction : color.rgb(110, 110, 110), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 15, " ─── Hệ Thống ───", bgcolor=hdrBg, text_color=color.rgb(80, 80, 100), text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 15, "", bgcolor=hdrBg, text_color=color.rgb(80, 80, 100), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 16, " Số Lượng Pivot", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 16, dash_piv_str, bgcolor=oddBg, text_color=dash_piv_col, text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 17, " Số Nến Đã Qua", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 17, dash_since_str, bgcolor=altBg, text_color=color.rgb(140, 180, 255), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 18, " ATR (14)", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 18, dash_atr_str, bgcolor=oddBg, text_color=color.rgb(200, 200, 60), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 19, " Số Lượng Mẫu Hình", bgcolor=altBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 19, dash_cnt_str, bgcolor=altBg, text_color=color.rgb(180, 180, 200), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 20, use_htf_bias ? " Xu Hướng HTF" : "", bgcolor=oddBg, text_color=dash_txt_color, text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 20, use_htf_bias ? (htf_bull ? "▲ Tăng" : "▼ Giảm") : "", bgcolor=oddBg, text_color=use_htf_bias ? (htf_bull ? _bull_c : _bear_c) : color.rgb(110, 110, 110), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 0, 21, " EWD v2.0", bgcolor=hdrBg, text_color=color.rgb(60, 60, 80), text_halign=text.align_left, text_font_family=font.family_monospace, text_size=size.small)
table.cell(dash, 1, 21, "Pine v6", bgcolor=hdrBg, text_color=color.rgb(60, 60, 80), text_halign=text.align_right, text_font_family=font.family_monospace, text_size=size.small)
