Probability Cones
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © joebaus
//@version=5

// ———————————————————— Acknowledgements {
// - Fortunate, a good friend who helped me significantly start my research.
// - Telugu Traders Community, for their video on calculating cones.
// - Savva Shanaev, for his NEDL tutorial on the Laplace distribution. 
// - JeylaniB, for his Pine Script V5 extension for VS Studio Code.
// - PineCoders and TradingView, for great Pine documentation and features.
// - @RicardoSantos, for example code and idea of the Select Date feature.
// - Anton Berlin, for his discussions on statistical interpretations.
// }

// ———————————————————— Indicator {
indicator(
  shorttitle	    = "Probability Cones", 
  title     	    = "Probability Cones", 
  max_lines_count   = 500,
  max_bars_back     = 5000,
  overlay   	    = true)
// }

// ———————————————————— Constants {
// All tooltip constants are prefixed with "T_".
T_SRC 		= "The data source to use for calculating the probability cones."
T_DEV       = "Select the calculation method for the cone deviations."
T_LOOKBACK 	= "The number of bars sampled for the probability calculations. Minimum value: 1 and Maximum value: 5000"
T_FORECAST  = "The number of bars to project the probability cones forward. At 70 bars with all cones enabled, TradingView's line limitations will be hit, and the indicator will begin to remove earlier lines. Either keep this input below 70 or hide cones to get extra drawing lines."
T_FILLS     = "The background color highlights between cone lines."
T_BARSBACK  = "The number of bars + or - to position the probability cones."
T_CONELOCK  = "Enables Anchor Type inputs. Keeps the cone origin stationary based on the Anchor Type selected. When disabled, cone origin will use a rolling window placement using the Bars Back to Place Cones input."
T_ANCHOR    = "Select the method to anchor the probability cone origin."
T_DATE      = "Keeps the cone origin stationary at the selected date."
T_HTF       = "Sets the cone's origin to the beginning of a specified timeframe. Updates the cones automatically when a new period begins."
T_OFFSET    = "The number of bars + or - to position cones after being anchored. Only effects the Higher Timeframe Anchor Type."
T_MEAN      = "Select the desired mean for the cones. The Auto setting will use the default, recommended means for the current Deviation input. By default: Standard uses Average, Laplace and Absolute Deviation use Median."
T_MEANDRIFT = "Adds or removes the drift to the cones caused by the mean's increasing or decreasing value in the future. Turning \"Use Mean Drift\" off projects forward only the initial value of the mean, and shifts the values of the cone's deviation lines relative to the mean."

// All group constants are prefixed with "G_".
G_SETTINGS	= "Cone Settings"
G_ANCHOR	= "Anchor Settings ⚓"
G_MEAN	    = "Mean Settings"
G_CONE1_SETTINGS    = "First Cone's Settings"
G_CONE2_SETTINGS    = "Second Cone's Settings"
G_CONE3_SETTINGS    = "Third Cone's Settings"

// Constants for i_deviation
DEV_STANDARD    = "Standard"
DEV_LAPLACE     = "Laplace Stdev"
DEV_MAD         = "Absolute"

// Constants for i_anchorType
AT_BAR  = "Bar"
AT_DATE = "Select Date"
AT_HTF  = "Higher Timeframe"

// Constants for i_mu
MU_AUTO     = "Auto"
MU_AVERAGE  = "Average"
MU_MEDIAN   = "Median"

// Constants for f_lineStyle()
LINE_STYLE_SOLID    = "Solid"
LINE_STYLE_DASHED   = "Dashed"
LINE_STYLE_DOTTED   = "Dotted"

// Inline constants.
INLINE_CONE_DEV     = "Cone Deviations"
INLINE_CONE_STYLE   = "Cone Line Styles"
INLINE_CONE_COLOR   = "Cone Line Colors"
INLINE_CONE_WIDTH   = "Cone Line Widths"
INLINE_FILL_COLOR   = "Fill Color"
INLINE_FILL_BOOL    = "Fill Bool"
INLINE_MEAN_1       = "Mean Inline Settings 1"
INLINE_MEAN_2       = "Mean Inline Settings 2"
// }

// ———————————————————— Inputs {
// Here is how the cone in variables are written:

// Cone Order:  "first", "second", or "third" cone.
// Position:    Upper "Up" or lower "Dn" line of the cone.
// Attribute:   "Color", "Width", etc.
// All inputs prefixed with "i_", all arrays prefixed with "a_".

// E.g. i_firstUpColor is the input for the first cone's, upper line, color.

// ———————————————————— General Settings Inputs {
i_src	    = input.source(
  defval    = close, 
  title     = "Source", 
  tooltip   = T_SRC, 
  group     = G_SETTINGS)

i_deviation = input.string(
  defval    = DEV_STANDARD, 
  title     = "Deviation", 
  options   = [DEV_STANDARD, 
               DEV_LAPLACE,
               DEV_MAD], 
  tooltip   = T_DEV, 
  group     = G_SETTINGS) 

i_lookBack  = input.int(
  defval    = 500, 
  title     = "Bar Lookback", 
  minval    = 1, 
  maxval    = 5000, 
  tooltip   = T_LOOKBACK, 
  group     = G_SETTINGS)

i_forecast  = input.int(
  defval    = 30, 
  title     = "Bar Forecast", 
  minval    = 1, 
  tooltip   = T_FORECAST, 
  group     = G_SETTINGS)

i_meanDriftBool = input.bool(
  defval    = true, 
  title     = "Use Mean Drift", 
  tooltip   = T_MEANDRIFT,
  group     = G_SETTINGS) 

i_fillBool  = input.bool(
  defval    = true, 
  title     = "Show Fills", 
  tooltip   = T_FILLS,
  group     = G_SETTINGS) 
// }

// ———————————————————— Anchor Settings {
i_barsBack  = input.int(
  defval    = 20, 
  title     = "Bars Back to Place Cones", 
  tooltip   = T_BARSBACK, 
  group     = G_ANCHOR) 

i_coneLock  = input.bool(
  defval    = false,
  title     = "Lock Cones to Anchor Type",
  tooltip   = T_CONELOCK,
  group     = G_ANCHOR)

i_anchorType    = input.string(
  defval    = AT_BAR, 
  title     = "Anchor Type", 
  options   = [AT_BAR,
               AT_DATE,
               AT_HTF],
  tooltip   = T_ANCHOR, 
  group     = G_ANCHOR) 

// @RicardoSantos contribution
i_anchorDate    = time ==  input.time(
  defval    = timestamp("2022-01-01"), 
  title     = "Select Date to Place Cones", 
  tooltip   = T_DATE,  
  group     = G_ANCHOR)

i_anchorHtf = input.timeframe(
  defval    = "W", 
  title     = "Higher Timeframe Anchor", 
  tooltip   = T_HTF, 
  group     = G_ANCHOR)

i_anchorOffset  = input.int(
  defval    = 1, 
  title     = "HTF Anchor Offset", 
  tooltip   = T_OFFSET, 
  group     = G_ANCHOR) 
// }

// ———————————————————— Mean Input Settings {
i_muBool    = input.bool(
  defval    = true,
  title     = "Show Mean",
  group     = G_MEAN)

i_muCalc    = input.string(
  defval    = MU_AUTO, 
  title     = "Mean Calculation", 
  options   = [MU_AUTO,
               MU_AVERAGE,
               MU_MEDIAN],
  tooltip   = T_MEAN,
  inline    = INLINE_MEAN_1,
  group     = G_MEAN) 

i_muColor   = input.color(
  defval    = color.new(color.orange, 0), 
  title     = "Color",
  inline    = INLINE_MEAN_2,
  group     = G_MEAN)

i_muWidth   = input.int(
  defval    = 2, 
  title     = "Width", 
  minval    = 1, 
  maxval    = 4, 
  inline    = INLINE_MEAN_2,
  group     = G_MEAN) 

i_muLineStyle   = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_MEAN_2,
  group     = G_MEAN)
// }

// ———————————————————— First Cone's Input Settings {
i_firstConeBool = input.bool(
  defval    = true, 
  title     = "Show First Cone", 
  group     = G_CONE1_SETTINGS) 

i_firstUpColor  = input.color(
  defval    = color.new(color.green, 0), 
  title     = "Upper Cone Color",
  inline    = INLINE_CONE_COLOR,
  group     = G_CONE1_SETTINGS) 

i_firstDnColor  = input.color(
  defval    = color.new(color.green, 0), 
  title     = "Lower Cone Color",
  inline    = INLINE_CONE_COLOR,
  group     = G_CONE1_SETTINGS) 

i_firstUpDev    = input.float(
  defval 	= 1, 
  title		= "Upper Deviation",
  step      = 0.01,
  inline    = INLINE_CONE_DEV,
  group		= G_CONE1_SETTINGS)

// Dn cone deviation inputs are positive, and made negative later.
i_firstDnDev    = input.float(
  defval 	= 1, 
  title		= "Lower Deviation",
  step      = 0.01,
  inline    = INLINE_CONE_DEV,
  group		= G_CONE1_SETTINGS)

i_firstUpLineStyle  = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Upper Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_CONE_STYLE,
  group     = G_CONE1_SETTINGS)

i_firstDnLineStyle  = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Lower Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_CONE_STYLE,
  group     = G_CONE1_SETTINGS) 

i_firstUpWidth  = input.int(
  defval    = 2, 
  title     = "Upper Cone Width", 
  minval    = 1, 
  maxval    = 4,  
  inline    = INLINE_CONE_WIDTH,
  group     = G_CONE1_SETTINGS) 

i_firstDnWidth  = input.int(
  defval    = 2, 
  title     = "Lower Cone Width", 
  minval    = 1, 
  maxval    = 4,  
  inline    = INLINE_CONE_WIDTH,
  group     = G_CONE1_SETTINGS) 

i_firstUpFillBool   = input.bool(
  defval    = true, 
  title     = "Show Upper Fill", 
  inline    = INLINE_FILL_BOOL,
  group     = G_CONE1_SETTINGS) 

i_firstDnFillBool   = input.bool(
  defval    = true, 
  title     = "Show Lower Fill", 
  inline    = INLINE_FILL_BOOL,
  group     = G_CONE1_SETTINGS) 

i_firstUpFill   = input.color(
  defval    = color.new(color.green, 95), 
  title     = "Upper Fill Color",
  inline    = INLINE_FILL_COLOR,
  group     = G_CONE1_SETTINGS) 

i_firstDnFill   = input.color(
  defval    = color.new(color.green, 95), 
  title     = "Lower Fill Color",
  inline    = INLINE_FILL_COLOR,
  group     = G_CONE1_SETTINGS) 
// }

// ———————————————————— Second Cone's Input Settings {
i_secondConeBool    = input.bool(
  defval    = true, 
  title     = "Show Second Cone", 
  group     = G_CONE2_SETTINGS) 

i_secondUpColor = input.color(
  defval    = color.new(color.blue, 0), 
  title     = "Upper Cone Color",
  inline    = INLINE_CONE_COLOR,
  group     = G_CONE2_SETTINGS) 

i_secondDnColor = input.color(
  defval    = color.new(color.blue, 0), 
  title     = "Lower Cone Color",
  inline    = INLINE_CONE_COLOR,
  group     = G_CONE2_SETTINGS) 

i_secondUpDev   = input.float(
  defval 	= 2, 
  title		= "Upper Deviation",
  step      = 0.01,
  inline    = INLINE_CONE_DEV,
  group		= G_CONE2_SETTINGS)

// Dn cone deviation inputs are positive, and made negative later.
i_secondDnDev   = input.float(
  defval 	= 2, 
  title		= "Lower Deviation",
  step      = 0.01,
  inline    = INLINE_CONE_DEV,
  group		= G_CONE2_SETTINGS)

i_secondUpLineStyle = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Upper Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_CONE_STYLE,
  group     = G_CONE2_SETTINGS)

i_secondDnLineStyle = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Lower Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_CONE_STYLE,
  group     = G_CONE2_SETTINGS) 

i_secondWidthUp = input.int(
  defval    = 2, 
  title     = "Upper Cone Width", 
  minval    = 1, 
  maxval    = 4,  
  inline    = INLINE_CONE_WIDTH,
  group     = G_CONE2_SETTINGS) 

i_secondDnWidth = input.int(
  defval    = 2, 
  title     = "Lower Cone Width", 
  minval    = 1, 
  maxval    = 4,  
  inline    = INLINE_CONE_WIDTH,
  group     = G_CONE2_SETTINGS) 

i_secondUpFillBool  = input.bool(
  defval    = true, 
  title     = "Show Upper Fill", 
  inline    = INLINE_FILL_BOOL,
  group     = G_CONE2_SETTINGS) 

i_secondDnFillBool  = input.bool(
  defval    = true, 
  title     = "Show Lower Fill", 
  inline    = INLINE_FILL_BOOL,
  group     = G_CONE2_SETTINGS) 

i_secondUpFill  = input.color(
  defval    = color.new(color.blue, 95), 
  title     = "Fill Upper Color",
  inline    = INLINE_FILL_COLOR,
  group     = G_CONE2_SETTINGS) 

i_secondDnFill  = input.color(
  defval    = color.new(color.blue, 95), 
  title     = "Fill Lower Color",
  inline    = INLINE_FILL_COLOR,
  group     = G_CONE2_SETTINGS) 
// }

// ———————————————————— Third Cone's Input Settings {
i_thirdConeBool = input.bool(
  defval    = true, 
  title     = "Show Third Cone", 
  group     = G_CONE3_SETTINGS) 

i_thirdUpColor  = input.color(
  defval    = color.new(color.red, 0), 
  title     = "Upper Cone Color",
  inline    = INLINE_CONE_COLOR,
  group     = G_CONE3_SETTINGS) 

i_thirdDnColor  = input.color(
  defval    = color.new(color.red, 0), 
  title     = "Lower Cone Color",
  inline    = INLINE_CONE_COLOR,
  group     = G_CONE3_SETTINGS) 

i_thirdUpDev    = input.float(
  defval 	= 3, 
  title		= "Upper Deviation",
  step      = 0.01,
  inline    = INLINE_CONE_DEV,
  group		= G_CONE3_SETTINGS)

// Dn cone deviation inputs are positive, made negative later.
i_thirdDnDev    = input.float(
  defval 	= 3, 
  title		= "Lower Deviation",
  step      = 0.01,
  inline    = INLINE_CONE_DEV,
  group		= G_CONE3_SETTINGS)

i_thirdUpLineStyle  = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Upper Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_CONE_STYLE,
  group     = G_CONE3_SETTINGS)

i_thirdDnLineStyle  = input.string(
  defval    = LINE_STYLE_DOTTED, 
  title     = "Lower Line Style", 
  options   = [LINE_STYLE_SOLID,
               LINE_STYLE_DASHED,
               LINE_STYLE_DOTTED],
  inline    = INLINE_CONE_STYLE,
  group     = G_CONE3_SETTINGS) 

i_thirdUpWidth  = input.int(
  defval    = 2, 
  title     = "Upper Cone Width", 
  minval    = 1, 
  maxval    = 4,  
  inline    = INLINE_CONE_WIDTH,
  group     = G_CONE3_SETTINGS) 

i_thirdDnWidth  = input.int(
  defval    = 2, 
  title     = "Lower Cone Width", 
  minval    = 1, 
  maxval    = 4,  
  inline    = INLINE_CONE_WIDTH,
  group     = G_CONE3_SETTINGS) 

i_thirdUpFillBool   = input.bool(
  defval    = true, 
  title     = "Show Upper Fill", 
  inline    = INLINE_FILL_BOOL,
  group     = G_CONE3_SETTINGS) 

i_thirdDnFillBool   = input.bool(
  defval    = true, 
  title     = "Show Lower Fill", 
  inline    = INLINE_FILL_BOOL,
  group     = G_CONE3_SETTINGS) 

i_thirdUpFill   = input.color(
  defval    = color.new(color.red, 95), 
  title     = "Fill Upper Color",
  inline    = INLINE_FILL_COLOR,
  group     = G_CONE3_SETTINGS) 

i_thirdDnFill   = input.color(
  defval    = color.new(color.red, 95), 
  title     = "Fill Lower Color",
  inline    = INLINE_FILL_COLOR,
  group     = G_CONE3_SETTINGS) 
// }

// }

// ———————————————————— Calculations {

// ———————————————————— Array Index Variables {
// coneForecast adds 1 to i_forecast.
// This prevents an array from being a length making the forecast 1 bar short.
coneForecast = i_forecast + 1

// coneForecastIndex stops repetitition in "for" loops.
// While i_forecast is equivalent, this variable is explicit for indexing.
coneForecastIndex = coneForecast - 1
// }

// ———————————————————— Cone Origin Anchor Variables {
// Barlock variable
barLock = ta.valuewhen(barstate.isnew == true, bar_index, 0)

// Date Select, anchor variable
// @RicardoSantos contribution
var int dateAnchor = na

// Last time i_anchorDate was true, get bar_index and set to dateAnchor.
if i_anchorDate == true
    dateAnchor := bar_index

// Get the close of the prior, historical higher timeframe.
// barmerge.lookahead_on resolves historical cone anchor repaints.
higherTimeframe = request.security(
  symbol        = syminfo.tickerid, 
  timeframe     = i_anchorHtf, 
  expression    = close[1], 
  lookahead     = barmerge.lookahead_on)

// Find the numbers of barssince the start a new candle based on i_anchorHtf.
htfAnchor = ta.barssince(higherTimeframe[1] != higherTimeframe)

// If i_coneLock is enabled, use the respective anchorBarIndex bar_index input.
// Otherwise, default back to the i_barsBack input.
anchorBar = switch i_coneLock
    true    => bar_index - i_barsBack - (bar_index - barLock[1] - 1)
    false   => bar_index - i_barsBack

anchorDate    = switch i_coneLock
    true    => dateAnchor
    false   => bar_index - i_barsBack

anchorHtf = switch i_coneLock
    true    => bar_index - htfAnchor - i_anchorOffset
    false   => bar_index - i_barsBack

// What bar index to start displaying the cones. Used for f_coneLine().
anchorBarIndex    = switch i_anchorType
    AT_BAR  => anchorBar
    AT_DATE => anchorDate
    AT_HTF  => anchorHtf

// If i_coneLock is enabled, use the respective i_anchorType subscript input.
// Otherwise, default back to the i_barsBack input.
anchorBarSub  = switch i_coneLock
    true    => i_barsBack + (bar_index - barLock[1] - 1)
    false   => i_barsBack

anchorDateSub = switch i_coneLock
    true    => bar_index - dateAnchor
    false   => i_barsBack

anchorHtfSub  = switch i_coneLock
    true    => htfAnchor + i_anchorOffset
    false   => i_barsBack

// Get the equivalent anchorBarIndex value to use as a subscript[] for variables.
// Used in "Devation and Mean Switches", and "Cone Value Array" sections.
anchorBarIndexSub   = switch i_anchorType
    AT_BAR  => anchorBarSub
    AT_DATE => anchorDateSub
    AT_HTF  => anchorHtfSub
// }

// ———————————————————— Log Returns Variables {
logReturns      = math.log(i_src / i_src[1])
logReturnsMed   = ta.median(logReturns, i_lookBack)
logReturnsAvg   = ta.sma(logReturns, i_lookBack) 
logReturnsDev   = ta.stdev(logReturns, i_lookBack)
// }

// ———————————————————— Mean Switches {
// Based on i_deviation, select the mean.
meanAuto    = switch i_deviation
    DEV_STANDARD    => logReturnsAvg[anchorBarIndexSub]
    DEV_LAPLACE     => logReturnsMed[anchorBarIndexSub] 
    DEV_MAD         => logReturnsMed[anchorBarIndexSub] 

// Based on the mean input, return autoMean or a manually selected mean.
meanSwitch  = switch i_muCalc
    MU_AUTO         => meanAuto
    MU_AVERAGE      => logReturnsAvg
    MU_MEDIAN       => logReturnsMed
// }

// ———————————————————— Absolute Deviation Calculation {
a_absDev    = array.new_float(i_lookBack, na) 

for i = 0 to i_lookBack - 1
    _absDev = math.abs(logReturns[i] - meanSwitch)  // Absolute Deviation Calculation
    array.set(id = a_absDev, index = i, value = _absDev) 

absDev  = array.avg(id = a_absDev)   // Absolute Deviation
// }

// ———————————————————— Laplace Standard Deviation Calculation {
laplaceVar = 2 * math.pow(absDev, 2)
laplaceStdev = math.sqrt(laplaceVar)
// }

// ———————————————————— Devation Switches {
devSelectUp = switch i_deviation
    DEV_STANDARD    => logReturnsDev[anchorBarIndexSub]
    DEV_LAPLACE     => laplaceStdev[anchorBarIndexSub]
    DEV_MAD         => absDev[anchorBarIndexSub]

devSelectDn = switch i_deviation
    DEV_STANDARD    => logReturnsDev[anchorBarIndexSub]
    DEV_LAPLACE     => laplaceStdev[anchorBarIndexSub]
    DEV_MAD         => absDev[anchorBarIndexSub]
// }

// ———————————————————— a_conePeriod and a_conePeriodSqrt {
// Holds an increasing int series: 1, 2, 3... up to coneForecast
// This counts the number of bars to forecast the cones forward.
a_conePeriod = array.new_int(size = coneForecast, initial_value = na)

// Holds square root of a_conePeriod.
// When multiplied by a deviation, generates the a cone line's curve.
a_conePeriodSqrt = array.new_float(size = coneForecast, initial_value = na)

for i = 0 to coneForecastIndex
    
    int _conePeriod = na
    _conePeriod  := i + 1
    array.set(id = a_conePeriod, index = i, value = _conePeriod) 
    
    _conePeriodSqrt = math.sqrt(number = _conePeriod)
    array.set(id = a_conePeriodSqrt, index = i, value = _conePeriodSqrt) 
// }

// ———————————————————— conePeriod and DevSqrt Arrays {
a_conePeriodAvg = array.new_float(size = coneForecast, initial_value = na)

// Arrays for the three cones.
a_firstUpDevSqrt    = array.new_float(size = coneForecast, initial_value = na)
a_firstDnDevSqrt    = array.new_float(size = coneForecast, initial_value = na)

a_secondUpDevSqrt   = array.new_float(size = coneForecast, initial_value = na)
a_secondDnDevSqrt   = array.new_float(size = coneForecast, initial_value = na)

a_thirdUpDevSqrt    = array.new_float(size = coneForecast, initial_value = na)
a_thirdDnDevSqrt    = array.new_float(size = coneForecast, initial_value = na)

for i = 0 to coneForecastIndex

    // When i_meanDriftBool is true, multiply the mean by a_conePeriod at i
    // If false, set the initial mean value, from i to coneForecastIndex, to a_conePeriodAvg
    _conePeriodAvg = switch i_meanDriftBool 
        true    => meanSwitch * array.get(id = a_conePeriod, index = i)
        false   => meanSwitch
    array.set(id = a_conePeriodAvg, index = i, value = _conePeriodAvg) 

    // Multiply the stdev of log returns by the sqrt of the cone period.
    _firstUpDevSqrt = i_firstUpDev * devSelectUp * array.get(id = a_conePeriodSqrt, index = i)
    array.set(id = a_firstUpDevSqrt,   index = i, value = _firstUpDevSqrt)

    _firstDnDevSqrt = i_firstDnDev * devSelectDn * array.get(id = a_conePeriodSqrt, index = i)
    array.set(id = a_firstDnDevSqrt,   index = i, value = _firstDnDevSqrt)

    _secondUpDevSqrt = i_secondUpDev * devSelectUp * array.get(id = a_conePeriodSqrt, index = i)
    array.set(id = a_secondUpDevSqrt,  index = i, value = _secondUpDevSqrt)

    _secondDnDevSqrt = i_secondDnDev * devSelectDn * array.get(id = a_conePeriodSqrt, index = i)
    array.set(id = a_secondDnDevSqrt,  index = i, value = _secondDnDevSqrt)

    _thirdUpDevSqrt = i_thirdUpDev * devSelectUp * array.get(id = a_conePeriodSqrt, index = i)
    array.set(id = a_thirdUpDevSqrt,   index = i, value = _thirdUpDevSqrt)

    _thirdDnDevSqrt = i_thirdDnDev * devSelectDn * array.get(id = a_conePeriodSqrt, index = i)
    array.set(id = a_thirdDnDevSqrt,   index = i, value = _thirdDnDevSqrt)
// }

// ———————————————————— Percent Arrays {
a_firstUpPercent    = array.new_float(size = coneForecast, initial_value = na)
a_firstDnPercent    = array.new_float(size = coneForecast, initial_value = na) 

a_secondUpPercent   = array.new_float(size = coneForecast, initial_value = na)
a_secondDnPercent   = array.new_float(size = coneForecast, initial_value = na) 

a_thirdUpPercent    = array.new_float(size = coneForecast, initial_value = na)
a_thirdDnPercent    = array.new_float(size = coneForecast, initial_value = na) 

for i = 0 to coneForecastIndex
    // If i_meanDriftBool is true, a_conePeriodAvg equals meanSwitch for i to coneForecastIndex

    _firstUpPercent =   array.get(id = a_conePeriodAvg, index = i) +
                      array.get(id = a_firstUpDevSqrt, index = i) 
    array.set(id = a_firstUpPercent, index = i, value = _firstUpPercent)

    _firstDnPercent =   array.get(id = a_conePeriodAvg, index = i) -
                      array.get(id = a_firstDnDevSqrt, index = i) 
    array.set(id = a_firstDnPercent, index = i, value = _firstDnPercent)

    _secondUpPercent =   array.get(id = a_conePeriodAvg, index = i) +
                      array.get(id = a_secondUpDevSqrt, index = i) 
    array.set(id = a_secondUpPercent, index = i, value = _secondUpPercent)

    _secondDnPercent =   array.get(id = a_conePeriodAvg, index = i) -
                      array.get(id = a_secondDnDevSqrt, index = i) 
    array.set(id = a_secondDnPercent, index = i, value = _secondDnPercent)

    _thirdUpPercent =   array.get(id = a_conePeriodAvg, index = i) +
                      array.get(id = a_thirdUpDevSqrt, index = i) 
    array.set(id = a_thirdUpPercent, index = i, value = _thirdUpPercent)

    _thirdDnPercent =   array.get(id = a_conePeriodAvg, index = i) -
                      array.get(id = a_thirdDnDevSqrt, index = i) 
    array.set(id = a_thirdDnPercent, index = i, value = _thirdDnPercent)
// }

// ———————————————————— Cone Value Arrays {
a_meanValue     = array.new_float(size = coneForecast, initial_value = na)

a_firstUpValue  = array.new_float(size = coneForecast, initial_value = na)
a_firstDnValue  = array.new_float(size = coneForecast, initial_value = na) 

a_secondUpValue = array.new_float(size = coneForecast, initial_value = na)
a_secondDnValue = array.new_float(size = coneForecast, initial_value = na) 

a_thirdUpValue  = array.new_float(size = coneForecast, initial_value = na)
a_thirdDnValue  = array.new_float(size = coneForecast, initial_value = na) 

for i = 0 to coneForecastIndex

    _a_meanValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_conePeriodAvg, index = i) )
    array.set(id = a_meanValue, index = i, value = _a_meanValue) 

    _firstUpConeValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_firstUpPercent, index = i) )
    array.set(id = a_firstUpValue, index = i, value = _firstUpConeValue) 
    
    _firstDnConeValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_firstDnPercent, index = i) )
    array.set(id = a_firstDnValue, index = i, value = _firstDnConeValue) 

    _secondUpConeValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_secondUpPercent, index = i) )
    array.set(id = a_secondUpValue, index = i, value = _secondUpConeValue) 

    _secondDnConeValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_secondDnPercent, index = i) )
    array.set(id = a_secondDnValue, index = i, value = _secondDnConeValue) 

    _thirdUpConeValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_thirdUpPercent, index = i) )
    array.set(id = a_thirdUpValue, index = i, value = _thirdUpConeValue) 

    _thirdDnConeValue = i_src[anchorBarIndexSub] * math.exp( array.get(id = a_thirdDnPercent, index = i) )
    array.set(id = a_thirdDnValue, index = i, value = _thirdDnConeValue) 
// }

// }

// ———————————————————— Lines and Fills {

// ———————————————————— Draw Functions {

// ———————————————————— Line Style Function {
f_lineStyle(_lineStyle) =>
    // @param _lineStyle, user input line style variable.
    _output = switch _lineStyle
        LINE_STYLE_SOLID    => line.style_solid 
        LINE_STYLE_DASHED   => line.style_dashed
        LINE_STYLE_DOTTED   => line.style_dotted
// }

// ———————————————————— Cone Line Function {
f_coneLine(_a_coneValue, _color, _style, _width, _coneToggle) =>

    // @param _a_coneValue, the array holding the cone's forecast values.
    // @param _color, line color variable.
    // @param _style, line style variable.
    // @param _width, line width variable.
    // @param _coneToggle, bool input for this line.

    var _a_coneLine = array.new_line(size = coneForecast, initial_value = na)

    // Offset "i" to get the next _a_coneValue to use as y2 in _coneLine.
    _a_x2Period     = array.new_int(size =  coneForecast, initial_value = na) 

    // If the respective cone and line input toggles are on, display the line.
    if _coneToggle == true

        // For loop to generate offset "i" array in _a_x2Period
        for i = 0 to coneForecastIndex - 1  // Index is one shorter than "i".
            _x2Period = i + 1               // Create offset index value from "i".
            array.set(id = _a_x2Period, index = i, value = _x2Period)

        for i = 0 to coneForecastIndex 

            _coneX1  = anchorBarIndex + i
            _coneX2  = anchorBarIndex + array.get(id = _a_x2Period, index = i)

            line _coneLine = na

            _coneLine   := line.new(
              x1        = _coneX1, 
              y1        = array.get(id = _a_coneValue, index = i ), 
              x2        = _coneX2, 
              y2        = array.get(id = _a_coneValue, index = array.get(id = _a_x2Period, index = i) ), 
              xloc      = xloc.bar_index,
              extend    = extend.none, 
              color     = _color, 
              style     = _style, 
              width     = _width)
            
            array.push(id = _a_coneLine, value = _coneLine)

            if array.size(id = _a_coneLine) > coneForecast
                _ln = array.shift(id = _a_coneLine)
                line.delete(id = _ln)   

    _a_coneLine
// }

// ———————————————————— Cone Fill Function {
f_coneFill(_a_line1, _a_line2, _color, _i_fillBool) =>

    // @param _a_line1, is the first line's array for the fill function.
    // @param _a_line2, is the second line's array for the fill function.
    // @param _color, color variable.
    // @param _i_fillBool, bool input for this fill.

    _a_linefill = array.new_linefill()

    if i_fillBool == true       // i_fillBool is a global variable.
        if _i_fillBool == true  // _i_fillBool is a local variable.
            for i = 0 to coneForecastIndex
        
                line _line1 = na
                line _line2 = na
                
                _line1 := array.get(id = _a_line1, index = i) 
                _line2 := array.get(id = _a_line2, index = i)
        
                _linefill = linefill.new(_line1, _line2, _color)
        
                array.push(id = _a_linefill, value = _linefill) 
        
                if array.size(id = _a_linefill) > coneForecast
                    _ln = array.shift(id = _a_linefill)
                    linefill.delete(id = _ln)   
// }

// }

// ———————————————————— Draw Indicator {

// ———————————————————— Draw Lines {
meanLine    = f_coneLine(
  a_meanValue, 
  i_muColor, 
  f_lineStyle(i_muLineStyle), 
  i_muWidth,
  i_muBool)

firstUpLine = f_coneLine(
  a_firstUpValue, 
  i_firstUpColor, 
  f_lineStyle(i_firstUpLineStyle), 
  i_firstUpWidth,
  i_firstConeBool)

firstDnLine = f_coneLine(
  a_firstDnValue, 
  i_firstDnColor, 
  f_lineStyle(i_firstDnLineStyle), 
  i_firstDnWidth,
  i_firstConeBool)

secondUpLine = f_coneLine(
  a_secondUpValue, 
  i_secondUpColor, 
  f_lineStyle(i_secondUpLineStyle), 
  i_secondWidthUp,
  i_secondConeBool)

secondDnLine = f_coneLine(
  a_secondDnValue, 
  i_secondDnColor, 
  f_lineStyle(i_secondDnLineStyle), 
  i_secondDnWidth,
  i_secondConeBool)

thirdUpLine = f_coneLine(
  a_thirdUpValue, 
  i_thirdUpColor, 
  f_lineStyle(i_thirdUpLineStyle), 
  i_thirdUpWidth,
  i_thirdConeBool)

thirdDnLine = f_coneLine(
  a_thirdDnValue, 
  i_thirdDnColor, 
  f_lineStyle(i_thirdDnLineStyle), 
  i_thirdDnWidth,
  i_thirdConeBool)
// }

// ———————————————————— Draw Fills
f_coneFill(meanLine, firstUpLine, i_firstUpFill, i_firstUpFillBool)
f_coneFill(meanLine, firstDnLine, i_firstDnFill, i_firstDnFillBool)
f_coneFill(firstUpLine, secondUpLine, i_secondUpFill, i_secondUpFillBool)
f_coneFill(firstDnLine, secondDnLine, i_secondDnFill, i_secondDnFillBool)
f_coneFill(secondUpLine, thirdUpLine, i_thirdUpFill, i_thirdUpFillBool)
f_coneFill(secondDnLine, thirdDnLine, i_thirdDnFill, i_thirdDnFillBool)
// }

// }