Library · Pine Script v6 · Library

ta

by alvinng214· code credited to TradingView

This Pine Script library exports multiple technical analysis functions for use in TradingView indicators and strategies.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code2,141
Settings0inputs
LicenceNone statedfile: MPL-2.0
Last update2 months ago5 Aug 2026

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 library, select all of the template text and paste. Press Save and give it a name.
  4. 4Publish or import itA library draws nothing. Publish it from the editor, then import its functions in your own scripts.

Source Code

2,141 lines of Pine Script v6 from S1_Silver_Bullet/ta.txt, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

ta.txt
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/

// © TradingView



//@version=6

library("ta")



// "ta" Library

// v12, 2025.12.06



// This code's style is based on the recommendations from the Pine Script User Manual's Style guide:

//    https://www.tradingview.com/pine-script-docs/writing/style-guide/







import TradingView/RelativeValue/3 as TVrv







// This library exports the following functions:



// • ao():                     Awesome Oscillator

// • aroon():                  Aroon Indicator

// • atr2():                   Average True Range (Alternative version)

// • cagr():                   Compound Annual Growth Rate

// • chandelier():             Chandelier Exit

// • chandelier2():            Chandelier Exit (Alternative version)

// • changePercent():          Calculate percentage change

// • coppock():                Coppock Curve

// • dema():                   Double Exponential Moving Average

// • dema2():                  Double Exponential Moving Average (Alternative version)

// • dm():                     Demarker Indicator

// • donchian():               Donchian Channel

// • ema2():                   Exponential Moving Average (Alternative version)

// • eom():                    Ease of Movement

// • er():                     Kaufman's Efficiency Ratio

// • frama():                  Fractal Adaptive Moving Average

// • ft():                     Fisher Transform

// • highestSince():           Highest value since condition

// • ht():                     Hilbert Transform function

// • ichimoku():               Ichimoku Cloud

// • ift():                    Inverse Fisher Transform

// • kama():                   Kaufman's Adaptive Moving Average

// • kvo():                    Klinger Volume Oscillator

// • lowestSince():            Lowest value since condition

// • macd2():                  Moving Average Convergence Divergence (Alternative version)

// • pmo():                    Price Momentum Oscillator

// • ppo():                    Percentage Price Oscillator

// • ppo2():                   Percentage Price Oscillator (Alternative version)

// • pzo():                    Price Zone Oscillator

// • relativeVolume():         Compare volume to its historical average

// • requestUpAndDownVolume(): Requests up/down volume data for a specified lower timeframe.

// • requestVolumeDelta():     Requests volume delta or cumulative volume delta from a specified lower timeframe.

// • rma2():                   Rolling Moving Average (Alternative version)

// • rms():                    Root Mean Square

// • rwi():                    Random Walk Index

// • specialK():               Pring's Special K

// • stc():                    Schaff Trend Cycle

// • stochFull():              Full Stochastic Oscillator

// • stochRsi():               Stochastic RSI

// • supertrend():             SuperTrend Indicator

// • supertrend2():            SuperTrend Indicator (Alternative version)

// • szo():                    Sentiment Zone Oscillator

// • t3():                     Tilson Moving Average (T3)

// • t3Alt():                  Tilson Moving Average (T3 Alternative version)

// • tema():                   Triple Exponential Moving Average

// • tema2():                  Triple Exponential Moving Average (Alternative version)

// • trima():                  Triangular Moving Average

// • trix():                   TRIX indicator

// • ulcerIndex():             Ulcer Index

// • uo():                     Ultimate Oscillator

// • vhf():                    Vertical Horizontal Filter

// • vi():                     Vortex Indicator

// • vStop():                  Volatility Stop

// • vStop2():                 Volatility Stop (Alternative version)

// • vzo():                    Volume Zone Oscillator

// • williamsFractal():        Williams' Fractal

// • wpo():                    Wave Period Oscillator







// @function                Calculates the dynamic Exponentially Weighted Moving Average used in

//                          multiple functions exported by this library.

// @param source            (series int/float) Series of values to process.

// @param alpha             (series int/float) The smoothing factor for the filter.

// @returns                 The dynamic exponentially weighted moving average value.

ewma(series float source, series float alpha) =>

    if alpha < 0

        runtime.error("Invalid smoothing factor. The value must not be negative.")

    float result = na

    result := alpha * source + (1.0 - alpha) * nz(result[1], source)





// @function                Calculates the value of the Awesome Oscillator.

// @param source            (series int/float) Series of values to process.

// @param shortLength       (simple int) Number of bars for the fast moving average.

// @param longLength        (simple int) Number of bars for the slow moving average.

// @returns                 (float) The oscillator value.

export ao(series float source = hl2, simple int shortLength = 5, simple int longLength = 34) =>

    float result = ta.sma(source, shortLength) - ta.sma(source, longLength)





// @function                Calculates the values of the Aroon indicator.

// @param length            (simple int) Number of bars (lookback length).

// @returns                 ([float, float]) A tuple of the Aroon-Up and Aroon-Down values.

export aroon(simple int length) =>

    float aroonDown = 100 * (ta.lowestbars(low,   length + 1) + length) / length

    float aroonUp   = 100 * (ta.highestbars(high, length + 1) + length) / length

    [aroonUp, aroonDown]





// @function                An alternative function to `ta.atr()` that supports a "series float" length value.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @returns                 (float) The ATR value.

export atr2(series float length) =>

    if length < 1

        runtime.error(str.format("Invalid length ({0}). The value must be greater than or equal to 1.", length))

    float alpha  = 1.0 / length

    float result = ewma(ta.tr(true), alpha)





// @function                Calculates the "Compound Annual Growth Rate" between two points in time.

// @param entryTime         (series int) The starting timestamp.

// @param entryPrice        (series int/float) The starting point's price.

// @param exitTime          (series int) The ending timestamp.

// @param exitPrice         (series int/float) The ending point's price.

// @returns                 (float) CAGR in % (50 is 50%). Returns `na` if there is not >=1D between `entryTime` and

//                          `exitTime`, or until the two time points have not been reached by the script.

export cagr(series int entryTime, series float entryPrice, series int exitTime, series float exitPrice) =>

    int   MS_IN_ONE_DAY = 24 * 60 * 60 * 1000

    float daysBetween = (exitTime - entryTime) / MS_IN_ONE_DAY

    float result = if daysBetween >= 1 and not (na(entryPrice) or na(exitPrice))

        float years = daysBetween / 365.

        float rate  = exitPrice / entryPrice

        100 * (math.pow(rate, 1 / years) - 1)

    else

        na





// @function                Calculates the long and short Chandelier Exit values. The long value subtracts

//                          Average True Range (ATR), multiplied by a specified amount, from the highest high over

//                          `length` bars. The short value adds the ATR to the lowest low over those bars.

// @param length            (series int) The number of bars for the highest high and lowest low.

// @param atrLength         (simple int) The ATR length.

// @param mult              (series int/float) The ATR multiplier.

// @returns                 ([float, float]) A tuple containing the following values:

//                           - The long Chandelier Exit value.

//                           - The short Chandelier Exit value.

export chandelier(series int length, simple int atrLength, series float mult) =>

    float atr = ta.atr(atrLength) * mult

    [ta.highest(length) - atr, ta.lowest(length) + atr]





// @function                An alternative function to `chandelier()` that supports a "series float" ATR length.

// @param length            (series int) The number of bars for the highest high and lowest low.

// @param atrLength         (series int/float) The ATR length.

// @param mult              (series int/float) The ATR multiplier.

// @returns                 ([float, float]) A tuple containing the following values:

//                           - The long Chandelier Exit value.

//                           - The short Chandelier Exit value.

export chandelier2(series int length, series float atrLength, series float mult) =>

    float atr = atr2(atrLength) * mult

    [ta.highest(length) - atr, ta.lowest(length) + atr]





// @function                Calculates the percentage difference between two values.

// @param newValue          (series int/float) The current value.

// @param oldValue          (series int/float) The previous value.

// @returns                 (float) The difference between `oldValue` and `newValue`, expressed as a percentage of

//                          `oldValue`.

export changePercent(series float newValue, series float oldValue) =>

    float result = 100 * (newValue - oldValue) / oldValue





// @function                Calculates the value of the Coppock Curve indicator.

// @param source            (series int/float) Series of values to process.

// @param longLength        (simple int) Number of bars back for the longer rate of change (ROC).

// @param shortLength       (simple int) Number of bars back for the shorter ROC.

// @param smoothLength      (simple int) Number of bars for the weigted moving average smoothing.

// @returns                 (float) The oscillator value.

export coppock(series float source, simple int longLength, simple int shortLength, simple int smoothLength) =>

    float result = ta.wma(ta.roc(source, longLength) + ta.roc(source, shortLength), smoothLength)





// @function                Calculates the value of the Double Exponential Moving Average (DEMA).

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The double exponentially weighted moving average of the `source`.

export dema(series float source, simple int length) =>

    float ema1   = ta.ema(source, length)

    float ema2   = ta.ema(ema1, length)

    float result = 2 * ema1 - ema2





// @function                An alternative function to `ta.ema()` that supports a "series float" length value.

// @param source            (series int/float) Series of values to process.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @returns                 (float) The exponentially weighted moving average of the `source`.

export ema2(series float source, series float length) =>

    if length < 1

        runtime.error(str.format("Invalid length ({0}). The value must be greater than or equal to 1.", length))

    float alpha  = 2.0 / (math.max(1.0, length) + 1.0)

    float result = ewma(source, alpha)





// @function                An alternative function to `dema()` that supports a "series float" length value.

// @param source            (series int/float) Series of values to process.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @returns                 (float) The double exponentially weighted moving average of the `source`.

export dema2(series float source, series float length) =>

    float ema1   = ema2(source, length)

    float ema2   = ema2(ema1, length)

    float result = 2 * ema1 - ema2





// @function                Calculates the value of the "Demarker" indicator.

//                          "DeMark®" is a registered trademark of DeMark Analytics, LLC. This code is neither

//                          endorsed, nor sponsored, nor affiliated with them.

// @param length            (simple int) Number of bars (lookback length).

// @returns                 (float) The oscillator value.

export dm(simple int length) =>

    float demax  =  math.max(ta.change(high), 0)

    float demin  = -math.min(ta.change(low),  0)

    float result =  ta.sma(demax, length) / (ta.sma(demax, length) + ta.sma(demin, length))





// @function                Calculates the values of a Donchian Channel using `high` and `low` over a given `length`.

// @param length            (series int) Number of bars (lookback length).

// @returns                 ([float, float, float]) A tuple containing the channel high, low, and median, respectively.

export donchian(series int length) =>

    float highest = ta.highest(length)

    float lowest  = ta.lowest(length)

    [highest, lowest, math.avg(highest, lowest)]





// @function                Calculates the value of the Ease of Movement indicator.

// @param length            (simple int) Number of bars (lookback length).

// @param div               (simple int) Optional. The factor for normalzing values. The default is 10000.

// @returns                 (float) The Ease of Movement value.

export eom(simple int length, simple int div = 10000) =>

    float result = ta.sma(div * ta.change(hl2) * (high - low) / volume, length)





// @function                Calculates Kaufman's Efficiency Ratio (ER), which represents the absolute change in a

//                          `source` series over `length` bars divided by the sum of absolute single-bar changes over

//                          the same length.

// @param source            (series int/float) Series of values to process.

// @param length            (series int) Number of bars (lookback length).

// @returns                 (float) The Efficiency Ratio of `source`.

export er(series float source, series int length) =>

    float absChange  = math.abs(ta.change(source, length))

    float sumChanges = math.sum(math.abs(ta.change(source)), length)

    float result = sumChanges == 0.0 ? 0.0 : absChange / sumChanges





// @function                Calculates the Fractal Adaptive Moving Average (FRAMA) by John Ehlers. FRAMA is an adaptive

//                          EMA-based filter that dynamically adjusts its smoothing factor based on fractal geometry.

// @param source            (series int/float) Series of values to process.

// @param length            (series int) Number of bars for the fractal dimension estimate.

// @returns                 (float) The Fractal Adaptive Moving Average of `source`.

export frama(series float source, series int length) =>

    int   len    = math.round(length / 2)

    float hh     = ta.highest(len)

    float ll     = ta.lowest(len)

    float n1     = (hh - ll) / len

    float n2     = (hh[len] - ll[len]) / len

    float n3     = (ta.highest(length) - ta.lowest(length)) / length

    float D      = math.log((n1 + n2) / n3) / math.log(2)

    float alpha  = math.exp(-4.6 * (D - 1))

    float result = ewma(source, alpha)





// @function                Calculates the value of the Fisher Transform indicator.

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Number of bars (lookback length).

// @returns                 (float) The oscillator value.

export ft(series float source, simple int length) =>

    float value1 = 0.0

    float fish   = 0.0

    float hh = ta.highest(source, length)

    float ll = ta.lowest(source,  length)

    value1 := 0.66 * ((source - ll) / (hh - ll) - 0.5) + 0.67 * nz(value1[1])

    float value2 = value1 > 0.99 ? 0.999 : value1 < -0.99 ? -0.999 : value1

    fish := 0.5 * math.log((1 + value2) / (1 - value2)) + 0.5 * nz(fish[1])

    float result = fish





// @function                Tracks the highest value of a series since the last occurrence of a condition.

// @param cond              (series bool) A condition which, when `true`, resets the tracking of the highest `source`.

// @param source            (series int/float) Optional. Series of values to process. The default is `high`.

// @returns                 (float) The highest `source` value since the last time the `cond` value was `true`.

export highestSince(series bool cond, series float source = high) =>

    var float result = na

    if cond

        result := source

    result := math.max(nz(source, result), nz(result, source))





// @function                Calculates the value of the Hilbert Transform indicator.

// @param source            (series int/float) Series of values to process.

// @returns                 (float) The oscillator value.

export ht(series float source) =>

    float result = 0.0962 * source + 0.5769 * nz(source[2]) - 0.5769 * nz(source[4]) - 0.0962 * nz(source[6])





// @function                Calculates the midpoint between the highest `high` and lowest `low` over `length` bars.

// @param length            (series int) Number of bars (lookback length).

// @returns                 The midpoint of the data.

midpoint(series int length) =>

    float result = math.avg(ta.highest(length), ta.lowest(length))





// @function                Calculates values of the Ichimoku Cloud indicator, including tenkan, kijun, senkouSpan1,

//                          senkouSpan2, and chikou.

//                          NOTE: offsets forward or backward can be done using the `offset` argument in `plot()`.

// @param conLength         (series int) Length for the Conversion Line (Tenkan). The default is 9 periods, which

//                          returns the midpoint of the 9 period Donchian Channel.

// @param baseLength        (series int) Length for the Base Line (Kijun-sen). The default is 26 periods, which returns

//                          the midpoint of the 26 period Donchian Channel.

// @param senkouLength      (series int) Length for the Senkou Span 2 (Leading Span B). The default is 52 periods,

//                          which returns the midpoint of the 52 period Donchian Channel.

// @returns                 ([float, float, float, float, float]) A tuple of the Tenkan, Kijun, Senkou Span 1,

//                          Senkou Span 2, and Chikou Span values. NOTE: by default, the senkouSpan1 and senkouSpan2

//                          should be plotted 26 periods in the future, and the Chikou Span plotted 26 days in the past.

export ichimoku(series int conLength = 9, series int baseLength = 26, series int senkouLength = 52) =>

    float tenkan      = midpoint(conLength)

    float kijun       = midpoint(baseLength)

    float senkouSpan1 = math.avg(tenkan, kijun)

    float senkouSpan2 = midpoint(senkouLength)

    float chikou      = close

    [tenkan, kijun, senkouSpan1, senkouSpan2, chikou]





// @function                Calculates the value of the Inverse Fisher Transform indicator.

// @param source            (series int/float) Series of values to process.

// @returns                 (float) The oscillator value.

export ift(series float source) =>

    float exp    = math.exp(2.0 * source)

    float result = (exp - 1.0) / (1.0 + exp)





// @function                Calculates Kaufman's Adaptive Moving Average (KAMA). KAMA is an EMA-based filter that

//                          dynamically adjusts its smoothing factor based on the value of Kaufman's Efficiency Ratio

//                          (ER). It moves toward price at a slower rate when ER is low, and at a faster rate when

//                          ER is high.

// @param source            (series int/float) Series of values to process.

// @param erLen             (series int) Length for the ER calculation.

// @param fastLen           (series int/float) Length for the fastest smoothing response.

// @param slowLen           (series int/float) Length for the slowest smoothing response.

// @returns                 (float) The KAMA of `source`.

export kama(series float source, series int erLen, series float fastLen, series float slowLen) =>

    float alphaFast = 2.0 / (fastLen + 1.0)

    float alphaSlow = 2.0 / (slowLen + 1.0)

    float alpha     = math.pow(er(source, erLen) * (alphaFast - alphaSlow) + alphaSlow, 2)

    float result    = ewma(source, alpha)





// @function                Calculates the values of the Klinger Volume Oscillator.

// @param fastLen           (simple int) Length for the fast EMA smoothing factor.

// @param slowLen           (simple int) Length for the slow EMA smoothing factor.

// @param trigLen           (simple int) Length for the trigger EMA smoothing factor.

// @returns                 ([float, float]) A tuple containing the KVO value and the trigger value.

export kvo(simple int fastLen, simple int slowLen, simple int trigLen) =>

    float trend   = math.sign(ta.change(hlc3)) * volume * 100

    float fast    = ta.ema(trend, fastLen)

    float slow    = ta.ema(trend, slowLen)

    float kvo     = fast - slow

    float trigger = ta.ema(kvo, trigLen)

    [kvo, trigger]





// @function                Tracks the lowest value of a series since the last occurrence of a condition.

// @param cond              (series bool) A condition which, when `true`, resets the tracking of the lowest `source`.

// @param source            (series int/float) Optional. Series of values to process. The default is `low`.

// @returns                 (float) The lowest `source` value since the last time the `cond` value was `true`.

export lowestSince(series bool cond, series float source = low) =>

    var float result = na

    if cond

        result := source

    result := math.min(nz(source, result), nz(result, source))





// @function                An alternative function to `ta.macd()` that supports "series float" EMA length values.

// @param source            (series int/float) Series of values to process.

// @param fastLen           (series int/float) The length for the fast EMA smoothing factor.

// @param slowLen           (series int/float) The length for the slow EMA smoothing factor.

// @param sigLen            (series int/float) The length for the signal EMA smoothing factor.

// @returns                 ([float, float, float]) A tuple containing the following values:

//                           - The Moving Average Convergence Divergence (MACD) value.

//                           - The EMA of the MACD (signal line).

//                           - The histogram value, representing the difference between the MACD and signal values.

export macd2(series float source, series float fastLen, series float slowLen, series float sigLen) =>

    float maFast = ema2(source, fastLen)

    float maSlow = ema2(source, slowLen)

    float macd   = maFast - maSlow

    float signal = ema2(macd, sigLen)

    float hist   = macd - signal

    [macd, signal, hist]





// @function                Calculates the values of the Price Momentum Oscillator (PMO). The PMO is a twice-smoothed

//                          percentage rate of change in a `source` series, typically accompanied by a smooth signal

//                          line.

// @param source            (series int/float) Series of values to process.

// @param length1           (series int/float) The first smoothing length.

// @param length2           (series int/float) The second smoothing length.

// @param sigLen            (series int/float) Signal EMA smoothing length.

// @returns                 ([float, float]) A tuple containing the following values:

//                           - The Price Momentum Oscillator.

//                           - The EMA of the PMO (signal line).

export pmo(series float source, series float length1, series float length2, series float sigLen) =>

    float roc    = ta.roc(source, 1)

    float pmo    = ewma(10.0 * ewma(roc, 2.0 / length1), 2.0 / length2)

    float signal = ema2(pmo, sigLen)

    [pmo, signal]





// @function                Calculates the values of the Percentage Price Oscillator (PPO). The PPO is a momentum

//                          oscillator that measures the difference between two EMAs as a percentage of the slower

//                          moving average.

// @param source            (series int/float) Series of values to process.

// @param fastLen           (simple int) The length for the fast EMA smoothing factor.

// @param slowLen           (simple int) The length for the slow EMA smoothing factor.

// @param sigLen            (simple int) The length for the signal EMA smoothing factor.

// @returns                 ([float, float, float]) A tuple containing the following values:

//                           - The Percentage Price Oscillator.

//                           - The EMA of the PPO (signal line).

//                           - The histogram value, representing the difference between the PPO and signal values.

export ppo(series float source, simple int fastLen, simple int slowLen, simple int sigLen) =>

    float maFast = ta.ema(source, fastLen)

    float maSlow = ta.ema(source, slowLen)

    float ppo    = changePercent(maFast, maSlow)

    float signal = ta.ema(ppo, sigLen)

    float hist   = ppo - signal

    [ppo, signal, hist]





// @function                An alternative function to `ppo()` that supports "series float" EMA length values.

// @param source            (series int/float) Series of values to process.

// @param fastLen           (series int/float) The length for the fast EMA smoothing factor.

// @param slowLen           (series int/float) The length for the slow EMA smoothing factor.

// @param sigLen            (series int/float) The length for the signal EMA smoothing factor.

// @returns                 ([float, float, float]) A tuple containing the following values:

//                           - The Percentage Price Oscillator.

//                           - The EMA of the PPO (signal line).

//                           - The histogram value, representing the difference between the PPO and signal values.

export ppo2(series float source, series float fastLen, series float slowLen, series float sigLen) =>

    float maFast = ema2(source, fastLen)

    float maSlow = ema2(source, slowLen)

    float ppo    = changePercent(maFast, maSlow)

    float signal = ema2(ppo, sigLen)

    float hist   = ppo - signal

    [ppo, signal, hist]





// @function                The "zone" calculation used in `pzo()` and `vzo()` functions.

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The oscillator value.

zone(series float source, simple int length) =>

    float result = 100 * nz(ta.ema(math.sign(ta.change(close)) * source, length) / ta.ema(source, length))





// @function                Calculates the value of the Price Zone Oscillator.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The oscillator value.

export pzo(simple int length) =>

    float result = zone(close, length)





// @function                Calculates the volume since the last change in the time value from the

//                          `anchorTimeframe`, the historical average volume using bars from past periods

//                          that have the same relative time offset as the current bar from the start of its

//                          period, and the ratio of these volumes. The volume values are cumulative by default,

//                          but can be adjusted to non-accumulated with the `isCumulative` parameter.

// @param length            (simple int) The number of periods to use for the historical average calculation.

// @param anchorTimeframe   (simple string) Optional. The anchor timeframe used in the calculation. The default is "1D".

// @param isCumulative      (simple bool) Optional. If `true`, the function accumulates volume values across each

//                          `anchorTimeframe` period. If `false`, the function uses non-cumulative volume. The

//                          default is `true`.

// @param adjustRealtime    (simple bool) Optional. If `true`, estimates the cumulative value on open bars based on the

//                          confirmed data since the last `anchor` condition. The default is `false`.

// @returns                 ([float, float, float]) A tuple containing the following data:

//                           - The current volume.

//                           - The average of volume values at equivalent time offsets from past anchors over the number

//                             of periods.

//                           - The ratio of the current volume to the historical average volume.

export relativeVolume(

     simple int  length,              simple string anchorTimeframe = "1D",

     simple bool isCumulative = true, simple bool   adjustRealtime  = true

 ) =>

    bool  anchor   = timeframe.change(anchorTimeframe)

    float currVol  = isCumulative ? TVrv.calcCumulativeSeries(volume, anchor, adjustRealtime) : volume

    float pastVol  = TVrv.averageAtTime(volume, length, anchorTimeframe, isCumulative)

    float volRatio = currVol / pastVol

    [currVol, pastVol, volRatio]





// @function                A helper function for use in `upAndDownVolumeCalc()`. It classifies the bar's data as

//                          positive or negative based on the values of `open` and `close`. The `upAndDownVolumeCalc()`

//                          function uses this helper to categorize volume data when it cannot directly determine

//                          the category using `bid` and `ask` values.

// @param currentValue      (series bool) Represents the latest category assigned to the data: `true` for positive, and

//                          `false` for negative. The function returns this value if the price-based conditions do not

//                          produce a different result.

// @returns                 (bool) `true` if the current bar's data is considered positive, and `false` otherwise.

priceCalc(series bool currentValue)=>

    bool result = switch

        close > open     => true

        close < open     => false

        close > close[1] => true

        close < close[1] => false

        => currentValue





// @function                A helper function for use in `requestUpAndDownVolume()` and `requestVolumeDelta()`. It

//                          calculates sums of polarized (positive and negative) `volume` values within a bar on

//                          script's main timeframe, and uses the sums to compute the bar's volume delta. The function

//                          also tracks the highest and lowest volume delta values observed within the bar.

//

//                          If the timeframe is "1T", and the values of `bid` and `ask` are *not* equal, the function

//                          uses the following logic to categorize each `volume` value as positive or negative:

//                              - If the `close` value is greater than or equal to the `ask` value, the volume is

//                                positive.

//                              - If the `close` value is less than or equal to the `bid` value, the volume is negative.

//                              - If the `close` value is *between* the `bid` and `ask` values, the volume is positive

//                                if the `close` value is greater than the median of those values, or negative if the

//                                value is less than the median.

//

//                          If the timeframe is higher than "1T", the `bid` and `ask` values are equal, or the `close`

//                          value equals the median of the `bid` and `ask` values, the function calls `priceCalc()` to

//                          use the following logic instead:

//                              - If the `close` value is greater than the `open` value, the volume is positive.

//                              - If the `close` value is less than the `open` value, the volume is negative.

//                              - If the `close` and `open` values are equal, the volume is positive if the current

//                                `close` value is greater than the previous value, or negative if the current value is

//                                less than the previous value.

//                              - If none of the above conditions apply, the current volume has the same positive or

//                                negative status as that of the previous bar's volume.

//

//                          NOTE: This function is intended for use in *lower-timeframe (LTF)* requests, as demonstrated

//                          by this library's `requestUpAndDownVolume()` and `requestVolumeDelta()` functions.

//                          When used in an LTF request, the function's results represent data calculated from

//                          the available intrabars within the *current bar* on the script's *main timeframe*. The

//                          calculations reset at the open of each bar on that timeframe.

// @returns                 ([float, float, float, float, float]) A tuple containing the following values:

//                              - The total positive (up) volume within the bar on the script's main timeframe.

//                              - The total negative (down) volume within the bar, expressed as a negative quantity.

//                              - The bar's volume delta (i.e., the net difference between up and down volume).

//                              - The highest volume delta observed within the bar.

//                              - The lowest volume delta observed within the bar.

upAndDownVolumeCalc() =>

    var float posVol      = 0.0

    var float negVol      = 0.0

    var float hiVol       = 0.0

    var float loVol       = 0.0

    var bool  isBuyVolume = close >= open

    bool newBar = switch

        timeframe.isticks => ta.change(request.security("", timeframe.main_period, time)) > 0

        => timeframe.change(timeframe.main_period)

    if newBar

        posVol := 0.0

        negVol := 0.0

        hiVol  := 0.0

        loVol  := 0.0

    if timeframe.isticks

        float avg = math.avg(ask, bid)

        isBuyVolume := switch

            close == ask and close == bid => priceCalc(isBuyVolume)

            close >= ask => true

            close <= bid => false

            close >  avg => true

            close <  avg => false

            => priceCalc(isBuyVolume)

    else

        isBuyVolume := priceCalc(isBuyVolume)

    if isBuyVolume

        posVol += volume

    else

        negVol -= volume

    float delta = posVol + negVol

    hiVol := math.max(delta, hiVol)

    loVol := math.min(delta, loVol)

    [posVol, negVol, delta, hiVol, loVol]





// @function                Checks whether a specified timeframe string represents a smaller timeframe than the

//                          script's main timeframe. If the specified string represents a higher timeframe, the

//                          function raises a runtime error.

// @param lowerTimeframe    (series string) The timeframe string to inspect.

// @returns                 (void) The function does not return a usable value.

checkLTF(series string lowerTimeframe) =>

    if timeframe.in_seconds(lowerTimeframe) > timeframe.in_seconds(timeframe.main_period)

        runtime.error(

             str.format(

                 "Invalid lower timeframe: {2}{0}{2}. The timeframe must be lower than or equal to {2}{1}{2}",

                 lowerTimeframe, timeframe.main_period, "'"

             )

         )





// @function                Requests data from a specified lower timeframe and categorizes the volume of each intrabar

//                          within the chart bar as positive (up) or negative (down). The function uses this polarized

//                          volume data to calculate the total positive volume, total negative volume, and volume delta

//                          for a bar on the script's main timeframe.

//

//                          Calls to this function count toward a script's `request.*()` call limit.

// @param lowerTimeframe    (series string) The timeframe of the requested intrabar data. Accepts a valid timeframe

//                          string (e.g., "5", "15", "1D"), an empty string, `timeframe.period`, or

//                          `timeframe.main_period`. Smaller timeframes provide higher precision but cover fewer bars

//                          on the script's main timeframe. Larger timeframes cover more bars on the script's main

//                          timeframe but offer less granularity. If the specified timeframe is higher than the script's

//                          main timeframe, it causes a runtime error.

// @returns                 ([float, float, float]) A tuple containing the following values:

//                              - The total positive (up) intrabar volume within the bar on the script's main timeframe.

//                              - The total negative (down) intrabar volume within the bar on the script's main

//                                timeframe, expressed as a negative quantity.

//                              - The bar's volume delta (i.e., the net difference between up and down intrabar volume).

export requestUpAndDownVolume(series string lowerTimeframe) =>

    checkLTF(lowerTimeframe)

    [posVol, negVol, delta, _, _] = request.security(syminfo.tickerid, lowerTimeframe, upAndDownVolumeCalc())

    [posVol, negVol, delta]





// @function                Requests data from a specified lower timeframe and categorizes the volume of each

//                          intrabar within a bar on the script's main timeframe as positive (up) or negative (down).

//                          The function uses this information to calculate the bar's volume delta, i.e., the difference

//                          between the total up and down intrabar volume.

//

//                          If the call specifies a `cumulativePeriod` argument representing a period larger than the

//                          main timeframe, it calculates the cumulative volume delta (CVD), which is a running sum

//                          of volume delta across all bars within the period. In addition, the function tracks the

//                          highest and lowest CVD values calculated within each bar over the period. The sum and

//                          highest/lowest calculations reset when a new period starts.

//

//                          Calls to this function count toward a script's `request.*()` call limit.

// @param lowerTimeframe    (series string) The timeframe of the requested intrabar data. Accepts a valid timeframe

//                          string (e.g., "5", "15", "1D"), an empty string, `timeframe.period`, or

//                          `timeframe.main_period`. Smaller timeframes provide higher precision but cover fewer bars

//                          on the script's main timeframe. Larger timeframes cover more bars on the script's main

//                          timeframe but offer less granularity. If the specified timeframe is higher than the script's

//                          main timeframe, it causes a runtime error.

// @param cumulativePeriod  (series string) Determines the span of the CVD period. Accepts a valid timeframe string

//                          (e.g., "5", "15", "1D"), an empty string, `timeframe.period`, or `timeframe.main_period`.

//                          The calculations reset after a new period starts. For example, a value of "1D" means that

//                          the function accumulates and tracks the values from each bar within a "1D" period and resets

//                          at the open of a new "1D" bar.

// @returns                 ([float, float, float, float]) A tuple containing the following values:

//                              - The opening volume delta/CVD at the start the bar on the script's main timeframe.

//                                This value is always 0 when a new cumulative period starts.

//                              - The maximum volume delta/CVD within the current cumulative period.

//                              - The minimum volume delta/CVD within the current cumulative period.

//                              - The current volume delta/CVD value.

export requestVolumeDelta(series string lowerTimeframe, series string cumulativePeriod = "") =>

    checkLTF(lowerTimeframe)

    [_, _, delta, maxVolume, minVolume] = request.security(syminfo.tickerid, lowerTimeframe, upAndDownVolumeCalc())

    var float lastVolume = 0.0

    bool anchorChange = str.length(str.trim(cumulativePeriod)) == 0 or

         timeframe.change(cumulativePeriod) or (not na(lastVolume) and na(lastVolume[1]))

    float openVolume = anchorChange ? 0.0 : lastVolume[1]

    float hiVolume  = openVolume + maxVolume

    float loVolume  = openVolume + minVolume

    lastVolume := openVolume + delta

    [openVolume, hiVolume, loVolume, lastVolume]





// @function                An alternative function to `ta.rma()` that supports a "series float" length value.

// @param source            (series int/float) Series of values to process.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @returns                 (float) The rolling moving average of the `source`.

export rma2(series float source, series float length) =>

    if length < 1

        runtime.error(str.format("Invalid length ({0}). The value must be greater than or equal to 1.", length))

    float alpha  = 1.0 / length

    float result = ewma(source, alpha)





// @function                Calculates the Root Mean Square of the `source` over a specified lookback length.

// @param source            (series int/float) Series of values to process.

// @param length            (series int) Number of bars (lookback length).

// @returns                 (float) The RMS value.

export rms(series float source, series int length) =>

    float result = math.sqrt(math.sum(math.pow(source, 2), length) / length)





// @function                Calculates the values of the Random Walk Index.

// @param length            (simple int) Lookback and ATR length.

// @returns                 ([float, float]) A tuple of the `rwiHigh` and `rwiLow` values.

export rwi(simple int length) =>

    float divisor = ta.atr(length) * math.sqrt(length)

    float rwiHigh = (high - nz(low[length])) / divisor

    float rwiLow  = (nz(high[length]) - low) / divisor

    [rwiHigh, rwiLow]





// @function                Calculates the values of Pring's Special K indicator. The Spcial K is a weighted sum of

//                          smoothed rates of change over multiple lengths, accompanied by a twice-smoothed signal

//                          line. The lengths and weights are derived from Martin Pring's market observations.

// @param source            (series int/float) Series of values to process.

// @param sigLen1           (series int) The first smoothing length for the signal line.

// @param sigLen2           (series int) The second smoothing length for the signal line.

// @returns                 ([float, float]) A tuple containing the following values:

//                           - The Special K value.

//                           - The twice-smoothed signal line of the Special K.

export specialK(series float source, series int sigLen1, series int sigLen2) =>

    float sk =

                  ta.sma(ta.roc(source, 10), 10) + ta.sma(ta.roc(source,  40),  50) + ta.sma(ta.roc(source, 195), 130)

         + 2.0 * (ta.sma(ta.roc(source, 15), 10) + ta.sma(ta.roc(source,  65),  65) + ta.sma(ta.roc(source, 265), 130))

         + 3.0 * (ta.sma(ta.roc(source, 20), 10) + ta.sma(ta.roc(source,  75),  75) + ta.sma(ta.roc(source, 390), 130))

         + 4.0 * (ta.sma(ta.roc(source, 30), 15) + ta.sma(ta.roc(source, 100), 100) + ta.sma(ta.roc(source, 530), 195))

    float signal = ta.sma(ta.sma(sk, sigLen1), sigLen2)

    [sk, signal]





// @function                Calculates the Schaff Trend Cycle indicator.

// @param source            (series int/float) Series of values to process.

// @param fast              (simple int) Length for the MACD fast smoothing factor.

// @param slow              (simple int) Length for the MACD slow smoothing factor.

// @param cycle             (simple int) Number of bars for the Stochastic calculation.

// @param d1                (simple int) Length for the initial %D smoothing factor.

// @param d2                (simple int) Length for the final %D smoothing factor.

// @returns                 (float) The STC for the `source` series.

export stc(series float source, simple int fast, simple int slow, simple int cycle, simple int d1, simple int d2) =>

    float macd   = ta.ema(source, fast) - ta.ema(source, slow)

    float k      = nz(fixnan(ta.stoch(macd, macd, macd, cycle)))

    float d      = ta.ema(k, d1)

    float kd     = nz(fixnan(ta.stoch(d, d, d, cycle)))

    float stc    = ta.ema(kd, d2)

    float result = math.max(math.min(stc, 100), 0)





// @function                Calculates the %K and %D values of the Full Stochastic indicator.

// @param periodK           (simple int) Number of bars for the Stochastic calculation.

// @param smoothK           (simple int) Number of bars for smoothing the %K series.

// @param periodD           (simple int) Number of bars for smoothing the %D series.

// @returns                 ([float, float]) A tuple containing the slow %K and the %D moving average.

export stochFull(simple int periodK, simple int smoothK, simple int periodD) =>

    float k = ta.sma(ta.stoch(close, high, low, periodK), smoothK)

    float d = ta.sma(k, periodD)

    [k, d]





// @function                Calculates the %K and %D values of the Stochastic RSI indicator.

// @param lengthRsi         (simple int) Length for the RSI smoothing factor.

// @param periodK           (simple int) Number of bars for the Stochastic calculation.

// @param smoothK           (simple int) Number of bars for smoothing the %K series.

// @param periodD           (simple int) Number of bars for smoothing the %D series.

// @param source            (series int/float) Optional. Series of values to process. The default is `close`.

// @returns                 ([float, float]) A tuple containing the slow %K and the %D moving average.

export stochRsi(

     simple int lengthRsi, simple int periodK, simple int smoothK, simple int periodD, series float source = close

 ) =>

    float rsi = ta.rsi(source, lengthRsi)

    float k   = ta.sma(ta.stoch(rsi, rsi, rsi, periodK), smoothK)

    float d   = ta.sma(k, periodD)

    [k, d]





// @function                Calculates the values of the SuperTrend indicator with the ability to take candle wicks

//                          into account, rather than only the closing price.

// @param factor            (series int/float) Multiplier for the ATR value.

// @param atrLength         (simple int) Length for the ATR smoothing factor calculation.

// @param wicks             (simple bool) Optional. Specifies whether the function uses `high` and `low` values to

//                          identify trend reversals (if `true`), or uses only `close` values (if `false`). The default

//                          is `false`.

// @returns                 ([float, int]) A tuple containing the Supertrend and trend direction values.

export supertrend(series float factor, simple int atrLength, simple bool wicks = false) =>

    float source        = hl2

    int   direction     = na

    float superTrend    = na

    float atr           = ta.atr(atrLength) * factor

    float upperBand     = source + atr

    float lowerBand     = source - atr

    float highPrice     = wicks ? high : close

    float lowPrice      = wicks ? low  : close

    float prevLowerBand = nz(lowerBand[1])

    float prevUpperBand = nz(upperBand[1])



    lowerBand := lowerBand > prevLowerBand or  lowPrice[1] < prevLowerBand ? lowerBand : prevLowerBand

    upperBand := upperBand < prevUpperBand or highPrice[1] > prevUpperBand ? upperBand : prevUpperBand

    float prevSuperTrend  = superTrend[1]

    if na(atr[1])

        direction := 1

    else if prevSuperTrend == prevUpperBand

        direction := highPrice > upperBand ? -1 : 1

    else

        direction := lowPrice < lowerBand ? 1 : -1

    superTrend := direction == -1 ? lowerBand : upperBand

    [superTrend, direction]





// @function                An alternative function to `supertrend()` that supports a "series float" ATR length.

// @param factor            (series int/float) Multiplier for the ATR value.

// @param atrLength         (series int/float) Length for the ATR smoothing factor calculation.

// @param wicks             (simple bool) Optional. Specifies whether the function uses `high` and `low` values to

//                          identify trend reversals (if `true`), or uses only `close` values (if `false`). The default

//                          is `false`.

// @returns                 ([float, int]) A tuple containing the Supertrend and trend direction values.

export supertrend2(series float factor, series float atrLength, simple bool wicks = false) =>

    float source        = hl2

    int   direction     = na

    float superTrend    = na

    float atr           = atr2(atrLength) * factor

    float upperBand     = source + atr

    float lowerBand     = source - atr

    float highPrice     = wicks ? high : close

    float lowPrice      = wicks ? low  : close

    float prevLowerBand = nz(lowerBand[1])

    float prevUpperBand = nz(upperBand[1])



    lowerBand := lowerBand > prevLowerBand or  lowPrice[1] < prevLowerBand ? lowerBand : prevLowerBand

    upperBand := upperBand < prevUpperBand or highPrice[1] > prevUpperBand ? upperBand : prevUpperBand

    float prevSuperTrend  = superTrend[1]

    if na(atr[1])

        direction := 1

    else if prevSuperTrend == prevUpperBand

        direction := highPrice > upperBand ? -1 : 1

    else

        direction := lowPrice < lowerBand ? 1 : -1

    superTrend := direction == -1 ? lowerBand : upperBand

    [superTrend, direction]





// @function                Calculates the Generalized DEMA (GD) used in the `t3()` function.

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @param vf                (simple float) Volume factor. Affects the responsiveness.

// @returns                 (float) The GD value of the `source`.

gd(series float source, simple int length, simple float vf) =>

    float result = ta.ema(source, length) * (1 + vf) - ta.ema(ta.ema(source, length), length) * vf





// @function                Calculates the value of the Tilson Moving Average (T3).

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @param vf                (simple float) Volume factor. Affects the responsiveness.

// @returns                 (float) The Tilson moving average of the `source`.

export t3(series float source, simple int length, simple float vf = 0.7) =>

    float result = gd(gd(gd(source, length, vf), length, vf), length, vf)





// @function                An alternative function to `gd()` that supports a "series float" length value.

// @param source            (series int/float) Series of values to process.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @param vf                (simple float) Volume factor. Affects the responsiveness.

// @returns                 (float) The GD value of the `source`.

gd2(series float source, series float length, simple float vf) =>

    float result = ema2(source, length) * (1 + vf) - ema2(ema2(source, length), length) * vf





// @function                An alternative function to `t3()` that supports a "series float" length value.

// @param source            (series int/float) Series of values to process.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @param vf                (simple float) Volume factor. Affects the responsiveness.

// @returns                 (float) The Tilson moving average of the `source`.

export t3Alt(series float source, series float length, simple float vf = 0.7) =>

    float result = gd2(gd2(gd2(source, length, vf), length, vf), length, vf)





// @function                Calculates the value of the Triple Exponential Moving Average (TEMA).

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The triple exponentially weighted moving average of the `source`.

export tema(series float source, simple int length) =>

    float ema1   = ta.ema(source, length)

    float ema2   = ta.ema(ema1, length)

    float ema3   = ta.ema(ema2, length)

    float result = 3 * (ema1 - ema2) + ema3





// @function                An alternative function to `tema()` that supports a "series float" length value.

// @param source            (series int/float) Series of values to process.

// @param length            (series int/float) Length for the smoothing factor calculation.

// @returns                 (float) The triple exponentially weighted moving average of the `source`.

export tema2(series float source, series float length) =>

    float ema1   = ema2(source, length)

    float ema2   = ema2(ema1, length)

    float ema3   = ema2(ema2, length)

    float result = 3 * (ema1 - ema2) + ema3





// @function                Calculates the value of the Triangular Moving Average (TRIMA).

// @param source            (series int/float) Series of values to process.

// @param length            (series int) Number of bars (lookback length).

// @returns                 (float) The triangular moving average of the `source`.

export trima(series float source, series int length) =>

    float result = ta.sma(ta.sma(source, math.ceil(length / 2)), math.floor(length / 2) + 1)





// @function                Calculates the values of the TRIX indicator.

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @param signalLength      (simple int) Length for smoothing the signal line.

// @param exponential       (simple bool) Optional. Specifies whether the function calculates the signal line using

//                          an exponential moving average (if `true`) or a simple moving average (if `false`). The

//                          default is `true`.

// @returns                 ([float, float, float]) A tuple containing the TRIX value, signal, and histogram values.

export trix(series float source, simple int length, simple int signalLength, simple bool exponential = true) =>

    float triple = ta.ema(ta.ema(ta.ema(source, length), length), length)

    float trix   = ta.roc(triple, 1)

    float signal = exponential ? ta.ema(trix, signalLength) : ta.sma(trix, signalLength)

    float hist   = trix - signal

    [trix, signal, hist]





// @function                Calculates the Ulcer Index based on a `source` value. The index represents the root mean

//                          square of drawdown percentages over a lookback length.

// @param source            (series int/float) Series of values to process.

// @param length            (series int) Number of bars (lookback length).

// @returns                 (float) The Ulcer Index.

export ulcerIndex(series float source, series int length) =>

    float highest  = ta.highest(source, length)

    float drawdown = changePercent(source, highest)

    float result   = rms(drawdown, length)





// @function                Calculates the value of the Sentiment Zone Oscillator.

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The oscillator value.

export szo(series float source, simple int length) =>

    float trend   = math.sign(ta.change(source))

    float sentPos = tema(trend, length)

    float result  = 100 * sentPos / length





// @function                Calculates the weighted average used in the `uo()` function.

// @param bp                (series int/float) A source series representing the "Buying Pressure" value.

// @param trange            (series int/float) A source series representing the True Range value.

// @param length            (simple int) Number of bars (lookback length).

// @returns                 (float) The weighted average value.

uoAverage(series float bp, series float trange, simple int length) =>

    float result = math.sum(bp, length) / math.sum(trange, length)





// @function                Calculates the value of the Ultimate Oscillator.

// @param fastLen           (series int) Number of bars for the fast smoothing average.

// @param midLen            (series int) Number of bars for the middle smoothing average.

// @param slowLen           (series int) Number of bars for the slow smoothing average.

// @returns                 (float) The Ultimate Oscillator.

export uo(simple int fastLen, simple int midLen, simple int slowLen) =>

    float tMax   = math.max(high, close[1])

    float tMin   = math.min(low,  close[1])

    float tr     = tMax  - tMin

    float bp     = close - tMin

    float avg1   = uoAverage(bp, tr, fastLen)

    float avg2   = uoAverage(bp, tr, midLen)

    float avg3   = uoAverage(bp, tr, slowLen)

    float result = 100 * (4 * avg1 + 2 * avg2 + avg3) / 7





// @function                Calculates the value of the Vertical Horizontal Filter.

// @param source            (series int/float) Series of values to process.

// @param length            (simple int) Number of bars (lookback length).

// @returns                 (float) The oscillator value.

export vhf(series float source, simple int length) =>

    float sumChanges = math.sum(math.abs(ta.change(source)), length)

    float result     = math.abs(ta.highest(source, length) - ta.lowest(source, length)) / sumChanges





// @function                Calculates the values of the Vortex Indicator.

// @param length            (simple int) Number of bars (lookback length).

// @returns                 ([float, float]) A tuple containing the VI+ and VI- values.

export vi(simple int length) =>

    divisor = math.sum(ta.atr(1), length)

    viPlus  = math.sum(math.abs(high -  nz(low[1])), length) / divisor

    viMinus = math.sum(math.abs(low  - nz(high[1])), length) / divisor

    [viPlus, viMinus]





// @function                Calculates an ATR-based stop value that trails behind the `source`. Can serve as a

//                          possible stop-loss guide and trend identifier.

// @param source            (series int/float) Series of values that the stop trails behind.

// @param atrLength         (simple int) Length for the ATR smoothing factor calculation.

// @param atrFactor         (series int/float) Optional. The multiplier of the ATR value. Affects the maximum distance

//                          between the stop and the `source` value. A value of 1 means the maximum distance is 100%

//                          of the ATR value. The default is 1.

// @returns                 ([float, bool]) A tuple containing the volatility stop and trend direction values.

export vStop(series float source, simple int atrLength, series float atrFactor = 1) =>

    float src  = nz(source, close)

    float atrM = nz(ta.atr(atrLength) * atrFactor, ta.tr(true))

    var bool  trendUp = true

    var float max     = src

    var float min     = src

    var float stop    = 0.0

    max     := math.max(max, src)

    min     := math.min(min, src)

    stop    := nz(trendUp ? math.max(stop, max - atrM) : math.min(stop, min + atrM), src)

    trendUp := src - stop >= 0.0

    if trendUp != trendUp[1]

        max  := src

        min  := src

        stop := trendUp ? max - atrM : min + atrM

    [stop, trendUp]





// @function                An alternative function to `vStop()` that supports a "series float" length value.

// @param source            (series int/float) Series of values that the stop trails behind.

// @param atrLength         (series int/float) Length for the ATR smoothing factor calculation.

// @param atrFactor         (series int/float) Optional. The multiplier of the ATR value. Affects the maximum distance

//                          between the stop and the `source` value. A value of 1 means the maximum distance is 100%

//                          of the ATR value. The default is 1.

// @returns                 ([float, bool]) A tuple of the volatility stop value and the trend direction as a "bool".

export vStop2(series float source, series float atrLength, series float atrFactor = 1) =>

    float src  = nz(source, close)

    float atrM = nz(atr2(atrLength) * atrFactor, ta.tr(true))

    var bool  trendUp = true

    var float max     = src

    var float min     = src

    var float stop    = 0.0

    max     := math.max(max, src)

    min     := math.min(min, src)

    stop    := nz(trendUp ? math.max(stop, max - atrM) : math.min(stop, min + atrM), src)

    trendUp := src - stop >= 0.0

    if trendUp != trendUp[1]

        max  := src

        min  := src

        stop := trendUp ? max - atrM : min + atrM

    [stop, trendUp]





// @function                Calculates the value of the Volume Zone Oscillator.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The oscillator value.

export vzo(simple int length) =>

    float result = zone(volume, length)





// @function                Detects Williams fractals (used by `williamsFractal()`).

// @param source            (series int/float) Series of values to process.

// @param n                 (series int) Lookback in bars.

// @param direction         (simple int) Direction of the fractal to detect (+1 for up, -1 for down).

// @returns                 (series bool) `true` when a fractal was detected, `false` otherwise.

flag(series float source, series int n, simple int direction) =>

    float src  = source * direction

    bool flag  = true

    bool flag0 = true

    bool flag1 = true

    bool flag2 = true

    bool flag3 = true

    bool flag4 = true

    for i = 1 to n

        flag  := flag  and (src[n - i] <  src[n])

        flag0 := flag0 and (src[n + i] <  src[n])

        flag1 := flag1 and (src[n + 1] <= src[n] and src[n + i + 1] < src[n])

        flag2 := flag2 and (src[n + 1] <= src[n] and src[n + 2] <= src[n] and src[n + i + 2] < src[n])

        flag3 := flag3 and (src[n + 1] <= src[n] and src[n + 2] <= src[n] and src[n + 3] <= src[n] and src[n + i + 3] < src[n])

        flag4 := flag4 and (src[n + 1] <= src[n] and src[n + 2] <= src[n] and src[n + 3] <= src[n] and src[n + 4] <= src[n] and src[n + i + 4] < src[n])

    bool flags = flag0 or flag1 or flag2 or flag3 or flag4

    bool result = (flag and flags)





// @function                Detects Williams Fractals.

// @param period            (series int) Number of bars (lookback length).

// @returns                 ([bool, bool]) A tuple of an up fractal and down fractal. Variables are true when detected.

export williamsFractal(series int period) =>

    bool upFractal   = flag(high, period,  1)

    bool downFractal = flag(low,  period, -1)

    [upFractal, downFractal]





// @function                Calculates the value of the Wave Period Oscillator.

// @param length            (simple int) Length for the smoothing factor calculation.

// @returns                 (float) The oscillator value.

export wpo(simple int length) =>

    float tt     = 2 * math.pi / math.asin(close[1] / high)

    float ti     = math.sign(ta.change(close)) * tt

    float result = ta.ema(ti, length)







plot(cagr(time[1], close[1], time, close))

Overview

ta includes helper functions for moving averages such as dema, ema2, t3, tema, and rma2, oscillators like macd2, stochFull, stochRsi, and ppo, plus specialized tools including supertrend, ichimoku, atr2, donchian, and volume-related indicators. Users import the library to access these reusable functions directly in their scripts. It contains no standalone plot commands or chart drawings and serves as a utility for extending custom trading logic.

Details

Published by

alvinng214 on GitHub

Code credit

TradingView, as written in the script's header

Type

Library, Pine Script v6

Draws

Library (no plots)

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.

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

261 stars

AIActivationFunctionsBipolarSigmoid is a Pine Script library that provides mathematical implementations of the bipolar sigmoid activation function and its derivatives for machine learning algorithms. It calculates bipolar sigmoid values bounded between -1 and

Library v5 AI / machine learning
Updated 4 years ago · None stated GitHub repository of AIActivationFunctionsBipolarSigmoid

KernelFunctions

by artificial-intelligence-edge
75 stars

KernelFunctions is a Pine Script v5 library that exports kernel weight functions for Nadaraya-Watson style estimation. It calculates a Rational Quadratic kernel, a Gaussian kernel based on a radial basis function, and a periodic kernel that models repeating be

Library v5
Updated 2 days ago · MIT GitHub repository of KernelFunctions

Ta

by nersent
29 stars

This Pine Script v5 library exports thin wrappers around built-in technical analysis functions. It covers moving averages, momentum measures such as RSI and CCI, volatility tools including ATR and standard deviation, range extremes, cross detection, and runnin

Library v5
Updated 11 months ago · Custom licence GitHub repository of Ta

Bands

by heyphat
26 stars

This library exports a Band type and functions that build a simple-moving-average basis with upper and lower envelopes from standard deviation. It classifies a source as above, below, or inside those envelopes, measures band width, and scales an imported z-sco

Library v6 Volatility & bandsMoving averages
Updated 2 months ago · AGPL-3.0 GitHub repository of Bands

Mylib

by ferranbt
21 stars

This script serves as a minimal utility library written in Pine Script v6. It provides an exported helper function that calculates the sum of two numeric arguments. As a reusable code library, it produces no visual plots, charts, or trading signals, and it con

Library v6
Updated 7 weeks ago · MPL-2.0 GitHub repository of Mylib

HLevel

by stupenkov
14 stars

HLevel is a Pine Script v5 utility library designed to manage horizontal price levels for cryptocurrency charts. It defines custom types for pivots and levels, along with methods to initialize, add, track, and expire price levels based on pivot high and pivot

Library v5
Updated 3 years ago · None stated GitHub repository of HLevel

More libraries

Trade Your Charts With a Regulated Broker

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

Compare brokers