Indicator · Pine Script v5 · Own pane

Ehlers Loops [BigBeluga]

by regalouisei· code credited to BigBeluga

Ehlers Loops is a separate-pane indicator that tracks up to five symbols.

View on GitHub

GitHub stars2on the repository
Pine versionv5runs as is
Lines of code364
Settings22inputs
LicenceNone statedfile: MPL-2.0
Last update8 months ago25 Feb 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 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

364 lines of Pine Script v5 from pinescript/editors_picks/ehlers-loops-bigbeluga.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

ehlers-loops-bigbeluga.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © BigBeluga

//@version=5
indicator("Ehlers Loops [BigBeluga]", overlay=false, max_lines_count = 500, max_labels_count = 500)

// =====================================================================================================================}
// INPUTS
// ====================================================================================================================={
int LPPeriod = input(10, title="Low Pass Period", group = "Ehlers Loops")
int HPPeriod = input(125, title="High Pass Period", group = "Ehlers Loops")

color m_col  = chart.fg_color
color s_col  = color.new(m_col, 70)
int   Offset = -100

bool on_1 = input.bool(true, "", inline = "1", group = "Symbols")
bool on_2 = input.bool(true, "", inline = "2", group = "Symbols")
bool on_3 = input.bool(true, "", inline = "3", group = "Symbols")
bool on_4 = input.bool(true, "", inline = "4", group = "Symbols")
bool on_5 = input.bool(true, "", inline = "5", group = "Symbols")


string sym1 = input.symbol("BTCUSD", inline = "1", group = "Symbols")
string sym2 = input.symbol("ETHUSD", inline = "2", group = "Symbols")
string sym3 = input.symbol("SOLUSD", inline = "3", group = "Symbols")
string sym4 = input.symbol("BNBUSD", inline = "4", group = "Symbols")
string sym5 = input.symbol("SPX",    inline = "5", group = "Symbols")

color col1 = input.color(#22d17c, "",  inline = "1", group = "Symbols")
color col2 = input.color(#20b6ca, "",   inline = "2", group = "Symbols")
color col3 = input.color(#c28120, "", inline = "3", group = "Symbols")
color col4 = input.color(#ccbb1f, "", inline = "4", group = "Symbols")
color col5 = input.color(#f23645, "",    inline = "5", group = "Symbols")

string sym_size = input.string("Small", "Symbol Size", ["Small", "Big"], group = "Symbols")

bool show_hist = input.bool(true, "Show histogram", group = "Histogram")
color hist_up   = input.color(#22d17c, "+", inline = "hist", group = "Histogram")
color hist_dn   = input.color(#f23645, "-", inline = "hist", group = "Histogram")

bool show_info = input.bool(false, "Info 🛈", group = "---")


// =====================================================================================================================}
// CALCULATIONS
// ====================================================================================================================={
request_data(symbol)=>
    request.security(symbol, "", [close[1], volume[1]], lookahead = barmerge.lookahead_on)


label_new(value, txt, change = true)=>
    if change
        label.delete(
             label.new(
             x         = bar_index+math.round(value),
             y         = 0, 
             text      = txt, 
             color     = na, 
             textcolor = color.new(m_col, 50)
             )[1]
             )
    if not change
        label.delete(
             label.new(
             x         = bar_index+Offset, 
             y         = value, 
             text      = txt, 
             color     = #363a4500, 
             style     = label.style_label_center, 
             textcolor = color.new(m_col, 50)
             )[1]
             )

line_new(value, change = true)=>
    if change
        line.delete(
             line.new(
             x1     = bar_index + value,
             y1     = 4, 
             x2     =  bar_index + value, 
             y2     = -4, 
             color  = s_col,
             style  = line.style_dotted
             )[1]
             )

    else
        line.delete(
             line.new(
             x1     = bar_index,
             y1     = value, 
             x2     = bar_index + Offset*2,
             y2     = value, 
             color  = s_col, 
             style  = line.style_dotted
             )[1]
             )

ehler_loop_x_y(src, volum)=>
    // Variables
    var float hpa1      = na
    var float hpb1      = na
    var float hpc1      = na
    var float hpc2      = na
    var float hpc3      = na
    var float ssa1      = na
    var float ssb1      = na
    var float ssc1      = na
    var float ssc2      = na
    var float ssc3      = na
    var float HP        = na
    var float VolHP     = na
    var float Price     = na
    var float PriceMS   = na
    var float PriceRMS  = na
    var float Vol       = na
    var float VolMS     = na
    var float VolRMS    = na

    // Initialization
    if (bar_index == 0)
        sqr_2 =  math.sqrt(2)
        hpa1 := math.exp(-sqr_2 * math.pi / HPPeriod)
        hpb1 := 2 * hpa1 * math.cos(sqr_2 * math.pi / HPPeriod)
        hpc2 := hpb1
        hpc3 := -hpa1 * hpa1
        hpc1 := (1 + hpc2 - hpc3) / 4
        ssa1 := math.exp(-sqr_2 * math.pi / LPPeriod)
        ssb1 := 2 * ssa1 * math.cos(sqr_2 * math.pi / LPPeriod)
        ssc2 := ssb1
        ssc3 := -ssa1 * ssa1
        ssc1 := 1 - ssc2 - ssc3

    // Normalized Roofing Filter for Price
    // 2 Pole Butterworth Highpass Filter
    HP := hpc1 * (src - 2 * nz(src[1]) + nz(src[2])) + hpc2 * nz(HP[1]) + hpc3 * nz(HP[2])
    if (bar_index < 3)
        HP := 0

    // Smooth with a Super Smoother Filter
    Price := ssc1 * (HP + nz(HP[1])) / 2 + ssc2 * nz(Price[1]) + ssc3 * nz(Price[2])
    if (bar_index < 3)
        Price := 0

    // Additional Variables
    float num1 = 2.42  * math.pow(10, -2)
    float num2 = 9.758 * math.pow(10, -1)

    // Scale Price in terms of Standard Deviations
    PriceMS := na(PriceMS) ? Price * Price : num1 * Price * Price + num2 * nz(PriceMS[1])
    PriceRMS := PriceMS != 0 ? Price / math.sqrt(PriceMS) : na

    // Normalized Roofing Filter for Volume
    // 2 Pole Butterworth Highpass Filter
    VolHP := hpc1 * (volum - 2 * nz(volum[1]) + nz(volum[2])) + hpc2 * nz(VolHP[1]) + hpc3 * nz(VolHP[2])
    if (bar_index < 3)
        VolHP := 0

    // Smooth with a Super Smoother Filter
    Vol := ssc1 * (VolHP + nz(VolHP[1])) / 2 + ssc2 * nz(Vol[1]) + ssc3 * nz(Vol[2])
    if (bar_index < 3)
        Vol := 0

    // Scale Volume in terms of Standard Deviations
    VolMS  := na(VolMS) ? Vol * Vol : num1 * Vol * Vol + num2 * nz(VolMS[1])
    VolRMS := VolMS != 0 ? Vol / math.sqrt(VolMS) : na

    [PriceRMS, VolRMS]

// The ploting of loops
loops_ploting(float xPos, float yPos, string sym, color  col,
           int  numSegments,   int  barScale,   int offsetVal) =>
    if barstate.islast
        var tail = array.new<line> (numSegments + 1)

        for i = 0 to numSegments
            float newY2 =     yPos[i]
            int   newX2 = int(xPos[i] * barScale)
            int   newX1 = int(xPos[1 + i] * barScale)
            float newY1 =     yPos[1 + i]

            newX2 := newX2 + offsetVal + bar_index
            newX1 := newX1 + offsetVal + bar_index

            if i < numSegments
                lineWidth = int(4 * (numSegments - i) / numSegments + 1)

                line.delete(array.get(tail, i))

                tailSegments = line.new(newX1, newY1, newX2, newY2, color=color.new(col, 30 + i * 5),
                         style=line.style_solid,  width=lineWidth)

                array.set(tail, i, tailSegments)
  
            pointMarker = i == 0 ? "●" : ""
            symbolLabel = i == 0 ? sym : ""

            if i == 0
                label.delete(label.new(
                                     newX2, 
                                     newY2, 
                                     pointMarker,  
                                     size       =size.large,
                                     color      =#00000000, 
                                     textcolor  =col,
                                     style      =label.style_label_center)[1])

                label.delete(label.new(
                                     newX2, 
                                     newY2, 
                                     symbolLabel,  
                                     size      = sym_size == "Big" ? size.normal : size.small,
                                     color     = #00000000, 
                                     textcolor = m_col,
                                     style     = label.style_label_down)[1])

// Draw histogram
histo(price_, volume_, symbol, step = 0, show_hist)=>
    if barstate.islast and show_hist
        n = bar_index + 70
        color1 = color.from_gradient(price_, -2, 2, hist_dn, hist_up)
        color2 = color.from_gradient(volume_, -2, 2, hist_dn, hist_up)

        line.delete(line.new(n+step, 0, n+step, price_, width = 15, color = color1)[1])
        line.delete(line.new(n+8+step, 0, n+8+step, volume_, width = 15, color = color2)[1])

        label.delete(
             label.new(n+step-1, 0, symbol, 
                     color      = color(na), 
                     style      = label.style_label_lower_right, 
                     textcolor  = m_col, 
                     size       = sym_size == "Big" ? size.normal : size.small)[1]
                     )

        label.delete(
             label.new(n+step-1, price_, "Price:\n"+str.tostring(math.round(price_, 2)), 
                     color      = color(na), 
                     style      = price_ > 0 ? label.style_label_down : label.style_label_up, 
                     textcolor  = color.new(m_col, 30), 
                     size       = size.small)[1]
                     )

        label.delete(
             label.new(n+8+step, volume_, "Vol:\n"+str.tostring(math.round(volume_, 2)), 
                     color      = color(na), 
                     style      = volume_ > 0 ? label.style_label_down : label.style_label_up, 
                     textcolor  = color.new(m_col, 30), 
                     size       = size.small)[1]
                     )


// Request Data
[src1, vol1] = request_data(sym1)
[src2, vol2] = request_data(sym2)
[src3, vol3] = request_data(sym3)
[src4, vol4] = request_data(sym4)
[src5, vol5] = request_data(sym5)

// =====================================================================================================================}
// PLOT
// ====================================================================================================================={

if barstate.islast
    step = Offset/4

    line_new(step)
    label_new(step, "3")
    line_new(step*2)
    label_new(step*2, "2")
    line_new(step*3)
    label_new(step*3, "1")
    line_new(step*4)
    label_new(step*4, "0")
    line_new(step*5)
    label_new(step*5, "-1")
    line_new(step*6)
    label_new(step*6, "-2")
    line_new(step*7)
    label_new(step*7, "-3")
    
    label_new(+11, "Volume")

    line_new(1, false)
    label_new(1, "    1", false)
    line_new(-1, false)
    label_new(-1, "    -1", false)
    line_new(2, false)
    label_new(2, "    2", false)
    line_new(-2, false)
    label_new(-2, "    -2", false)
    line_new(3, false)
    label_new(3, "    3", false)
    line_new(-3, false)
    label_new(-3, "    -3", false)
    
    label_new(4.5, "Price", false) 

    // Center Lines
    line.delete(line.new(bar_index + Offset, 4, bar_index + Offset, -4, color = color.new(m_col, 50), style = line.style_solid)[1])
    line.delete(line.new(bar_index, 0, bar_index + Offset*2, 0, color = color.new(m_col, 50), style = line.style_solid)[1])

    if show_info
        var info = table.new(position.top_right, 10, 10)
        info.cell(0, 0, "1. 🡅 volume and 🡅 price. Generally, this is considered a
                         trend continuation condition. 
                         \n2. 🡇 volume and 🡅 price. This is generally considered
                         an extinguishing of demand.
                         \n3. 🡇 volume and 🡇 price. This is generally considered an
                         extinguishing of supply.
                         \n4. 🡅 volume and 🡇 price. This is generally considered a
                         continuation of a downtrend.
                         ",
                         text_color = s_col,
                         text_halign = text.align_left)


array<string> sym_1 = str.split(sym1, ":")
array<string> sym_2 = str.split(sym2, ":")
array<string> sym_3 = str.split(sym3, ":")
array<string> sym_4 = str.split(sym4, ":")
array<string> sym_5 = str.split(sym5, ":")

if barstate.islast and (on_5 or on_4 or on_3 or on_2 or on_1) and show_hist
    line.delete(line.new(bar_index+45, 0, bar_index+210, 0, color = m_col, style = line.style_solid)[1])

    line.delete(line.new(bar_index+45, 1, bar_index+210, 1, color = color.new(m_col, 70), style = line.style_dotted)[1])
    line.delete(line.new(bar_index+45, 2, bar_index+210, 2, color = color.new(m_col, 70), style = line.style_dotted)[1])
    line.delete(line.new(bar_index+45, 3, bar_index+210, 3, color = color.new(m_col, 70), style = line.style_dotted)[1])
    line.delete(line.new(bar_index+45, 4, bar_index+210, 4, color = color.new(m_col, 70), style = line.style_dotted)[1])

    line.delete(line.new(bar_index+45,-1, bar_index+210,-1, color = color.new(m_col, 70), style = line.style_dotted)[1])
    line.delete(line.new(bar_index+45,-2, bar_index+210,-2, color = color.new(m_col, 70), style = line.style_dotted)[1])
    line.delete(line.new(bar_index+45,-3, bar_index+210,-3, color = color.new(m_col, 70), style = line.style_dotted)[1])
    line.delete(line.new(bar_index+45,-4, bar_index+210,-4, color = color.new(m_col, 70), style = line.style_dotted)[1])

int   step   = 30

if on_1
    [price_1, volume_1] = ehler_loop_x_y(src1, vol1)  
    loops_ploting(volume_1, price_1, sym_1.last(),col1, 10, 25, Offset)
    histo(price_1, volume_1, sym_1.last(), 0, show_hist)

if on_2
    [price_2, volume_2] = ehler_loop_x_y(src2, vol2)
    loops_ploting(volume_2, price_2, sym_2.last(),col2, 10, 25, Offset)
    histo(price_2, volume_2, sym_2.last(), step, show_hist)

if on_3
    [price_3, volume_3] = ehler_loop_x_y(src3, vol3)
    loops_ploting(volume_3, price_3, sym_3.last(),col3, 10, 25, Offset)
    histo(price_3, volume_3, sym_3.last(), step*2, show_hist)
        
if on_4
    [price_4, volume_4] = ehler_loop_x_y(src4, vol4)
    loops_ploting(volume_4, price_4, sym_4.last(),col4, 10, 25, Offset)
    histo(price_4, volume_4, sym_4.last(), step*3, show_hist)
        
if on_5
    [price_5, volume_5] = ehler_loop_x_y(src5, vol5)
    loops_ploting(volume_5, price_5, sym_5.last(),col5, 10, 25, Offset)
    histo(price_5, volume_5, sym_5.last(), step*4, show_hist)

// =====================================================================================================================}

Overview

Ehlers Loops [BigBeluga] requests each symbol's prior close and volume, with low-pass and high-pass periods as the main filter settings. Enabled symbols are drawn with colored labels and lines, and label size can be small or big. A histogram can be shown with separate colors for positive and negative values. An info display is available but off by default. It is not a strategy and has no entries or exits.

Details

Published by

regalouisei on GitHub

Code credit

BigBeluga, as written in the script's header

Type

Indicator, Pine Script v5

Draws

Separate pane below the chart

Category

Volume, Screeners & dashboards

Markets

Crypto, Indices

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.

Settings

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

SettingTypeDefaultVariable
Low Pass Periodint10LPPeriod
High Pass Periodint125HPPeriod
on_1booltrueon_1
on_2booltrueon_2
on_3booltrueon_3
on_4booltrueon_4
on_5booltrueon_5
sym1symbolBTCUSDsym1
sym2symbolETHUSDsym2
sym3symbolSOLUSDsym3
sym4symbolBNBUSDsym4
sym5symbolSPXsym5
Show all 22 settings
SettingTypeDefaultVariable
col1color#22d17ccol1
col2color#20b6cacol2
col3color#c28120col3
col4color#ccbb1fcol4
col5color#f23645col5
Symbol SizestringSmallsym_size
Show histogrambooltrueshow_hist
+color#22d17chist_up
-color#f23645hist_dn
Info 🛈boolfalseshow_info
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

Oscillator Suite

by TamaraKGreen
46 stars

Oscillator Suite plots a normalised price oscillator in a separate pane and overlays a signal line that can use SMA, EMA, WMA, HMA, RMA, VWMA, T3, ZEMA, KAMA, or GKEMA. It marks bullish and bearish divergences, a smoothed money-flow series, confluence areas an

Indicator v5 Oscillators & momentumDivergence
Updated 7 weeks ago · None stated GitHub repository of Oscillator Suite

Relative Strength Table

by ChartsLector
41 stars

This indicator builds a table of relative strength for up to six user-chosen symbols against a benchmark, defaulting to SPY. It measures strength over four lookback periods, can average the visible periods, and can add relative volume as current volume divided

Indicator v6 Screeners & dashboardsVolume
Updated 2 days ago · None stated GitHub repository of Relative Strength Table

This indicator calculates the Relative Strength Index (RSI) alongside a simple moving average to generate directional momentum signals in a separate pane. It supports Break Flip and Break Continuous scanning modes for long and short setups. A wide array of opt

Indicator v5 Oscillators & momentumVolatility & bands
Updated 1 year ago · None stated GitHub repository of Momentum Setup: RSI Direction Confirmation
11 stars

This indicator plots a smoothed Z-score of cumulative volume delta in a separate pane, showing whether buying or selling pressure is dominant and when the reading enters extreme zones. It marks spot accumulation, climax or exhaustion, and pivot-based price-vol

Indicator v6 Oscillators & momentumVolume Repaints
Updated 7 weeks ago · MIT GitHub repository of CVD Z-Score [NeuNue]

The Candle Pressure Index measures buying versus selling pressure from candle geometry and relative volume. Each bar combines close location, body ratio, and volume rank into a raw pressure value. An exponential moving average of that pressure forms the CPI os

Indicator v6 Oscillators & momentumVolume
Updated yesterday · MIT GitHub repository of Candle Pressure Index [WavesUnchained]

Nexural OrderFlow Matrix

by JasonTeixeira
9 stars

Nexural OrderFlow Matrix is an order flow visualization tool that plots a detailed heatmap table and stacked imbalance bars in a separate pane. It calculates volume metrics using lower timeframe volume delta data, displaying per-candle metrics such as Delta, D

Indicator v6 VolumeScreeners & dashboards
Updated 12 days ago · Custom licence GitHub repository of Nexural OrderFlow Matrix

More indicators

Trade Your Charts With a Regulated Broker

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

Compare brokers