PriceActionToolkit.pine
Copy
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tamth_
//@version=6
indicator("Price Action Toolkit", overlay = true, precision = 2, max_labels_count = 500, max_lines_count = 500, max_boxes_count = 1000, max_bars_back = 5000)
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
// Colors
color TRANSPARENT_COLOR = #ffffff00
color WHITE_COLOR = #ffffff
color BLACK_COLOR = #000000
color RED_COLOR = #F72585
color ORANGE_COLOR = #fb5607
color YELLOW_COLOR = #ffbe0b
color GREEN_COLOR = #2a9d8f
color AQUA_COLOR = #4CC9F0
color BLUE_COLOR = #4895EF
color PURPLE_COLOR = #3F37C9
color PINK_COLOR = #B5179E
color LIGHT_GRAY_COLOR = #364156
color DARK_GRAY_COLOR = #212d40
color TEXT_COLOR = #ced4da
//-----------------------------------------------------------------------------
// Common Variables
//-----------------------------------------------------------------------------
// Bar index and input
series int barIdx = bar_index
//-----------------------------------------------------------------------------
// Common Methods
//-----------------------------------------------------------------------------
// Debug label function
debug(simple string txt) =>
var label lbl = label.new(barIdx, na, txt, xloc.bar_index, yloc.price, color(na), label.style_none, WHITE_COLOR, size.large, text.align_left)
label.set_xy(lbl, barIdx, ta.highest(10)[1])
label.set_text(lbl, txt)
getDefHtf() =>
switch timeframe.period
"3" => "30"
"5" => "60"
"15" => "240"
"30" => "480"
"60" => "D"
"240" => "W"
"1D" => "M"
"1M" => "12M"
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// ATR
//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
atrGrp = "ATR"
atrShowed = input.bool(true, "Show", group = atrGrp)
atrLen = input.int(14, "Length", group = atrGrp)
//-----------------------------------------------------------------------------
// Calculate & Render
//-----------------------------------------------------------------------------
atr = ta.atr(atrLen)
if atrShowed and barstate.isconfirmed
table.cell(table.new(position.bottom_right, 1, 1), 0, 0, str.format("ATR: {0}", str.tostring(atr, '#.#####')), bgcolor = TRANSPARENT_COLOR, text_color = TEXT_COLOR, text_size = size.small)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// KAMAs
//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
kamaGrp = "Kaufman Adaptive Moving Average"
kamaShowed = input.bool(false, "Show", group = kamaGrp)
kamaSrc = input.source(close, title = "Source", group = kamaGrp)
kama1Grp = "K1"
kama1Showed = input.bool(true, title = "K1", group = kamaGrp, inline = kama1Grp)
kama1Tf = input.timeframe("", title = "", group = kamaGrp, inline = kama1Grp)
kama1Len = input.int(21, title = "", group = kamaGrp, inline = kama1Grp)
kama1FastEmaLen = input.int(2, title = "", group = kamaGrp, inline = kama1Grp)
kama1SlowEmaLen = input.int(30, title = "", group = kamaGrp, inline = kama1Grp)
kama2Grp = "K2"
kama2Showed = input.bool(true, title = "K2", group = kamaGrp, inline = kama2Grp)
kama2Tf = input.timeframe("", title = "", group = kamaGrp, inline = kama2Grp)
kama2Len = input.int(21, title = "", group = kamaGrp, inline = kama2Grp)
kama2FastEmaLen = input.int(2, title = "", group = kamaGrp, inline = kama2Grp)
kama2SlowEmaLen = input.int(30, title = "", group = kamaGrp, inline = kama2Grp)
//-----------------------------------------------------------------------------
// Methods
//-----------------------------------------------------------------------------
getKama(src, len, fastEmaLen, slowEmaLen) =>
mom = math.abs(ta.change(src, len))
volatility = math.sum(math.abs(ta.change(src)), len)
efficiencyRatio = volatility != 0 ? mom / volatility : 0
fastAlpha = 2 / (fastEmaLen + 1)
slowAlpha = 2 / (slowEmaLen + 1)
alpha = math.pow(efficiencyRatio * (fastAlpha - slowAlpha) + slowAlpha, 2)
kama = 0.0
kama := alpha * src + (1 - alpha) * nz(kama[1], src)
//-----------------------------------------------------------------------------
// Calculate
//-----------------------------------------------------------------------------
kama1 = request.security(syminfo.tickerid, kama1Tf, getKama(kamaSrc, kama1Len, kama1FastEmaLen, kama1SlowEmaLen), gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_off)
kama2 = request.security(syminfo.tickerid, kama2Tf != "" ? kama2Tf : getDefHtf(), getKama(kamaSrc, kama2Len, kama2FastEmaLen, kama2SlowEmaLen), gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_off)
//-----------------------------------------------------------------------------
// Render
//-----------------------------------------------------------------------------
plot(kamaShowed and kama1Showed ? kama1 : na, title = "KAMA 1", linewidth = 1, color = AQUA_COLOR, display = display.pane)
plot(kamaShowed and kama2Showed ? kama2 : na, title = "KAMA 2", linewidth = 1, color = PURPLE_COLOR, display = display.pane)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Supply/Demand
//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
sdGrp = "Supply/Demand"
swingLength = input.int(8, title = 'Swing Length', group = sdGrp)
showLastXOb = input.int(4, title = 'Show Last X Order Blocks', minval = 1, maxval = 10, group = sdGrp)
violationType = input.string('Wick', title = 'Violation Check', options = ['Wick', 'Close'], group = sdGrp)
hideOverlap = input.string('True', title = 'Hide Overlap', options = ['True', 'False'], group = sdGrp)
upObColor = input.color(GREEN_COLOR, title = 'Colors', group = sdGrp, inline = 'vs')
downObColor = input.color(RED_COLOR, title = ' ', group = sdGrp, inline = 'vs')
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
type SRSwing
float y = na
int x = na
bool crossed = false
type SROb
float top = na
float btm = na
int barStart
float bullishStr
float bearishStr
box obBox
box bullishBox
box bearishBox
float vol
bool broken
line seperatorLine
line orderTextSeperator
type SRMarket
string mssOrBos
int direction
line marketLine
int lastLineTime
label marketLabel
//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
var array<SROb> bullishOb = array.new<SROb>()
var array<SROb> bearishOb = array.new<SROb>()
var SRMarket marketStructure = SRMarket.new(na, na, na, 0)
var float top = na
var float btm = na
top := ta.pivothigh(swingLength, swingLength)
btm := ta.pivotlow(swingLength, swingLength)
var SRSwing topp = SRSwing.new()
var SRSwing btmm = SRSwing.new()
if not na(top)
topp.x := time[swingLength]
topp.y := high[swingLength]
topp.crossed := false
topp.crossed
if not na(btm)
btmm.x := time[swingLength]
btmm.y := low[swingLength]
btmm.crossed := false
btmm.crossed
//-----------------------------------------------------------------------------
// Methods
//-----------------------------------------------------------------------------
calculateStrengths(barIndex) =>
float bullishStrength = 0.0
float bearishStrength = 0.0
int barsToConsider = swingLength
for i = 0 to barsToConsider - 1 by 1
if barIndex - i >= 0
float openn = open[barIndex - i]
float highh = high[barIndex - i]
float loww = low[barIndex - i]
float closee = close[barIndex - i]
float volumee = volume[barIndex - i]
if openn > closee
bearishStrength := bearishStrength + volumee
bearishStrength
else
bullishStrength := bullishStrength + volumee
bullishStrength
[bullishStrength, bearishStrength]
isOverlapping(newBlock, existingArray) =>
bool flag = false
if existingArray.size() > 0
for i = 0 to existingArray.size() - 1 by 1
existingBlock = array.get(existingArray, i)
if newBlock.top >= existingBlock.btm and newBlock.top <= existingBlock.top or newBlock.btm >= existingBlock.btm and newBlock.btm <= existingBlock.top
flag := true
flag
flag
drawBox(volatilityBlock) =>
volatilityBlock.bullishBox := box.new(left = volatilityBlock.barStart, right = time, top = volatilityBlock.top, bottom = volatilityBlock.btm + (volatilityBlock.top - volatilityBlock.btm) / 2, bgcolor = color.new(upObColor, 80), border_color = na, xloc = xloc.bar_time)
volatilityBlock.bearishBox := box.new(left = volatilityBlock.barStart, right = time, top = volatilityBlock.btm + (volatilityBlock.top - volatilityBlock.btm) / 2, bottom = volatilityBlock.btm, bgcolor = color.new(downObColor, 80), border_color = na, xloc = xloc.bar_time)
volatilityBlock.obBox := box.new(left = volatilityBlock.barStart, right = time, top = volatilityBlock.top, bottom = volatilityBlock.btm, bgcolor = color.new(DARK_GRAY_COLOR, 75), border_color = na, xloc = xloc.bar_time)
volatilityBlock.seperatorLine := line.new(x1 = volatilityBlock.barStart, y1 = volatilityBlock.btm + (volatilityBlock.top - volatilityBlock.btm) / 2, x2 = time, y2 = volatilityBlock.btm + (volatilityBlock.top - volatilityBlock.btm) / 2, color = color.new(DARK_GRAY_COLOR, 50), width = 1, xloc = xloc.bar_time, style = line.style_dashed)
volatilityBlock.orderTextSeperator := line.new(x1 = volatilityBlock.barStart, y1 = volatilityBlock.top, x2 = volatilityBlock.barStart, y2 = volatilityBlock.btm, color = color.new(DARK_GRAY_COLOR, 50), xloc = xloc.bar_time, style = line.style_solid)
volatilityBlock.orderTextSeperator
//-----------------------------------------------------------------------------
// Calculate & Render
//-----------------------------------------------------------------------------
if close < btmm.y and btmm.crossed == false
btmm.crossed := true
marketStructure.mssOrBos := na(marketStructure.mssOrBos) ? 'mss' : marketStructure.direction == -1 ? 'bos' : 'mss'
marketStructure.direction := -1
lineColor = LIGHT_GRAY_COLOR
// marketStructure.marketLine := line.new(x1 = btmm.x, y1 = btmm.y, x2 = time, y2 = btmm.y, xloc = xloc.bar_time, color = lineColor)
marketStructure.lastLineTime := btmm.x
labelText = marketStructure.mssOrBos == 'mss' ? 'MSS' : 'BOS'
labelX = math.round(math.avg(btmm.x, time))
// marketStructure.marketLabel := label.new(x = labelX, y = btmm.y, text = labelText, color = TRANSPARENT_COLOR, textcolor = lineColor, style = label.style_label_up, xloc = xloc.bar_time, size = size.tiny)
float highAndGreenTop = 0
float highAndGreenBtm = 0
int highAndGreenTime = 0
int selectedIndex = 0
float vol = na
for i = 1 to swingLength by 1
if close[i] > open[i] and high[i] > highAndGreenTop
highAndGreenTop := high[i]
highAndGreenBtm := low[i]
highAndGreenTime := time[i]
vol := volume[i]
selectedIndex := i
selectedIndex
[bullishStrength, bearishStrength] = calculateStrengths(selectedIndex)
newOb = SROb.new(highAndGreenTop, highAndGreenBtm, highAndGreenTime)
newOb.bullishStr := bullishStrength
newOb.bearishStr := bearishStrength
newOb.vol := vol
newOb.broken := false
if not isOverlapping(newOb, bearishOb) and hideOverlap == 'True'
array.push(bearishOb, newOb)
drawBox(newOb)
if hideOverlap == 'False'
array.push(bearishOb, newOb)
drawBox(newOb)
if array.size(bearishOb) > showLastXOb
oldOb = array.shift(bearishOb)
box.delete(oldOb.bullishBox)
box.delete(oldOb.bearishBox)
box.delete(oldOb.obBox)
line.delete(oldOb.seperatorLine)
line.delete(oldOb.orderTextSeperator)
else if close > topp.y and topp.crossed == false
topp.crossed := true
marketStructure.mssOrBos := na(marketStructure.mssOrBos) ? 'mss' : marketStructure.direction == 1 ? 'bos' : 'mss'
marketStructure.direction := 1
lineColor = LIGHT_GRAY_COLOR
marketStructure.lastLineTime := topp.x
labelText = marketStructure.mssOrBos == 'mss' ? 'MSS' : 'BOS'
labelX = math.round(math.avg(topp.x, time))
float lowAndRedBtm = 999999999999
float lowAndRedTop = na
int lowAndRedTime = 0
int selectedIndex = 0
float vol = na
for i = 1 to swingLength by 1
if close[i] < open[i] and low[i] < lowAndRedBtm
lowAndRedBtm := low[i]
lowAndRedTop := high[i]
lowAndRedTime := time[i]
vol := volume[i]
selectedIndex := i
selectedIndex
[bullishStrength, bearishStrength] = calculateStrengths(selectedIndex)
newOb = SROb.new(lowAndRedTop, lowAndRedBtm, lowAndRedTime)
newOb.bullishStr := bullishStrength
newOb.bearishStr := bearishStrength
newOb.vol := vol
newOb.broken := false
if not isOverlapping(newOb, bullishOb) and hideOverlap == 'True'
array.push(bullishOb, newOb)
drawBox(newOb)
if hideOverlap == 'False'
array.push(bullishOb, newOb)
drawBox(newOb)
if array.size(bullishOb) > showLastXOb
oldOb = array.shift(bullishOb)
box.delete(oldOb.bullishBox)
box.delete(oldOb.bearishBox)
box.delete(oldOb.obBox)
line.delete(oldOb.seperatorLine)
line.delete(oldOb.orderTextSeperator)
if array.size(bullishOb) > 0
for i = 0 to array.size(bullishOb) - 1 by 1
currentOb = array.get(bullishOb, i)
totalStr = currentOb.bullishStr + currentOb.bearishStr
bullishBoxWidth = currentOb.bullishStr / totalStr * ((currentOb.obBox.get_left() + time) / 2 - currentOb.barStart)
bearishBoxWidth = currentOb.bearishStr / totalStr * ((currentOb.obBox.get_left() + time) / 2 - currentOb.barStart)
currentOb.bullishBox.set_right(math.round(currentOb.barStart + bullishBoxWidth))
currentOb.bearishBox.set_right(math.round(currentOb.barStart + bearishBoxWidth))
currentOb.obBox.set_right(time)
line.set_xy2(currentOb.seperatorLine, (currentOb.obBox.get_left() + time) / 2, currentOb.btm + (currentOb.top - currentOb.btm) / 2)
line.set_xy1(currentOb.orderTextSeperator, (currentOb.obBox.get_left() + time) / 2, currentOb.top)
line.set_xy2(currentOb.orderTextSeperator, (currentOb.obBox.get_left() + time) / 2, currentOb.btm)
violation = violationType == 'Wick' and low < currentOb.btm or violationType == 'Close' and close < currentOb.btm
if violation
box.delete(currentOb.bullishBox)
box.delete(currentOb.bearishBox)
box.delete(currentOb.obBox)
line.delete(currentOb.seperatorLine)
line.delete(currentOb.orderTextSeperator)
array.remove(bullishOb, i)
break
if array.size(bearishOb) > 0
for i = 0 to array.size(bearishOb) - 1 by 1
currentOb = array.get(bearishOb, i)
totalStr = currentOb.bullishStr + currentOb.bearishStr
bullishBoxWidth = currentOb.bullishStr / totalStr * ((currentOb.obBox.get_left() + time) / 2 - currentOb.barStart)
bearishBoxWidth = currentOb.bearishStr / totalStr * ((currentOb.obBox.get_left() + time) / 2 - currentOb.barStart)
currentOb.bullishBox.set_right(math.round(currentOb.barStart + bullishBoxWidth))
currentOb.bearishBox.set_right(math.round(currentOb.barStart + bearishBoxWidth))
currentOb.obBox.set_right(time)
line.set_xy2(currentOb.seperatorLine, (currentOb.obBox.get_left() + time) / 2, currentOb.btm + (currentOb.top - currentOb.btm) / 2)
line.set_xy1(currentOb.orderTextSeperator, (currentOb.obBox.get_left() + time) / 2, currentOb.top)
line.set_xy2(currentOb.orderTextSeperator, (currentOb.obBox.get_left() + time) / 2, currentOb.btm)
violation = violationType == 'Wick' and high > currentOb.top or violationType == 'Close' and close > currentOb.top
if violation
box.delete(currentOb.bullishBox)
box.delete(currentOb.bearishBox)
box.delete(currentOb.obBox)
line.delete(currentOb.seperatorLine)
line.delete(currentOb.orderTextSeperator)
array.remove(bearishOb, i)
break
//-----------------------------------------------------------------------------
Show all 392 lines