// This source code is subject to the terms of the Mozilla Public License 2.
0 at
[Link]
// © Algoryze
//@version=5
indicator("Kiran Indicator", overlay=true, max_lines_count=500,
max_boxes_count=500, max_labels_count=500)
// Function to check if a new day has started
_isNewDay(utcOffsetInMs) =>
dow = dayofweek(time + utcOffsetInMs)
dayChanged = dow != dow[1]
dayChanged
// Function to check if a new week has started
_isNewWeek(utcOffsetInMs) =>
woy = weekofyear(time + utcOffsetInMs)
weekChanged = woy != woy[1]
weekChanged
// Function to get the highest, lowest, and closing prices of the previous day
_getPreviousDayLevels(utcOffsetInMs) =>
dow = dayofweek(time + utcOffsetInMs)
var prevDayHigh = high
var prevDayLow = low
var prevDayClose = close
var dayHigh = high
var dayLow = low
var dayClose = close
if (dow != dow[1])
prevDayHigh := dayHigh[1]
prevDayLow := dayLow[1]
prevDayClose := close[1]
dayHigh := high
dayLow := low
dayClose := close
else
dayHigh := [Link](dayHigh, high)
dayLow := [Link](dayLow, low)
dayClose := close
[prevDayHigh, prevDayLow, prevDayClose]
// Function to get the day of the week text
_getDayOfWeekText(utcOffsetInMs) =>
var weekdayFullNames = [Link]("Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday")
weekdayText = [Link](weekdayFullNames, dayofweek(time + utcOffsetInMs) - 1)
weekdayText
// Input for custom UTC offset
utcOffset = [Link](0, title="UTC Offset (in hours)", minval=-12, maxval=12)
utcOffsetInMs = utcOffset * 60 * 60 * 1000
// Daily and Weekly separator inputs
dailySeparatorColor = [Link]([Link], title='Daily Separator Color')
weeklySeparatorColor = [Link]([Link], title='Weekly Separator Color')
// Variables for tracking mid-day index
var int midDayBarIndex = na
var float midDayPrice = na
// Reset midpoint calculation at the start of a new day
if _isNewDay(utcOffsetInMs)
midDayBarIndex := bar_index
midDayPrice := (high + low) / 2 // Start with the first midpoint
// Adjust mid-day position as time progresses
if not na(midDayBarIndex) and bar_index - midDayBarIndex < [Link]((bar_index -
midDayBarIndex) / 2)
midDayBarIndex := bar_index
midDayPrice := (high + low) / 2
// Plot daily separator line
if _isNewDay(utcOffsetInMs)
[Link](bar_index, low, bar_index, high, color=dailySeparatorColor, width=1,
extend=[Link])
// Plot weekly separator line
if _isNewWeek(utcOffsetInMs)
[Link](bar_index, low, bar_index, high, color=weeklySeparatorColor, width=3,
extend=[Link])
// Get previous day high, low & close
[prevDayHigh, prevDayLow, prevDayClose] = _getPreviousDayLevels(utcOffsetInMs)
// Plot highest, lowest, and closing prices of the previous day
plot(prevDayHigh, title="Prev Day High", color=[Link],
style=plot.style_stepline)
plot(prevDayLow, title="Prev Day Low", color=[Link],
style=plot.style_stepline)
plot(prevDayClose, title="Prev Day Close", color=[Link],
style=plot.style_stepline)
// Display labels for previous day's levels
[Link](bar_index, prevDayHigh, text="Prev HOD", textcolor=[Link],
style=label.style_label_down, size=[Link])
[Link](bar_index, prevDayLow, text="Prev LOD", textcolor=[Link],
style=label.style_label_up, size=[Link])
[Link](bar_index, prevDayClose, text="Prev Close", textcolor=[Link],
style=label.style_label_left, size=[Link])
// Display day of the week label at mid-day region
if _isNewDay(utcOffsetInMs)
[Link](midDayBarIndex, midDayPrice, text=_getDayOfWeekText(utcOffsetInMs),
color=[Link], textcolor=[Link], style=label.style_label_down)
// 🔹 EMA Calculation (User-Selectable Length)
emaLength = [Link](20, title="EMA Length", minval=1, maxval=200) // Users can
adjust EMA length
emaSource = close
emaOutput = [Link](emaSource, emaLength)
plot(emaOutput, title="EMA", color=[Link], linewidth=2)
// 🔹 Optional Smoothing Moving Average
GRP = "Smoothing MA"
maTypeInput = [Link]("None", "Type", options=["None", "SMA", "SMA + BB",
"EMA", "SMMA", "WMA", "VWMA"], group=GRP)
maLengthInput = [Link](20, "Smoothing MA Length", group=GRP)
bbMultInput = [Link](2.0, "BB Multiplier", minval=0.1, maxval=5, group=GRP)
// Function to calculate different MA types
ma(source, length, type) =>
switch type
"SMA" => [Link](source, length)
"EMA" => [Link](source, length)
"SMMA" => [Link](source, length)
"WMA" => [Link](source, length)
"VWMA" => [Link](source, length)
"SMA + BB" => [Link](source, length)
=> na
smoothingMA = ma(emaOutput, maLengthInput, maTypeInput)
smoothingStDev = maTypeInput == "SMA + BB" ? [Link](emaOutput, maLengthInput) *
bbMultInput : na
plot(smoothingMA, title="Smoothed MA", color=[Link], linewidth=2,
display=maTypeInput != "None" ? [Link] : [Link])
// Bollinger Bands (if selected)
bbUpper = plot(maTypeInput == "SMA + BB" ? smoothingMA + smoothingStDev : na,
title="Upper BB", color=[Link])
bbLower = plot(maTypeInput == "SMA + BB" ? smoothingMA - smoothingStDev : na,
title="Lower BB", color=[Link])
fill(bbUpper, bbLower, color=[Link]([Link], 90), title="BB Fill")
bool showSessionNames = [Link](true, "Show session names")
bool showSessionOC = [Link](true, "Draw session open and close lines")
bool showSessionTickRange = [Link](true, "Show tick range for each session")
bool showSessionAverage = [Link](true, "Show average price per session")
const string TZ_TOOLTIP_TEXT = "The session's time zone, specified in either GMT
notation (e.g., 'GMT-5') or as an IANA time zone database name (e.g.,
'America/New_York')."
+ " We recommend the latter since it includes other time-related changes, such as
daylight savings."
const string FIRST_SESSION_GROUP = "First Session"
showFirst = [Link](true, "Show session", group = FIRST_SESSION_GROUP,
display = [Link])
firstSessionName = [Link]("Tokyo", "Displayed name", group =
FIRST_SESSION_GROUP, display = [Link])
firstSessionTime = [Link]("0900-1500", "Session time", group =
FIRST_SESSION_GROUP, display = [Link])
firstSessionTZ = [Link]("Asia/Tokyo", "Session timezone", group =
FIRST_SESSION_GROUP, display = [Link], tooltip = TZ_TOOLTIP_TEXT)
firstSessionColor = [Link]([Link](#2962FF, 85), "Session color", group =
FIRST_SESSION_GROUP)
const string SECOND_SESSION_GROUP = "Second session"
showSecond = [Link](true, "Show session", group = SECOND_SESSION_GROUP,
display = [Link])
secondSessionName = [Link]("London", "Displayed name", group =
SECOND_SESSION_GROUP, display = [Link])
secondSessionTime = [Link]("0830-1630", "Session time", group =
SECOND_SESSION_GROUP, display = [Link])
secondSessionTZ = [Link]("Europe/London", "Session timezone", group =
SECOND_SESSION_GROUP, display = [Link], tooltip = TZ_TOOLTIP_TEXT)
secondSessionColor = [Link]([Link](#FF9800, 85), "Session color", group =
SECOND_SESSION_GROUP)
const string THIRD_SESSION_GROUP = "Third session"
showThird = [Link](true, "Show session", group = THIRD_SESSION_GROUP,
display = [Link])
thirdSessionName = [Link]("New York", "Displayed name", group =
THIRD_SESSION_GROUP, display = [Link])
thirdSessionTime = [Link]("0930-1600", "Session time", group =
THIRD_SESSION_GROUP, display = [Link])
thirdSessionTZ = [Link]("America/New_York", "Session timezone", group =
THIRD_SESSION_GROUP, display = [Link], tooltip = TZ_TOOLTIP_TEXT)
thirdSessionColor = [Link]([Link](#089981, 85), "Session color", group =
THIRD_SESSION_GROUP)
type SessionDisplay
box sessionBox
label sessionLabel
line openLine
line avgLine
line closeLine
float sumClose
int numOfBars
type SessionInfo
color color
string name
string session
string timezone
SessionDisplay active = na
method setName(SessionDisplay this, string name) =>
sessionLabel = [Link]
sessionBox = [Link]
boxText = [Link]<string>()
if showSessionTickRange
[Link]("Range: " + [Link]((sessionBox.get_top() -
sessionBox.get_bottom()) / [Link], [Link]))
if showSessionAverage
[Link]("Avg: " + [Link]([Link] / [Link],
[Link]))
if showSessionNames
[Link](name)
sessionLabel.set_y(sessionBox.get_bottom())
sessionLabel.set_text([Link](boxText, "\n"))
method createSessionDisplay(SessionInfo this) =>
boxColor = [Link]
opaqueColor = [Link](boxColor, 0)
dis = [Link](
sessionBox = [Link](bar_index, high, bar_index, low, bgcolor = boxColor,
border_color = na),
sessionLabel = [Link](bar_index, low, "", style =
label.style_label_upper_left, textalign = text.align_left, textcolor = opaqueColor,
color = color(na)),
openLine = showSessionOC ? [Link](bar_index, open, bar_index, open, color
= opaqueColor, style = line.style_dashed, width = 1) : na,
closeLine = showSessionOC ? [Link](bar_index, close, bar_index, close,
color = opaqueColor, style = line.style_dashed, width = 1) : na,
avgLine = showSessionAverage ? [Link](bar_index, close, bar_index,
close, style = line.style_dotted, width = 2, color = opaqueColor) : na,
sumClose = close,
numOfBars = 1
)
[Link]([Link], [Link], boxColor)
[Link]([Link])
[Link] := dis
method updateSessionDisplay(SessionInfo this) =>
sessionDisp = [Link]
sessionBox = [Link]
openLine = [Link]
closeLine = [Link]
avgLine = [Link]
[Link] += close
[Link] += 1
sessionBox.set_top([Link](sessionBox.get_top(), high))
sessionBox.set_bottom([Link](sessionBox.get_bottom(), low))
sessionBox.set_right(bar_index)
[Link]([Link])
if showSessionOC
openLine.set_x2(bar_index)
closeLine.set_x2(bar_index)
closeLine.set_y1(close)
closeLine.set_y2(close)
if showSessionAverage
avgLine.set_x2(bar_index)
avg = [Link] / [Link]
avgLine.set_y1(avg)
avgLine.set_y2(avg)
sessionDisp
method update(SessionInfo this) =>
bool isChange = [Link]("1D")
if (not na(time("", [Link], [Link]))) // inSession
if na([Link]) or isChange
[Link]()
else
[Link]()
else if not na([Link])
[Link] := na
getSessionInfos()=>
array<SessionInfo> sessionInfos = [Link]<SessionInfo>()
if showFirst
[Link]([Link](firstSessionColor, firstSessionName,
firstSessionTime, firstSessionTZ))
if showSecond
[Link]([Link](secondSessionColor, secondSessionName,
secondSessionTime, secondSessionTZ))
if showThird
[Link]([Link](thirdSessionColor, thirdSessionName,
thirdSessionTime, thirdSessionTZ))
sessionInfos
var array<SessionInfo> sessionInfos = getSessionInfos()
if [Link]
[Link]("This indicator can only be used on intraday timeframes.")
for info in sessionInfos
[Link]()