1. Mô tả chỉ báo Cup & Handle (Zeiierman)
Chỉ báo nhận diện mô hình Cup & Handle (Cốc và Quai Cốc) - một trong những mô hình biểu đồ kinh điển nhất trong phân tích kỹ thuật
1.1 Concept của chỉ báo
Chỉ báo Cup & Handle dựa trên lý thuyết về mô hình tâm lý thị trường được phát hiện bởi William O'Neil. Mô hình này tin rằng:
- Giai đoạn "Cốc" (Cup): Thể hiện quá trình giá giảm dần, tạo đáy, rồi phục hồi trở lại mức ban đầu. Đây là giai đoạn thị trường "lắng đọng" sau một đợt tăng trước đó, người bán yếu dần thoát ra, và người mua mạnh tích lũy.
- Giai đoạn "Quai cốc" (Handle): Sau khi hình thành cốc, giá có một đợt điều chỉnh nhỏ (pullback) tạo thành quai cốc. Đây là lần "test" cuối cùng trước khi bứt phá.
- Breakout (Bứt phá): Khi giá vượt qua mức "miệng cốc" (rim), đây là tín hiệu xu hướng tăng mạnh sắp diễn ra, với mục tiêu giá bằng độ sâu của cốc.
Chỉ báo này tự động phát hiện cả mô hình tăng (Cup & Handle) và mô hình giảm (Inverted Cup & Handle) dựa trên các điểm pivot (đỉnh/đáy dao động) của giá.
1.2 Chức năng của chỉ báo
-
Hiển thị mô hình Cup & Handle:
- Đường cong "Cốc": Vẽ bằng đường polyline cong (curved) nối 3 điểm: miệng trái → đáy cốc → miệng phải. Màu xanh lá cho mô hình tăng, đỏ cho mô hình giảm.
- Đường cong "Quai cốc": Vẽ từ miệng phải → điểm thấp nhất của quai → điểm dự kiến breakout. Cùng màu với cốc.
- Vùng tô màu: Tô màu nhạt bên trong cốc và quai cốc để dễ nhận diện.
- Nhãn tên mô hình: Hiển thị chữ "Cup+Handle" hoặc "Inv Cup+Handle" tại giữa cốc.
- Đường mục tiêu (Target line): Đường ngang chỉ mức giá mục tiêu sau khi breakout, được tính bằng: Rim Price ± (Cup Depth × Target Multiplier)
-
Alert (Cảnh báo):
- "Cup & Handle (Brewed)": Kích hoạt khi phát hiện mô hình tăng hợp lệ.
- "Inverted Cup & Handle (Brewed)": Kích hoạt khi phát hiện mô hình giảm hợp lệ.
1.3 Cách dùng chỉ báo
- Xác định cơ hội vào lệnh: Khi chỉ báo vẽ mô hình Cup & Handle và giá breakout khỏi rim (nếu bật "Require breakout confirmation"), đây là tín hiệu vào lệnh BUY (mô hình tăng) hoặc SELL (mô hình giảm).
- Đặt mục tiêu Take Profit: Sử dụng đường Target Line làm mức chốt lời. Mặc định là 0.5× độ sâu cốc, có thể điều chỉnh qua "Target multiplier".
- Đặt Stop Loss: Đặt SL dưới mức "Invalidation" (mặc định 61.8% độ sâu quai cốc tính từ rim). Nếu giá chạm mức này, mô hình bị phá vỡ.
- Lọc tín hiệu chất lượng: Điều chỉnh các tham số như "Rim similarity tolerance", "Handle retrace min/max" để lọc ra các mô hình chuẩn xác hơn, giảm nhiễu.
- Kết hợp với khung thời gian lớn: Mô hình Cup & Handle hiệu quả nhất trên khung H4, Daily, Weekly. Tránh dùng trên khung quá nhỏ (M1, M5) vì nhiễu.
1.4 Cách hoạt động của chỉ báo
Đầu vào & vai trò
- pivotSpan (Số nguyên, mặc định: 10): Số nến cần để xác nhận một đỉnh/đáy dao động (pivot). Ví dụ pivotSpan=10 nghĩa là cần 10 nến bên trái và 10 nến bên phải đều thấp hơn (đối với đỉnh) hoặc cao hơn (đối với đáy) thì mới xác nhận pivot. Tăng pivotSpan → ít pivot hơn nhưng mạnh hơn, mô hình ít hơn nhưng chất lượng cao. Giảm pivotSpan → nhiều pivot hơn, nhiều tín hiệu nhưng nhiều nhiễu.
- rimTolPct (Số nguyên %, mặc định: 18%): Độ sai lệch cho phép giữa miệng trái và miệng phải của cốc. Ví dụ nếu miệng trái ở 100$, miệng phải ở 110$, sai lệch = 10%. Nếu rimTolPct=18% thì chấp nhận, nếu rimTolPct=5% thì loại bỏ. Giảm rimTolPct → cốc phải cân đối hơn, ít mô hình hơn nhưng chuẩn xác. Tăng rimTolPct → chấp nhận cốc lệch nhiều hơn, nhiều mô hình hơn.
- hMin (Số thập phân, mặc định: 0.12): Độ sâu tối thiểu của quai cốc so với độ sâu cốc. Ví dụ nếu cốc sâu 100$, quai cốc phải sâu ít nhất 12$ (0.12×100). Quá nhỏ → quai cốc quá nông, không đủ "test" lại, tín hiệu yếu.
- hMax (Số thập phân, mặc định: 0.55): Độ sâu tối đa của quai cốc. Ví dụ nếu cốc sâu 100$, quai cốc không được sâu quá 55$. Quá lớn → quai cốc quá sâu, mô hình lộn xộn, không còn là Cup & Handle chuẩn.
- killAtFib (Số thập phân, mặc định: 61.8%): Mức "vô hiệu hoá" mô hình. Nếu giá rơi xuống quá 61.8% độ sâu quai cốc (tính từ rim), mô hình bị phá vỡ. Đây là mức Stop Loss an toàn. Giảm → SL chặt hơn, ít rủi ro nhưng dễ bị dừng sớm. Tăng → SL lỏng hơn, chấp nhận dao động lớn hơn.
- needConfirm (Tick chọn true/false, mặc định: false): Có yêu cầu giá phải breakout qua rim hay không. false → phát hiện sớm ngay khi mô hình hình thành. true → chỉ kích hoạt khi giá đã vượt qua rim, tín hiệu chất lượng cao hơn nhưng muộn hơn.
- targetMult (Số thập phân, mặc định: 0.5): Hệ số nhân để tính mục tiêu giá. Ví dụ cốc sâu 100$, rim ở 200$, target = 200 + (100×0.5) = 250$. Tăng → mục tiêu xa hơn, lợi nhuận lớn nhưng khó đạt. Giảm → mục tiêu gần hơn, dễ đạt nhưng lợi nhuận nhỏ.
- showName, bgBull, lnBull, bgBear, lnBear, wOk, stOk, showTarget, targetWidth, targetStyle: Các tuỳ chọn hiển thị (bật/tắt nhãn, màu sắc, độ dày đường, kiểu đường). Không ảnh hưởng logic phát hiện, chỉ ảnh hưởng giao diện.
Các khối logic chính
🎯 Flow 1: Phát hiện mô hình Cup & Handle
-
Bước 1 - Thu thập Pivot (Đỉnh/Đáy dao động):
- Chỉ báo sử dụng hàm ta.pivothigh() và ta.pivotlow() để tìm các đỉnh và đáy dao động dựa trên pivotSpan.
- Mỗi khi tìm thấy pivot, nó được lưu vào một "danh sách pivot" (array) với 3 thông tin: giá (p), vị trí nến (i), hướng (d) (+1 = đỉnh, -1 = đáy).
- Danh sách này chỉ giữ tối đa 12 pivot gần nhất (nếu quá 12, pivot cũ nhất bị xoá).
- Ví dụ: Nếu pivotSpan=10, giá tạo đỉnh tại nến 100 với giá 50$, và 10 nến trước + 10 nến sau đều thấp hơn 50$, thì pivot này được lưu: {p: 50, i: 100, d: +1}.
-
Bước 2 - Nhận diện chuỗi 4 pivot hợp lệ:
- Chỉ báo lấy 4 pivot gần nhất từ danh sách: s0, s1, s2, s3.
- Mô hình tăng (Cup & Handle): Chuỗi phải là: Đỉnh → Đáy → Đỉnh → Đáy (s0.d=+1, s1.d=-1, s2.d=+1, s3.d=-1).
- Mô hình giảm (Inverted Cup & Handle): Chuỗi phải là: Đáy → Đỉnh → Đáy → Đỉnh (s0.d=-1, s1.d=+1, s2.d=-1, s3.d=+1).
- Ví dụ mô hình tăng: s0 = đỉnh 100$ (miệng trái), s1 = đáy 80$ (đáy cốc), s2 = đỉnh 98$ (miệng phải), s3 = đáy 92$ (đáy quai cốc).
-
Bước 3 - Kiểm tra điều kiện "Cốc" hợp lệ:
- Rim similarity (Độ tương đồng miệng cốc): So sánh giá của s0 (miệng trái) và s2 (miệng phải). Nếu sai lệch ≤ rimTolPct% thì hợp lệ.
- Ví dụ: s0=100$, s2=110$, sai lệch = |100-110|/100 = 10%. Nếu rimTolPct=18% → hợp lệ. Nếu rimTolPct=5% → loại bỏ.
- Tính độ sâu cốc (depth): depth = |rimPrice - Bp|, trong đó rimPrice = min(s0, s2) đối với mô hình tăng, hoặc max(s0, s2) đối với mô hình giảm.
- Ví dụ mô hình tăng: s0=100$, s2=98$, s1=80$ → rimPrice=98$ (lấy thấp hơn), depth=|98-80|=18$.
-
Bước 4 - Kiểm tra điều kiện "Quai cốc" hợp lệ:
- Tính độ sâu quai cốc (hRet): hRet = |rimPrice - Hp| / depth, trong đó Hp là giá của s3 (đáy quai cốc).
- Ví dụ: rimPrice=98$, Hp=92$, depth=18$ → hRet = |98-92|/18 = 6/18 = 0.33 (33%).
- Kiểm tra hRet nằm trong khoảng [hMin, hMax]: Nếu hMin=0.12, hMax=0.55, thì 0.33 nằm trong khoảng → hợp lệ.
- Kiểm tra vị trí quai cốc: Đối với mô hình tăng, Hp phải < rimPrice (quai cốc phải thấp hơn miệng cốc). Đối với mô hình giảm, Hp phải > rimPrice.
-
Bước 5 - Kiểm tra Breakout (nếu bật needConfirm):
- Nếu needConfirm=true, chỉ báo chỉ kích hoạt khi giá đóng cửa (close) vượt qua rimPrice.
- Mô hình tăng: close > rimPrice.
- Mô hình giảm: close < rimPrice.
- Nếu needConfirm=false, bỏ qua bước này, kích hoạt ngay khi mô hình hình thành.
-
Bước 6 - Loại bỏ trùng lặp:
- Kiểm tra xem mô hình mới có trùng với mô hình trước đó không (dựa trên vị trí rim và giá rim).
- Nếu trùng (sai lệch < 0.15%), bỏ qua để tránh vẽ nhiều lần.
🎨 Flow 2: Vẽ mô hình lên biểu đồ
-
Vẽ đường cong "Cốc":
- Tạo 3 điểm: điểm 1 (Li, rimPrice), điểm 2 (midBar, Bp), điểm 3 (Ri, rimPrice).
- Dùng hàm polyline.new() với tham số curved=true để vẽ đường cong nối 3 điểm này.
- Màu đường và màu tô được chọn dựa trên mô hình tăng/giảm (bgBull/lnBull hoặc bgBear/lnBear).
-
Vẽ đường cong "Quai cốc":
- Tạo 3 điểm: điểm 1 (Ri, rimPrice), điểm 2 (Hi, Hp), điểm 3 (projBar, rimPrice).
- projBar = Hi + (Hi - Ri), tức là kéo dài quai cốc về phía trước để tạo hình quai hoàn chỉnh.
- Vẽ tương tự như cốc, dùng polyline cong.
-
Vẽ đường mục tiêu (Target Line):
- Nếu showTarget=true, vẽ đường ngang từ Ri đến Hi+25 nến, tại mức giá tgtPrice.
- tgtPrice = Rp + (depth × targetMult) đối với mô hình tăng, hoặc Rp - (depth × targetMult) đối với mô hình giảm.
- Ví dụ: Rp=98$, depth=18$, targetMult=0.5 → tgtPrice = 98 + (18×0.5) = 107$.
-
Vẽ nhãn tên mô hình:
- Nếu showName=true, vẽ nhãn "Cup+Handle" hoặc "Inv Cup+Handle" tại giữa cốc (midBar, rimPrice).
🔔 Flow 3: Kích hoạt Alert
- Khi mô hình hợp lệ được phát hiện, biến newSignal = true và newSide = +1 (tăng) hoặc -1 (giảm).
- Hàm alertcondition() kiểm tra điều kiện này và kích hoạt alert tương ứng.
- Alert "Cup & Handle (Brewed)": Kích hoạt khi newSignal=true và newSide=+1.
- Alert "Inverted Cup & Handle (Brewed)": Kích hoạt khi newSignal=true và newSide=-1.
Đầu ra & vai trò trong sử dụng
- Đường cong Cup & Handle: Giúp trader nhận diện trực quan mô hình trên biểu đồ, xác định vùng tích lũy và điểm breakout tiềm năng.
- Đường Target Line: Chỉ mức giá mục tiêu để chốt lời, dựa trên lý thuyết độ sâu cốc.
- Mức Invalidation (invPrice): Mức giá mà nếu chạm vào, mô hình bị phá vỡ. Dùng để đặt Stop Loss. Ví dụ: invPrice = Rp - (depth × 0.618) cho mô hình tăng.
- Alert: Thông báo kịp thời khi mô hình xuất hiện, giúp trader không bỏ lỡ cơ hội.
Kết Quả Backtest - Chiến Lược Cup & Handle
Phân tích hiệu suất và cài đặt tối ưu cho chiến lược giao dịch
Phát Triển Chiến Lược
Để tìm ra phương án tối ưu nhất khi vào lệnh và quản lý rủi ro cho chỉ báo này, mình đã chuyển đổi chỉ báo thành chiến lược/strategy trên TradingView với đầy đủ các chức năng quản lý vốn và rủi ro chuyên nghiệp.
Các Tính Năng Chính Của Strategy
🎯 Quản Lý Vào Lệnh
- Bật/Tắt Strategy: Bật hoặc tắt thực thi chiến lược
- Kiểm Soát Hướng: Cho phép vị thế LONG, SHORT, hoặc cả hai
- Loại Lệnh Vào: Chọn giữa lệnh Market hoặc Limit
- Thoát Khi Tín Hiệu Ngược: Tự động đóng vị thế khi có tín hiệu ngược chiều xuất hiện
💰 Quản Lý Kích Thước Vị Thế
- Loại Kích Thước: Fixed Contracts (số lượng cố định) hoặc Percentage of Equity (phần trăm vốn)
- Phần Trăm Vốn: Đặt phần trăm vốn sử dụng cho mỗi giao dịch
🛡️ Quản Lý Stop Loss
- Loại Stop Loss: Swing Point (dựa trên chu kỳ swing lookback)
- Nhìn Lại Swing: Số nến nhìn lại để phát hiện điểm swing
- Spread Điều Chỉnh: Khoảng cách đệm bổ sung cho stop loss
🎯 Quản Lý Take Profit
- Tỷ Lệ Risk:Reward: Đặt TP dựa trên khoảng cách SL (ví dụ: RR = 4 nghĩa là TP gấp 4 lần SL)
⚡ Bảo Vệ Break Even
- Kích Hoạt BE Tại RR: Tự động chuyển SL về break even khi giá đạt mức RR nhất định
- Offset Từ Entry: Khoảng cách đệm từ giá vào lệnh
📊 Trực Quan Hóa
- Hiển Thị Box TP/SL: Hiển thị các hộp trực quan cho mức take profit và stop loss
- Màu Tùy Chỉnh: Màu riêng biệt cho hộp TP và SL
- Độ Dài Box: Thời lượng hiển thị hộp trực quan tính bằng số nến
Kết Quả Hiệu Suất
Sau khi backtest kỹ lưỡng, chiến lược đã đạt được các chỉ số hiệu suất ấn tượng:
Cài Đặt Tối Ưu
Các cài đặt sau đây đã chứng minh hiệu quả nhất qua quá trình backtest:
Phát Hiện Cup & Handle
Cài Đặt Strategy
Kích Thước Vị Thế
Stop Loss
Take Profit
Break Even
Trực Quan Hóa
Tài Nguyên
📚 Useful Resources
Discover more tools and courses to enhance your trading skills
// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
// https://creativecommons.org/licenses/by-nc-sa/4.0/
// © Zeiierman {
//@version=6
indicator("Cup & Handle (Zeiierman)", overlay=true, max_lines_count=500, max_labels_count=500, max_polylines_count=100)
//}
// ~~ Tooltips {
var string t1 = "Pivot span:\nControls how many bars are used to confirm swing highs/lows.\nHigher = fewer but stronger pivots.\nLower = more signals but more noise."
var string t2 = "Rim similarity tolerance (%):\nHow close the left rim and right rim must be.\nLower = stricter, cleaner cups.\nHigher = more patterns detected."
var string t3 = "Handle retrace min:\nMinimum depth of the handle pullback relative to cup depth.\nToo small = weak handle.\nTypical: 0.10–0.15."
var string t4 = "Handle retrace max:\nMaximum depth of the handle pullback.\nToo large = messy structure.\nTypical: 0.45–0.60."
var string t5 = "Invalidation (handle max retrace %):\nDefines when the pattern fails.\nLower = tighter stop.\nHigher = looser stop."
var string t6 = "Require breakout confirmation:\nIf enabled, pattern triggers only after price breaks above (bull) or below (bear) the rim.\nOff = earlier detection.\nOn = higher quality confirmation."
var string t7 = "Target multiplier (× cup depth):\nControls how far the projection target is.\n1.0 = classic rim ± depth.\n0.3–0.7 = closer targets."
var string t8 = "Show pattern name:\nDisplays a label on the cup structure."
var string t9 = "Bullish fill:\nBackground fill color for bullish cup & handle."
var string t10 = "Bullish border:\nOutline color for bullish cup & handle."
var string t11 = "Bearish fill:\nBackground fill color for inverted (bearish) cup & handle."
var string t12 = "Bearish border:\nOutline color for inverted (bearish) cup & handle."
var string t13 = "Width:\nLine thickness of the cup and handle curves."
var string t14 = "Style:\nLine style of the cup and handle curves."
var string t15 = "Show target line:\nDraws the projected price target line for the pattern."
var string t16 = "Target width:\nThickness of the target projection line."
var string t17 = "Target style:\nLine style of the target projection line."
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Settings {
pivotSpan = input.int(10, "Pivot span", minval=2, step=1, group="Cup & Handle", tooltip=t1)
rimTolPct = input.int(18, "Rim similarity tolerance (%)", minval=0, maxval=50, step=1, group="Cup & Handle", tooltip=t2)
hMin = input.float(0.12, "Handle retrace min", minval=0.01, step=0.01, group="Cup & Handle", tooltip=t3)
hMax = input.float(0.55, "Handle retrace max", minval=0.05, step=0.01, group="Cup & Handle", tooltip=t4)
killAtFib = input.float(61.8, "Invalidation (handle max retrace %) ", minval=10, maxval=100, step=0.1, group="Cup & Handle", tooltip=t5) / 100.0
needConfirm = input.bool(false, "Require breakout confirmation", group="Cup & Handle", tooltip=t6)
targetMult = input.float(0.5, "Target multiplier (× cup depth)", minval=0.1, maxval=3.0, step=0.05, group="Cup & Handle", tooltip=t7)
showName = input.bool(true, "Show pattern name", group="Style", tooltip=t8)
bgBull = input.color(color.new(color.lime, 82), "Bullish fill", group="Style", inline="bull", tooltip=t9)
lnBull = input.color(color.new(color.lime, 35), "Bullish border", group="Style", inline="bull", tooltip=t10)
bgBear = input.color(color.new(color.red, 82), "Bearish fill", group="Style", inline="bear", tooltip=t11)
lnBear = input.color(color.new(color.red, 35), "Bearish border", group="Style", inline="bear", tooltip=t12)
wOk = input.int(2, "Width", minval=1, group="Style", inline="w1", tooltip=t13)
stOk = input.string("Solid", "Style", options=["Solid","Dashed","Dotted"], group="Style", inline="w1", tooltip=t14)
showTarget = input.bool(true, "Show target line", group="Style", tooltip=t15)
targetWidth = input.int(2, "Target width", minval=1, group="Style", inline="t1", tooltip=t16)
targetStyle = input.string("Dashed", "Target style", options=["Solid","Dashed","Dotted"], group="Style", inline="t1", tooltip=t17)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Helpers {
f_lineStyle(string s) =>
switch s
"Solid" => line.style_solid
"Dashed" => line.style_dashed
"Dotted" => line.style_dotted
=> line.style_solid
f_near(float a, float b, float tolPct) =>
a == 0 or b == 0 ? false : math.abs(a - b) / math.abs(a) <= tolPct / 100.0
f_depth(float rim, float bowl) =>
math.abs(rim - bowl)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Pivot stream {
type Swing
float p
int i
int d // +1 = high pivot, -1 = low pivot
var Swing[] swings = array.new()
f_pushSwing(float price, int idx, int dir) =>
if array.size(swings) == 0
array.push(swings, Swing.new(price, idx, dir))
else
last = array.get(swings, array.size(swings) - 1)
if last.d == dir
better = dir == 1 ? price > last.p : price < last.p
if better
array.set(swings, array.size(swings) - 1, Swing.new(price, idx, dir))
else
array.push(swings, Swing.new(price, idx, dir))
if array.size(swings) > 12
array.shift(swings)
ph = ta.pivothigh(high, pivotSpan, pivotSpan)
pl = ta.pivotlow(low, pivotSpan, pivotSpan)
if not na(ph)
f_pushSwing(ph, bar_index - pivotSpan, +1)
if not na(pl)
f_pushSwing(pl, bar_index - pivotSpan, -1)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Pattern record + storage {
type BrewPattern
chart.point[] cupPts
chart.point[] hdlPts
polyline cupLine
polyline hdlLine
line tgtLine
label nameTag
int side
int state // 1 active, -1 invalid, 2 target hit
float rimPrice
float invPrice
float tgtPrice
int rimBar
var BrewPattern[] found = array.new()
f_kill(BrewPattern pat) =>
polyline.delete(pat.cupLine)
polyline.delete(pat.hdlLine)
if not na(pat.tgtLine)
line.delete(pat.tgtLine)
if not na(pat.nameTag)
label.delete(pat.nameTag)
f_isDuplicate(int rimIdx, float rimPx) =>
if array.size(found) == 0
false
else
last = array.get(found, array.size(found) - 1)
rimIdx == last.rimBar or f_near(rimPx, last.rimPrice, 0.15)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Detection {
Swing s0 = na
Swing s1 = na
Swing s2 = na
Swing s3 = na
int n = array.size(swings)
if n >= 4
s0 := array.get(swings, n - 4)
s1 := array.get(swings, n - 3)
s2 := array.get(swings, n - 2)
s3 := array.get(swings, n - 1)
bool newSignal = false
int newSide = 0
if not na(s0) and not na(s1) and not na(s2) and not na(s3)
isSeqNorm = (s0.d == +1 and s1.d == -1 and s2.d == +1 and s3.d == -1)
isSeqInv = (s0.d == -1 and s1.d == +1 and s2.d == -1 and s3.d == +1)
if isSeqNorm or isSeqInv
side = isSeqNorm ? +1 : -1
Lp = s0.p, Li = s0.i
Bp = s1.p, Bi = s1.i
Rp = s2.p, Ri = s2.i
Hp = s3.p, Hi = s3.i
useFill = side == +1 ? bgBull : bgBear
useLine = side == +1 ? lnBull : lnBear
rimPrice = side == +1 ? math.min(Lp, Rp) : math.max(Lp, Rp)
depth = f_depth(rimPrice, Bp)
rimOk = f_near(Lp, Rp, rimTolPct)
hRet = depth == 0 ? 10.0 : math.abs(rimPrice - Hp) / depth
handleOk = (hRet >= hMin and hRet <= hMax)
sideOk = side == +1 ? Hp < rimPrice : Hp > rimPrice
invPrice = side == +1 ? (Rp - depth * killAtFib) : (Rp + depth * killAtFib)
tgtPrice = side == +1 ? (Rp + depth * targetMult) : (Rp - depth * targetMult)
confirmOk = not needConfirm ? true : (side == +1 ? close > rimPrice : close < rimPrice)
ok = rimOk and handleOk and sideOk and confirmOk
if ok and not f_isDuplicate(Li, rimPrice)
midBar = Ri - (Ri - Li) / 2
cupPts = array.new()
array.push(cupPts, chart.point.from_index(Li, rimPrice))
array.push(cupPts, chart.point.from_index(midBar, Bp))
array.push(cupPts, chart.point.from_index(Ri, rimPrice))
hdlPts = array.new()
projBar = Hi + (Hi - Ri)
array.push(hdlPts, chart.point.from_index(Ri, rimPrice))
array.push(hdlPts, chart.point.from_index(Hi, Hp))
array.push(hdlPts, chart.point.from_index(projBar, rimPrice))
cupPL = polyline.new(cupPts, line_color=useLine, fill_color=useFill, line_width=wOk, line_style=f_lineStyle(stOk), curved=true)
hdlPL = polyline.new(hdlPts, line_color=useLine, fill_color=useFill, line_width=wOk, line_style=f_lineStyle(stOk), curved=true)
// target line
extendBars = 25
line tgtLn = na
if showTarget
tgtCol = side == +1 ? color.new(color.lime, 0) : color.new(color.red, 0)
tgtLn := line.new(Ri, tgtPrice, Hi + extendBars, tgtPrice, color=tgtCol, width=targetWidth, style=f_lineStyle(targetStyle))
label tag = na
if showName
txt = side == +1 ? "Cup+Handle" : "Inv Cup+Handle"
tagCol = side == +1 ? color.new(color.lime, 70) : color.new(color.red, 70)
tag := label.new(midBar, rimPrice, txt, style=label.style_label_center, textcolor=color.white, color=tagCol, size=size.small)
rec = BrewPattern.new(
cupPts, hdlPts,
cupPL, hdlPL,
tgtLn,
tag,
side, 1,
rimPrice, invPrice, tgtPrice,
Li
)
array.push(found, rec)
newSignal := true
newSide := side
if array.size(found) > 0
last = array.get(found, array.size(found)-1)
if last.state == 1
invHit = (last.side == +1 and low <= last.invPrice) or
(last.side == -1 and high >= last.invPrice)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Alerts {
alertcondition(newSignal and newSide == +1, title="Cup & Handle (Brewed)", message="Cup & Handle detected on {{ticker}}")
alertcondition(newSignal and newSide == -1, title="Inverted Cup & Handle (Brewed)", message="Inverted Cup & Handle detected on {{ticker}}")
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
Indicator Insider

Volume Phân Kỳ là Rác, Vứt nó đi!!
Khắc phục volume phân kỳ truyền thống từ mặt lý thuyết đến code.

04/02/026 Cup & Handle
Cup & Handle Strategy – Advanced TradingView Trading Bot with Automated Risk Management
Discover the Cup & Handle Pattern Strategy, a professional PineScript trading bot for TradingView that automatically identifies classic cup and handle chart patterns. This automated trading strategy combines technical pattern recognition with comprehensive risk management features including

27/01/026 Spring & Upthrust Trap
Phân tích backtest chiến lược Spring & Upthrust Trap với winrate 34.9%, lợi nhuận +4.95%, profit factor 2.021. Hướng dẫn cài đặt tối ưu và quản lý rủi ro hiệu quả.




