本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © finallynitin
//credits to ajithcpas
//modified from "CPR (Central Pivot Range)" script by ajithcpas https://www.tradingview.com/v/R6lRetr0/
//@version=6
indicator('Simple CPR for intraday index trading', shorttitle = 'Simple CPR', overlay = true, max_lines_count = 500, max_labels_count = 500)
AUTO = 'Auto'
DAILY = 'Daily'
WEEKLY = 'Weekly'
MONTHLY = 'Monthly'
QUARTERLY = 'Quarterly'
HALF_YEARLY = 'Half-yearly'
YEARLY = 'Yearly'
TRADITIONAL = 'Traditional'
FIBONACCI = 'Fibonacci'
CLASSIC = 'Classic'
CAMARILLA = 'Camarilla'
// Input fields
kind = input.string(title = 'Type', defval = 'Traditional', options = [TRADITIONAL, FIBONACCI, CLASSIC, CAMARILLA])
cpr_time_frame = input.string(title = 'CPR Timeframe', defval = AUTO, options = [AUTO, DAILY, WEEKLY, MONTHLY, QUARTERLY, HALF_YEARLY, YEARLY])
look_back = input.int(title = 'Number of CPR Back', defval = 1, minval = 1, maxval = 5000)
position_labels = input.string('Right', 'Labels Position', options = ['Left', 'Right'])
line_width = input.int(title = 'Line Width', defval = 3, minval = 1, maxval = 100)
hist_sr_show = input.bool(true, 'Show Historical SR Pivots')
is_daily_based = input.bool(title = 'Use Daily-based Values', defval = true, tooltip = 'When this option is unchecked, CPR will use intraday data while calculating on intraday charts. If Extended Hours are displayed on the chart, they will be taken into account during the CPR level calculation. If intraday OHLC values are different from daily-based values (normal for stocks), the CPR levels will also differ.')
// Variables
var arr_time = array.new_int()
var p = array.new_float()
var tp = array.new_float()
var bp = array.new_float()
var SR_COLOR = #FB8C00
var DEV_SR_COLOR = #E2BEE7
var pdh_arr = array.new_float()
var pdl_arr = array.new_float()
// Daily previous-day series
pdHighSer = request.security(syminfo.tickerid, 'D', high[1], lookahead = barmerge.lookahead_on)
pdLowSer = request.security(syminfo.tickerid, 'D', low[1], lookahead = barmerge.lookahead_on)
//CPR Customisation
cpr_show = input.bool(true, '', inline = 'CPR', group = 'CPR Customisation')
cpr_color = input.color(color.blue, 'Show CPR', inline = 'CPR', group = 'CPR Customisation')
cpr_show_lines = input.bool(true, 'Show CPR Lines', group = 'CPR Customisation')
cpr_show_fill = input.bool(false, 'Show CPR Fill', group = 'CPR Customisation')
cpr_show_prices = input.bool(false, 'Show CPR Price', group = 'CPR Customisation')
cpr_show_labels = input.bool(false, 'Show CPR Label', group = 'CPR Customisation')
cpr_line_style = input.string('Dotted', 'CPR Line Style', options = ['Solid', 'Dashed', 'Dotted'], group = 'CPR Customisation')
//Pivot Customisation
sr_show = input.bool(true, 'Show SR Levels', inline = 'Show SR Pivots', group = 'Pivot Customisation')
sr_show_labels = input.bool(true, 'Show SR Label', group = 'Pivot Customisation')
sr_show_prices = input.bool(true, 'Show SR Price', group = 'Pivot Customisation')
//Pivots
var r0_5 = array.new_float()
var s0_5 = array.new_float()
s0_5_show = input.bool(false, '', inline = 'S0.5/R0.5', group = 'Pivot Display')
s0_5_color = input.color(SR_COLOR, 'S0.5', inline = 'S0.5/R0.5', group = 'Pivot Display')
r0_5_show = input.bool(false, '', inline = 'S0.5/R0.5', group = 'Pivot Display')
r0_5_color = input.color(SR_COLOR, 'R0.5', inline = 'S0.5/R0.5', group = 'Pivot Display')
var r1 = array.new_float()
var s1 = array.new_float()
s1_show = input.bool(true, '', inline = 'S1/R1', group = 'Pivot Display')
s1_color = input.color(SR_COLOR, 'S1', inline = 'S1/R1', group = 'Pivot Display')
r1_show = input.bool(true, '', inline = 'S1/R1', group = 'Pivot Display')
r1_color = input.color(SR_COLOR, 'R1', inline = 'S1/R1', group = 'Pivot Display')
var r1_5 = array.new_float()
var s1_5 = array.new_float()
s1_5_show = input.bool(false, '', inline = 'S1.5/R1.5', group = 'Pivot Display')
s1_5_color = input.color(SR_COLOR, 'S1.5', inline = 'S1.5/R1.5', group = 'Pivot Display')
r1_5_show = input.bool(false, '', inline = 'S1.5/R1.5', group = 'Pivot Display')
r1_5_color = input.color(SR_COLOR, 'R1.5', inline = 'S1.5/R1.5', group = 'Pivot Display')
var r2 = array.new_float()
var s2 = array.new_float()
s2_show = input.bool(false, '', inline = 'S2/R2', group = 'Pivot Display')
s2_color = input.color(SR_COLOR, 'S2', inline = 'S2/R2', group = 'Pivot Display')
r2_show = input.bool(false, '', inline = 'S2/R2', group = 'Pivot Display')
r2_color = input.color(SR_COLOR, 'R2', inline = 'S2/R2', group = 'Pivot Display')
var r2_5 = array.new_float()
var s2_5 = array.new_float()
s2_5_show = input.bool(false, '', inline = 'S2.5/R2.5', group = 'Pivot Display')
s2_5_color = input.color(SR_COLOR, 'S2.5', inline = 'S2.5/R2.5', group = 'Pivot Display')
r2_5_show = input.bool(false, '', inline = 'S2.5/R2.5', group = 'Pivot Display')
r2_5_color = input.color(SR_COLOR, 'R2.5', inline = 'S2.5/R2.5', group = 'Pivot Display')
var r3 = array.new_float()
var s3 = array.new_float()
s3_show = input.bool(false, '', inline = 'S3/R3', group = 'Pivot Display')
s3_color = input.color(SR_COLOR, 'S3', inline = 'S3/R3', group = 'Pivot Display')
r3_show = input.bool(false, '', inline = 'S3/R3', group = 'Pivot Display')
r3_color = input.color(SR_COLOR, 'R3', inline = 'S3/R3', group = 'Pivot Display')
var r3_5 = array.new_float()
var s3_5 = array.new_float()
s3_5_show = input.bool(false, '', inline = 'S3.5/R3.5', group = 'Pivot Display')
s3_5_color = input.color(SR_COLOR, 'S3.5', inline = 'S3.5/R3.5', group = 'Pivot Display')
r3_5_show = input.bool(false, '', inline = 'S3.5/R3.5', group = 'Pivot Display')
r3_5_color = input.color(SR_COLOR, 'R3.5', inline = 'S3.5/R3.5', group = 'Pivot Display')
var r4 = array.new_float()
var s4 = array.new_float()
s4_show = input.bool(false, '', inline = 'S4/R4', group = 'Pivot Display')
s4_color = input.color(SR_COLOR, 'S4', inline = 'S4/R4', group = 'Pivot Display')
r4_show = input.bool(false, '', inline = 'S4/R4', group = 'Pivot Display')
r4_color = input.color(SR_COLOR, 'R4', inline = 'S4/R4', group = 'Pivot Display')
var r4_5 = array.new_float()
var s4_5 = array.new_float()
s4_5_show = input.bool(false, '', inline = 'S4.5/R4.5', group = 'Pivot Display')
s4_5_color = input.color(SR_COLOR, 'S4.5', inline = 'S4.5/R4.5', group = 'Pivot Display')
r4_5_show = input.bool(false, '', inline = 'S4.5/R4.5', group = 'Pivot Display')
r4_5_color = input.color(SR_COLOR, 'R4.5', inline = 'S4.5/R4.5', group = 'Pivot Display')
var r5 = array.new_float()
var s5 = array.new_float()
s5_show = input.bool(false, '', inline = 'S5/R5', group = 'Pivot Display')
s5_color = input.color(SR_COLOR, 'S5', inline = 'S5/R5', group = 'Pivot Display')
r5_show = input.bool(false, '', inline = 'S5/R5', group = 'Pivot Display')
r5_color = input.color(SR_COLOR, 'R5', inline = 'S5/R5', group = 'Pivot Display')
//Developing CPR
dev_cpr_show = input.bool(false, '', inline = 'Dev CPR', group = 'Developing CPR levels')
dev_cpr_color = input.color(DEV_SR_COLOR, 'Dev CPR', inline = 'Dev CPR', group = 'Developing CPR levels')
var dev_r1 = array.new_float()
var dev_s1 = array.new_float()
dev_s1_show = input.bool(false, '', inline = 'S1/R1', group = 'Developing CPR levels')
dev_s1_color = input.color(DEV_SR_COLOR, 'S1', inline = 'S1/R1', group = 'Developing CPR levels')
dev_r1_show = input.bool(false, '', inline = 'S1/R1', group = 'Developing CPR levels')
dev_r1_color = input.color(DEV_SR_COLOR, 'R1', inline = 'S1/R1', group = 'Developing CPR levels')
extend_dev_cpr_line = input.bool(false, '', inline = 'extend', group = 'Developing CPR levels')
dev_cpr_show_labels = input.bool(true, 'Show Dev CPR Labels', group = 'Developing CPR levels')
dev_cpr_show_prices = input.bool(false, 'Show Dev CPR Price Levels', group = 'Developing CPR levels')
dev_r1_show_labels = input.bool(true, 'Show Dev R1 Labels', group = 'Developing CPR levels')
dev_r1_show_prices = input.bool(false, 'Show Dev R1 Price Levels', group = 'Developing CPR levels')
dev_s1_show_labels = input.bool(true, 'Show Dev S1 Labels', group = 'Developing CPR levels')
dev_s1_show_prices = input.bool(false, 'Show Dev S1 Price Levels', group = 'Developing CPR levels')
// — Group for CPR↔SR fill —
fill_cpr_r1 = input.bool(false, 'Fill CPR → R1', group='Pivot Customisation')
fill_cpr_r1_col = input.color(color.new(color.orange, 75), 'CPR–R1 Fill Color', group='Pivot Customisation')
fill_cpr_s1 = input.bool(false, 'Fill CPR → S1', group='Pivot Customisation')
fill_cpr_s1_col = input.color(color.new(color.orange, 75), 'CPR–S1 Fill Color', group='Pivot Customisation')
dev_cpr_line_days = input.int(title = 'Extend line by days', defval = 1, minval = 1, maxval = 10, inline = 'extend', group = 'Developing CPR levels', tooltip = 'Enable this when the Dev CPR lines are not visible(i.e. there is a trading holiday in upcoming session).')
check_holidays = input.bool(true, 'Check NSE/BSE holidays', group = 'Developing CPR levels', tooltip = 'Enable this when the Dev CPR lines are not visible(i.e. there is a trading holiday in upcoming session).')
// --- Session Display Toggles ---
show_day = input.bool(false, title = 'Show Previous High/Low', group = 'Session High Low')
session_hl_line_style = input.string(defval = 'Solid', title = 'Line Style', options = ['Solid', 'Dotted', 'Dashed'], group = 'Session High Low')
show_day_open = input.bool(defval = false, title = 'Show Current Day', group = 'Session Open')
session_high_color = input.color(defval = color.aqua , title = 'High Line Color', group = 'Session High Low')
session_low_color = input.color(defval = color.aqua, title = 'Low Line Color', group = 'Session High Low')
session_open_color = input.color(defval = color.aqua, title = 'Line Color', group = 'Session Open')
session_open_line_style = input.string(defval = 'Dashed', title = 'Line Style', options = ['Solid', 'Dotted', 'Dashed'], group = 'Session Open')
// --- PDH/PDL label/price toggles ---
pd_show_labels = input.bool(true, 'Show PH/PL Labels', group='Session High Low')
pd_show_prices = input.bool(true, 'Show PH/PL Prices', group='Session High Low')
//Code
pivotX_open = float(na)
pivotX_open := nz(pivotX_open[1], open)
pivotX_high = float(na)
pivotX_high := nz(pivotX_high[1], high)
pivotX_low = float(na)
pivotX_low := nz(pivotX_low[1], low)
pivotX_prev_open = float(na)
pivotX_prev_open := nz(pivotX_prev_open[1])
pivotX_prev_high = float(na)
pivotX_prev_high := nz(pivotX_prev_high[1])
pivotX_prev_low = float(na)
pivotX_prev_low := nz(pivotX_prev_low[1])
pivotX_prev_close = float(na)
pivotX_prev_close := nz(pivotX_prev_close[1])
get_pivot_resolution() =>
resolution = 'M'
if cpr_time_frame == AUTO
if timeframe.isintraday
resolution := timeframe.multiplier <= 15 ? 'D' : 'W'
resolution
else if timeframe.isdaily
resolution := 'M'
resolution
else if timeframe.isweekly
resolution := '6M'
resolution
else
resolution := '12M'
resolution
else if cpr_time_frame == DAILY
resolution := 'D'
resolution
else if cpr_time_frame == WEEKLY
resolution := 'W'
resolution
else if cpr_time_frame == MONTHLY
resolution := 'M'
resolution
else if cpr_time_frame == QUARTERLY
resolution := '3M'
resolution
else if cpr_time_frame == HALF_YEARLY
resolution := '6M'
resolution
else if cpr_time_frame == YEARLY
resolution := '12M'
resolution
resolution
var lines = array.new_line()
var labels = array.new_label()
draw_line(i, pivot, col, line_style = line.style_solid) =>
line aLine = na
if array.size(arr_time) > 1
aLine := line.new(array.get(arr_time, i), array.get(pivot, i), array.get(arr_time, i + 1), array.get(pivot, i), color = col, xloc = xloc.bar_time, width = line_width, style = line_style)
array.push(lines, aLine)
aLine
//Modify draw_label to accept flags and use the right toggles
//Accepts two extra booleans for CPR vs. SR
draw_label(i, y, txt, txt_color, is_cpr = false, is_sr = false) =>
_showLbl = is_cpr ? cpr_show_labels : is_sr ? sr_show_labels : true
_showPrc = is_cpr ? cpr_show_prices : is_sr ? sr_show_prices : true
if _showLbl or _showPrc
display = ''
if _showLbl and _showPrc and txt != ''
display := str.format(' {0} - {1}', txt, math.round_to_mintick(y))
display
else if _showLbl and txt != ''
display := ' ' + txt
display
else
display := str.format(' {0}', math.round_to_mintick(y))
display
x = position_labels == 'Left' ? array.get(arr_time, i) : array.get(arr_time, i + 1)
array.push(labels, label.new(x = x, y = y, text = display, textcolor = txt_color, style = label.style_none, color = #00000000, xloc = xloc.bar_time))
pd_label_text(_name, _price, _showLbl, _showPrc) =>
// returns the padded label string (or '' if nothing to show)
txt = ''
if _showLbl and _showPrc
txt := str.format(' {0} - {1}', _name, math.round_to_mintick(_price))
else if _showLbl
txt := ' ' + _name
else if _showPrc
txt := str.format(' {0}', math.round_to_mintick(_price))
txt
traditional() =>
pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
_r1 = pivotX_Median * 2 - pivotX_prev_low
_s1 = pivotX_Median * 2 - pivotX_prev_high
_r2 = pivotX_Median + 1 * (pivotX_prev_high - pivotX_prev_low)
_s2 = pivotX_Median - 1 * (pivotX_prev_high - pivotX_prev_low)
//_r3 = pivotX_Median * 2 + (pivotX_prev_high - 2 * pivotX_prev_low)
_r3 = _r1 + pivotX_prev_high - pivotX_prev_low
//_s3 = pivotX_Median * 2 - (2 * pivotX_prev_high - pivotX_prev_low)
_s3 = _s1 - pivotX_prev_high + pivotX_prev_low
//_r4 = pivotX_Median * 3 + (pivotX_prev_high - 3 * pivotX_prev_low)
_r4 = _r3 + _r2 - _r1
//_s4 = pivotX_Median * 3 - (3 * pivotX_prev_high - pivotX_prev_low)
_s4 = _s3 + _s2 - _s1
//_r5 = pivotX_Median * 4 + (pivotX_prev_high - 4 * pivotX_prev_low)
_r5 = _r4 + _r3 - _r2
//_s5 = pivotX_Median * 4 - (4 * pivotX_prev_high - pivotX_prev_low)
_s5 = _s4 + _s3 - _s2
array.push(r0_5, (pivotX_Median + _r1) / 2)
array.push(s0_5, (pivotX_Median + _s1) / 2)
array.push(r1, _r1)
array.push(s1, _s1)
array.push(r1_5, (_r1 + _r2) / 2)
array.push(s1_5, (_s1 + _s2) / 2)
array.push(r2, _r2)
array.push(s2, _s2)
array.push(r2_5, (_r2 + _r3) / 2)
array.push(s2_5, (_s2 + _s3) / 2)
array.push(r3, _r3)
array.push(s3, _s3)
array.push(r3_5, (_r3 + _r4) / 2)
array.push(s3_5, (_s3 + _s4) / 2)
array.push(r4, _r4)
array.push(s4, _s4)
array.push(r4_5, (_r4 + _r5) / 2)
array.push(s4_5, (_s4 + _s5) / 2)
array.push(r5, _r5)
array.push(s5, _s5)
fibonacci() =>
pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
pivot_range = pivotX_prev_high - pivotX_prev_low
array.push(r1, pivotX_Median + 0.382 * pivot_range)
array.push(s1, pivotX_Median - 0.382 * pivot_range)
array.push(r2, pivotX_Median + 0.618 * pivot_range)
array.push(s2, pivotX_Median - 0.618 * pivot_range)
array.push(r3, pivotX_Median + 1 * pivot_range)
array.push(s3, pivotX_Median - 1 * pivot_range)
classic() =>
pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
pivot_range = pivotX_prev_high - pivotX_prev_low
array.push(r1, pivotX_Median * 2 - pivotX_prev_low)
array.push(s1, pivotX_Median * 2 - pivotX_prev_high)
array.push(r2, pivotX_Median + 1 * pivot_range)
array.push(s2, pivotX_Median - 1 * pivot_range)
array.push(r3, pivotX_Median + 2 * pivot_range)
array.push(s3, pivotX_Median - 2 * pivot_range)
array.push(r4, pivotX_Median + 3 * pivot_range)
array.push(s4, pivotX_Median - 3 * pivot_range)
camarilla() =>
pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
pivot_range = pivotX_prev_high - pivotX_prev_low
array.push(r1, pivotX_prev_close + pivot_range * 1.1 / 12.0)
array.push(s1, pivotX_prev_close - pivot_range * 1.1 / 12.0)
array.push(r2, pivotX_prev_close + pivot_range * 1.1 / 6.0)
array.push(s2, pivotX_prev_close - pivot_range * 1.1 / 6.0)
array.push(r3, pivotX_prev_close + pivot_range * 1.1 / 4.0)
array.push(s3, pivotX_prev_close - pivot_range * 1.1 / 4.0)
array.push(r4, pivotX_prev_close + pivot_range * 1.1 / 2.0)
array.push(s4, pivotX_prev_close - pivot_range * 1.1 / 2.0)
r5_val = pivotX_prev_high / pivotX_prev_low * pivotX_prev_close
array.push(r5, r5_val)
array.push(s5, 2 * pivotX_prev_close - r5_val)
calc_pivot() =>
pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
pivotX_Bottom = (pivotX_prev_high + pivotX_prev_low) / 2
pivotX_Top = pivotX_Median * 2 - pivotX_Bottom
if pivotX_Bottom > pivotX_Top
temp = pivotX_Bottom
pivotX_Bottom := pivotX_Top
pivotX_Top := temp
pivotX_Top
array.push(p, pivotX_Median)
array.push(tp, pivotX_Top)
array.push(bp, pivotX_Bottom)
// Capture the prev-day H/L for this CPR segment
array.push(pdh_arr, pdHighSer)
array.push(pdl_arr, pdLowSer)
if kind == TRADITIONAL
traditional()
else if kind == FIBONACCI
fibonacci()
else if kind == CLASSIC
classic()
else if kind == CAMARILLA
camarilla()
resolution = get_pivot_resolution()
calc_high(prev, curr) =>
if na(prev) or na(curr)
nz(prev, nz(curr, na))
else
math.max(prev, curr)
calc_low(prev, curr) =>
if not na(prev) and not na(curr)
math.min(prev, curr)
else
nz(prev, nz(curr, na))
[sec_open, sec_high, sec_low, prev_sec_open, prev_sec_high, prev_sec_low, prev_sec_close, prev_sec_time] = request.security(syminfo.tickerid, resolution, [open, high, low, open[1], high[1], low[1], close[1], time[1]], lookahead = barmerge.lookahead_on)
sec_open_gaps_on = request.security(syminfo.tickerid, resolution, open, gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_on)
var is_change = false
var uses_current_bar = false
var change_time = int(na)
is_time_change = ta.change(time(resolution)) != 0
if is_time_change
change_time := time
change_time
var start_time = time
without_time_change = barstate.islast and array.size(arr_time) == 0
is_can_calc_pivot = not uses_current_bar and is_time_change or uses_current_bar and not na(sec_open_gaps_on) or without_time_change
enough_bars_for_calculate = prev_sec_time >= start_time or is_daily_based
if is_can_calc_pivot and enough_bars_for_calculate
if array.size(arr_time) == 0 and is_daily_based
pivotX_prev_open := prev_sec_open[1]
pivotX_prev_high := prev_sec_high[1]
pivotX_prev_low := prev_sec_low[1]
pivotX_prev_close := prev_sec_close[1]
pivotX_open := sec_open[1]
pivotX_high := sec_high[1]
pivotX_low := sec_low[1]
array.push(arr_time, start_time)
calc_pivot()
if is_daily_based
pivotX_prev_open := prev_sec_open
pivotX_prev_high := prev_sec_high
pivotX_prev_low := prev_sec_low
pivotX_prev_close := prev_sec_close
pivotX_open := sec_open
pivotX_high := sec_high
pivotX_low := sec_low
pivotX_low
else
pivotX_prev_high := pivotX_high
pivotX_prev_low := pivotX_low
pivotX_prev_open := pivotX_open
pivotX_prev_close := close[1]
pivotX_open := open
pivotX_high := high
pivotX_low := low
pivotX_low
if barstate.islast and not is_change and array.size(arr_time) > 0 and not without_time_change
array.set(arr_time, array.size(arr_time) - 1, change_time)
else if without_time_change
array.push(arr_time, start_time)
else
array.push(arr_time, nz(change_time, time))
calc_pivot()
if array.size(arr_time) > look_back
if array.size(arr_time) > 0
array.shift(arr_time)
if array.size(p) > 0 and cpr_show
array.shift(p)
if array.size(tp) > 0 and cpr_show
array.shift(tp)
if array.size(bp) > 0 and cpr_show
array.shift(bp)
if array.size(pdh_arr) > 0
array.shift(pdh_arr)
if array.size(pdl_arr) > 0
array.shift(pdl_arr)
if sr_show or hist_sr_show
if array.size(r0_5) > 0 and r0_5_show
array.shift(r0_5)
if array.size(s0_5) > 0 and s0_5_show
array.shift(s0_5)
if array.size(r1) > 0 and r1_show
array.shift(r1)
if array.size(s1) > 0 and s1_show
array.shift(s1)
if array.size(r1_5) > 0 and r1_5_show
array.shift(r1_5)
if array.size(s1_5) > 0 and s1_5_show
array.shift(s1_5)
if array.size(r2) > 0 and r2_show
array.shift(r2)
if array.size(s2) > 0 and s2_show
array.shift(s2)
if array.size(r2_5) > 0 and r2_5_show
array.shift(r2_5)
if array.size(s2_5) > 0 and s2_5_show
array.shift(s2_5)
if array.size(r3) > 0 and r3_show
array.shift(r3)
if array.size(s3) > 0 and s3_show
array.shift(s3)
if array.size(r3_5) > 0 and r3_5_show
array.shift(r3_5)
if array.size(s3_5) > 0 and s3_5_show
array.shift(s3_5)
if array.size(r4) > 0 and r4_show
array.shift(r4)
if array.size(s4) > 0 and s4_show
array.shift(s4)
if array.size(r4_5) > 0 and r4_5_show
array.shift(r4_5)
if array.size(s4_5) > 0 and s4_5_show
array.shift(s4_5)
if array.size(r5) > 0 and r5_show
array.shift(r5)
if array.size(s5) > 0 and s5_show
array.shift(s5)
is_change := true
is_change
else if not is_daily_based
pivotX_high := math.max(pivotX_high, high)
pivotX_low := math.min(pivotX_low, low)
pivotX_low
if barstate.islast and not is_daily_based and array.size(arr_time) == 0
runtime.error('Not enough intraday data to calculate CPR. Lower the CPR Timeframe or turn on the \'Use Daily-based Values\' option in the indicator settings.')
if barstate.islast and array.size(arr_time) > 0 and is_change
is_change := false
array.push(arr_time, time_close(resolution))
for idx = 0 to array.size(lines) - 1 by 1
if array.size(lines) > 0
line.delete(array.shift(lines))
if array.size(labels) > 0
label.delete(array.shift(labels))
line cpLine = na
line r1Line = na
line s1Line = na
j = array.size(arr_time) - 2
for idx = 0 to j by 1
style_cpr = cpr_line_style == 'Solid' ? line.style_solid : cpr_line_style == 'Dashed' ? line.style_dashed : line.style_dotted
if array.size(p) > 0 and cpr_show
cpLine := draw_line(idx, p, cpr_show_lines ? cpr_color : color.new(cpr_color, 100), style_cpr)
line tp_line = na
line bp_line = na
if array.size(tp) > 0 and array.size(bp) > 0 and cpr_show
tp_line := draw_line(idx, tp, cpr_show_lines ? cpr_color : color.new(cpr_color, 100), style_cpr)
bp_line := draw_line(idx, bp, cpr_show_lines ? cpr_color : color.new(cpr_color, 100), style_cpr)
if cpr_show_fill
linefill.new(tp_line, bp_line, color.new(cpr_color, 70))
// — draw R1 & S1 on the last bar and remember handles —
if idx == j and sr_show
if r1_show
r1Line := draw_line(idx, r1, r1_color)
draw_label(idx, array.get(r1, idx), 'R1', r1_color, false, true)
if s1_show
s1Line := draw_line(idx, s1, s1_color)
draw_label(idx, array.get(s1, idx), 'S1', s1_color, false, true)
// — fills between CPR middle-line and R1/S1 —
if idx == j and cpr_show
if fill_cpr_r1 and not na(cpLine) and not na(r1Line)
linefill.new(cpLine, r1Line, fill_cpr_r1_col)
if fill_cpr_s1 and not na(cpLine) and not na(s1Line)
linefill.new(cpLine, s1Line, fill_cpr_r1_col)
// --- draw SR levels ---
for idx = 0 to j by 1
if hist_sr_show and idx < j or sr_show and idx == j
// R0.5 / S0.5
if r0_5_show
draw_line(idx, r0_5, r0_5_color, line.style_dashed)
draw_label(idx, array.get(r0_5, idx), 'R0.5', r0_5_color, false, true)
if s0_5_show
draw_line(idx, s0_5, s0_5_color, line.style_dashed)
draw_label(idx, array.get(s0_5, idx), 'S0.5', s0_5_color, false, true)
if r1_show
draw_line(idx, r1, r1_color)
r1lvl = array.get(r1, idx)
pct = (r1lvl - close) / close * 100
pctStr = str.tostring(pct, '#.0')
displayR1 = str.format(' R1 - {0} ({1}%)', math.round_to_mintick(r1lvl), pctStr)
xR1 = position_labels == 'Left' ? array.get(arr_time, idx) : array.get(arr_time, idx + 1)
draw_label(idx, array.get(r1, idx), "R1", r1_color, false, true)
if s1_show
draw_line(idx, s1, s1_color)
s1lvl = array.get(s1, idx)
displayS1 = str.format(' S1 - {0}', math.round_to_mintick(s1lvl))
xS1 = position_labels == 'Left' ? array.get(arr_time, idx) : array.get(arr_time, idx + 1)
draw_label(idx, array.get(s1, idx), "S1", s1_color, false, true)
// R1.5 / S1.5
if r1_5_show
draw_line(idx, r1_5, r1_5_color, line.style_dashed)
draw_label(idx, array.get(r1_5, idx), 'R1.5', r1_5_color, false, true)
if s1_5_show
draw_line(idx, s1_5, s1_5_color, line.style_dashed)
draw_label(idx, array.get(s1_5, idx), 'S1.5', s1_5_color, false, true)
// R2 / S2
if r2_show
draw_line(idx, r2, r2_color)
draw_label(idx, array.get(r2, idx), 'R2', r2_color, false, true)
if s2_show
draw_line(idx, s2, s2_color)
draw_label(idx, array.get(s2, idx), 'S2', s2_color, false, true)
// R2.5 / S2.5
if r2_5_show
draw_line(idx, r2_5, r2_5_color, line.style_dashed)
draw_label(idx, array.get(r2_5, idx), 'R2.5', r2_5_color, false, true)
if s2_5_show
draw_line(idx, s2_5, s2_5_color, line.style_dashed)
draw_label(idx, array.get(s2_5, idx), 'S2.5', s2_5_color, false, true)
// R3 / S3
if r3_show
draw_line(idx, r3, r3_color)
draw_label(idx, array.get(r3, idx), 'R3', r3_color, false, true)
if s3_show
draw_line(idx, s3, s3_color)
draw_label(idx, array.get(s3, idx), 'S3', s3_color, false, true)
// R3.5 / S3.5
if r3_5_show
draw_line(idx, r3_5, r3_5_color, line.style_dashed)
draw_label(idx, array.get(r3_5, idx), 'R3.5', r3_5_color, false, true)
if s3_5_show
draw_line(idx, s3_5, s3_5_color, line.style_dashed)
draw_label(idx, array.get(s3_5, idx), 'S3.5', s3_5_color, false, true)
// R4 / S4
if r4_show
draw_line(idx, r4, r4_color)
draw_label(idx, array.get(r4, idx), 'R4', r4_color, false, true)
if s4_show
draw_line(idx, s4, s4_color)
draw_label(idx, array.get(s4, idx), 'S4', s4_color, false, true)
// R4.5 / S4.5
if r4_5_show
draw_line(idx, r4_5, r4_5_color, line.style_dashed)
draw_label(idx, array.get(r4_5, idx), 'R4.5', r4_5_color, false, true)
if s4_5_show
draw_line(idx, s4_5, s4_5_color, line.style_dashed)
draw_label(idx, array.get(s4_5, idx), 'S4.5', s4_5_color, false, true)
// R5 / S5
if r5_show
draw_line(idx, r5, r5_color)
draw_label(idx, array.get(r5, idx), 'R5', r5_color, false, true)
if s5_show
draw_line(idx, s5, s5_color)
draw_label(idx, array.get(s5, idx), 'S5', s5_color, false, true)
i = array.size(arr_time) - 2
if array.size(p) > 0 and cpr_show
draw_label(i, array.get(p, i), 'CPR', cpr_color, true, false)
if array.size(tp) > 0 and cpr_show
draw_label(i, array.get(tp, i), '', cpr_color, true, false)
if array.size(bp) > 0 and cpr_show
draw_label(i, array.get(bp, i), '', cpr_color, true, false)
// --- PDH / PDL limited to the last `look_back` CPR periods (no steplines) ---
if show_day and array.size(arr_time) > 1 and array.size(pdh_arr) == array.size(p)
// map style string → line.style_*
pd_style = session_hl_line_style == 'Solid' ? line.style_solid :
session_hl_line_style == 'Dashed' ? line.style_dashed :
line.style_dotted
// draw only for the most-recent `look_back` CPR segments
start_idx = math.max(0, j - (look_back - 1))
for k = start_idx to j
// horizontal segment for PDH between CPR period k start/end
if not na(array.get(pdh_arr, k))
line_pdH = line.new(x1 = array.get(arr_time, k), y1 = array.get(pdh_arr, k),x2 = array.get(arr_time, k + 1), y2 = array.get(pdh_arr, k),xloc = xloc.bar_time, color = session_high_color,width = line_width, style = pd_style)
array.push(lines, line_pdH)
// PDH label
if pd_show_labels or pd_show_prices
_p = array.get(pdh_arr, k)
_x = position_labels == 'Left' ? array.get(arr_time, k) : array.get(arr_time, k + 1)
_t = pd_label_text('PH', _p, pd_show_labels, pd_show_prices)
if _t != ''
array.push(labels, label.new(x = _x, y = _p, xloc = xloc.bar_time,
text = _t, textcolor = session_high_color,
style = label.style_none, color = #00000000))
// horizontal segment for PDL between CPR period k start/end
if not na(array.get(pdl_arr, k))
line_pdL = line.new(x1 = array.get(arr_time, k), y1 = array.get(pdl_arr, k),x2 = array.get(arr_time, k + 1), y2 = array.get(pdl_arr, k),xloc = xloc.bar_time, color = session_low_color,width = line_width, style = pd_style)
array.push(lines, line_pdL)
// PDL label
if pd_show_labels or pd_show_prices
_p = array.get(pdl_arr, k)
_x = position_labels == 'Left' ? array.get(arr_time, k) : array.get(arr_time, k + 1)
_t = pd_label_text('PL', _p, pd_show_labels, pd_show_prices)
if _t != ''
array.push(labels, label.new(x = _x, y = _p, xloc = xloc.bar_time,
text = _t, textcolor = session_low_color,
style = label.style_none, color = #00000000))
isHoliday(_date) =>
is_holiday = _date == timestamp(2024, 12, 25, 15, 30) or _date == timestamp(2025, 02, 26, 15, 30) or _date == timestamp(2025, 03, 14, 15, 30) or _date == timestamp(2025, 03, 31, 15, 30) or _date == timestamp(2025, 04, 10, 15, 30) or _date == timestamp(2025, 04, 14, 15, 30) or _date == timestamp(2025, 04, 18, 15, 30) or _date == timestamp(2025, 05, 01, 15, 30) or _date == timestamp(2025, 08, 15, 15, 30) or _date == timestamp(2025, 08, 27, 15, 30) or _date == timestamp(2025, 10, 02, 15, 30) or _date == timestamp(2025, 10, 21, 15, 30) or _date == timestamp(2025, 10, 22, 15, 30) or _date == timestamp(2025, 11, 05, 15, 30) or _date == timestamp(2025, 12, 25, 15, 30)
is_holiday
getDevEndTime() =>
ONE_DAY = 1000 * 60 * 60 * 24
var dev_end_time = 0
if resolution == 'D'
dev_end_time := time_close(resolution) + ONE_DAY
dev_end_time
else if resolution == 'W'
dev_end_time := time_close(resolution) + ONE_DAY * 7
dev_end_time
else if resolution == 'M'
dev_end_time := time_close(resolution) + ONE_DAY * 30
dev_end_time
else if resolution == '6M'
dev_end_time := time_close(resolution) + ONE_DAY * 30 * 6
dev_end_time
else
dev_end_time := time_close(resolution) + ONE_DAY * 30 * 12
dev_end_time
while dayofweek(dev_end_time) == dayofweek.saturday or dayofweek(dev_end_time) == dayofweek.sunday or check_holidays and isHoliday(dev_end_time)
dev_end_time := dev_end_time + ONE_DAY
dev_end_time
if extend_dev_cpr_line
dev_end_time := dev_end_time + ONE_DAY * dev_cpr_line_days
dev_end_time
dev_end_time
drawLineAndLabel(_price, _line_color, _text, _text_color, is_dev = false) =>
labelText = _text
if is_dev
if _text == 'Dev R1'
labelText := 'Dev R1'
else if _text == 'Dev S1'
labelText := 'Dev S1'
else if _text == 'Dev CPR'
labelText := 'Dev CPR'
_showLbl = true
_showPrc = true
if is_dev
if _text == 'Dev CPR'
_showLbl := dev_cpr_show_labels
_showPrc := dev_cpr_show_prices
else if _text == 'Dev R1'
_showLbl := dev_r1_show_labels
_showPrc := dev_r1_show_prices
else if _text == 'Dev S1'
_showLbl := dev_s1_show_labels
_showPrc := dev_s1_show_prices
else
// empty-text Dev CPR edges use Dev CPR toggles
_showLbl := dev_cpr_show_labels
_showPrc := dev_cpr_show_prices
start_time = time_close(resolution)
end_time = is_dev ? getDevEndTime() : time_close(resolution)
_aLine = line.new(x1 = start_time, y1 = _price, x2 = end_time, y2 = _price,
xloc = xloc.bar_time, color = _line_color, width = line_width)
line.delete(_aLine[1])
if _showLbl or _showPrc
var string display = ''
// Special: Dev R1 with % distance
if is_dev and _text == 'Dev R1' and _showPrc
pct = (_price - close) / close * 100
pctStr = str.tostring(pct, '#.0')
if _showLbl
display := str.format(' {0} - {1} ({2}%)',
labelText, math.round_to_mintick(_price), pctStr)
else
display := str.format(' {0} ({1}%)',
math.round_to_mintick(_price), pctStr)
else
// If there is NO label text (top/bottom CPR edges), still show price when enabled
if labelText == ''
if _showPrc
display := str.format(' {0}', math.round_to_mintick(_price))
// else display remains empty (no text and no price)
else
// label text exists: combine according to toggles
if _showLbl and _showPrc
display := str.format(' {0} - {1}',
labelText, math.round_to_mintick(_price))
else if _showLbl
display := ' ' + labelText
else if _showPrc
display := str.format(' {0}', math.round_to_mintick(_price))
if display != ''
label.new(x = end_time, y = _price, xloc = xloc.bar_time,
text = display, textcolor = _line_color, style = label.style_none)
_aLine
[curr_h, curr_l, curr_c] = request.security(syminfo.tickerid, resolution, [high, low, close], lookahead = barmerge.lookahead_on)
if barstate.islast
dpp = (curr_h + curr_l + curr_c) / 3.0
dbc = (curr_h + curr_l) / 2.0
dtc = dpp * 2 - dbc
dev_top = dtc > dbc ? dtc : dbc
dev_bot = dbc < dtc ? dbc : dtc
if dev_cpr_show
dtp = drawLineAndLabel(dev_top, dev_cpr_color, '', dev_cpr_color, true)
drawLineAndLabel(dpp, dev_cpr_color, 'Dev CPR', dev_cpr_color, true)
dbp = drawLineAndLabel(dev_bot, dev_cpr_color, '', dev_cpr_color, true)
linefill.new(dtp, dbp, color.new(dev_cpr_color, 70))
if dev_r1_show
_dev_r1 = dpp * 2 - curr_l
if kind == FIBONACCI
_dev_r1 := dpp + 0.382 * (curr_h - curr_l)
_dev_r1
drawLineAndLabel(_dev_r1, dev_r1_color, 'Dev R1', dev_r1_color, true)
if dev_s1_show
_dev_s1 = dpp * 2 - curr_h
if kind == FIBONACCI
_dev_s1 := dpp - 0.382 * (curr_h - curr_l)
_dev_s1
drawLineAndLabel(_dev_s1, dev_s1_color, 'Dev S1', dev_s1_color, true)
// Functions
getAllTimeHigh() =>
h = 0.0
h := bar_index == 0 ? high : high > h[1] ? high : h[1]
h
getAllTimeLow() =>
l = 0.0
l := bar_index == 0 ? low : low < l[1] ? low : l[1]
l
get_resolution() =>
resolution = 'M'
if timeframe.isintraday
resolution := timeframe.multiplier <= 15 ? 'D' : 'W'
resolution
else if timeframe.isweekly or timeframe.ismonthly
resolution := '12M'
resolution
resolution
// Session line drawer (no extend)
drawLine(price, _text, lineColor, lineStyle, showLabels, showPrices) =>
fLineStyle = switch lineStyle
'Dotted' => line.style_dotted
'Dashed' => line.style_dashed
=> line.style_solid
endOfDay = time_tradingday + 105000000
aLine = line.new(x1 = time_tradingday, y1 = price,x2 = endOfDay, y2 = price,xloc = xloc.bar_time,color = lineColor,style = fLineStyle)
line.delete(aLine[1])
fText = _text
if showLabels and showPrices
fText := str.format('{0} - {1}', _text, math.round_to_mintick(price))
else if showPrices
fText := str.format('{0}', math.round_to_mintick(price))
if showLabels or showPrices
aLabel = label.new(endOfDay, price, xloc=xloc.bar_time,
text=str.format(' {0}', fText),
textcolor=lineColor, style=label.style_none)
label.delete(aLabel[1])
drawOpen(show, resolution, labelText, lineColor, lineStyle, showLabels, showPrices) =>
_open = request.security(syminfo.tickerid, resolution, open)
if show
drawLine(_open, labelText, lineColor, lineStyle, showLabels, showPrices)
drawHighLow(show, resolution, labelTextHigh, labelTextLow, highColor, lowColor, lineStyle, showLabels, showPrices) =>
[_high, _low] = request.security(syminfo.tickerid, resolution, [high[1], low[1]])
if show and not na(_high)
drawLine(_high, labelTextHigh, highColor, lineStyle, showLabels, showPrices)
drawLine(_low, labelTextLow, lowColor, lineStyle, showLabels, showPrices)
// Session Open
drawOpen(show_day_open, 'D', ' Day Open', session_open_color, session_open_line_style, true, true)