Indicator · Pine Script v5 · Own pane

LS Volatility Index

by andreperez

The LS Volatility Index measures price volatility relative to a customizable moving average.

View on GitHub

GitHub stars2on the repository
Pine versionv5runs as is
Lines of code386
Settings40inputs
LicenceMPL-2.0
Last update3 years ago27 Nov 2022

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

386 lines of Pine Script v5 from LS Volatility Index.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

LS Volatility Index.pine
// @version=5
// @License This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// @Author andre_007
// @description LS Volatility Index
// @Thanks and credits:
//      - Alexandre Wolwacz (Stormer), Fabrício Lorenz, Fábio Figueiredo (Vlad): for explanation of the original indicator
//      - Feature scaler (for normalization)
//      - HPotter (for calc of Historical Volatility)
//      - © The_Caretaker (for theme of color spectrum)

indicator("LS Volatility Index", shorttitle='LS Volatility Index', format=format.price, precision=2, timeframe="")

// ------------------------- Constants {
var string GROUP_MA     = 'Moving Average of Price'
var string GROUP_LS     = 'LS Volatility Index'
var string GROUP_LS_AL  = 'Alerts for LS'
var string GROUP_ATR    = 'ATR - Average True Range'
var string GROUP_ATR_AL = 'Alerts for ATR'
var string TOOLTIP_1    = 'Moving Average of price.\n' +
  'The distance of the price to this moving average will be calculate through the LS indicator.\n' + 
  'The period has no effect on the VWAP.'
var string TOOLTIP_2    = 'Period used in normalization calculation.\n' + 
  'Normalization involves transforming the indicator in the range from 0 to 100.\n' + 
  'High values decrease noise, but as a side effect they can make it difficult to visualize current movements.\n' +
  'Low values increase noise, and as a side effect it generates a lot of pollution and false flags.'
var string TOOLTIP_4    = 'This will show the ATR (Average True Range)'
var string TOOLTIP_6    = 'Values used in normalization range'
var string TOOLTIP_7    = 'Calculates the index dividing by historical volatility, that is, obtaining the ratio between candle variation and historical volatility.'
var string TOOLTIP_8    = 'Individual colors do not apply when the theme is not the default'
var string SMA          = 'Simple Moving Average'
var string EMA          = 'Exponential Moving Average'
var string HMA          = 'Hull Moving Average'
var string ALMA         = 'Arnaud Legoux Moving Average'
var string MEDIAN       = 'Median'
var string VWAP         = 'VWAP'
var color TRANSPARENT   = color.new(color.white, 100)

var arrayColorBGR = array.new_color(na)
var arrayColorBR = array.new_color(na)
if barstate.isfirst
    array.push ( arrayColorBGR, #0000FF )
    array.push ( arrayColorBGR, #000AFF ), array.push ( arrayColorBGR, #0014FF ), array.push ( arrayColorBGR, #001FFF ), array.push ( arrayColorBGR, #0029FF ), array.push ( arrayColorBGR, #0033FF ),
    array.push ( arrayColorBGR, #003DFF ), array.push ( arrayColorBGR, #0047FF ), array.push ( arrayColorBGR, #0052FF ), array.push ( arrayColorBGR, #005CFF ), array.push ( arrayColorBGR, #0066FF ),
    array.push ( arrayColorBGR, #0070FF ), array.push ( arrayColorBGR, #007AFF ), array.push ( arrayColorBGR, #0085FF ), array.push ( arrayColorBGR, #008FFF ), array.push ( arrayColorBGR, #0099FF ),
    array.push ( arrayColorBGR, #00A3FF ), array.push ( arrayColorBGR, #00ADFF ), array.push ( arrayColorBGR, #00B8FF ), array.push ( arrayColorBGR, #00C2FF ), array.push ( arrayColorBGR, #00CCFF ),
    array.push ( arrayColorBGR, #00D6FF ), array.push ( arrayColorBGR, #00E0FF ), array.push ( arrayColorBGR, #00EBFF ), array.push ( arrayColorBGR, #00F5FF ), array.push ( arrayColorBGR, #00FFFF ),
    array.push ( arrayColorBGR, #00FFF5 ), array.push ( arrayColorBGR, #00FFEB ), array.push ( arrayColorBGR, #00FFE0 ), array.push ( arrayColorBGR, #00FFD6 ), array.push ( arrayColorBGR, #00FFCC ),
    array.push ( arrayColorBGR, #00FFC2 ), array.push ( arrayColorBGR, #00FFB8 ), array.push ( arrayColorBGR, #00FFAD ), array.push ( arrayColorBGR, #00FFA3 ), array.push ( arrayColorBGR, #00FF99 ),
    array.push ( arrayColorBGR, #00FF8F ), array.push ( arrayColorBGR, #00FF85 ), array.push ( arrayColorBGR, #00FF7A ), array.push ( arrayColorBGR, #00FF70 ), array.push ( arrayColorBGR, #00FF66 ),
    array.push ( arrayColorBGR, #00FF5C ), array.push ( arrayColorBGR, #00FF52 ), array.push ( arrayColorBGR, #00FF47 ), array.push ( arrayColorBGR, #00FF3D ), array.push ( arrayColorBGR, #00FF33 ),
    array.push ( arrayColorBGR, #00FF29 ), array.push ( arrayColorBGR, #00FF1F ), array.push ( arrayColorBGR, #00FF14 ), array.push ( arrayColorBGR, #00FF0A ), array.push ( arrayColorBGR, #00FF00 ),
    array.push ( arrayColorBGR, #0AFF00 ), array.push ( arrayColorBGR, #14FF00 ), array.push ( arrayColorBGR, #1FFF00 ), array.push ( arrayColorBGR, #29FF00 ), array.push ( arrayColorBGR, #33FF00 ),
    array.push ( arrayColorBGR, #3DFF00 ), array.push ( arrayColorBGR, #47FF00 ), array.push ( arrayColorBGR, #52FF00 ), array.push ( arrayColorBGR, #5CFF00 ), array.push ( arrayColorBGR, #66FF00 ),
    array.push ( arrayColorBGR, #70FF00 ), array.push ( arrayColorBGR, #7AFF00 ), array.push ( arrayColorBGR, #85FF00 ), array.push ( arrayColorBGR, #8FFF00 ), array.push ( arrayColorBGR, #99FF00 ),
    array.push ( arrayColorBGR, #A3FF00 ), array.push ( arrayColorBGR, #ADFF00 ), array.push ( arrayColorBGR, #B8FF00 ), array.push ( arrayColorBGR, #C2FF00 ), array.push ( arrayColorBGR, #CCFF00 ),
    array.push ( arrayColorBGR, #D6FF00 ), array.push ( arrayColorBGR, #E0FF00 ), array.push ( arrayColorBGR, #EBFF00 ), array.push ( arrayColorBGR, #F5FF00 ), array.push ( arrayColorBGR, #FFFF00 ),
    array.push ( arrayColorBGR, #FFF500 ), array.push ( arrayColorBGR, #FFEB00 ), array.push ( arrayColorBGR, #FFE000 ), array.push ( arrayColorBGR, #FFD600 ), array.push ( arrayColorBGR, #FFCC00 ),
    array.push ( arrayColorBGR, #FFC200 ), array.push ( arrayColorBGR, #FFB800 ), array.push ( arrayColorBGR, #FFAD00 ), array.push ( arrayColorBGR, #FFA300 ), array.push ( arrayColorBGR, #FF9900 ),
    array.push ( arrayColorBGR, #FF8F00 ), array.push ( arrayColorBGR, #FF8500 ), array.push ( arrayColorBGR, #FF7A00 ), array.push ( arrayColorBGR, #FF7000 ), array.push ( arrayColorBGR, #FF6600 ),
    array.push ( arrayColorBGR, #FF5C00 ), array.push ( arrayColorBGR, #FF5200 ), array.push ( arrayColorBGR, #FF4700 ), array.push ( arrayColorBGR, #FF3D00 ), array.push ( arrayColorBGR, #FF3300 ),
    array.push ( arrayColorBGR, #FF2900 ), array.push ( arrayColorBGR, #FF1F00 ), array.push ( arrayColorBGR, #FF1400 ), array.push ( arrayColorBGR, #FF0000 ), array.push ( arrayColorBGR, #FF0000 )
    
    array.push ( arrayColorBR, #0000FF )
    array.push ( arrayColorBR, #0200FC ), array.push ( arrayColorBR, #0500F9 ), array.push ( arrayColorBR, #0700F7 ), array.push ( arrayColorBR, #0A00F4 ), array.push ( arrayColorBR, #0C00F2 ),
    array.push ( arrayColorBR, #0F00EF ), array.push ( arrayColorBR, #1100ED ), array.push ( arrayColorBR, #1400EA ), array.push ( arrayColorBR, #1600E8 ), array.push ( arrayColorBR, #1900E5 ),
    array.push ( arrayColorBR, #1C00E2 ), array.push ( arrayColorBR, #1E00E0 ), array.push ( arrayColorBR, #2100DD ), array.push ( arrayColorBR, #2300DB ), array.push ( arrayColorBR, #2600D8 ),
    array.push ( arrayColorBR, #2800D6 ), array.push ( arrayColorBR, #2B00D3 ), array.push ( arrayColorBR, #2D00D1 ), array.push ( arrayColorBR, #3000CE ), array.push ( arrayColorBR, #3300CC ),
    array.push ( arrayColorBR, #3500C9 ), array.push ( arrayColorBR, #3800C6 ), array.push ( arrayColorBR, #3A00C4 ), array.push ( arrayColorBR, #3D00C1 ), array.push ( arrayColorBR, #3F00BF ),
    array.push ( arrayColorBR, #4200BC ), array.push ( arrayColorBR, #4400BA ), array.push ( arrayColorBR, #4700B7 ), array.push ( arrayColorBR, #4900B5 ), array.push ( arrayColorBR, #4C00B2 ),
    array.push ( arrayColorBR, #4F00AF ), array.push ( arrayColorBR, #5100AD ), array.push ( arrayColorBR, #5400AA ), array.push ( arrayColorBR, #5600A8 ), array.push ( arrayColorBR, #5900A5 ),
    array.push ( arrayColorBR, #5B00A3 ), array.push ( arrayColorBR, #5E00A0 ), array.push ( arrayColorBR, #60009E ), array.push ( arrayColorBR, #63009B ), array.push ( arrayColorBR, #660099 ),
    array.push ( arrayColorBR, #680096 ), array.push ( arrayColorBR, #6B0093 ), array.push ( arrayColorBR, #6D0091 ), array.push ( arrayColorBR, #70008E ), array.push ( arrayColorBR, #72008C ),
    array.push ( arrayColorBR, #750089 ), array.push ( arrayColorBR, #770087 ), array.push ( arrayColorBR, #7A0084 ), array.push ( arrayColorBR, #7C0082 ), array.push ( arrayColorBR, #7F007F ),
    array.push ( arrayColorBR, #82007C ), array.push ( arrayColorBR, #84007A ), array.push ( arrayColorBR, #870077 ), array.push ( arrayColorBR, #890075 ), array.push ( arrayColorBR, #8C0072 ),
    array.push ( arrayColorBR, #8E0070 ), array.push ( arrayColorBR, #91006D ), array.push ( arrayColorBR, #93006B ), array.push ( arrayColorBR, #960068 ), array.push ( arrayColorBR, #990066 ),
    array.push ( arrayColorBR, #9B0063 ), array.push ( arrayColorBR, #9E0060 ), array.push ( arrayColorBR, #A0005E ), array.push ( arrayColorBR, #A3005B ), array.push ( arrayColorBR, #A50059 ),
    array.push ( arrayColorBR, #A80056 ), array.push ( arrayColorBR, #AA0054 ), array.push ( arrayColorBR, #AD0051 ), array.push ( arrayColorBR, #AF004F ), array.push ( arrayColorBR, #B2004C ),
    array.push ( arrayColorBR, #B50049 ), array.push ( arrayColorBR, #B70047 ), array.push ( arrayColorBR, #BA0044 ), array.push ( arrayColorBR, #BC0042 ), array.push ( arrayColorBR, #BF003F ),
    array.push ( arrayColorBR, #C1003D ), array.push ( arrayColorBR, #C4003A ), array.push ( arrayColorBR, #C60038 ), array.push ( arrayColorBR, #C90035 ), array.push ( arrayColorBR, #CC0033 ),
    array.push ( arrayColorBR, #CE0030 ), array.push ( arrayColorBR, #D1002D ), array.push ( arrayColorBR, #D3002B ), array.push ( arrayColorBR, #D60028 ), array.push ( arrayColorBR, #D80026 ),
    array.push ( arrayColorBR, #DB0023 ), array.push ( arrayColorBR, #DD0021 ), array.push ( arrayColorBR, #E0001E ), array.push ( arrayColorBR, #E2001C ), array.push ( arrayColorBR, #E50019 ),
    array.push ( arrayColorBR, #E80016 ), array.push ( arrayColorBR, #EA0014 ), array.push ( arrayColorBR, #ED0011 ), array.push ( arrayColorBR, #EF000F ), array.push ( arrayColorBR, #F2000C ),
    array.push ( arrayColorBR, #F4000A ), array.push ( arrayColorBR, #F70007 ), array.push ( arrayColorBR, #F90005 ), array.push ( arrayColorBR, #FC0002 ), array.push ( arrayColorBR, #FF0000 )    
// ------------------------- }

// ------------------------- Inputs {

//---------------------
// LS Index
//---------------------
// Moving Average of Price
float srcMaPrice            = input.source(defval=close, title='Source', inline='1', group=GROUP_MA, tooltip=TOOLTIP_1)
var string typeMaPrice      = input.string(defval=EMA, title='Type',
  options=[SMA, EMA, HMA, ALMA, MEDIAN, VWAP],
  inline='1', group=GROUP_MA)
var int lenMaPrice          = input.int(defval=55, title='Length', inline='1', minval=1, group=GROUP_MA)

// LS Volatility Index
var int lenHistVol          = input.int(defval=89, title='Length for Historical Volatility', inline='4', minval=1, group=GROUP_LS)
var int lenNormal           = input.int(defval=89, title='Normalization Length', inline='5', minval=1, tooltip=TOOLTIP_2, group=GROUP_LS)
var color colorBottom       = input.color(defval=color.new(#3af13c, 0), title='Bottom', inline='6', group=GROUP_LS)
var int lowerEndLs          = input.int(defval=0, title='', inline='6', group=GROUP_LS, tooltip=TOOLTIP_6)
var color colorTop          = input.color(defval=color.new(#ff0000, 0), title='Top', inline='6', group=GROUP_LS)
var int upperEndLs          = input.int(defval=100, title='', inline='6', group=GROUP_LS, tooltip=TOOLTIP_6)

// Smooth LS
var bool boolSmoothLS       = input.bool(defval=false, title='Smooth indicator?', inline='10', group=GROUP_LS)
var string typeMaSmooth     = input.string(defval=EMA, title='Type', 
  options=[SMA, EMA, HMA, ALMA], inline='10', group=GROUP_LS)
var int lenSmoothLS         = input.int(defval=5, title='Length', inline='10', minval=1, group=GROUP_LS)

// Moving Average of LS
var bool showMaLS           = input.bool(defval=true, title='Show moving average?', inline='20', group=GROUP_LS)
var string typeMaLS         = input.string(defval=EMA, title='Type', 
  options=[SMA, EMA, HMA, ALMA, MEDIAN], inline='20', group=GROUP_LS)
var int lenMaLS             = input.int(defval=5, title='Length', inline='20', minval=1, group=GROUP_LS)

var color colorMaLS         = input.color(defval=color.white, title='Color of MA', inline='21', group=GROUP_LS)
var bool alterColorMaLs     = input.bool(defval=false, title='Change color of MA when above or bellow indicator?', inline='21', group=GROUP_LS)
var color colorAboveMaLS    = input.color(defval=color.new(#ff0000, 0), title='MA bellow indicator', inline='22', group=GROUP_LS)
var color colorBellowMaLS   = input.color(defval=color.new(#3af13c, 0), title='MA above indicator', inline='22', group=GROUP_LS)
var bool ribbonMaLs         = input.bool(defval=false, title='Apply ribbon filling between indicator and MA?', inline='23', group=GROUP_LS)

// Theme
var string themeLS          = input.string(defval='Default', title='Theme for LS', 
  options=['Default', 'Spectrum Blue-Green-Red', 'Spectrum Blue-Red'], inline='25', group=GROUP_LS, tooltip=TOOLTIP_8)

//--> Alerts
// Markers
var bool showMarkers        = input.bool(defval=true, title='Show markers when indicator reaches limit?', inline='30', group=GROUP_LS_AL)
var color colorMarkerBottom = input.color(defval=color.new(#3af13c, 0), title='Bottom', inline='31', group=GROUP_LS_AL)
var int bottomMarkerLS      = input.int(defval=0, title='', inline='31', group=GROUP_LS_AL)
var color colorMarkerTop    = input.color(defval=color.new(#ff0000, 0), title='Top', inline='31', group=GROUP_LS_AL)
var int topMarkerLS         = input.int(defval=100, title='', inline='31', group=GROUP_LS_AL)

// Fill Background
var bool showFill           = input.bool(defval=false, title='Fill background when indicator reaches limit?', inline='40', group=GROUP_LS_AL)
var color colorNearBg       = input.color(defval=color.new(#3af13c, 75), title='Bottom', inline='41', group=GROUP_LS_AL)
var int bottomFillLS        = input.int(defval=0, title='', inline='41', group=GROUP_LS_AL)
var color colorFarBg        = input.color(defval=color.new(#ff0000, 75), title='Top', inline='41', group=GROUP_LS_AL)
var int topFillLS           = input.int(defval=100, title='', inline='41', group=GROUP_LS_AL)

// Bar Color
var bool showBarColor       = input.bool(defval=true, title='Change bar color when indicator reaches limit?', inline='50', group=GROUP_LS_AL)
var color colorNearBar      = input.color(defval=color.new(#1101ff, 0), title='Bottom', inline='51', group=GROUP_LS_AL)
var int bottomBarLS         = input.int(defval=0, title='', inline='51', group=GROUP_LS_AL)
var color colorFarBar       = input.color(defval=color.new(#1101ff, 0), title='Top', inline='51', group=GROUP_LS_AL)
var int topBarLS            = input.int(defval=100, title='', inline='51', group=GROUP_LS_AL)

// Cross
var bool crossLS            = input.bool(defval=false, title='Show marker when indicator crosses moving average?', inline='52', group=GROUP_LS_AL)
var color colorCrossOver    = input.color(defval=color.new(#ff0000, 0), title='Cross Over', inline='53', group=GROUP_LS_AL)
var color colorCrossUnder   = input.color(defval=color.new(#3af13c, 0), title='Cross Under', inline='53', group=GROUP_LS_AL)

var bool showFillCross      = input.bool(defval=false, title='Fill background when indicator crosses MA?', inline='54', group=GROUP_LS_AL)
var color colorCrossOverBg  = input.color(defval=color.new(#ff0000, 75), title='Cross Over', inline='55', group=GROUP_LS_AL)
var color colorCrossUnderBg = input.color(defval=color.new(#3af13c, 75), title='Cross Under', inline='55', group=GROUP_LS_AL)

//---------------------
// ATR
//---------------------
var bool showATRvol         = input.bool(defval=true, title='Show ATR?', inline='60', group=GROUP_ATR, tooltip=TOOLTIP_4)
var int lenATR              = input.int(defval=1, minval=1, title='Length', inline='60', group=GROUP_ATR, tooltip=TOOLTIP_4)

var bool calcHistVol        = input.bool(defval=true, title='Consider Historical Volatility?', inline='61', group=GROUP_ATR, tooltip=TOOLTIP_7)

var color colorATRbottom    = input.color(defval=color.new(#0EEAFF, 50), title='Bottom', inline='62', group=GROUP_ATR)
var int bottomATR           = input.int(defval=0, title='', inline='62', group=GROUP_ATR)
var color colorATRtop       = input.color(defval=color.new(#1101ff, 0), title='Top', inline='62', group=GROUP_ATR)
var int topATR              = input.int(defval=100, title='', inline='62', group=GROUP_ATR, tooltip=TOOLTIP_6)

// Smooth
var bool boolSmoothATR      = input.bool(defval=true, title='Smooth ATR?', inline='65', group=GROUP_ATR)
var string typeMaSmoothATR  = input.string(defval=EMA, title='Type', 
  options=[SMA, EMA, HMA, ALMA], inline='65', group=GROUP_ATR)
var int lenSmoothATR        = input.int(defval=5, title='Length', inline='65', minval=1, group=GROUP_ATR)

// Theme
var string themeATR         = input.string(defval='Spectrum Blue-Red', title='Theme for ATR', 
  options=['Default', 'Spectrum Blue-Green-Red', 'Spectrum Blue-Red'], inline='66', group=GROUP_ATR, tooltip=TOOLTIP_8)

// --> Alerts
// Markers
var bool showMarkersATR     = input.bool(defval=true, title='Show markers when indicator reaches limit?', inline='70', group=GROUP_ATR_AL)
var color colorMarkerATRbot = input.color(defval=color.new(#3af13c, 0), title='Bottom', inline='71', group=GROUP_ATR_AL)
var int bottomMarkerATR     = input.int(defval=5, title='', inline='71', group=GROUP_ATR_AL)
var color colorMarkerATRtop = input.color(defval=color.new(#ff0000, 0), title='Top', inline='71', group=GROUP_ATR_AL)
var int topMarkerATR        = input.int(defval=65, title='', inline='71', group=GROUP_ATR_AL)

// Fill Background
var bool showFillATR        = input.bool(defval=false, title='Fill background when indicator reaches limit?', inline='80', group=GROUP_ATR_AL)
var color colorNearBgATR    = input.color(defval=color.new(#3af13c, 75), title='Bottom', inline='81', group=GROUP_ATR_AL)
var int bottomFillATR       = input.int(defval=5, title='', inline='81', group=GROUP_ATR_AL)
var color colorFarBgATR     = input.color(defval=color.new(#ff0000, 75), title='Top', inline='81', group=GROUP_ATR_AL)
var int topFillATR          = input.int(defval=65, title='', inline='81', group=GROUP_ATR_AL)

// Bar Color
var bool showBarColorATR    = input.bool(defval=true, title='Change bar color when indicator reaches limit?', inline='90', group=GROUP_ATR_AL)
var color colorNearBarATR   = input.color(defval=color.new(#1101ff, 0), title='Bottom', inline='91', group=GROUP_ATR_AL)
var int bottomBarATR        = input.int(defval=5, title='', inline='91', group=GROUP_ATR_AL)
var color colorFarBarATR    = input.color(defval=color.new(#1101ff, 0), title='Top', inline='91', group=GROUP_ATR_AL)
var int topBarATR           = input.int(defval=65, title='', inline='91', group=GROUP_ATR_AL)

// ------------------------- }

// ------------------------- Historical Volatility {
fHistoricalVolatility() =>
    historicalVolatility = 0.0
    
    xATR = ta.atr(lenHistVol)
    historicalVolatility := ((lenHistVol - 1) * nz(historicalVolatility[1], 0) + xATR) / lenHistVol
// ------------------------- }

// ------------------------- Moving Average {
fCalcMa(series float src, simple string type, simple int len) =>
    maRet = switch type
        SMA => ta.sma(src, len)
        EMA => ta.ema(src, len)
        HMA => ta.hma(src, len)
        ALMA => ta.alma(src, len, 0.85, 6, false)
        MEDIAN => ta.median(src, len)
        VWAP => ta.vwap(src)
// ------------------------- }

// ------------------------- Normalization {
fNormalize(series float src, simple int len, simple float _lowerEnd, simple float _upperEnd) =>
    min = ta.lowest(source=src, length=len)
    max = ta.highest(source=src, length=len)
    valueNormal = _lowerEnd + ( (src - min) * (_upperEnd - _lowerEnd)/(max - min) )
// ------------------------- }


// ------------------------- LS Volatility Index {
ma = fCalcMa(srcMaPrice, typeMaPrice, lenMaPrice)
distance = math.abs ( (high >= ma ? high : low) - ma) / ma
distance := distance * 100
historicalVolatility = fHistoricalVolatility()
lsVolatility = (distance/historicalVolatility) * 100

// Normalization
lsNormalized = fNormalize(src=lsVolatility, len=lenNormal, _lowerEnd=lowerEndLs, _upperEnd=upperEndLs)

// Smooth
if boolSmoothLS
    lsNormalized := fCalcMa(lsNormalized, typeMaSmooth, lenSmoothLS)

// Moving Average of LS Volatility Index
float maLS = na
if showMaLS
    maLS := fCalcMa(lsNormalized, typeMaLS, lenMaLS)
// ------------------------- }

// ------------------------- ATR {
float candleAmplitude =  ta.atr(lenATR)      // na(high[1])? high-low : math.max(math.max(high - low, math.abs(high - close[1])), math.abs(low - close[1]))
atrVolatilityIndex = if calcHistVol
    (candleAmplitude/historicalVolatility) * 100
else
    candleAmplitude

// Normalization
atrVolatilityIndexNormal = fNormalize(src=atrVolatilityIndex, len=lenNormal, _lowerEnd=bottomATR, _upperEnd=topATR)

// Smooth
if boolSmoothATR
    atrVolatilityIndexNormal := fCalcMa(atrVolatilityIndexNormal, typeMaSmoothATR, lenSmoothATR)
// ------------------------- }

// ------------------------- Colors {
fSetColorBGR(percent) =>
    array.get ( arrayColorBGR, math.round ( percent ) )

fSetColorBR(percent) =>
    array.get ( arrayColorBR, math.round ( percent ) )    
// ------------------------- }

// ------------------------- Plots - LS Volatility Index {
colorLS = switch themeLS
    'Default' => color.from_gradient(lsNormalized > lsNormalized[1] ? lsNormalized : lsNormalized[1], lowerEndLs, upperEndLs, colorBottom, colorTop)
    'Spectrum Blue-Green-Red' => fSetColorBGR(lsNormalized)
    'Spectrum Blue-Red' => fSetColorBR(lsNormalized)

colorMaLS := if alterColorMaLs
    if lsNormalized > maLS
        colorAboveMaLS
    else
        colorBellowMaLS        
else
    colorMaLS
    
lsPlot = plot(lsNormalized, color=colorLS, linewidth=2, title='LS Volatility Index')
maLsPlot = plot(maLS, color=colorMaLS, linewidth=2, title='Moving Average of LS Volatility Index')

// Lines
hLine000 = hline(0, color=TRANSPARENT, linestyle=hline.style_dotted, title='Botton Line')
hLine030 = hline(30, color=color.new(#ff0000, 0), linestyle=hline.style_dotted, title='Alert of Volatility')
hLine100 = hline(100, color=TRANSPARENT, linestyle=hline.style_dotted, title='Top Line')

plotchar(showMarkers and lsNormalized<=bottomMarkerLS ? lsNormalized : na, title='Marker when indicator reachs bottom', color=colorMarkerBottom, location=location.absolute, char='●', size=size.tiny)
plotchar(showMarkers and lsNormalized>=topMarkerLS ? lsNormalized : na, title='Marker when indicator reachs top', color=colorMarkerTop, location=location.absolute, char='●', size=size.tiny)


colorFillLsBottom = if showFill
    if lsNormalized <= bottomFillLS or lsNormalized[1] <= bottomFillLS
        colorNearBg
    else
        na
else
    na
    
colorFillLsTop = if showFill
    if lsNormalized >= topFillLS or lsNormalized[1] >= topFillLS
        colorFarBg
    else
        na
else
    na
    
fill(hLine000, hLine100, color=colorFillLsBottom, title='Fill background when indicator reachs bottom')
fill(hLine000, hLine100, color=colorFillLsTop, title='Fill background when indicator reachs top')

barcolor(barstate.isconfirmed and showBarColor and lsNormalized <= bottomBarLS ? colorNearBar : na, title='Bar color when indicator reachs bottom')
barcolor(barstate.isconfirmed and showBarColor and lsNormalized >= topBarLS ? colorFarBar : na, title='Bar color when indicator reachs top')

fill(lsPlot, maLsPlot, color=showMaLS and ribbonMaLs ? colorLS : na, title='Ribbon filling between indicator and MA')

// Crossover
plotshape(crossLS and ta.crossover(lsNormalized, maLS) ? maLS : na, title="Crossover", location=location.absolute, style=shape.xcross, size=size.tiny, color=colorCrossOver)
plotshape(crossLS and ta.crossunder(lsNormalized, maLS) ? maLS : na, title="Crossunder", location=location.absolute, style=shape.xcross, size=size.tiny, color=colorCrossUnder)

color _colorCrossOverBg = if showFillCross
    if ta.crossover(lsNormalized, maLS)
        colorCrossOverBg
    else
        na
else
    na
    
color _colorCrossUnderBg = if showFillCross
    if ta.crossunder(lsNormalized, maLS)
        colorCrossUnderBg
    else
        na
else
    na

fill(hLine000, hLine100, color=_colorCrossOverBg, title='Fill background when indicator cross over MA')
fill(hLine000, hLine100, color=_colorCrossUnderBg, title='Fill background when indicator cross under MA')

// ------------------------- }

// ------------------------- Plots - ATR {
colorAtr = if showATRvol
    switch themeATR
        'Default' => color.from_gradient(atrVolatilityIndexNormal > atrVolatilityIndexNormal[1] ? atrVolatilityIndexNormal : atrVolatilityIndexNormal[1], bottomATR, topATR, colorATRbottom, colorATRtop)
        'Spectrum Blue-Green-Red' => fSetColorBGR(atrVolatilityIndexNormal)
        'Spectrum Blue-Red' => fSetColorBR(atrVolatilityIndexNormal)    
else
    na

plot(atrVolatilityIndexNormal, color=colorAtr, linewidth=1, title='ATR', style=plot.style_histogram)

barcolor(showATRvol and barstate.isconfirmed and showBarColorATR and atrVolatilityIndexNormal <= bottomBarATR ? colorNearBarATR : na, title='Bar color when ATR reachs bottom')
barcolor(showATRvol and barstate.isconfirmed and showBarColorATR and atrVolatilityIndexNormal >= topBarATR ? colorFarBarATR : na, title='Bar color when ATR reachs top')

plotchar(showATRvol and showMarkersATR and atrVolatilityIndexNormal <= bottomMarkerATR ? bottomATR : na, title='Marker when ATR reachs bottom', color=colorMarkerATRbot, location=location.absolute, char='▪', size=size.tiny)
plotchar(showATRvol and showMarkersATR and atrVolatilityIndexNormal >= topMarkerATR ? atrVolatilityIndexNormal : na, title='Marker when ATR reachs top', color=colorMarkerATRtop, location=location.absolute, char='▪', size=size.tiny)

colorFillAtrBottom = if showFillATR 
    if atrVolatilityIndexNormal <= bottomFillATR or atrVolatilityIndexNormal[1] <= bottomFillATR
        colorNearBgATR
    else 
        na
else
    na
    
colorFillAtrTop = if showFillATR
    if atrVolatilityIndexNormal >= topFillATR or atrVolatilityIndexNormal[1] >= topFillATR
        colorFarBgATR
    else 
        na
else
    na

fill(hLine000, hLine100, color=colorFillAtrBottom, title='Fill background when ATR reachs bottom')
fill(hLine000, hLine100, color=colorFillAtrTop, title='Fill background when ATR reachs top')
// ------------------------- }

Overview

LS Volatility Index computes the percentage distance of the current price from the chosen source (such as close or open) and normalizes this value by historical volatility, producing a 0-to-100 scale where 0 indicates price at the average and 100 shows extreme deviation. The indicator plots in a separate pane and supports smoothing, additional moving averages, color theming, and background fills for limit zones. It helps identify mean-reversion opportunities when prices stretch far from the average or trend-following setups when values remain within normal ranges, while also flagging potential crashes or divergences.

Details

Published by

andreperez on GitHub

Draws

Separate pane below the chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

pinescriptpinescript-algorithmspinescript-indicatorsstormertradingtradingviewtradingview-chart-analysisls-volatilitytechincal-analysis

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
SourcesourceclosesrcMaPrice
TypestringEMAtypeMaPrice
Lengthint55lenMaPrice
Length for Historical Volatilityint89lenHistVol
Normalization Lengthint89lenNormal
Bottomcolorcolor.new(#3af13c, 0)colorBottom
lowerEndLsint0lowerEndLs
Topcolorcolor.new(#ff0000, 0)colorTop
upperEndLsint100upperEndLs
Smooth indicator?boolfalseboolSmoothLS
TypestringEMAtypeMaSmooth
Lengthint5lenSmoothLS
Show all 40 settings
SettingTypeDefaultVariable
Show moving average?booltrueshowMaLS
TypestringEMAtypeMaLS
Lengthint5lenMaLS
Color of MAcolorcolor.whitecolorMaLS
Change color of MA when above or bellow indicator?boolfalsealterColorMaLs
MA bellow indicatorcolorcolor.new(#ff0000, 0)colorAboveMaLS
MA above indicatorcolorcolor.new(#3af13c, 0)colorBellowMaLS
Apply ribbon filling between indicator and MA?boolfalseribbonMaLs
Theme for LSstringDefaultthemeLS
Show markers when indicator reaches limit?booltrueshowMarkers
Bottomcolorcolor.new(#3af13c, 0)colorMarkerBottom
bottomMarkerLSint0bottomMarkerLS
Topcolorcolor.new(#ff0000, 0)colorMarkerTop
topMarkerLSint100topMarkerLS
Fill background when indicator reaches limit?boolfalseshowFill
Bottomcolorcolor.new(#3af13c, 75)colorNearBg
bottomFillLSint0bottomFillLS
Topcolorcolor.new(#ff0000, 75)colorFarBg
topFillLSint100topFillLS
Change bar color when indicator reaches limit?booltrueshowBarColor
Bottomcolorcolor.new(#1101ff, 0)colorNearBar
bottomBarLSint0bottomBarLS
Topcolorcolor.new(#1101ff, 0)colorFarBar
topBarLSint100topBarLS
Show marker when indicator crosses moving average?boolfalsecrossLS
Cross Overcolorcolor.new(#ff0000, 0)colorCrossOver
Cross Undercolorcolor.new(#3af13c, 0)colorCrossUnder
Fill background when indicator crosses MA?boolfalseshowFillCross
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

3 stars

This indicator demonstrates debugging visualization patterns for Pine Script. It plots value tracking with mean, min, and max reference lines, condition markers using shapes and arrows, historical comparisons with standard deviation bands, multi-series overlay

Indicator v5 Moving averagesVolatility & bands
Updated 7 months ago · None stated GitHub repository of Debugging Visualization Patterns
3 stars

The Linchuan Event Indicator plots multi-timeframe opening price zones alongside key moving averages and Bollinger Bands in a separate indicator pane. It tracks opening price lines and colored expansion zones across 5-minute, 30-minute, 1-hour, and 4-hour time

Indicator v5 Support & resistanceMoving averages
Updated 5 months ago · None stated GitHub repository of Linchuan Event Indicator

This indicator calculates dynamic grid trading boundaries derived from Bollinger Bands to define upper, lower, and middle range levels. It computes moving average basis lines and standard deviation bands, applying user-defined offsets, smoothing, and minimum o

Indicator v6 Volatility & bandsSupport & resistance Repaints
Updated 8 months ago · MIT GitHub repository of Grid Bot Bollinger Bands [psyll]

Composite Market Bias

by mrme000m
1 stars

Composite Market Bias is a separate-pane indicator that scores bullish and bearish conditions from RSI, fast versus slow EMA, MACD histogram, Bollinger Band position, and price versus a 50-period EMA. It plots the resulting bias score with RSI, EMA trend, MACD

Indicator v5 Oscillators & momentumMoving averages
Updated 7 weeks ago · None stated GitHub repository of Composite Market Bias

Snag - VWAP

by dearvn
257 stars

This indicator plots a custom Anchored Volume-Weighted Average Price (VWAP) directly on the price chart along with optional standard deviation bands. Users can anchor the VWAP to standard time periods like sessions, weeks, or months, or to corporate events suc

Indicator v5 Moving averagesVolatility & bands Repaints
Updated 7 weeks ago · None stated GitHub repository of Snag - VWAP

More Volatility & bands scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers