Indicator · Pine Script v5 · Own pane

Oscillator

by TamTH-Dev· code credited to tamth_

Oscillator combines WaveTrend calculations, Money Flow Oscillator (MFO), custom VWAP tracking, and volume breakout analysis into a single separate-pane indicator.

View on GitHub

GitHub stars2on the repository
Pine versionv5runs as is
Lines of code179
Settings14inputs
LicenceNone statedfile: MPL-2.0
Last update5 weeks ago18 Sep 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

179 lines of Pine Script v5 from collections/MarketCipher.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

MarketCipher.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tamth_

// @version=5
indicator("Oscillator", shorttitle = "Oscillator", overlay = false, max_bars_back = 5000, max_lines_count = 500, max_boxes_count = 500, max_labels_count = 500)


//-----------------------------------------------------------------------------*
//  Constants
//-----------------------------------------------------------------------------{
color TRANSPARENT_COLOR = #ffffff00
color WHITE_COLOR = #EFEFEF
color RED_COLOR = #DD326B
color AQUA_COLOR = #04ADBF
color YELLOW_COLOR = #E8D81E
color PURPLE_COLOR = #764AF1
color GREEN_COLOR = #17DFAD
color LIGHT_GRAY_COLOR = #364156
color DARK_GRAY_COLOR = #212d40

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


//-----------------------------------------------------------------------------*
// Common Variables
//-----------------------------------------------------------------------------{
series int barIdx = bar_index
series bool confirmed = barstate.isconfirmed

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


//-----------------------------------------------------------------------------*
// Common Functions
//-----------------------------------------------------------------------------{
debug(simple string txt) =>
    // Create label on the first bar
    var label = label.new(barIdx, na, txt, xloc.bar_index, yloc.price, color(na), label.style_none, WHITE_COLOR, size.large, text.align_left)
    // On next bars, update the label"s x and y position, and the text it displays
    label.set_xy(label, barIdx, ta.highest(10)[1])
    label.set_text(label, txt)

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


//-----------------------------------------------------------------------------*
// Settings
//-----------------------------------------------------------------------------{
string thresholdGrp = "Threshold"
bool thresholdShowed = input.bool(true, title = "Show", group = thresholdGrp)
int overboughtThreshold = input.int(60, title = "Overbought Threshold", group = thresholdGrp)
int oversoldThreshold = input.int(-60, title = "Oversold Threshold", group = thresholdGrp)
string wtGrp = "Waves Trend"
bool wtShowed = input.bool(true, title = "Show", group = wtGrp)
int wtChlPrd = input.int(9, title = "Channel Period", group = wtGrp)
int wtAvgPrd = input.int(12, title = "Average Period", group = wtGrp)
float wtMaSrc = input.source(hlc3, title = "MA Source", group = wtGrp)
int wtMaLen = input.int(3, title = "MA Length", group = wtGrp)
string mfoGrp = "MFO"
bool mfoShowed = input.bool(true, title = "Show", group = mfoGrp)
// bool mfoBarShowed = input.bool(true, title = "Support Bar", group = mfoGrp)
int mfoPrd = input.int(60, title = "Period", group = mfoGrp)
int mfoMult = input.int(150, title = "Area Multiplier", group = mfoGrp)
string vwapGrp = "VWAP"
bool vwapShowed = input.bool(true, title = "Show", group = vwapGrp)
string vaGrp = "Volume Analysis"
int vaLen = input.int(14, "Length", group = vaGrp)
float vaBreakoutFactor = input.float(3.1, title = "Breakout Factor", group = vaGrp)

//-----------------------------------------------------------------------------}
// Functions
//-----------------------------------------------------------------------------{
getTopFractal(series float src) => src[4] < src[2] and src[3] < src[2] and src[2] > src[1] and src[2] > src[0]
getBotFractal(series float src) => src[4] > src[2] and src[3] > src[2] and src[2] < src[1] and src[2] < src[0]
fractalize(series float src) =>
    series bool isBotFractal = getBotFractal(src)
    series bool isTopFractal = getTopFractal(src)
    isTopFractal ? 1 : isBotFractal ? -1 : 0

getDivPoints(series float src, int topLimit, int botLimit) =>
    series bool isTopFractal = not na(fractalize(src) > 0 and src[2] >= topLimit ? src[2] : na)
    series bool isBotFractal = not na(fractalize(src) < 0 and src[2] <= botLimit ? src[2] : na)
    float highPrev = ta.valuewhen(isTopFractal, src[2], 0)[2]
    float highPrice = ta.valuewhen(isTopFractal, high[2], 0)[2]
    float lowPrev = ta.valuewhen(isBotFractal, src[2], 0)[2]
    float lowPrice = ta.valuewhen(isBotFractal, low[2], 0)[2]
    bool isBearish = isTopFractal and high[2] > highPrice and src[2] < highPrev
    bool isBullish = isBotFractal and low[2] < lowPrice and src[2] > lowPrev
    [isTopFractal, isBotFractal, lowPrev, isBearish, isBullish]

getWtAndVwap() =>
    float src = request.security(syminfo.tickerid, timeframe.period, wtMaSrc)
    float esa = ta.ema(src, wtChlPrd)
    float d = ta.ema(math.abs(src - esa), wtChlPrd)
    float ci = (src - esa) / (0.015 * d)
    float leadingWt = ta.ema(ci, wtAvgPrd)
    float laggingWt = ta.sma(leadingWt, wtMaLen)
    bool isOversold = laggingWt <= oversoldThreshold
    bool isOverbought = laggingWt >= overboughtThreshold
    bool wtCross = ta.cross(leadingWt, laggingWt)
    bool wtCrossUp = laggingWt - leadingWt <= 0
    bool wtCrossDn = laggingWt - leadingWt >= 0
    float vwap = leadingWt - laggingWt
    [leadingWt, laggingWt, isOversold, isOverbought, wtCross, wtCrossUp, wtCrossDn, vwap]

getHaVal(series float src) => request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, src)

getMfo() =>
    series float haOpen = getHaVal(open)
    series float haClose = getHaVal(close)
    series float haHigh = getHaVal(high)
    series float haLow = getHaVal(low)
    mfo = ta.sma((haClose - haOpen) / (haHigh - haLow) * mfoMult, mfoPrd)

//-----------------------------------------------------------------------------}
// Get values
//-----------------------------------------------------------------------------{
int WT_LONG_BEARISH_DIV_LEVEL = 45
int WT_LONG_BULLISH_DIV_LEVEL = -65
int WT_SHORT_BEARISH_DIV_LEVEL = 15
int WT_SHORT_BULLISH_DIV_LEVEL = -40
series float _close = request.security(syminfo.tickerid, timeframe.period, close)
series float _high = request.security(syminfo.tickerid, timeframe.period, high)
series float _low = request.security(syminfo.tickerid, timeframe.period, low)
float mfo = getMfo()
[leadingWt, laggingWt, isOversold, isOverbought, cross, crossUp, crossDn, vwap] = getWtAndVwap()
[wtLongTopFractal, wtLongBotFractal, wtLongLowPrev, isWtLongBearishDiv, isWtLongBullishDiv] = getDivPoints(laggingWt, WT_LONG_BEARISH_DIV_LEVEL, WT_LONG_BULLISH_DIV_LEVEL)
[wtShortTopFractal, wtShortBotFractal, wtShortLowPrev, isWtShortBearishDiv, isWtShortBullishDiv] =  getDivPoints(laggingWt, WT_SHORT_BEARISH_DIV_LEVEL, WT_SHORT_BULLISH_DIV_LEVEL)
bool isBuySignal = ta.crossover(leadingWt, laggingWt)
bool isSellSignal = ta.crossunder(leadingWt, laggingWt)
bool isDivBuySignal = isWtLongBullishDiv or isWtShortBullishDiv
bool isDivSellSignal = isWtLongBearishDiv or isWtShortBearishDiv

series float vaAvg = ta.sma(volume, vaLen)
series float vaMultHigh = vaAvg * 3
series float vaMultMid = vaMultHigh / 2
series float vaMultLow  = vaAvg / 2
series float vaBullish = close > open ? volume : 0
series float vaBearish = open > close ? volume : 0
series float vaSmoothBullish = ta.sma(vaBullish, vaLen)
series float vaSmoothBearish = ta.sma(vaBearish, vaLen)
series float vaExt = ta.crossover(volume, vaMultHigh) ? volume : na
series float vaHigh = ta.crossover(volume, vaMultMid) ? volume : na
series bool vaGsig = not na(ta.crossover(vaBullish, vaSmoothBullish * vaBreakoutFactor) ? volume : na)
series bool vaRsig = not na(ta.crossover(vaBearish, vaSmoothBearish * vaBreakoutFactor) ? volume : na)
series bool vaGsigHigh = ta.crossover(vaBullish, vaSmoothBullish * vaBreakoutFactor) and not na(vaHigh)
series bool vaRsigHigh = ta.crossover(vaBearish, vaSmoothBearish * vaBreakoutFactor) and not na(vaHigh)
series bool vaGsigExt = ta.crossover(vaBullish, vaSmoothBullish * vaBreakoutFactor) and not na(vaExt)
series bool vaRsigExt = ta.crossover(vaBearish, vaSmoothBearish * vaBreakoutFactor) and not na(vaExt)

//-----------------------------------------------------------------------------}
// Render values
//-----------------------------------------------------------------------------{
color vaTopBarColor = vaGsig or vaGsigHigh or vaGsigExt ? (vaGsig or vaGsigHigh ? GREEN_COLOR : YELLOW_COLOR) : color.new(LIGHT_GRAY_COLOR, 50)
color vaBotBarColor = vaRsig or vaRsigHigh or vaRsigExt ? (vaRsig or vaRsigHigh ? RED_COLOR : PURPLE_COLOR) : color.new(LIGHT_GRAY_COLOR, 50)
var vaTopLineSt = plot(105, title = "Top Volume Bar", color = TRANSPARENT_COLOR, editable = false, display = display.pane)
var vaTopLineNd = plot(100, title = "Top Volume Bar", color = TRANSPARENT_COLOR, editable = false, display = display.pane)
var vaBotLineSt = plot(-100, title = "Bottom Volume Bar", color = TRANSPARENT_COLOR, editable = false, display = display.pane)
var veBotLineNd = plot(-105, title = "Bottom Volume Bar", color = TRANSPARENT_COLOR, editable = false, display = display.pane)
fill(vaTopLineSt, vaTopLineNd, title = "Top Volume Bar Color", color = vaTopBarColor)
fill(vaBotLineSt, veBotLineNd, title = "Bottom Volume Bar Color", color = vaBotBarColor)

plot(thresholdShowed ? overboughtThreshold : na, title = "Overbought Threshold", color = DARK_GRAY_COLOR, display = display.pane, linewidth = 1, style = plot.style_cross)
plot(thresholdShowed ? oversoldThreshold : na, title = "Oversold Threshold", color = DARK_GRAY_COLOR, display = display.pane, linewidth = 1, style = plot.style_cross)
plot(vwapShowed ? vwap : na, title = "VWAP", color = color.new(LIGHT_GRAY_COLOR, 10), style = plot.style_area)
plot(mfoShowed ? mfo : na, title = "MFO", color = mfo > 0 ? color.new(GREEN_COLOR, 80) : color.new(RED_COLOR, 80), linewidth = 2, style = plot.style_area)

color leadingWtColor = leadingWt >= laggingWt ? color.new(AQUA_COLOR, 20) : color.new(WHITE_COLOR, 20)
var leadingWtPlot = plot(wtShowed ? leadingWt : na, title = "Leading Wave Trend", color = leadingWtColor, linewidth = 2, style = plot.style_line, display = display.pane)
var laggingWtPlot = plot(wtShowed ? laggingWt : na, title = "Lagging Wave Trend", color = TRANSPARENT_COLOR, linewidth = 1, style = plot.style_line, display = display.pane)
color wtFillColor = leadingWt >= laggingWt ? color.new(AQUA_COLOR, 75) : color.new(WHITE_COLOR, 75)
fill(leadingWtPlot, laggingWtPlot, title = 'Wave Trend', color = wtFillColor)

plot(0, title = "Zero Line", color = color.new(DARK_GRAY_COLOR, 80), display = display.pane)

plot(isBuySignal and confirmed ? laggingWt : na, title = "Buy Signal", color = color.new(AQUA_COLOR, 20), linewidth = 2, style = plot.style_circles, display = display.pane)
plot(isSellSignal and confirmed  ? laggingWt : na, title = "Sell Signal", color = color.new(WHITE_COLOR, 20), linewidth = 2, style = plot.style_circles, display = display.pane)
plot(isDivBuySignal and confirmed ? -110 : na, title = "Divergence Buy Signal", color = AQUA_COLOR, linewidth = 2, style = plot.style_circles, offset = -2, display = display.pane)
plot(isDivSellSignal and confirmed ? 110 : na , title = "Divergence Sell Signal", color = WHITE_COLOR, linewidth = 2, style = plot.style_circles, offset = -2, display = display.pane)

Overview

Oscillator calculates oscillator wave values along with moving average smoothing to highlight overbought and oversold thresholds. Users can toggle individual components including WaveTrend lines, MFO background fills, VWAP readings, and threshold reference lines through input settings.

Details

Published by

TamTH-Dev on GitHub

Code credit

tamth_, as written in the script's header

Type

Indicator, Pine Script v5

Draws

Separate pane below the chart

Category

Oscillators & momentum, Volatility & bands, Volume

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.

Settings

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

SettingTypeDefaultVariable
ShowbooltruethresholdShowed
Overbought Thresholdint60overboughtThreshold
Oversold Thresholdint-60oversoldThreshold
ShowbooltruewtShowed
Channel Periodint9wtChlPrd
Average Periodint12wtAvgPrd
MA Sourcesourcehlc3wtMaSrc
MA Lengthint3wtMaLen
ShowbooltruemfoShowed
Periodint60mfoPrd
Area Multiplierint150mfoMult
ShowbooltruevwapShowed
Show all 14 settings
SettingTypeDefaultVariable
Lengthint14vaLen
Breakout Factorfloat3.1vaBreakoutFactor
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

114 stars

This indicator standardizes price inputs using z-score normalization before calculating a relative strength index (RSI). It generates trade signals when standardized price components cross over or under the standardized RSI feature. Signals can be filtered by

Indicator v4 Oscillators & momentumVolatility & bands Repaints
Updated 1 year ago · None stated GitHub repository of Preprosessed & Standardized RSI

PPO ATR Bands

by cryptorife
75 stars

PPO ATR Bands plots a percentage price oscillator in a separate pane. It compares a Hull average of typical price with a volume-weighted exponential average of Parabolic SAR, then scales three true-range bands around the slow average into matching oscillator l

Indicator v4 Oscillators & momentumMoving averages
Updated 3 years ago · GPL-3.0 GitHub repository of PPO ATR Bands

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

NFI v6

by koradiyakaushal
12 stars

This Pine v4 study ports early NostalgiaForInfinity V6 conditions onto the price chart. It computes two Bollinger setups, several EMAs and SMAs, RSI, MFI, a percent SMA spread labeled EWO, a 14-period choppiness value, and short and longer volume medians. Fixe

Indicator v4 Moving averagesVolatility & bands
Updated 5 years ago · MIT GitHub repository of NFI v6

The script calculates a variant of the Fear & Greed Index using rate of return, accumulation distribution money flow weighted by volume, and volatility from VIX. It offers display options for the raw index value or price candles scaled by the index level. Smoo

Indicator v5 Oscillators & momentumVolatility & bands Repaints
Updated 4 years ago · MPL-2.0 GitHub repository of Trading Psychology - Fear & Greed Index by DGT

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