100% found this document useful (1 vote)
77 views20 pages

Order Block Matrix

The document is a Pine Script code for an Order Block Matrix indicator used in trading analysis. It includes various input parameters for customizing the order block display, such as volume formatting, block settings, and visual settings. The script defines functions to generate and update order blocks based on market conditions, including bullish and bearish scenarios.

Uploaded by

Krishna Lad
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
77 views20 pages

Order Block Matrix

The document is a Pine Script code for an Order Block Matrix indicator used in trading analysis. It includes various input parameters for customizing the order block display, such as volume formatting, block settings, and visual settings. The script defines functions to generate and update order blocks based on market conditions, including bullish and bearish scenarios.

Uploaded by

Krishna Lad
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

Order block matrix

//@version=5
indicator("Order Block Matrix [Alpha Extract]", overlay=true, max_bars_back=5000,
max_boxes_count=500, max_lines_count=500)

formatVolume(vol) =>
vol >= 1000000 ? str.tostring(math.round(vol / 1000000, 2)) + "M" :
vol >= 1000 ? str.tostring(math.round(vol / 1000, 2)) + "K" :
str.tostring(math.round(vol, 2))

// === ORDER BLOCKS INPUTS ===


obLookback = input.int(10, "Order Block Breadth", minval=1, group="Order Blocks")
obmode = input×string("Full", "Method", options=["Breadth", "Full"],
tooltip="[Breadth] Use Breadth to adjust coordinate of the orderblocks\n[Full] Use whole candle
body", group="Order Blocks")
obmiti = input×string("Close", "Risk Method", options=["Close", "Wick"],
tooltip="Risk method for when to trigger order blocks", group="Order Blocks")
obMaxBlocks = input×int(6, "Maximum Order Blocks", minval=1, maxval=500, group="Order
Blocks")

windowsis = true
mswindow = 1000

amountOfBoxes = input×int(7, "Number of Grid Segments", minval=3, maxval=20, group="VISUAL


SETTINGS")
showBorder = input.bool(true, "Show Block Borders", group="VISUAL SETTINGS")
borderWidth = input×int(1, "Border Width", minval=0, maxval=4, group="VISUAL SETTINGS")
showVolume = input.bool(true, "Show Volume Text", group="VISUAL SETTINGS")
volumePosition = input.float(0.80, "Volume Text Position (0-1)", minval=0.1, maxval=5.1, step=0.05,
group="VISUAL SETTINGS")

obHighVolumeColor = color.new(#089981, 10)


obLowVolumeColor = color.new(#089981, 85)
obBearHighVolumeColor = color.new(#f23645, 10)
obBearLowVolumeColor = color.new(#f23645, 85)
obBullBorderColor = color.new(#089981, 20)
obBearBorderColor = color.new(#ffa8af, 20)
obBullFillColor = color.new(#089981, 65)
obBearFillColor = color.new(#f23645, 65)
volumeTextColor = color.white

// === SCREENER TABLE INPUTS ===


showScreener = input.bool(true, "Show Screener Table", group="Screener")
tablePosition = input.string("Top Right", "Table Position",
options=["Top Left", "Top Right", "Bottom Left", "Bottom Right"], group="Screener")
tableSize = input.string("Normal", "Table Size",
options=["Small", "Normal", "Large"], group="Screener")

// Table position mapping


var position =
tablePosition == "Top Left" ? position.top_left :
tablePosition == "Top Right" ? position.top_right :
tablePosition == "Bottom Left" ? position.bottom_left :
position.bottom_right

// Table size mapping


var tSize =
tableSize == "Small" ? size.small :
tableSize == "Large" ? size.large :
size.normal

// === ENHANCED ORDER BLOCK TYPE ===


type orderBlock
array<box> boxArray
array<float> boxVolumes
float topValue
float botValue
int leftTime
int rightTime
int rightTime
string direction
float totalVolume
label volumeLabel
line volumeLine
bool mitigated
line topLine
line botLine
linefill bgFill

var float atr = ta.atr(14)


atr := ta.atr(14)

var array<orderBlock> bullBlocks = array.new<orderBlock>()


var array<orderBlock> bearBlocks = array.new<orderBlock>()

var float last_bull_volume = 0.0


var float last_bear_volume = 0.0
var string dom_block = "None"
var float block_strength = 0.0
var float price_distance = 0.0
var int touch_count = 0
var float block_size = 0.0
var float size_ratio = 1.0

var bool bull_touch = false


var bool bear_touch = false
var bool bull_reject = false
var bool bear_reject = false
var bool new_bull = false
var bool new_bear = false

bull_touch := false
bear_touch := false
bull_reject := false
bear_reject := false
bear_reject := false
new_bull := false
new_bear := false

generateBorderLines(orderBlock block, topValue, botValue) =>


if showBorder
borderColor = block.direction == "Bull" ? obBullBorderColor : obBearBorderColor
fillColor = block.direction == "Bull" ? obBullFillColor : obBearFillColor

newTopLine = line×new(
x1 = block.leftTime,
y1 = topValue,
x2 = time,
y2 = topValue,
xloc = xloc.bar_time,
extend = extend.none,
color = borderColor,
style = line.style_solid,
width = borderWidth)

newbotLine = line.new(
x1 = block.leftTime,
y1 = botValue,
x2 = time,
y2 = botValue,
xloc = xloc.bar_time,
extend = extend.none,
color = borderColor,
style = line.style_solid,
width = borderWidth)

newlinefill = linefill.new(newTopLine, newbotLine, fillColor)


[newTopLine, newbotLine, newlinefill]
else
[na, na, na]
// Generate volume boxes for an order block
generateVolumeBoxes(orderBlock block, float orderVolume) =>
volumeArray = array.new_float(amountOfBoxes, 0)
array.set(volumeArray, 0, orderVolume)

boxesArray = array.new_box()

startValue = block.topValue
increment = (block×topValue - block×botValue) / amountOfBoxes

highestVolume = orderVolume
timeLength = time - block.leftTime

timeRatio = highestVolume > 0 ? timeLength / highestVolume * 0.9 : 0

for i = 0 to amountOfBoxes - 1
topOfGrid = startValue - (increment × i)
botOfGrid = startValue - (increment × (i + 1))

multiplier = 1.0
if i == 0 or i == amountOfBoxes - 1
multiplier := 0.4
else if i == 1 or i == amountOfBoxes - 2
multiplier := 0.6
else if i == 2 or i == amountOfBoxes - 3
multiplier := 0.8
else
multiplier := 1.0

segmentVolume = orderVolume × multiplier / amountOfBoxes × 2


array.set(volumeArray, i, segmentVolume)

color highVol = block.direction == "Bull" ? obHighVolumeColor : obBearHighVolumeColor


color lowVol = block.direction == "Bull" ? obLowVolumeColor : obBearLowVolumeColor
color boxColor = color.from_gradient(multiplier, 0.2, 1.0, lowVol, highVol)

maxWidth = math×min(timeLength × 1.2, segmentVolume * timeRatio)

newBox = box.new(
left = block.leftTime,
top = topOfGrid,
right = block×leftTime + math×round(maxWidth),
bottom = botOfGrid,
border_color = boxColor,
border_width = 1,
xloc = xloc.bar_time,
bgcolor = boxColor,
extend = extend×none)

array.push(boxesArray, newBox)

[boxesArray, volumeArray, array.sum(volumeArray)]

updateBoxes(orderBlock block, currentTime) =>


if array.size(block.boxArray) > 0
highestVolume = array×max(block×boxVolumes)
timeLength = currentTime - block.leftTime
timeRatio = highestVolume > 0 ? timeLength / highestVolume * 0.9 : 0

for i = 0 to math.min(amountOfBoxes - 1, array.size(block.boxArray) - 1)


if i < array.size(block.boxVolumes)
boxVolume = array.get(block.boxVolumes, i)
if not na(boxVolume)
maxWidth = math.min(timeLength * 1.2, boxVolume * timeRatio)
box.set_right(array.get(block.boxArray, i), block.leftTime + math.round(maxWidth))

if not na(block.topLine) and not na(block.botLine)


line.set_x2(block.topLine, currentTime)
line.set_x2(block.botLine, currentTime)
if not na(block.volumeLine) and not na(block.volumeLabel) and showVolume
blockCenter = (block.topValue + block.botValue) / 2
lineStartX = block×leftTime + math×round((currentTime - block×leftTime) × 0.95)
lineEndX = lineStartX + math×round((currentTime - block×leftTime) × 0.2)

lineEndY = block.direction == "Bull" ?


blockCenter + (block.topValue - block.botValue) * 0.3 :
blockCenter - (block.topValue - block.botValue) * 0.3

line.set_x1(block.volumeLine, lineStartX)
line.set_y1(block.volumeLine, blockCenter)
line.set_x2(block.volumeLine, lineEndX)
line.set_y2(block.volumeLine, lineEndY)

label.set_x(block.volumeLabel, lineEndX)
label.set_y(block.volumeLabel, lineEndY)

wipeBlock(orderBlock block) =>


if not na(block.topLine)
line.delete(block.topLine)
if not na(block.botLine)
line.delete(block.botLine)
if not na(block.bgFill)
linefill.delete(block.bgFill)

if not na(block.volumeLabel)
label.delete(block.volumeLabel)

if not na(block.volumeLine)
line.delete(block.volumeLine)

if array.size(block.boxArray) > 0
for i = array×size(block×boxArray) - 1 to 0
selectedBox = array.get(block.boxArray, i)
box.delete(selectedBox)

checkObCondition(tuning)=>
bear = false
for i = tuning - 1 to 0
start = tuning - 1
if i == start
if close[i] <= open[i]
break
else
if close[i] > open[i]
break

if i == 0
bear := true

bull = false
for i = tuning - 1 to 0
start = tuning - 1
if i == start
if close[i] >= open[i]
break
else
if close[i] < open[i]
break

if i == 0
bull := true

bullAlt = (high[tuning] - low[tuning]) > atr[tuning] * 0.8 and close[tuning] > open[tuning] and
low[tuning] < low[tuning+1]
bearAlt = (high[tuning] - low[tuning]) > atr[tuning] * 0.8 and close[tuning] < open[tuning] and
high[tuning] > high[tuning+1]

[bear or bearAlt, bull or bullAlt]


inWindowRange = windowsis ? bar_index > (last_bar_index - mswindow) : true
processBar = inWindowRange or not windowsis

if barstate.isfirst
if bullBlocks.size() > 0
for i = bullBlocks×size() - 1 to 0
block = bullBlocks×get(i)
wipeBlock(block)

if bearBlocks.size() > 0
for i = bearBlocks×size() - 1 to 0
block = bearBlocks×get(i)
wipeBlock(block)

bullBlocks.clear()
bearBlocks.clear()

if processBar
[is_bearish, is_bullish] = checkObCondition(obLookback)

if barstate.isconfirmed
if is_bullish
new_bull := true

topValue = high[obLookback - 1]
botValue = obmode == "Breadth" ?
(low[obLookback - 1] + atr * 1) > high[obLookback - 1] ?
high[obLookback - 1] : (low[obLookback - 1] + atr * 1) :
low[obLookback - 1]

leftTime = time[obLookback - 1]

createNewBlock = true
if bullBlocks.size() > 0
for i = bullBlocks×size() - 1 to 0
block = bullBlocks×get(i)
if math.max(block.botValue, botValue) <= math.min(block.topValue, topValue)
wipeBlock(block)
bullBlocks.remove(i)
createNewBlock := true

if createNewBlock
orderVolume = volume[obLookback - 1]

newBlock = orderBlock.new(
array.new_box(),
array.new_float(amountOfBoxes, 0),
topValue,
botValue,
leftTime,
time,
"Bull",
orderVolume,
na,
na,
false,
na,
na,
na)

[topLine, botLine, bgFill] = generateBorderLines(newBlock, topValue, botValue)


newBlock.topLine := topLine
newBlock.botLine := botLine
newBlock.bgFill := bgFill

[boxArray, volumeArray, totalVolume] = generateVolumeBoxes(newBlock, orderVolume)


newBlock.boxArray := boxArray
newBlock.boxVolumes := volumeArray
newBlock.totalVolume := totalVolume
if showVolume
blockCenter = (topValue + botValue) / 2
lineStartX = leftTime + math×round((time - leftTime) × 0.95)
lineEndX = lineStartX + math×round((time - leftTime) × 0.2)
lineEndY = blockCenter + (topValue - botValue) × 0.3

newBlock.volumeLine := line.new(
x1 = lineStartX,
y1 = blockCenter,
x2 = lineEndX,
y2 = lineEndY,
xloc = xloc.bar_time,
extend = extend×none,
color = color×new(volumeTextColor, 20),
style = line.style_solid,
width = 1)

formattedVolume = formatVolume(orderVolume) + " " + syminfo×basecurrency


newBlock.volumeLabel := label.new(
x = lineEndX,
y = lineEndY,
text = formattedVolume,
textcolor = volumeTextColor,
style = label.style_none,
xloc = xloc.bar_time,
size = size×normal)

array.push(bullBlocks, newBlock)
last_bull_volume := orderVolume

if is_bearish
new_bear := true

topValue = obmode == "Breadth" ?


(high[obLookback - 1] - atr * 1) < low[obLookback - 1] ?
low[obLookback - 1] : (high[obLookback - 1] - atr * 1) :
high[obLookback - 1]

botValue = low[obLookback - 1]
leftTime = time[obLookback - 1]

createNewBlock = true
if bearBlocks.size() > 0
for i = bearBlocks×size() - 1 to 0
block = bearBlocks×get(i)
if math.max(block.botValue, botValue) <= math.min(block.topValue, topValue)
wipeBlock(block)
bearBlocks.remove(i)
createNewBlock := true

if createNewBlock
orderVolume = volume[obLookback - 1]

newBlock = orderBlock.new(
array.new_box(),
array.new_float(amountOfBoxes, 0),
topValue,
botValue,
leftTime,
time,
"Bear",
orderVolume,
na,
na,
false,
na,
na,
na)
[topLine, botLine, bgFill] = generateBorderLines(newBlock, topValue, botValue)
newBlock.topLine := topLine
newBlock.botLine := botLine
newBlock.bgFill := bgFill

[boxArray, volumeArray, totalVolume] = generateVolumeBoxes(newBlock, orderVolume)


newBlock.boxArray := boxArray
newBlock.boxVolumes := volumeArray
newBlock.totalVolume := totalVolume

if showVolume
blockCenter = (topValue + botValue) / 2
lineStartX = leftTime + math×round((time - leftTime) × 0.95)
lineEndX = lineStartX + math×round((time - leftTime) × 0.2)
lineEndY = blockCenter - (topValue - botValue) × 0.3

newBlock.volumeLine := line.new(
x1 = lineStartX,
y1 = blockCenter,
x2 = lineEndX,
y2 = lineEndY,
xloc = xloc.bar_time,
extend = extend×none,
color = color×new(volumeTextColor, 20),
style = line.style_solid,
width = 1)

formattedVolume = formatVolume(orderVolume) + " " + syminfo×basecurrency


newBlock.volumeLabel := label.new(
x = lineEndX,
y = lineEndY,
text = formattedVolume,
textcolor = volumeTextColor,
style = label.style_none,
xloc = xloc.bar_time,
size = size×normal)

array.push(bearBlocks, newBlock)
last_bear_volume := orderVolume

if bullBlocks.size() > 0
for i = bullBlocks×size() - 1 to 0
if i < bullBlocks.size()
block = bullBlocks×get(i)

if not block.mitigated
mitigated = obmiti == "Close" ?
math.min(close, open) < block.botValue :
obmiti == "Wick" ?
low < block.botValue :
obmiti == "Avg" ?
low < (block.topValue + block.botValue) / 2 :
false

if mitigated
block.mitigated := true

wipeBlock(block)

bullBlocks.remove(i)
continue

if close <= block.topValue and close >= block.botValue


bull_touch := true

if low <= block.botValue and close >= block.botValue


bull_reject := true

updateBoxes(block, time)
if bearBlocks.size() > 0
for i = bearBlocks×size() - 1 to 0
if i < bearBlocks.size()
block = bearBlocks×get(i)

if not block.mitigated
mitigated = obmiti == "Close" ?
math.max(close, open) > block.topValue :
obmiti == "Wick" ?
high > block.topValue :
obmiti == "Avg" ?
high > (block.topValue + block.botValue) / 2 :
false

if mitigated
block.mitigated := true

wipeBlock(block)

bearBlocks.remove(i)
continue

if close <= block.topValue and close >= block.botValue


bear_touch := true

if high >= block.topValue and close <= block.topValue


bear_reject := true

updateBoxes(block, time)

if bullBlocks.size() > obMaxBlocks


bullBlocks_to_remove = bullBlocks×size() - obMaxBlocks

for _ = 0 to bullBlocks_to_remove - 1
if bullBlocks.size() <= 0
break

oldestIdx = 0
oldestTime = time_close + 999999999

for i = 0 to bullBlocks.size() - 1
block = bullBlocks×get(i)
if block.leftTime < oldestTime
oldestTime := block.leftTime
oldestIdx := i

if oldestIdx < bullBlocks.size()


oldBlock = bullBlocks×get(oldestIdx)

wipeBlock(oldBlock)

bullBlocks.remove(oldestIdx)

while bearBlocks.size() > obMaxBlocks


oldestIdx = 0
oldestTime = time

for i = 0 to bearBlocks.size() - 1
block = bearBlocks×get(i)
if block.leftTime < oldestTime
oldestTime := block.leftTime
oldestIdx := i

oldBlock = bearBlocks×get(oldestIdx)

wipeBlock(oldBlock)

bearBlocks.remove(oldestIdx)

if barstate.islast
float nearest_bull_distance = 1000000.0
float nearest_bear_distance = 1000000.0
int nearest_bull_idx = -1
int nearest_bear_idx = -1

if bullBlocks.size() > 0
for i = 0 to bullBlocks.size() - 1
block = bullBlocks×get(i)
if close > block.botValue
float dist = (close - block×botValue) / close × 100
if dist < nearest_bull_distance
nearest_bull_distance := dist
nearest_bull_idx := i

if bearBlocks.size() > 0
for i = 0 to bearBlocks.size() - 1
block = bearBlocks×get(i)
if close < block.topValue
float dist = (block×topValue - close) / close × 100
if dist < nearest_bear_distance
nearest_bear_distance := dist
nearest_bear_idx := i

if nearest_bull_distance < nearest_bear_distance and nearest_bull_idx >= 0


dom_block := "Bullish"
if nearest_bull_idx < bullBlocks.size()
bullBlock = bullBlocks.get(nearest_bull_idx)
block_strength := bullBlock.totalVolume / ta.sma(volume, 20)
price_distance := nearest_bull_distance
block_size := bullBlock.topValue - bullBlock.botValue
size_ratio := block_size / atr
else if nearest_bear_distance < nearest_bull_distance and nearest_bear_idx >= 0
dom_block := "Bearish"
if nearest_bear_idx < bearBlocks.size()
bearBlock = bearBlocks.get(nearest_bear_idx)
block_strength := bearBlock.totalVolume / ta.sma(volume, 20)
price_distance := nearest_bear_distance
block_size := bearBlock.topValue - bearBlock.botValue
size_ratio := block_size / atr
else
dom_block := "None"

// Create screener table


if showScreener
var table screener = table.new(position, 7, 3, color.new(#000000, 0),
border_color=color×white, border_width=1, frame_color=color×white, frame_width=1)

table.set_border_color(screener, color.white)
table.set_border_width(screener, 1)

table.clear(screener, 0, 0, 6, 2)
color headerBg = color×new(#000000, 0)
color bullishBg = color×new(#008060, 0)

table.merge_cells(screener, 0, 0, 6, 0)
table.cell(screener, 0, 0, "Order Blocks Screener" + (windowsis ? " (Window Mode)" : ""),
text_color=color×white, bgcolor=headerBg, text_size=tSize)

// Header row
table.cell(screener, 0, 1, "Symbol", text_color=color×white, bgcolor=headerBg, text_size=tSize)
table.cell(screener, 1, 1, "Timeframe", text_color=color×white, bgcolor=headerBg,
text_size=tSize)
table.cell(screener, 2, 1, "Order Block", text_color=color×white, bgcolor=headerBg,
text_size=tSize)
table.cell(screener, 3, 1, "Status", text_color=color×white, bgcolor=headerBg, text_size=tSize)
table.cell(screener, 4, 1, "Retests", text_color=color×white, bgcolor=headerBg, text_size=tSize)
table.cell(screener, 5, 1, "Bullish Volume", text_color=color×new(#02ffe6, 0),
bgcolor=headerBg, text_size=tSize)
table.cell(screener, 6, 1, "Bearish Volume", text_color=color×new(#ff4040, 0),
bgcolor=headerBg, text_size=tSize)
// Data row
table.cell(screener, 0, 2, syminfo.ticker, text_color=color×white, bgcolor=bullishBg,
text_size=tSize)
table.cell(screener, 1, 2, timeframe.period, text_color=color×white, bgcolor=bullishBg,
text_size=tSize)

string blockEmoji = dom_block == "Bullish" ? " " : dom_block == "Bearish" ? " ":" "
string blockText = dom_block + " " + blockEmoji
color blockTextColor = dom_block == "Bullish" ? color.rgb(255, 255, 255) : dom_block ==
"Bearish" ? color.red : color.gray
table.cell(screener, 2, 2, blockText, text_color=blockTextColor, bgcolor=bullishBg,
text_size=tSize)

string status = ""


if price_distance < 1.0
status := "Near"
else if price_distance < 3.0
status := "Medium"
else
status := "Far"
table.cell(screener, 3, 2, status, text_color=color.white, bgcolor=bullishBg, text_size=tSize)

// Retests count
string retestText = touch_count > 0 ? str.tostring(touch_count) : "None"
table.cell(screener, 4, 2, retestText, text_color=color.white, bgcolor=bullishBg, text_size=tSize)

// Volume information
table.cell(screener, 5, 2, formatVolume(last_bull_volume), text_color=color.white,
bgcolor=bullishBg, text_size=tSize)
table.cell(screener, 6, 2, formatVolume(last_bear_volume), text_color=color.white,
bgcolor=bullishBg, text_size=tSize)

// Alert conditions
alertcondition(condition = bull_touch, title = "Price Inside Bullish Max Volume Zone")
alertcondition(condition = bear_touch, title = "Price Inside Bearish Max Volume Zone")
alertcondition(condition = bull_reject, title = "Confirmed Rejection Off Bullish Max Volume Zone")
alertcondition(condition = bear_reject, title = "Confirmed Rejection Off Bearish Max Volume Zone")
alertcondition(condition = new_bull, title = "New Bullish Order Block")
alertcondition(condition = new_bear, title = "New Bearish Order Block")

You might also like