1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.
Source Code
1,348 lines of Pine Script v5 from SMC3.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.
SMC3.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// Big thanks to AlbaTherium for orginal script https://www.tradingview.com/script/nSSzkNji-AlbaTherium-Structure-mapping-v2-0/
// Author: Ma Bang Chu from https://t.me/wyckoffneverdie
//@version=5
indicator("Structure TA", "ICT TA", true, max_bars_back = 5000, max_labels_count = 500, max_lines_count = 500)
//drawing options
DefaultStructSetting = "Structure Settings"
groupAsianSessionRange2 = "Settings"
show_session = input(defval=false, title='Show Sessions', group=groupAsianSessionRange2, inline="session1")
bias_reason = input.bool(false, "Show Bias Reasoning", tooltip = "Giải thích lý do tại sao áp dụng Daily bias", group = groupAsianSessionRange2)
//Seasonal Adjustment Input
season = input.string(defval='Winter/Spring', options=['Winter/Spring', 'Summer/Fall'], title='US Season', group=groupAsianSessionRange2, inline="session1")
structure_type = input.string ("Choch with IDM",title='Structure type', group=DefaultStructSetting, options=["Choch without IDM", "Choch with IDM"])
showHL = input.bool(false, "Mark H/L", inline = "HL_Struct", group = DefaultStructSetting)
colorHL = input.color(color.rgb(0, 0, 0, 8), "High/Low", group = DefaultStructSetting, inline = "HL_Struct")
showVolMajor = input.bool(true, "Show Volume on Major HL", group = DefaultStructSetting)
showCircleHL = input.bool(true, "Mark Circle", inline = "HL_Circle", group = DefaultStructSetting)
bull = input.color(color.rgb(76, 175, 79, 8), "Bullish", inline = "HL_Circle", group = DefaultStructSetting)
bear = input.color(color.rgb(255, 82, 82, 8) , "Bearish", inline = "HL_Circle", group = DefaultStructSetting)
showMn = input.bool(true, "Show Internal Structure", inline = "internalStructure" , group = DefaultStructSetting)
internalStructureType = input.string("auto", title="Size",
options=["auto", "tiny", "small", "default", "large", "very large"], group = DefaultStructSetting, inline = 'internalStructure')
size_internalStructure = switch internalStructureType
"tiny" => size.tiny
"small" => size.small
"default" => size.normal
"large" => size.large
"very large" => size.huge
"auto" => size.auto
puUpco = input.color(#f57f17 , "High pivots", inline = "Line3", group = DefaultStructSetting)
puDnco = input.color(#006064, "Low pivots" , inline = "Line3", group = DefaultStructSetting)
showVolGann = input.bool(true, "Show Volume on Gann waves", group = DefaultStructSetting)
showBOS = input.bool(true, "Show B O S", group = DefaultStructSetting, inline = "sShowLine")
showChoChStructure = input.bool(true, "Show CHoCH", group = DefaultStructSetting, inline = "sShowLine")
showIDM = input.bool(true,"Show IDM", group = DefaultStructSetting, inline = "sShowLine")
showPdh = input.bool(true,"Show PDH", group = DefaultStructSetting, inline = "sShowLinePDH")
lengPdh = input.int(19, title="", group=DefaultStructSetting, inline = "sShowLinePDH")
showPdl = input.bool(true,"Show PDL", group = DefaultStructSetting, inline = "sShowLinePDL")
lengPdl = input.int(19, title="", group=DefaultStructSetting, inline = "sShowLinePDL")
showMid = input.bool(false, "Show Equilibrium", group = DefaultStructSetting, inline = "sShowLineEqu")
lengMid = input.int(19, title="", group=DefaultStructSetting, inline = "sShowLineEqu")
showSw = input.bool(true, "Show H/L sweeping lines", group = DefaultStructSetting, inline = "sShowLinesweep")
markX = input.bool(true, 'Mark "X"', group = DefaultStructSetting, inline = "sShowLinesweep")
colorSweep = input.color(color.purple, "Sweeping Color", group = DefaultStructSetting, inline = "sShowLinesweep")
showTP = input.bool(true, 'Show Target profit', group = DefaultStructSetting, inline = "STarget")
colorTP = input.color(#b2b5be, 'Target Color', group = DefaultStructSetting, inline = "STarget")
showliveBOS = input.bool(true,"Show live BOS", inline = "liveB", group = DefaultStructSetting)
lengBos = input.int(11, title="", inline = "liveB", group=DefaultStructSetting)
showliveChoch = input.bool(true,"Show live ChoCh", inline = "liveCho", group = DefaultStructSetting)
lengChoch = input.int(11, title="", inline = "liveCho", group=DefaultStructSetting)
showliveIDM = input.bool(true,"Show live IDM", inline = "liveI", group = DefaultStructSetting)
lengIDM = input.int(11, title="", inline = "liveI", group=DefaultStructSetting)
colorIDM = input.color(color.rgb(68, 68, 68, 8), "IDM Color", inline = "liveI", group=DefaultStructSetting)
showSCOB = input.bool(true, "Show SCOB", group = DefaultStructSetting, inline = "SCOB")
scobUp = input.color(color.aqua , "Bullish SCOB", group = DefaultStructSetting, inline = "SCOB")
scobDn = input.color(color.fuchsia, "Bearish SCOB", group = DefaultStructSetting, inline = "SCOB")
showISB = input.bool(true, 'Show ISB', group = DefaultStructSetting, inline = "ISB")
colorISB = input.color(#fbc02d,'Inside Bar', group = DefaultStructSetting, inline = "ISB")
showOSB = input.bool(true, 'Show OSB', group = DefaultStructSetting, inline = "OSB")
colorOSB_up_Structure = input.color(#4caf50,'Bullish OSB', group = DefaultStructSetting, inline = "OSB")
colorOSB_down_Structure = input.color(#c12418,'Bearish OSB', group = DefaultStructSetting, inline = "OSB")
showPOI = input.bool(true, "Show POI", group="POI settings")
poi_type = input.string ("---",title='POI type', group="POI settings", options=["---", "Mother Bar"])
mergeRatio = input.float(defval=0, minval=0, maxval=0.5, step=0.02, title="Merge Ratio", group="POI settings" )
maxBarHistory = input.int(1000, title="Max IPA age", group="POI settings")
colorDemand = input.color(#d6e3ca63, 'Demand', group = "POI settings")
colorSupply = input.color(#ecaa9e63, 'Supply', group = "POI settings")
colorMitigated = input.color(#c0c0c033, 'Mitigated', group = "POI settings")
UltraVol = "Candle Name + Volume Vsa"
//Công thức//
lengthVolumeMA = input.int(34,minval=1,title="Length of MA applied on Volume",group = UltraVol)
ratioUltraVolume = input.float(1.25,minval=1,title="Ultra High Volume Ratio", group = UltraVol)
showLabelCandle = input.bool(false, "Show Label", group=UltraVol, inline = 'timing1')
candleUltraVolType = input.string("tiny", title="Size",
options=["auto", "tiny", "small", "default", "large", "very large"], group = UltraVol, inline = 'timing1')
sizeCandleUltraVolume = switch candleUltraVolType
"tiny" => size.tiny
"small" => size.small
"default" => size.normal
"large" => size.large
"very large" => size.huge
"auto" => size.auto
colorLabelCandle = input.color(#111111, 'Label Color', group=UltraVol, inline = 'timing1')
getVolume() =>
float volumeMA = 0
volumeMA := nz(volumeMA[1]) + (volume-nz(volumeMA[1])) / lengthVolumeMA
ultraHighVolumeMin = volumeMA * ratioUltraVolume
volUltraHigh = volume >= ultraHighVolumeMin? true : false
//#region variable declaration
//Constant
const string IDM_TEXT = "IDM"
const string CHOCH_TEXT = "CHoCH"
const string BOS_TEXT = "BOS"
const string PDH_TEXT = "PDH"
const string PDL_TEXT = "PDL"
const string MID_TEXT = "0.5"
const string ULTRAVOLUME = " has UltraVolume"
// Hàm tính tổng volume từ thời điểm t1 đến t2
f_get_range_volume(_t1, _t2) =>
float _v = 0.0
int i1 = -1
int i2 = -1
for i = 0 to 5000
if time[i] == _t1
i1 := i
if time[i] == _t2
i2 := i
if i1 != -1 and i2 != -1
break
if i1 != -1 and i2 != -1
int start = math.min(i1, i2)
int end = math.max(i1, i2)
for i = start to end
_v += nz(volume[i])
_v
//high low
var puHigh = high
var puLow = low
var L = low
var H = high
var idmLow = low
var idmHigh = high
var lastH = high
var lastL = low
var H_lastH = high
var L_lastHH = low
var H_lastLL = high
var L_lastL = low
var motherHigh = high[1]
var motherLow = low[1]
//bar indexes
var int motherBar = time[1]
var int puBar = na
var int puHBar = na
var int puLBar = na
var int idmLBar = na
var int idmHBar = na
var int HBar = time
var int LBar = time
var int lastHBar = time
var int lastLBar = time
//structure confirm
var bool mnStrc = na
var bool prevMnStrc = na
var bool isPrevBos = na
var bool findIDM = false
var bool isBosUp = false
var bool isBosDn = false
var bool isCocUp = true
var bool isCocDn = true
// Lưu trữ mốc thời gian của Đỉnh/Đáy nhỏ trước đó
var float lastInternalHighTime = na
var float lastInternalLowTime = na
// Mảng lưu label mũi tên Internal (để xóa sau)
var arrMnLabel = array.new_label(0)
//poi
var bool isSweepOBS = false
var int current_OBS = na
var float high_MOBS = na
var float low_MOBS = na
var bool isSweepOBD = false
var int current_OBD = na
var float low_MOBD = na
var float high_MOBD = na
//Array
var arrTopBotBar = array.new_int(1, time)
var arrTop = array.new_float(1, high)
var arrBot = array.new_float(1, low)
var arrPbHBar= array.new_int(0)
var arrPbHigh = array.new_float(0)
var arrPbLBar = array.new_int(0)
var arrPbLow = array.new_float(0)
var demandZone = array.new_box(0)
var supplyZone = array.new_box(0)
var mitigatedZoneSupply = array.new_string(0)
var mitigatedZoneDemand = array.new_string(0)
var arrIdmHigh = array.new_float(0)
var arrIdmLow = array.new_float(0)
var arrIdmHBar = array.new_int(0)
var arrIdmLBar = array.new_int(0)
var arrLastH = array.new_float(0)
var arrLastHBar = array.new_int(0)
var arrLastL = array.new_float(0)
var arrLastLBar = array.new_int(0)
var arrIdmLine = array.new_line(0)
var arrIdmLabel = array.new_label(0)
var arrBCLine = array.new_line(0)
var arrBCLabel = array.new_label(0)
var arrHLLabel = array.new_label(0)
var arrHLCircle = array.new_label(0)
// Mảng quản lý label volume cho Major và Internal
var arrHLVolLabel = array.new_label(0)
// Mảng cho Gann waves (F1, SF1)
var arrGannVolLabel = array.new_label(0)
//color
color transp = color.new(color.gray,100)
thongbao(_message) =>
log.info(str.tostring(_message))
showmang(array) =>
if(array.size(array) > 0)
thongbao("---- Show Mang: ----")
for i=0 to array.size(array) - 1
thongbao( "phan tu "+str.tostring(i)+" : "+ str.tostring(array.get(array,i)) +' -- ')
// Hiển thị loại nến ra chart và thông báo khi ở vùng Mua hoặc bán
activeAlert(_message) =>
alert(syminfo.ticker + ":" + timeframe.period + "m => "+ _message)
alertBarPattern(string zone, string str, bool mustAlert = false) =>
// zone : bull or bear or na
// dinh nghia toan bo nen la false
osb_up = false
osb_down = false
eng_up = false
eng_down = false
// mm_up = false
// mm_down = false
// doji_up_black = false
// doji_up_blue = false
// doji_up = false
// doji_down_black = false
// doji_down_blue = false
// doji_down = false
// dinh nghia sweep nen
sweep_low = false
sweep_high = false
back_wick_high = high[1]
back_body_high = open[1] >= close[1] ? open[1] : close[1]
back_body_low = open[1] >= close[1] ? close[1] : open[1]
back_wick_low = low[1]
now_wick_high = high
now_body_high = open >= close ? open : close
now_body_low = open >= close ? close : open
now_wick_low = low
// Kiem tra nen la loai gi
float Candle_body = 0.5
//scan nến osb-eng - mera mera - csw//
candle_up = close > open
candle_down = close < open
osb_up := high > high[1] and low < low[1] and close > close[1]
osb_down := high > high[1] and low < low[1] and close < close[1]
eng_up := open >= close[1] and close > high[1] and (close - open) >= Candle_body*(high - low)
eng_down := open <= close[1] and close < low[1] and (open - close) >= Candle_body*(high - low)
// mm_up := osb_up and close[2] > close[3] and close[1] > close[2]
// mm_down := osb_down and close[2] < close[3] and close[1] < close[2]
// doji_up_blue := low <= low[1] and candle_up and (open - low) > (high - open) and (open - low) >= Candle_body*(high - low)
// doji_up_black := low <= low[1] and candle_down and (close - low) > (high - close) and (close - low) >= Candle_body*(high - low)
// doji_up := doji_up_blue or doji_up_black
// doji_down_black := candle_down and high >= high[1] and (high - open) > (low - open) and (high - open) >= Candle_body*(high - low)
// doji_down_blue := candle_up and high >= high[1] and (high - close) > (close - open) and (high - close) >= Candle_body*(high - low)
// doji_down := doji_down_black or doji_down_blue
sweep_low := back_wick_low > now_wick_low and (back_body_low <= now_body_low or back_wick_low < now_body_low)
sweep_high := back_wick_high < now_wick_high and (back_body_high >= now_body_high or back_wick_high > now_body_high)
// setup text và thông báo
var textEntry = 'na'
var textAlert = 'na'
var last_text = ''
timeStyleShapeTrade = label.style_none
position_candle = yloc.abovebar
if zone == 'na'
if (osb_up and barstate.isconfirmed)
textEntry := 'OSC ⇑'
textAlert := 'Order Single Candle ⇑'
position_candle := yloc.belowbar
else if (osb_down and barstate.isconfirmed)
textEntry := 'OSC ⇓'
textAlert := 'Order Single Candle ⇓'
// else if (doji_up and barstate.isconfirmed)
// textEntry := 'DJ ⇑'
// textAlert := 'Doji ⇑'
// position_candle := yloc.belowbar
// else if (doji_down and barstate.isconfirmed)
// textEntry := 'DJ ⇓'
// textAlert := 'Doji ⇓'
else if (sweep_high and barstate.isconfirmed)
textEntry := 'SW ⇓'
textAlert := 'Sweep high back candle ⇓'
else if (sweep_low and barstate.isconfirmed)
textEntry := 'SL ⇑'
textAlert := 'Sweep low back candle ⇑'
position_candle := yloc.belowbar
else if zone == 'bull'
if (osb_up and barstate.isconfirmed)
textEntry := 'OSC ⇑'
textAlert := 'Order Single Candle ⇑'
position_candle := yloc.belowbar
else if (eng_up and barstate.isconfirmed)
textEntry := 'EG ⇑'
textAlert := 'Engulfing ⇑'
position_candle := yloc.belowbar
// else if (doji_up and barstate.isconfirmed)
// textEntry := 'DJ ⇑'
// textAlert := 'Doji ⇑'
// position_candle := yloc.belowbar
else if (sweep_low and barstate.isconfirmed)
textEntry := 'SL ⇑'
textAlert := 'Sweep low back candle ⇑'
position_candle := yloc.belowbar
else if zone == 'bear'
if (osb_down and barstate.isconfirmed)
textEntry := 'OSC ⇓'
textAlert := 'Order Single Candle ⇓'
else if (eng_down and barstate.isconfirmed)
textEntry := 'EG ⇓'
textAlert := 'Engulfing ⇓'
// else if (doji_down and barstate.isconfirmed)
// textEntry := 'DJ ⇓'
// textAlert := 'Doji ⇓'
else if (sweep_high and barstate.isconfirmed)
textEntry := 'SW ⇓'
textAlert := 'Sweep high back candle ⇓'
volUltraHigh = getVolume()
last_text := str
// hiển thị ra chart
if barstate.isconfirmed and textEntry != 'na'
last_text := last_text + '; ' + textAlert
if showLabelCandle
textEntry := volUltraHigh ? textEntry + 'V' : textEntry
label.new(bar_index, high, textEntry, yloc=position_candle, color=colorLabelCandle, style=timeStyleShapeTrade, textcolor=colorLabelCandle, size=sizeCandleUltraVolume)
activeAlert(last_text)
else if mustAlert
activeAlert(last_text)
textEntry := 'na'
textAlert := 'na'
last_text := ''
volUltraHigh := false
// end test function
//Caculate
curTf = timeframe.in_seconds(timeframe.period)
dayTf = timeframe.in_seconds("1D")
i_loop = 2*dayTf/curTf
[pdh, pdl] = request.security(syminfo.tickerid, 'D', [high[1], low[1]])
len = curTf*1000
//#endregion
//#region Inside Bar
isb = motherHigh > high and motherLow < low
if isb
motherHigh := motherHigh
motherLow := motherLow
motherBar := motherBar
else
motherHigh := high
motherLow := low
motherBar := time
//#endregion
//#region drawing function
isGreenBar(int bar) => close[bar] > open[bar]
textCenter(int left, int right) => int(math.avg(left,right))
getStyleLabel(bool style) => style ? label.style_label_down : label.style_label_up
getStyleArrow(bool style) => style ? label.style_arrowdown : label.style_arrowup
getYloc(bool style) => style ? yloc.abovebar : yloc.belowbar
getDirection(bool trend, int HBar, int LBar, float H, float L) =>
x = trend ? HBar : LBar
y = trend ? H : L
[x, y]
getTextLabel(float current, float last, string same, string diff) => current > last ? same : diff
getPdhlBar(float value) =>
int x = na
if value == pdh
for i = i_loop to 1 by 1
if (high[i] == pdh)
x := time[i]
break
else
for i = i_loop to 1 by 1
if (low[i] == pdl)
x := time[i]
break
x
updateTopBotValue() =>
array.push(arrTop, high)
array.push(arrBot, low)
array.push(arrTopBotBar, time)
updateLastHLValue() =>
array.push(arrLastH,lastH)
array.push(arrLastHBar,lastHBar)
array.push(arrLastL,lastL)
array.push(arrLastLBar,lastLBar)
updateIdmHigh() =>
if low < L
array.push(arrIdmHigh,puHigh)
array.push(arrIdmHBar,puHBar)
updateIdmLow() =>
if high > H
array.push(arrIdmLow,puLow)
array.push(arrIdmLBar,puLBar)
getNLastValue(arr, n) =>
if array.size(arr) > n - 1
array.get(arr, array.size(arr) - n)
removeNLastLabel(arr, n) =>
if array.size(arr) > n - 1
label.delete(array.get(arr, array.size(arr) - n))
removeNLastLine(arr, n) =>
if array.size(arr) > n - 1
line.delete(array.get(arr, array.size(arr) - n))
removeLastLabel(arr, n) =>
if array.size(arr) > n - 1
for i = 1 to n
label.delete(array.get(arr, array.size(arr) - i))
removeLastLine(arr, n) =>
if array.size(arr) > n - 1
for i = 1 to n
line.delete(array.get(arr, array.size(arr) - i))
fixStrcAfterBos() =>
removeLastLabel(arrBCLabel, 1)
removeLastLine(arrBCLine, 1)
removeLastLabel(arrIdmLabel, 1)
removeLastLine(arrIdmLine, 1)
removeLastLabel(arrHLLabel, 2)
removeLastLabel(arrHLCircle, 2)
// Xóa label volume
removeLastLabel(arrHLVolLabel, 2)
fixStrcAfterChoch() =>
removeLastLabel(arrBCLabel, 2)
removeLastLine(arrBCLine, 2)
removeNLastLabel(arrHLLabel, 2)
removeNLastLabel(arrHLLabel, 3)
removeNLastLabel(arrHLCircle, 2)
removeNLastLabel(arrHLCircle, 3)
removeNLastLabel(arrIdmLabel, 2)
removeNLastLine(arrIdmLine, 2)
// Xóa label volume
removeNLastLabel(arrHLVolLabel, 2)
removeNLastLabel(arrHLVolLabel, 3)
drawIDM(bool trend) =>
[x, y] = getDirection(trend, idmLBar, idmHBar, idmLow, idmHigh)
_direction = trend ? " ⇑ " : " ⇓ "
zone = trend ? "bull" : "bear"
colorText = trend and H_lastH > L_lastHH or not trend and H_lastLL > L_lastL ? color.red : colorIDM
if showIDM
ln = line.new(x, y, time, y, xloc.bar_time, color = colorIDM, style = line.style_dotted)
lbl = label.new(textCenter(time, x), y, IDM_TEXT, xloc.bar_time, color = transp, textcolor = colorText, style = getStyleLabel(not trend), size = size.tiny)
if barstate.isconfirmed
str = _direction + " Price Cross "+ IDM_TEXT + (getVolume() ? ULTRAVOLUME : '')
alertBarPattern(zone,str,true)
array.push(arrIdmLine,ln)
array.push(arrIdmLabel,lbl)
array.clear(trend ? arrIdmLow : arrIdmHigh)
array.clear(trend ? arrIdmLBar : arrIdmHBar)
drawStructure(name, trend) =>
[x, y] = getDirection(trend, lastHBar, lastLBar, lastH, lastL)
color = trend ? bull : bear
_direction = trend ? " ⇑ " : " ⇓ "
zone = trend ? "bull" : "bear"
if name == "BOS" and showBOS
ln = line.new(x, y, time, y, xloc.bar_time, color = color, style = line.style_dashed)
lbl = label.new(textCenter(time, x), y, BOS_TEXT, xloc.bar_time, color = transp, style = getStyleLabel(trend), textcolor = color, size = size.tiny)
array.push(arrBCLine,ln)
array.push(arrBCLabel,lbl)
if barstate.isconfirmed
str = BOS_TEXT + _direction + (getVolume() ? ULTRAVOLUME : '')
alertBarPattern(zone,str,true)
if name == "ChoCh" and showChoChStructure
ln = line.new(x, y, time, y, xloc.bar_time, color = color, style = line.style_dashed)
lbl = label.new(textCenter(time, x), y, CHOCH_TEXT, xloc.bar_time, color = transp, style = getStyleLabel(trend), textcolor = color, size = size.tiny)
array.push(arrBCLine,ln)
array.push(arrBCLabel,lbl)
if barstate.isconfirmed
str = CHOCH_TEXT + _direction + (getVolume() ? ULTRAVOLUME: '')
alertBarPattern(zone,str,true)
drawLiveStrc(bool condition, bool direction, color color1, color color2, string txt, int length) =>
if condition and barstate.islast
colorText = direction ? color1 : color2
[x, y] = if txt == IDM_TEXT
getDirection(direction, idmHBar, idmLBar, idmHigh, idmLow)
else
getDirection(direction, lastHBar, lastLBar, lastH, lastL)
_txt = txt + " - " + str.tostring(y)
ln = line.new(x, y, time + len*length, y, xloc.bar_time, color = colorIDM, style = line.style_dotted),
lbl = label.new(time + len*length, y, _txt, xloc.bar_time, color = transp, textcolor = colorText, style = label.style_label_left, size = size.tiny)
if x == x[1]
line.delete(ln[1])
label.delete(lbl[1])
drawPrevStrc(bool condition, string txt) =>
[x, y, color, x2, style] = switch
txt == PDH_TEXT => [getPdhlBar(pdh), pdh, bull, time + len*lengPdh, line.style_solid]
txt == PDL_TEXT => [getPdhlBar(pdl), pdl, bear, time + len*lengPdl, line.style_solid]
txt == MID_TEXT => [math.min(lastLBar, lastHBar), math.avg(lastL, lastH), colorIDM, time + len*lengMid, line.style_dotted]
_txt = txt + " - " + str.tostring(y)
if condition and barstate.islast
ln = line.new(x, y, x2, y, xloc.bar_time, color = color, style = style)
lbl = label.new(x2, y, _txt, xloc.bar_time, color = transp, textcolor = color, style = label.style_label_left, size = size.small)
if x == x[1]
line.delete(ln[1])
label.delete(lbl[1])
labelMn(bool trend) =>
// Lấy tọa độ X (thời gian) và Y (giá) của đỉnh/đáy hiện tại
[x, y] = getDirection(trend, puHBar, puLBar, puHigh, puLow)
color_mn = trend ? puDnco : puUpco
// 1. Vẽ mũi tên cấu trúc (Sẵn có)
if showMn
lblArrow = label.new(x, y, "", xloc.bar_time, getYloc(trend), color_mn, getStyleArrow(trend), size = size_internalStructure)
array.push(arrMnLabel, lblArrow)
// 2. TÍNH VOLUME CHO SÓNG GANN (Phần bổ sung/sửa lỗi)
if showVolGann // showVolGann là input bạn đã định nghĩa ở
// Xác định mốc thời gian bắt đầu (là đỉnh/đáy Internal trước đó)
float t_start = trend ? lastInternalLowTime : lastInternalHighTime
float t_end = x // Thời gian của đỉnh/đáy hiện tại
float _vGann = 0.0
if not na(t_start) and not na(t_end)
_vGann := f_get_range_volume(t_start, t_end)
// Định dạng văn bản Volume (ví dụ: 10.5K hoặc 500)
string volText = _vGann > 0 ? (_vGann >= 1000 ? str.tostring(_vGann / 1000, "#.##") + "K" : str.tostring(_vGann, "#")) : ""
if volText != ""
// Vẽ label Volume cho sóng Gann
// Đặt label ngược hướng với mũi tên để tránh đè lên nhau
lblVolGann = label.new(x, y, volText,
xloc.bar_time,
yloc = trend ? yloc.abovebar : yloc.belowbar,
color = color.new(color.white, 100),
textcolor = color_mn,
style = trend ? label.style_label_down : label.style_label_up,
size = size.tiny)
array.push(arrGannVolLabel, lblVolGann)
labelHL(bool trend) =>
[x, y] = getDirection(trend, HBar, LBar, H, L)
txt = trend ? getTextLabel(H, getNLastValue(arrLastH, 1), "HH", "LH") : getTextLabel(L, getNLastValue(arrLastL, 1), "HL", "LL")
// Tính volume (cộng dồn từ chân sóng trước)
float t_start = trend ? lastLBar : lastHBar
float t_end = trend ? HBar : LBar
float _v = 0.0
if not na(t_start) and not na(t_end)
_v := f_get_range_volume(t_start, t_end)
string volText = _v > 0 ? (_v >= 1000 ? str.tostring(_v / 1000, "#.##") + "K" : str.tostring(_v, "#")) : ""
string volDisplay = volText != "" ? "(" + volText + ")" : ""
// Vẽ label chính
if showHL
lbl = label.new(x, y, txt, xloc.bar_time, color = transp, textcolor = colorHL, style = getStyleLabel(trend), size = size.small)
array.push(arrHLLabel, lbl)
if showCircleHL
lbl2 = label.new(x, y, '', xloc.bar_time, getYloc(trend), color = trend ? bull : bear, style = label.style_circle, size = size.tiny)
array.push(arrHLCircle, lbl2)
// Vẽ volume: đặt ở cùng x, lệch y một khoảng theo hướng ngược lại
if volDisplay != "" and showVolMajor
float offset = (high - low) * 0.5 // 50% chiều cao nến hiện tại
float yVol = trend ? y + offset : y - offset
yVol := trend ? math.min(yVol, high * 1.02) : math.max(yVol, low * 0.98) // giới hạn an toàn
lblVol = label.new(x, yVol, volDisplay, xloc.bar_time,
color = color.new(color.black, 100),
textcolor = color.new(color.black, 0),
style = getStyleLabel(not trend), // style ngược lại để dễ phân biệt
size = size.small)
array.push(arrHLVolLabel, lblVol)
sweepHL(bool trend) =>
[x, y] = getDirection(trend, lastHBar, lastLBar, lastH, lastL)
_direction = trend ? " ⇓ " : " ⇑ "
zone = trend ? "bear" : "bull"
if showSw
line.new(x, y, time, y, xloc.bar_time, color = colorSweep, style = line.style_dotted)
if markX
label.new(textCenter(time, x), y, "x", xloc.bar_time, color = transp, textcolor = colorSweep, style = getStyleLabel(trend), size = size.tiny)
if barstate.isconfirmed
str = _direction +" Sweeping..."+ (getVolume() ? ULTRAVOLUME: '')
alertBarPattern(zone,str,true)
TP(H, L) =>
target = isCocUp ? high + math.abs(H - L) : low - math.abs(H - L)
target := target < 0 ? 0 : target
if showTP
line.new(bar_index, isCocUp ? open : close, bar_index, target, color = colorTP, style = line.style_arrow_right)
// line.new(bar_index, isCocUp ? high : low, bar_index, target, color = colorTP, style = line.style_arrow_right)
createBox(left, right, top, bottom, color) =>
box.new(left=left, right=right, top=top, bottom=bottom, xloc = xloc.bar_time, bgcolor=color, border_color=color, extend = extend.right)
removeZone(zoneArray, box zone) =>
index = array.indexof(zoneArray, zone)
box.delete(zone)
array.remove(zoneArray, index)
marginZone(zone) => [box.get_top(zone), box.get_bottom(zone), box.get_left(zone)]
handleZone(zoneArray, left, top, bot, color) =>
_top = top
_bot = bot
_left = left
zone = getNLastValue(zoneArray, 1)
[topZone, botZone, leftZone] = marginZone(zone)
rangeTop = math.abs(_top-topZone)/(topZone-botZone) < mergeRatio
rangeBot = math.abs(_bot-botZone)/(topZone-botZone) < mergeRatio
//Merge zone
if _top >= topZone and _bot <= botZone or rangeTop or rangeBot
_top := math.max(_top,topZone)
_bot := math.min(_bot,botZone)
_left := leftZone
removeZone(zoneArray, zone)
if not (_top <= topZone and _bot >= botZone)
array.push(zoneArray, createBox(_left, time, _top, _bot, color))
processZones(zones, isSupply) =>
if array.size(zones) > 0
if(barstate.isconfirmed)
iHigh = high
iLow = low
iClose = close
iHighPre = high[1]
iLowPre = low[1]
iOpenPre = open[1]
iClosePre = close[1]
for i = array.size(zones) - 1 to 0 by 1
zone = array.get(zones, i)
[topZone, botZone, leftZone] = marginZone(zone)
str = ''
//bar = "High: " + str.tostring(iHigh) + " Low: " + str.tostring(iLow) + " Close: " + str.tostring(iClose)
//bar2 = "High 2: " + str.tostring(iHighPre) + " Low 2: " + str.tostring(iLowPre) + " Close 2: " + str.tostring(iClosePre)
//Breaker block zones
if isSupply and low[1] < botZone and close[1] > topZone
array.push(demandZone, createBox(leftZone, time[1], topZone, botZone, colorDemand))
// if barstate.isconfirmed
// str := "Price ⇑ reject supplyZone : " + str.tostring(topZone) + (getVolume() ? ULTRAVOLUME: '')
// alertBarPattern('bear',str)
else if not isSupply and high[1] > topZone and close[1] < botZone
array.push(supplyZone, createBox(leftZone, time[1], topZone, botZone, colorSupply))
// if barstate.isconfirmed
// str := "Price ⇓ reject demandZone : " + str.tostring(botZone) + (getVolume() ? ULTRAVOLUME: '')
// alertBarPattern('bull',str)
//Mitigated zones
// SupplyZone
else if (isSupply and high[1] >= botZone and high[1] < topZone)
box.set_right(zone, time[1])
box.set_extend(zone,extend.none)
box.set_bgcolor(zone, colorMitigated)
box.set_border_color(zone, colorMitigated)
topbot = str.tostring(topZone)+str.tostring(botZone)
// khong la isb ,nen truoc do la nen tang, gia dong cua phai nam duoi Low nen truoc, hoac sweept high nen truoc
// if (isb == false and iOpenPre < iClosePre and ((iClose < iHighPre or iLow < iLowPre) or (iHighPre < iHigh and iClose < iHighPre)) )
// Low O < Low, EG hoac sweept
if (isb == false and iLow < iLowPre and (iHighPre < topZone and iHighPre >= botZone and iClose < iLowPre) or (iHigh >= botZone and iHigh < topZone and iHigh > iHighPre and iClose < iHighPre and iClose > iClosePre))
str := "POI supplyZone ⇓ (Bearish); "+ (getVolume() ? ULTRAVOLUME: '') +" Zone: top " + str.tostring(topZone)+" & bot " + str.tostring(botZone)
if ((iHighPre < topZone and iHighPre >= botZone and iClose < iLowPre))
str := str + "; Type: EG"
else if (iHigh >= botZone and iHigh < topZone and iHigh > iHighPre and iClose < iHighPre and iClose > iClosePre)
str := str + "; Type: Sweept"
// thongbao(str +" \n "+ bar+" \n "+ bar2)
thongbao(str)
alertBarPattern('bear',str)
// if not array.includes(mitigatedZoneSupply, topbot)
// if barstate.isconfirmed
// alertBarPattern('bear',"Mitigated supplyZone (Bearish): " + str.tostring(botZone))
// array.push(mitigatedZoneSupply, topbot)
// Demand zone
else if not isSupply and low[1] <= topZone and low[1] > botZone
box.set_right(zone, time[1])
box.set_extend(zone,extend.none)
box.set_bgcolor(zone, colorMitigated)
box.set_border_color(zone, colorMitigated)
bottop = str.tostring(botZone)+str.tostring(topZone)
// khong la isb, nen truoc do la nen giam, gia dong cua phai nam tren High nen truoc, hoac sweept low nen truoc
// if (isb == false and iOpenPre > iClosePre and ((iClose > iLowPre or iHigh > iHighPre) or (iLowPre > iLow and iClose > iLowPre)))
// High < High O, EG hoac sweept
if (isb == false and iHigh > iHighPre and (iLowPre > botZone and iLowPre <= topZone and iClose > iHighPre) or (iLow >= botZone and iLow < topZone and iLow < iLowPre and iClose > iLowPre and iClose > iClosePre))
str := "POI demandZone ⇑ (Bullish); "+ (getVolume() ? ULTRAVOLUME: '') +" Zone: top " + str.tostring(topZone)+" & bot " + str.tostring(botZone)
if (iLowPre > botZone and iLowPre <= topZone and iClose > iHighPre)
str := str + "; ==> Type: EG"
else if (iLow >= botZone and iLow < topZone and iLow < iLowPre and iClose > iLowPre and iClose > iClosePre)
str := str + "; ==> Type: Sweept"
//thongbao(str +" \n "+ bar+" \n "+ bar2)
thongbao(str)
alertBarPattern('bull',str)
//
// if not array.includes(mitigatedZoneDemand, bottop)
// alertBarPattern('bull',"Mitigated demandZone (Bullish):"+ str.tostring(topZone))
// array.push(mitigatedZoneDemand, bottop)
// first_elem_str = "First element: " + str.tostring(array.size(mitigatedZoneDemand)) +' - '+ str.tostring((array.size(mitigatedZoneSupply)))
// var tbl = table.new(position.top_right, 1, 1, color.yellow)
// if (barstate.islast)
// // label.new(bar_index, high, first_elem_str)
// table.cell(tbl, 0, 0, first_elem_str)
//Delete sweep zones
if (time[1] - leftZone > len*maxBarHistory) or (isSupply and high[1] >= topZone) or (not isSupply and low[1] <= botZone)
removeZone(zones, zone)
if array.size(mitigatedZoneDemand) > 0
array.pop(mitigatedZoneDemand)
if array.size(mitigatedZoneSupply) > 0
array.pop(mitigatedZoneSupply)
// array.remove(array.first(mitigatedZoneDemand))
scob(zones, isSupply) =>
[topZone, botZone, leftZone] = marginZone(getNLastValue(zones, 1))
avgV = ta.ema(volume, 20)
spread = math.abs(close - open)
if not isb[1] and ((volume[1] > avgV[1]) or (spread[1] < spread))
if not isSupply and low[1] < low[2] and low[1] < low and close > high[1] and low[1] > botZone and low[1] < topZone
scobUp
else if isSupply and high[1] > high[2] and high[1] > high and close < low[1] and high[1] < topZone and high[1] > botZone
scobDn
else
na
//#endregion
//#region get value from array
top = getNLastValue(arrTop, 1)
bot = getNLastValue(arrBot, 1)
topBotBar = getNLastValue(arrTopBotBar, 1)
top1 = getNLastValue(arrTop, 2)
bot1 = getNLastValue(arrBot, 2)
topBotBar1 = getNLastValue(arrTopBotBar, 2)
//#endregion
//#region Outside Bar
osb = high > top and low < bot
//#endregion
//#region Minor Structure
if high >= top and low <= bot //notrend
updateIdmHigh()
updateIdmLow()
if not na(mnStrc)
prevMnStrc := mnStrc ? true : false
else
if prevMnStrc and isGreenBar(0) and not isGreenBar(1)
puHigh := top
puHBar := topBotBar
labelMn(true)
if not na(puHBar)
lastInternalHighTime := puHBar
labelMn(false)
if not na(puLBar)
lastInternalLowTime := puLBar
if high > H
array.push(arrIdmLow,low)
array.push(arrIdmLBar,time)
if not prevMnStrc and not isGreenBar(0) and isGreenBar(1)
puLow := bot
puLBar := topBotBar
labelMn(true)
if not na(puHBar)
lastInternalHighTime := puHBar
labelMn(false)
if not na(puLBar)
lastInternalLowTime := puLBar
if low < L
array.push(arrIdmHigh,high)
array.push(arrIdmHBar,time)
updateTopBotValue()
puHigh := high
puLow := low
puHBar := time
puLBar := time
mnStrc := na
if high >= top and low > bot //uptrend
if prevMnStrc and na(mnStrc)
puHigh := top1
puHBar := topBotBar1
labelMn(true)
if not na(puHBar)
lastInternalHighTime := puHBar
labelMn(false)
if not na(puLBar)
lastInternalLowTime := puLBar
else if (not prevMnStrc and na(mnStrc)) or not mnStrc
labelMn(false)
if not na(puLBar)
lastInternalLowTime := puLBar
updateIdmLow()
updateTopBotValue()
puHigh := high
puHBar := time
prevMnStrc := na
mnStrc := true
if high < top and low <= bot //downtrend
if not prevMnStrc and na(mnStrc)
puLow := bot1
puLBar := topBotBar1
labelMn(false)
if not na(puLBar)
lastInternalLowTime := puLBar
labelMn(true)
if not na(puHBar)
lastInternalHighTime := puHBar
else if (prevMnStrc and na(mnStrc)) or mnStrc
labelMn(true)
if not na(puHBar)
lastInternalHighTime := puHBar
updateIdmHigh()
updateTopBotValue()
puLow := low
puLBar := time
prevMnStrc := na
mnStrc := false
//#endregion
//#region update IDM
if high >= H
H := high
HBar := time
L_lastHH := low
idmLow := getNLastValue(arrIdmLow, 1)
idmLBar := getNLastValue(arrIdmLBar, 1)
if low <= L
L := low
LBar := time
H_lastLL := high
idmHigh := getNLastValue(arrIdmHigh, 1)
idmHBar := getNLastValue(arrIdmHBar, 1)
//#endregion
// #region structure mapping
// Check for IDM
if findIDM and isCocUp and isCocUp
if low < idmLow
findIDM := false
isBosUp := false
L := low
LBar := time
if structure_type == "Choch with IDM" and idmLow == lastL
if isPrevBos
fixStrcAfterBos()
lastL := getNLastValue(arrLastL, 1)
lastLBar := getNLastValue(arrLastLBar, 1)
lastH := H
lastHBar := HBar
drawIDM(true)
labelHL(true) //Confirm HH
updateLastHLValue()
H_lastH := getNLastValue(arrLastH, 1)
else
fixStrcAfterChoch()
isCocUp := false
isCocDn := true
else
lastH := H
lastHBar := HBar
drawIDM(true)
labelHL(true) //Confirm HH
updateLastHLValue()
H_lastH := getNLastValue(arrLastH, 1)
if findIDM and isCocDn and isBosDn
if high > idmHigh
findIDM := false
isBosDn := false
H := high
HBar := time
if structure_type == "Choch with IDM" and idmHigh == lastH
if isPrevBos
fixStrcAfterBos()
lastH := getNLastValue(arrLastH, 1)
lastHBar := getNLastValue(arrLastHBar, 1)
lastL := L
lastLBar := LBar
drawIDM(false)
labelHL(false) //Confirm LL
updateLastHLValue()
L_lastL := getNLastValue(arrLastL, 1)
else
fixStrcAfterChoch()
isCocUp := true
isCocDn := false
else
lastL := L
lastLBar := LBar
drawIDM(false)
labelHL(false) //Confirm LL
updateLastHLValue()
L_lastL := getNLastValue(arrLastL, 1)
//Check for ChoCh
if isCocDn and high > lastH
if structure_type == "Choch without IDM" and idmHigh == lastH and close > idmHigh
removeLastLabel(arrIdmLabel, 1)
removeLastLine(arrIdmLine, 1)
if close > lastH
drawStructure("ChoCh", true) //Confirm CocUp
findIDM := true
isBosUp := true
isCocUp := true
isBosDn := false
isCocDn := false
isPrevBos := false
L_lastL := getNLastValue(arrLastL, 1)
TP(lastH,lastL)
else
if idmHigh == lastH
removeLastLine(arrIdmLine, 1)
sweepHL(true)
if isCocUp and low < lastL
if structure_type == "Choch without IDM" and idmLow == lastL and close < idmLow
removeLastLabel(arrIdmLabel, 1)
removeLastLine(arrIdmLine, 1)
if close < lastL
drawStructure("ChoCh", false) //Confirm CocDn
findIDM := true
isBosUp := false
isCocUp := false
isBosDn := true
isCocDn := true
isPrevBos := false
H_lastH := getNLastValue(arrLastH, 1)
TP(lastH,lastL)
else
if idmLow == lastL
removeLastLine(arrIdmLine, 1)
sweepHL(false)
//Check for BoS
if not findIDM and not isBosUp and isCocUp
if high > lastH
if close > lastH
drawStructure("BOS", true) //Confirm BosUp
findIDM := true
isBosUp := true
isCocUp := true
isBosDn := false
isCocDn := false
isPrevBos := true
labelHL(false) //Confirm HL
lastL := L
lastLBar := LBar
L_lastL := L
TP(lastH,lastL)
else
sweepHL(true)
if not findIDM and not isBosDn and isCocDn
if low < lastL
if close < lastL
drawStructure("BOS", false) //Confirm BosDn
findIDM := true
isBosUp := false
isCocUp := false
isBosDn := true
isCocDn := true
isPrevBos := true
labelHL(true) //Confirm LH
lastH := H
lastHBar := HBar
H_lastH := H
TP(lastH,lastL)
else
sweepHL(false)
//#endregion
//#trigger update High and Low
if high > lastH
lastH := high
lastHBar := time
if low < lastL
lastL := low
lastLBar := time
//#endregion
if showPOI
if isSweepOBS
if low_MOBS > high[2]
if high_MOBS < high[3] and low[3] > high[1]
handleZone(supplyZone, time[3], high[3], low[3], colorSupply)
else
handleZone(supplyZone, current_OBS, high_MOBS, low_MOBS, colorSupply)
if high_MOBS > high[3] and low[3] > high[1]
handleZone(supplyZone, time[3], high[2], low[3], colorSupply)
isSweepOBS := false
else
if poi_type == "Mother Bar" and isb[3]
high_MOBS := math.max(high_MOBS,motherHigh[3])
low_MOBS := math.min(low_MOBS,motherLow[3])
current_OBS := math.min(current_OBS,motherBar)
else
high_MOBS := high[3]
low_MOBS := low[3]
current_OBS := time[3]
else
high_MOBS := high[4]
low_MOBS := low[4]
current_OBS := time[4]
if high_MOBS > high[5] and high_MOBS > high[3]
isSweepOBS := true
if isSweepOBD
if high_MOBD < low[2]
if low[3] < low_MOBD and high[3] < low[1]
handleZone(demandZone, time[3], high[3], low[3], colorDemand)
else
handleZone(demandZone, current_OBD, high_MOBD, low_MOBD, colorDemand)
if low_MOBD < low[3] and high[3] < low[1]
handleZone(demandZone, time[3], high[3], low[2], colorDemand)
isSweepOBD := false
else
if poi_type == "Mother Bar" and isb[3]
high_MOBD := math.max(high_MOBD,motherHigh[3])
low_MOBD := math.min(low_MOBD,motherLow[3])
current_OBD := math.min(current_OBD,motherBar)
else
high_MOBD := high[3]
low_MOBD := low[3]
current_OBD := time[3]
else
low_MOBD := low[4]
high_MOBD := high[4]
current_OBD := time[4]
if low_MOBD < low[5] and low_MOBD < low[3]
isSweepOBD := true
//#endregion
// test function
checkBarPattern() =>
// zone = 'bull'
//zone = 'bear'
zone = 'na'
alertBarPattern(zone,'Candle')
// test function
test() =>
// zone = 'bull'
//zone = 'bear'
zone = 'na'
alertBarPattern(zone,'T : ',true)
//#region run function
barcolor(showSCOB ? scob(supplyZone, true) : na, -1)
barcolor(showSCOB ? scob(demandZone, false) : na, -1)
barcolor(showISB and isb ? colorISB : na, 0,title="InSide Bar")
barcolor(osb and isGreenBar(0) and showOSB ? colorOSB_up_Structure : na)
barcolor(osb and not isGreenBar(0) and showOSB ? colorOSB_down_Structure : na)
processZones(supplyZone, true)
processZones(demandZone, false)
drawLiveStrc(showliveIDM and findIDM, not isCocUp, colorIDM, colorIDM, IDM_TEXT, lengIDM)
drawLiveStrc(showliveChoch, not isCocUp, bull, bear, CHOCH_TEXT, lengChoch)
drawLiveStrc(showliveBOS and not findIDM, isCocUp, bull, bear, BOS_TEXT, lengBos)
drawPrevStrc(showPdh, PDH_TEXT)
drawPrevStrc(showPdl, PDL_TEXT)
drawPrevStrc(showMid, MID_TEXT)
// checkBarPattern()
//test()
//#endregion
//----- Gann wave-------
// --- INPUTS ---
DefaultGannMLSetting = "Cấu hình Sóng F1"
showF1GannML = input.bool(true, "Hiển thị F1 (Dotted)", group = DefaultGannMLSetting, inline = "f1")
showSF1GannML = input.bool(true, "Hiển thị S-F1 (Solid)", group = DefaultGannMLSetting, inline = "f1")
colorF1GannML = input.color(#2c2c2c, "", group = DefaultGannMLSetting, inline = "f1")
showChoChF1GannML = input.bool(true, "CHoCH F1", group = DefaultGannMLSetting, inline = "choch")
showChoChSF1GannML = input.bool(true, "CHoCH S-F1", group = DefaultGannMLSetting, inline = "choch")
// --- FUNCTIONS ---
alertGann(string str) =>
alert(syminfo.ticker + ":" + timeframe.period + "m => " + str)
// Tính toán sóng Gann cơ bản
f_CalculateFn1(_pointX, _pointY, arrayXn, arrayYn, arrayXFn1, arrayYFn1) =>
int _resultdraw = 0
if((array.get(arrayYFn1,0) >= array.get(arrayYFn1,1) and array.get(arrayYn,0) < array.get(arrayYFn1,1)) or (array.get(arrayYFn1,0) <= array.get(arrayYFn1,1) and array.get(arrayYn,0) > array.get(arrayYFn1,1)))
array.unshift(arrayXFn1,_pointX), array.unshift(arrayYFn1,_pointY), _resultdraw := 1
else if(array.get(arrayYFn1,0) >= array.get(arrayYFn1,1) and (array.get(arrayYn,0) < array.get(arrayYn,1) and array.get(arrayYn,0) < array.get(arrayYn,2) and array.get(arrayYn,1) < array.get(arrayYn,3)) and array.get(arrayYn,2) < array.get(arrayYn,3))
array.unshift(arrayXFn1,_pointX), array.unshift(arrayYFn1,_pointY), _resultdraw := 1
else if(array.get(arrayYFn1,0) <= array.get(arrayYFn1,1) and (array.get(arrayYn,0) > array.get(arrayYn,1) and array.get(arrayYn,0) > array.get(arrayYn,2) and array.get(arrayYn,1) > array.get(arrayYn,3)) and array.get(arrayYn,2) > array.get(arrayYn,3))
array.unshift(arrayXFn1,_pointX), array.unshift(arrayYFn1,_pointY), _resultdraw := 1
else if(array.get(arrayYFn1,0) >= array.get(arrayYFn1,1) and _pointY >= array.get(arrayYFn1,0) and (_pointY >= array.get(arrayYFn1,0) or (array.get(arrayYn,0) > array.get(arrayYn,2) and array.get(arrayYn,2) > array.get(arrayYn,1)) or (array.get(arrayYn,0) > array.get(arrayYn,1) and array.get(arrayYn,1) > array.get(arrayYn,2) and array.get(arrayYn,2) > array.get(arrayYn,3))))
array.set(arrayXFn1, 0, _pointX), array.set(arrayYFn1, 0, _pointY), _resultdraw := 2
else if(array.get(arrayYFn1,0) <= array.get(arrayYFn1,1) and _pointY <= array.get(arrayYFn1,0) and (_pointY <= array.get(arrayYFn1,0) or (array.get(arrayYn,0) < array.get(arrayYn,2) and array.get(arrayYn,2) < array.get(arrayYn,1)) or (array.get(arrayYn,0) < array.get(arrayYn,1) and array.get(arrayYn,1) < array.get(arrayYn,2) and array.get(arrayYn,2) < array.get(arrayYn,3))))
array.set(arrayXFn1, 0, _pointX), array.set(arrayYFn1, 0, _pointY), _resultdraw := 2
[_resultdraw]
// Tính toán sóng phụ (Sub-swing)
f_CalculateSFn1(_pointX, _pointY, _arrayMark, _mIdxMark, arraySXFn1, arraySYFn1) =>
int _resultdraw = 0
if(array.get(_arrayMark,_mIdxMark) == 0)
if((array.get(arraySYFn1,0) >= array.get(arraySYFn1,1) and _pointY >= array.get(arraySYFn1,0)) or (array.get(arraySYFn1,0) <= array.get(arraySYFn1,1) and _pointY <= array.get(arraySYFn1,0)))
array.set(arraySXFn1, 0, _pointX), array.set(arraySYFn1, 0, _pointY), _resultdraw := 2
else if((array.get(arraySYFn1,0) >= array.get(arraySYFn1,1) and _pointY < array.get(arraySYFn1,1)) or (array.get(arraySYFn1,0) <= array.get(arraySYFn1,1) and _pointY > array.get(arraySYFn1,1)))
array.unshift(arraySXFn1,_pointX), array.unshift(arraySYFn1,_pointY), _resultdraw := 1
else if((array.get(arraySYFn1,0) >= array.get(arraySYFn1,1) and _pointY < array.get(arraySYFn1,0) and _pointY > array.get(arraySYFn1,1)) or (array.get(arraySYFn1,0) <= array.get(arraySYFn1,1) and _pointY > array.get(arraySYFn1,0) and _pointY < array.get(arraySYFn1,1)))
array.unshift(arraySXFn1,_pointX), array.unshift(arraySYFn1,_pointY), array.set(_arrayMark,_mIdxMark,_pointY), _resultdraw := 1
else if(array.get(_arrayMark,_mIdxMark) > 0)
if((array.get(arraySYFn1,0) >= array.get(arraySYFn1,1) and _pointY < array.get(arraySYFn1,1)) or (array.get(arraySYFn1,0) <= array.get(arraySYFn1,1) and _pointY > array.get(arraySYFn1,1)))
array.unshift(arraySXFn1,_pointX), array.unshift(arraySYFn1,_pointY), array.set(_arrayMark,_mIdxMark,0), _resultdraw := 1
else if((array.get(arraySYFn1,0) >= array.get(arraySYFn1,1) and _pointY > array.get(arraySYFn1,2)) or (array.get(arraySYFn1,0) <= array.get(arraySYFn1,1) and _pointY < array.get(arraySYFn1,2)))
array.set(arraySXFn1, 0, _pointX), array.set(arraySYFn1, 0, _pointY), array.set(_arrayMark,_mIdxMark,0), _resultdraw := 2
else if((array.get(arraySYFn1,0) >= array.get(arraySYFn1,1) and _pointY <= array.get(arraySYFn1,2) and _pointY >= array.get(arraySYFn1,0)) or (array.get(arraySYFn1,0) <= array.get(arraySYFn1,1) and _pointY >= array.get(arraySYFn1,2) and _pointY <= array.get(arraySYFn1,0)))
array.set(arraySXFn1, 0, _pointX), array.set(arraySYFn1, 0, _pointY), array.set(_arrayMark,_mIdxMark,_pointY), _resultdraw := 2
[_resultdraw]
f_CalculateRemoveDuplicateLine(arrayLine, arraySLine) =>
if(array.size(arraySLine) > 1 and array.size(arrayLine) > 1)
if(line.get_y1(array.get(arraySLine,1)) == line.get_y1(array.get(arrayLine,1)) and line.get_y2(array.get(arraySLine,1)) == line.get_y2(array.get(arrayLine,1)) and line.get_x1(array.get(arraySLine,1)) == line.get_x1(array.get(arrayLine,1)) and line.get_x2(array.get(arraySLine,1)) == line.get_x2(array.get(arrayLine,1)))
line.delete(array.get(arrayLine,1))
array.remove(arrayLine,1)
f_CalculateChoCh(arraySXFn1, arraySYFn1) =>
int _X = 0, float _Y = 0
if((array.get(arraySYFn1,3) > array.get(arraySYFn1,2) and array.get(arraySYFn1,3) < array.get(arraySYFn1,1) and array.get(arraySYFn1,0) < array.get(arraySYFn1,2)) or (array.get(arraySYFn1,3) < array.get(arraySYFn1,2) and array.get(arraySYFn1,3) > array.get(arraySYFn1,1) and array.get(arraySYFn1,0) > array.get(arraySYFn1,2)))
_X := array.get(arraySXFn1,2), _Y := array.get(arraySYFn1,2)
[_X, _Y]
f_CalculateDrawF(_drawF, arrayLine, arrayX, arrayY, showChoCh, arrayMChoCh, idxChoCh, _color) =>
if(_drawF > 0)
if(_drawF == 1)
array.unshift(arrayLine, line.new(array.get(arrayX,1), array.get(arrayY,1), array.get(arrayX,0), array.get(arrayY,0), color = _color, xloc = xloc.bar_time, width = 1, style = line.style_dotted))
else if(_drawF == 2 and array.size(arrayLine) > 0)
line.set_xy2(array.get(arrayLine,0), array.get(arrayX,0), array.get(arrayY,0))
[XCh, YCh] = f_CalculateChoCh(arrayX, arrayY)
if(showChoCh and YCh > 0 and array.get(arrayMChoCh, idxChoCh) != YCh)
array.set(arrayMChoCh, idxChoCh, YCh)
line.new(XCh, YCh, time, YCh, color = _color, xloc = xloc.bar_time, width = 1, style = line.style_dotted)
alertGann("i-Minor CHoCH")
f_CalculateDrawSF(_drawSF, arrayLine, arraySLine, arraySX, arraySY, showChoCh, arrayMChoCh, idxChoCh, _color) =>
if(_drawSF > 0)
if(_drawSF == 1)
array.unshift(arraySLine, line.new(array.get(arraySX,1), array.get(arraySY,1), array.get(arraySX,0), array.get(arraySY,0), color = _color, xloc = xloc.bar_time, width = 1))
else if(_drawSF == 2 and array.size(arraySLine) > 0)
line.set_xy2(array.get(arraySLine,0), array.get(arraySX,0), array.get(arraySY,0))
f_CalculateRemoveDuplicateLine(arrayLine, arraySLine)
[XChS, YChS] = f_CalculateChoCh(arraySX, arraySY)
// SỬA TẠI ĐÂY: Bỏ idxIdxChoCh =
if(showChoCh and YChS > 0 and array.get(arrayMChoCh, idxChoCh) != YChS)
array.set(arrayMChoCh, idxChoCh, YChS)
line.new(XChS, YChS, time, YChS, color = _color, xloc = xloc.bar_time, width = 1, style = line.style_dashed)
alertGann("Minor CHoCH")
// --- ARRAYS & VARIABLES ---
var arrayMarkGannML = array.new_float(1, 0) // Chỉ cần 1 chỉ số cho F1
var arrayMarkChoChGannML = array.new_float(2, 0) // Chỉ cần 2 chỉ số cho F1 và SF1
var arrayXF0GannML = array.new_int(5, time)
var arrayYF0GannML = array.new_float(5, close)
var arrayXF1GannML = array.new_int(5, time)
var arrayYF1GannML = array.new_float(5, close)
var arrayLineF1GannML = array.new_line()
var arraySXF1GannML = array.new_int(5, time)
var arraySYF1GannML = array.new_float(5, close)
var arraySLineF1GannML = array.new_line()
// --- MAIN EXECUTION ---
f_CalculateAndDrawFn1(_pointX, _pointY) =>
array.unshift(arrayXF0GannML, _pointX)
array.unshift(arrayYF0GannML, _pointY)
if(showF1GannML or showSF1GannML)
[drawF1] = f_CalculateFn1(_pointX, _pointY, arrayXF0GannML, arrayYF0GannML, arrayXF1GannML, arrayYF1GannML)
f_CalculateDrawF(showF1GannML ? drawF1 : 0, arrayLineF1GannML, arrayXF1GannML, arrayYF1GannML, showChoChF1GannML, arrayMarkChoChGannML, 0, colorF1GannML)
if(drawF1 > 0 and showSF1GannML)
[drawSF1] = f_CalculateSFn1(_pointX, _pointY, arrayMarkGannML, 0, arraySXF1GannML, arraySYF1GannML)
f_CalculateDrawSF(showSF1GannML ? drawSF1 : 0, arrayLineF1GannML, arraySLineF1GannML, arraySXF1GannML, arraySYF1GannML, showChoChSF1GannML, arrayMarkChoChGannML, 1, colorF1GannML)
f_CalculateAndDraw(_pointX, _pointY1, _pointY2) =>
if((array.get(arrayYF0GannML,0) > _pointY1 and array.get(arrayYF0GannML,0) > _pointY2) or (array.get(arrayYF0GannML,0) < _pointY1 and array.get(arrayYF0GannML,0) < _pointY2))
f_CalculateAndDrawFn1(time, array.get(arrayYF0GannML,1))
f_CalculateAndDrawFn1(time, _pointY1)
f_CalculateAndDrawFn1(time, _pointY2)
highPrev = high
lowPrev = low
if(barstate.isconfirmed)
if(high > highPrev[1] and low > lowPrev[1])
f_CalculateAndDraw(time, low, high)
else if(high < highPrev[1] and low < lowPrev[1])
f_CalculateAndDraw(time, high, low)
else if((high >= highPrev[1] and low < lowPrev[1]) or (high > highPrev[1] and low <= lowPrev[1]))
if(close > open)
f_CalculateAndDraw(time, low, high)
else
f_CalculateAndDraw(time, high, low)
else if(high[0] <= highPrev[1] and low[0] >= lowPrev[1])
highPrev := highPrev[1]
lowPrev := lowPrev[1]
// end region Gann wave
// ==========================================================
// BẢN FIX TRIỆT ĐỂ: CHỈ VẼ SÓNG CHUẨN (SHIFT HIGH/LOW)
// ==========================================================
// 1. Khai báo mảng bộ nhớ (Dùng tên biến hoàn toàn mới để tránh trùng)
var label[] vLabels = array.new_label(2, na)
var float[] vValues = array.new_float(5, 0.0) // [0]:Giá, [1]:Time, [2]:State(0:H,1:L), [3]:Mốc phá vỡ, [4]:Đỉnh/Đáy cũ
float _p = array.get(vValues, 0)
int _t = int(array.get(vValues, 1))
float _st = array.get(vValues, 2)
float _breakP = array.get(vValues, 3)
// 2. Pivot 3 nến
bool _h = high[1] > high[0] and high[1] > high[2]
bool _l = low[1] < low[0] and low[1] < low[2]
// 3. LOGIC XỬ LÝ ĐỈNH (SWING HIGH)
if _h
// Nếu đang tìm Đỉnh (0) hoặc giá cao hơn đỉnh cũ (Dời đỉnh)
if na(_st) or _st == 0.0 or (_st == 1.0 and high[1] > _p)
if na(_p) or high[1] > _p
label.delete(array.get(vLabels, 0))
label.delete(array.get(vLabels, 1))
float _vol = f_get_range_volume(_t, time[1])
string _txt = _vol >= 1000 ? str.tostring(_vol / 1000, "#.#") + "K" : str.tostring(_vol, "#")
// Vẽ mũi tên và volume (Dùng tham số tường minh để tránh lỗi)
label _la = label.new(x=time[1], y=high[1], text="", xloc=xloc.bar_time, yloc=yloc.abovebar, color=puDnco, style=label.style_arrowdown, size=size_internalStructure)
label _lv = na
if showVolGann
_lv := label.new(x=time[1], y=high[1], text=_txt, xloc=xloc.bar_time, yloc=yloc.abovebar, color=color.new(color.white, 100), textcolor=puDnco, style=label.style_label_down, size=size_internalStructure)
array.set(vLabels, 0, _la)
array.set(vLabels, 1, _lv)
array.set(vValues, 0, high[1])
array.set(vValues, 1, time[1])
array.set(vValues, 2, 0.0)
array.set(vValues, 3, low[1]) // Đặt mốc chặn: Muốn tạo đáy phải phá giá thấp nến này
// 4. LOGIC XỬ LÝ ĐÁY (SWING LOW)
if _l
// Chỉ vẽ đáy nếu giá thấp hơn mốc chặn _breakP (Phá vỡ cấu trúc nến đỉnh)
if (_st == 0.0 and low[1] < _breakP) or (_st == 1.0 and low[1] < _p)
label.delete(array.get(vLabels, 0))
label.delete(array.get(vLabels, 1))
float _vol = f_get_range_volume(_t, time[1])
string _txt = _vol >= 1000 ? str.tostring(_vol / 1000, "#.#") + "K" : str.tostring(_vol, "#")
label _la = label.new(x=time[1], y=low[1], text="", xloc=xloc.bar_time, yloc=yloc.belowbar, color=puUpco, style=label.style_arrowup, size=size_internalStructure)
label _lv = na
if showVolGann
_lv := label.new(x=time[1], y=low[1], text=_txt, xloc=xloc.bar_time, yloc=yloc.belowbar, color=color.new(color.white, 100), textcolor=puUpco, style=label.style_label_up, size=size_internalStructure)
array.set(vLabels, 0, _la)
array.set(vLabels, 1, _lv)
array.set(vValues, 0, low[1])
array.set(vValues, 1, time[1])
array.set(vValues, 2, 1.0)
array.set(vValues, 3, high[1]) // Đặt mốc chặn: Muốn tạo đỉnh phải phá giá cao nến này
Overview
Structure TA marks swing highs and lows, break of structure and change of character events, optionally with an inducement step, and shows internal structure and volume on major swings. It also draws previous day high and low lines, an optional equilibrium line, sweep lines with markers, target levels and live structure breaks. Optional session shading and a daily bias explanation can be switched on, with a seasonal time adjustment. It is based on another author's script credited in the code.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Show Sessions
bool
false
show_session
Show Bias Reasoning
bool
false
bias_reason
US Season
string
Winter/Spring
season
Structure type
string
Choch with IDM
structure_type
Mark H/L
bool
false
showHL
High/Low
color
color.rgb(0, 0, 0, 8)
colorHL
Show Volume on Major HL
bool
true
showVolMajor
Mark Circle
bool
true
showCircleHL
Bullish
color
color.rgb(76, 175, 79, 8)
bull
Bearish
color
color.rgb(255, 82, 82, 8)
bear
Show Internal Structure
bool
true
showMn
Size
string
auto
internalStructureType
Show all 40 settings
Setting
Type
Default
Variable
High pivots
color
#f57f17
puUpco
Low pivots
color
#006064
puDnco
Show Volume on Gann waves
bool
true
showVolGann
Show B O S
bool
true
showBOS
Show CHoCH
bool
true
showChoChStructure
Show IDM
bool
true
showIDM
Show PDH
bool
true
showPdh
lengPdh
int
19
lengPdh
Show PDL
bool
true
showPdl
lengPdl
int
19
lengPdl
Show Equilibrium
bool
false
showMid
lengMid
int
19
lengMid
Show H/L sweeping lines
bool
true
showSw
Mark "X"
bool
true
markX
Sweeping Color
color
color.purple
colorSweep
Show Target profit
bool
true
showTP
Target Color
color
#b2b5be
colorTP
Show live BOS
bool
true
showliveBOS
lengBos
int
11
lengBos
Show live ChoCh
bool
true
showliveChoch
lengChoch
int
11
lengChoch
Show live IDM
bool
true
showliveIDM
lengIDM
int
11
lengIDM
IDM Color
color
color.rgb(68, 68, 68, 8)
colorIDM
Show SCOB
bool
true
showSCOB
Bullish SCOB
color
color.aqua
scobUp
Bearish SCOB
color
color.fuchsia
scobDn
Show ISB
bool
true
showISB
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and
This indicator plots labels on the TradingView price chart to mark ARK Invest's buy and sell trades for the DE stock. Buy transactions appear in green with X1 or X2 multipliers showing the number of ARK ETFs involved on the same day; sells appear in red. The m
This Pine Script indicator plots a ZigZag on the price chart. It identifies reversal points when price moves more than a set percentage from the last pivot. The script calculates forecasts using zigzag data and labels detected geometric patterns including harm
The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh
Indicatorv6SMC / ICT / price actionSessions & time
This indicator implements the Fractal Model concept to plot market structure shifts, liquidity sweeps, and Change in State of Delivery (CISD) levels. It overlays custom higher-timeframe candle previews, open prices, and time markers directly on the price chart
This indicator calculates pivot highs and pivot lows to detect liquidity sweeps and Swing Failure Patterns. It identifies when price breaks past recent key swing highs or lows within a configurable historical window, then looks for a quick reversal or change i