QRAT2025 / Pinescript Folder /4CCP Pattern detector /4CCP Pattern detector-pinescript.js
algorembrant's picture
Add files using upload-large-folder tool
66a32a6 verified
//@version=5
indicator("4CCP + 6CBP Pattern Detector + 30minute bars (Asia/Manila)", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500)
// ────────────── Restrict to 1-Minute Timeframe
is_1m = timeframe.period == "1"
// ────────────── Candle Data
o = open
h = high
l = low
c = close
// ────────────── Helpers for Manila time formatting
f_two(n) => n < 10 ? "0" + str.tostring(n) : str.tostring(n)
// return "HH:MM" for a given bar offset (use offset = 0 for current bar, 2 for bar_index[2], etc.)
manilaTimeStr(offset) =>
// use built-in time[] timestamp and extract hour/minute in specified timezone
hh = hour(time[offset], "Asia/Manila")
mm = minute(time[offset], "Asia/Manila")
f_two(hh) + ":" + f_two(mm)
// If you prefer HH:MM:SS, replace the return with:
// ss = second(time[offset], "Asia/Manila")
// f_two(hh) + ":" + f_two(mm) + ":" + f_two(ss)
// ────────────── Utility
isBull(c_, o_) => c_ > o_
isBear(c_, o_) => c_ < o_
// ────────────── Body coords (top, bottom, mid)
getBodyCoords(_o, _c) =>
_top = math.max(_o, _c)
_bot = math.min(_o, _c)
_mid = (_top + _bot) / 2
[_top, _bot, _mid]
// ────────────── 4CCP Patterns
// 4CCP-T1.1 Bullish
t1_1 = isBull(c[3], o[3]) and
isBear(c[2], o[2]) and c[2] < o[3] and
isBull(c[1], o[1]) and c[1] > o[2] and c[1] > c[3] and
isBull(c, o) and c > c[1] and c > o[2] and c > c[3]
// 4CCP-T1.2 Bullish Type 2
t1_2 = isBull(c[3], o[3]) and
isBear(c[2], o[2]) and c[2] < o[3] and
isBull(c[1], o[1]) and c[1] > c[2] and c[1] < o[2] and
isBull(c, o) and c > c[1] and c > o[2] and c > c[3]
// 4CCP-T2.1 Bearish
t2_1 = isBear(c[3], o[3]) and
isBull(c[2], o[2]) and c[2] > o[3] and
isBear(c[1], o[1]) and c[1] < o[2] and c[1] < c[3] and
isBear(c, o) and c < c[1] and c < o[2] and c < c[3]
// 4CCP-T2.2 Bearish Type 2
t2_2 = isBear(c[3], o[3]) and
isBull(c[2], o[2]) and c[2] > o[3] and
isBear(c[1], o[1]) and c[1] < c[2] and c[1] > o[2] and
isBear(c, o) and c < c[1] and c < o[2] and c < c[3]
// ────────────── Persistent arrays
var box[] boxes = array.new_box()
var line[] lines = array.new_line()
var label[] labs = array.new_label()
// ────────────── Draw helper (WITH Manila time stamp)
drawBoxAndLine(cond, baseBarOffset, extendBars, colorFill) =>
if is_1m and cond
[top, bot, mid] = getBodyCoords(open[baseBarOffset], close[baseBarOffset])
x1 = bar_index - baseBarOffset
x2 = x1 + extendBars
bx = box.new(left = x1, right = x2, top = top, bottom = bot,
bgcolor = color.new(colorFill, 70), border_color = colorFill)
ln = line.new(x1 = x1, y1 = mid, x2 = x2, y2 = mid,
color = colorFill, width = 1, style = line.style_dotted)
array.push(boxes, bx)
array.push(lines, ln)
// Manila timestamp for the pattern bar
ts = manilaTimeStr(baseBarOffset)
tLabel = label.new( x1, top,ts, style = label.style_label_down,textcolor = color.rgb(0, 0, 0), color = color.new(colorFill, 100),size = size.small )
array.push(labs, tLabel)
// ────────────── Draw all patterns
drawBoxAndLine(t1_1, 2, 5, color.rgb(0, 192, 255))
drawBoxAndLine(t1_2, 2, 5, color.rgb(0, 38, 255))
drawBoxAndLine(t2_1, 2, 5, color.rgb(255, 64, 64))
drawBoxAndLine(t2_2, 2, 5, color.rgb(255, 128, 0))
// ────────────────────────────
// Helper Function: Midpoint
get_mid(_o, _c) => (_o + _c) / 2
// ────────────────────────────
// 6CBP Logic
bear_bull1 = c[5] > o[5]
bear_bull2 = c[4] > o[4] and c[4] > c[5]
bear_bear3 = c[3] < o[3] and c[3] < o[4]
bear_bull4 = c[2] > c[3] and c[2] < o[3]
bear_bear5 = c[1] < o[2] and c[1] < c[3] and c[1] < o[4]
bear_bear6 = c < o and c < o[5] and c < c[1]
bearish_6CBP = bear_bull1 and bear_bull2 and bear_bear3 and bear_bull4 and bear_bear5 and bear_bear6
o4_bear = o[2]
c4_bear = c[2]
h4_bear = h[2]
l4_bear = l[2]
mid4_bear = get_mid(o4_bear, c4_bear)
// Bullish inverse
bull_bear1 = c[5] < o[5]
bull_bear2 = c[4] < o[4] and c[4] < c[5]
bull_bull3 = c[3] > o[3] and c[3] > o[4]
bull_bear4 = c[2] < c[3] and c[2] > o[3]
bull_bull5 = c[1] > o[2] and c[1] > c[3] and c[1] > o[4]
bull_bull6 = c > o and c > o[5] and c > c[1]
bullish_6CBP = bull_bear1 and bull_bear2 and bull_bull3 and bull_bear4 and bull_bull5 and bull_bull6
o4_bull = o[2]
c4_bull = c[2]
h4_bull = h[2]
l4_bull = l[2]
mid4_bull = get_mid(o4_bull, c4_bull)
// ────────────────────────────
// πŸŸ₯ Bearish 6CBP
if bearish_6CBP
// Tiny diamond on top wick of 4th candle
label.new(bar_index[2], h4_bear, "6CBP↓", style=label.style_diamond, color=color.new(color.red, 0), textcolor=color.new(#000000, 0), size=size.tiny)
// Rectangle for 4th candle’s body, extended 10 bars right
box.new(left=bar_index[2], right=bar_index[2] + 10, top=math.max(o4_bear, c4_bear), bottom=math.min(o4_bear, c4_bear),bgcolor=color.new(color.red, 85),border_color=color.new(color.red, 0))
// Midline for reference
line.new(bar_index[2], mid4_bear, bar_index[2] + 10, mid4_bear, color=color.new(color.red, 0), width=1 )
// βœ… Manila timestamp for this 4th-bar (offset = 2)
label.new(bar_index[2], h4_bear, manilaTimeStr(2), style = label.style_label_down, textcolor = color.rgb(0, 0, 0), color = color.new(color.red, 100), size = size.small)
// ────────────────────────────
// 🟩 Bullish 6CBP
if bullish_6CBP
// Tiny diamond on bottom wick of 4th candle
label.new(bar_index[2], l4_bull, text="6CBP↑",style=label.style_diamond,color=color.new(color.lime, 0),textcolor=color.new(#000000, 0), size=size.tiny )
// Rectangle for 4th candle’s body, extended 10 bars right
box.new(left=bar_index[2], right=bar_index[2] + 10, top=math.max(o4_bull, c4_bull),bottom=math.min(o4_bull, c4_bull), bgcolor=color.new(color.lime, 85), border_color=color.new(color.lime, 0) )
// Midline for reference
line.new( bar_index[2], mid4_bull, bar_index[2] + 10, mid4_bull, color=color.new(color.lime, 0), width=1 )
// βœ… Manila timestamp for this 4th-bar (offset = 2)
label.new( bar_index[2], l4_bull, manilaTimeStr(2),style = label.style_label_up, textcolor = color.rgb(0, 0, 0),color = color.new(color.lime, 100), size = size.small)
///////////////////////////////
// === INPUTS ===
showSeconds = input.bool(false, "Show seconds (HH:MM:SS)", inline="s")
labelBg = input.color(color.new(#363a45, 100), "Label background")
labelTxtColor = input.color(color.rgb(0, 0, 0), "Label text color")
// === HELPERS: lowercase day and month names ===
f_dayname(_d) =>_d == dayofweek.monday ? "mon" : _d == dayofweek.tuesday ? "tue" :_d == dayofweek.wednesday ? "wed" :_d == dayofweek.thursday ? "thu" :_d == dayofweek.friday ? "fri" : _d == dayofweek.saturday ? "sat" : "sun"
f_monthname(_m) => _m == 1 ? "jan" : _m == 2 ? "feb" :_m == 3 ? "mar" :_m == 4 ? "apr" : _m == 5 ? "may" : _m == 6 ? "jun" : _m == 7 ? "jul" :_m == 8 ? "aug" : _m == 9 ? "sep" : _m == 10 ? "oct" : _m == 11 ? "nov" : "dec"
// === TIME CONVERSION TO ASIA/MANILA (UTC+8) ===
t_now_manila = timenow + (13 * 60 * 60 * 1000) // correct offset is +8 hours
// Extract components in Asia/Manila timezone
hh = hour(t_now_manila)
min_ = minute(t_now_manila)
sec_ = second(t_now_manila)
dofw = dayofweek(t_now_manila)
mon = month(t_now_manila)
dy = dayofmonth(t_now_manila)
yr = year(t_now_manila)
// Format helpers
ff_two(n) => n < 10 ? "0" + str.tostring(n) : str.tostring(n)
// Format "HH:MM" or "HH:MM:SS"
timeStr = showSeconds ? ff_two(hh) + ":" + ff_two(min_) + ":" + ff_two(sec_) : ff_two(hh) + ":" + ff_two(min_) + " utc8"
// Format "mon/oct 27/2025"
dateStr = f_dayname(dofw) + "/" + f_monthname(mon) + " " + ff_two(dy) + "/" + str.tostring(yr)
lblText = timeStr + " " + "\n " + dateStr
// === DRAW LABEL ON MOST RECENT CLOSE ===
var label lbl = na
if barstate.islast
if na(lbl)
lbl := label.new( bar_index - 5 , close, lblText, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=labelBg, textcolor=labelTxtColor, size=size.small )
else
label.set_xy(lbl, bar_index, close)
label.set_text(lbl, lblText)
label.set_color(lbl, labelBg)
label.set_textcolor(lbl, labelTxtColor)
label.set_size(lbl, size.small)
//30minute bar candles Logic\
// ---- SETTINGS ----
len = input.int(30, "Number of CLOSED 30m candles", minval=1)
offset = input.int(5, "Offset from right edge (bars)")
spacing = 3 // horizontal footprint per 30m candle (2 body + 1 gap)
// ---- COLOR SETTINGS ----
bullColor = input.color(color.new(#dbdbdb, 0), "Bull Candle Color")
bearColor = input.color(color.new(#2e2e2e, 0), "Bear Candle Color")
wickColor = input.color(#2e2e2e, "Wick Color")
borderCol = input.color(#2e2e2e, "Border Color")
// ---- GET 30m CLOSED series ----
[o30, h30, l30, c30] = request.security(syminfo.tickerid, "30", [open, high, low, close], barmerge.gaps_on)
// ---- detect 30m boundary ----
isNew30Boundary = ta.change(time("30"))
// ---- Buffers for closed candles ----
var float[] bufO = array.new_float(len, na)
var float[] bufH = array.new_float(len, na)
var float[] bufL = array.new_float(len, na)
var float[] bufC = array.new_float(len, na)
// Maintain buffer if len changed
if array.size(bufO) != len
bufO := array.new_float(len, na)
bufH := array.new_float(len, na)
bufL := array.new_float(len, na)
bufC := array.new_float(len, na)
// ---- Store CLOSED 30m candle on new boundary ----
if isNew30Boundary
closedO = o30[1]
closedH = h30[1]
closedL = l30[1]
closedC = c30[1]
if not na(closedO) and not na(closedC)
array.unshift(bufO, closedO)
array.unshift(bufH, closedH)
array.unshift(bufL, closedL)
array.unshift(bufC, closedC)
if array.size(bufO) > len
array.pop(bufO)
array.pop(bufH)
array.pop(bufL)
array.pop(bufC)
// ---- Historical Prefill ----
var bool didPrefill = false
if not didPrefill
maxScanBars = 2000
var float[] tO = array.new_float()
var float[] tH = array.new_float()
var float[] tL = array.new_float()
var float[] tC = array.new_float()
for i = 1 to maxScanBars
if bar_index - i < 0
break
if time("30")[i] != time("30")[i+1]
co = o30[i+1]
ch = h30[i+1]
cl = l30[i+1]
cc = c30[i+1]
if not na(co) and not na(cc)
array.push(tO, co)
array.push(tH, ch)
array.push(tL, cl)
array.push(tC, cc)
if array.size(tO) >= len
break
if array.size(tO) > 0
bufO := array.new_float()
bufH := array.new_float()
bufL := array.new_float()
bufC := array.new_float()
for j = array.size(tO) - 1 to 0 by -1
array.push(bufO, array.get(tO, j))
array.push(bufH, array.get(tH, j))
array.push(bufL, array.get(tL, j))
array.push(bufC, array.get(tC, j))
while array.size(bufO) < len
array.push(bufO, na)
array.push(bufH, na)
array.push(bufL, na)
array.push(bufC, na)
didPrefill := true
// ---- LIVE 30m candle on lower TF (manual accumulation) ----
tf_sec = 30 * 60 // 30 minutes in seconds
curr30_open_time = math.floor(time / 1000 / tf_sec) * tf_sec * 1000 // start time of current 30m candle in ms
var float liveO = na
var float liveH = na
var float liveL = na
var float liveC = na
if na(liveO) or time == curr30_open_time
liveO := open
liveH := high
liveL := low
liveH := math.max(liveH, high)
liveL := math.min(liveL, low)
liveC := close
// ---- DRAW ----
var box[] bodies = array.new_box()
var line[] wicks = array.new_line()
if barstate.isfirst
// +1 slot for LIVE candle
for i = 0 to len
array.push(bodies, na)
array.push(wicks, na)
// ---- RENDER ----
anchor = bar_index
for i = 0 to len
_o = i == 0 ? liveO : array.get(bufO, i - 1)
_h = i == 0 ? liveH : array.get(bufH, i - 1)
_l = i == 0 ? liveL : array.get(bufL, i - 1)
_c = i == 0 ? liveC : array.get(bufC, i - 1)
if na(_o) or na(_c)
continue
hi = math.max(_o, _c)
lo = math.min(_o, _c)
xL = anchor + offset + (len - i + 1) * spacing
xR = xL + 2
xM = xL + 1
_bg = _c >= _o ? bullColor : bearColor
// body
body = array.get(bodies, i)
if na(body)
body := box.new(xL, hi, xR, lo, border_color=borderCol, bgcolor=_bg)
array.set(bodies, i, body)
else
box.set_left(body, xL)
box.set_right(body, xR)
box.set_top(body, hi)
box.set_bottom(body, lo)
box.set_bgcolor(body, _bg)
// wick
wick = array.get(wicks, i)
if na(wick)
wick := line.new(xM, _h, xM, _l, width=1, color=wickColor)
array.set(wicks, i, wick)
else
line.set_x1(wick, xM)
line.set_x2(wick, xM)
line.set_y1(wick, _h)
line.set_y2(wick, _l)