Skip to content

Instantly share code, notes, and snippets.

@ViralTaco
Created December 26, 2025 18:15
Show Gist options
  • Select an option

  • Save ViralTaco/f8d077d73b0f87439eac86323e7f0927 to your computer and use it in GitHub Desktop.

Select an option

Save ViralTaco/f8d077d73b0f87439eac86323e7f0927 to your computer and use it in GitHub Desktop.
A custom indicator for tradingview. Adapted from the Elder's Force Indicator
//Copyright © 2025 unsigned_lemon
//Read the license agreement (at the bottom of the page), before using this indicator.
//@version=6
//@description RSI Style Elder Force Index with bar coloring
indicator(title = "Viral Force Index Enhanced", shorttitle = "vfi v3", format = format.volume,
precision = 4)
// ===== CONSTANTS =====
var int kMaxFreeBarsBack = 5000 - 1
// Group Constants
string G_VFI = "VFI Settings"
string G_LINREG = "Linear Regression"
string G_EXTREME = "Extreme Levels"
string G_STYLE = "Styling"
// ===== TYPES =====
type DebugPanel
table id
bool show
// Initialize the table
method init(DebugPanel this, simple int columns = 2, simple int rows = 7) =>
if this.show and barstate.islast
this.id := table.new(position = position.top_right,
columns = columns,
rows = rows,
bgcolor = color.new(color.gray, 95),
border_width = 1,
border_color = color.gray)
table.cell(this.id, 0, 0, "PARAMETER", text_color = color.white)
table.cell(this.id, 1, 0, "VALUE", text_color = color.white)
// Update a row in the table
method update_row(DebugPanel this, int row, string label, string val, color val_color) =>
if this.show and barstate.islast
table.cell(this.id, 0, row, label, text_color = color.gray)
table.cell(this.id, 1, row, val, text_color = val_color)
// ===== INPUTS =====
// Group 1: VFI Settings
float source = input.source(close, "Source", group = G_VFI, tooltip = "The source price to use for calculations.")
int length = input.int(13, "EMA Length", minval = 1, group = G_VFI, tooltip = "The length of the EMA smoothing.")
int max_lookback_bars = input.int(500, "Lookback Length", minval = 2,
maxval = kMaxFreeBarsBack, group = G_VFI, tooltip = "Number of bars to look back for scaling and percentile rank.")
// Group 2: Linear Regression
int linreg_length = input.int(13, "Linear Regression Length", minval = 1,
group = G_LINREG, tooltip = "Length for the Linear Regression calculation.")
int linreg_offset = input.int(3, "Linear Regression Offset", group = G_LINREG, tooltip = "Offset for the Linear Regression.")
// Group 3: Extreme Levels
float upper_threshold = input.float(95.0, "Upper Threshold", minval = 50, maxval = 100,
step = 0.5, group = G_EXTREME, tooltip = "Percentile rank threshold for overbought conditions.")
float lower_threshold = input.float(5.0, "Lower Threshold", minval = 0, maxval = 50,
step = 0.5, group = G_EXTREME, tooltip = "Percentile rank threshold for oversold conditions.")
// Group 4: Styling
var color up_color = input.color(#7bed36, "Up Color", group = G_STYLE, inline = "colors", tooltip = "Color for positive values.")
var color down_color = input.color(#f79400, "Down Color", group = G_STYLE, inline = "colors", tooltip = "Color for negative values.")
var color extreme_color = input.color(color.blue, "Extreme Color", group = G_STYLE,
inline = "colors", tooltip = "Color for extreme levels.")
bool use_linreg_color = input.bool(true, "Use Linear Regression for Bar Color", group = G_STYLE,
tooltip = "If true, uses the Linear Regression slope for bar coloring.")
bool linreg_gradient_on = input.bool(true, "Use gradient color for linear regression line",
group = G_STYLE, inline = "colors2")
var color linreg_solid = input.color(color.white, "Linear regression line color",
group = G_STYLE, inline = "colors2", active = not linreg_gradient_on)
bool show_debug = input.bool(true, "Show Debug Panel", group = G_STYLE, tooltip = "Toggle the visibility of the debug panel.")
// ===== CALCULATIONS =====
varip series float volume_symbol = input.source(volume, "use volume ticker")
float price_change = ta.change(source / syminfo.mintick)
if price_change == 0
price_change := price_change[1]
float raw_change = price_change * volume_symbol
// Simplified scaling factor
float kFactor = math.max(ta.highest(math.abs(raw_change), max_lookback_bars) / 1000, 1.0)
// Calculate VFI with improved EMA smoothing
float raw_vfi = raw_change / kFactor
float vfi = ta.ema(raw_vfi, length)
// Use fixed lookback for percent rank to ensure consistency
float normed_rank = ta.percentrank(vfi, max_lookback_bars)
// Improved extreme detection using statistical thresholds
bool is_extreme_level = normed_rank >= upper_threshold or normed_rank <= lower_threshold
// Linear regression for trend detection
float linreg = ta.linreg(vfi, linreg_length, linreg_offset)
// Color calculations
color current_color = color.from_gradient(vfi, -50, 50, down_color, up_color)
color extreme_color_final = is_extreme_level ? extreme_color : current_color
color smooth_color = color.from_gradient(linreg, -25, 25, down_color, up_color)
color bar_fill_color = use_linreg_color ? smooth_color : extreme_color_final
color colin = linreg_gradient_on ? smooth_color : linreg_solid
// ===== PLOTS & VISUALS =====
// Main VFI plot with improved styling
plot(vfi, "VFI",
color = extreme_color_final,
style = plot.style_histogram,
linewidth = 1,
histbase = 0)
// Linear regression trend line
plot(linreg, "Linear Regression",
color = colin,
style = plot.style_line,
linewidth = 1)
// Reference levels
hline(100, "Upper Bound", color = color.new(color.white, 70), linestyle = hline.style_dotted)
h75 = hline(75, "Upper Quartile", color = color.new(color.white, 80), linestyle = hline.style_dotted)
h50 = hline(50, "Mid Upper", color = color.new(color.white, 90), linestyle = hline.style_dotted)
h25 = hline(25, "Low Upper", color = color.new(color.white, 90), linestyle = hline.style_dotted)
h0 = hline(0, "Zero Line", color = color.new(color.gray, 50), linestyle = hline.style_dotted)
hm25 = hline(-25, "High Lower", color = color.new(color.white, 90), linestyle = hline.style_dotted)
hm50 = hline(-50, "Mid Lower", color = color.new(color.white, 90), linestyle = hline.style_dotted)
hm75 = hline(-75, "Lower Quartile", color = color.new(color.white, 80), linestyle = hline.style_dotted)
hline(-100, "Lower Bound", color = color.new(color.white, 70), linestyle = hline.style_dotted)
// Fills
fill(h0, h25, color.new(up_color, 95), title = "0-25 Fill")
fill(h25, h50, color.new(up_color, 90), title = "25-50 Fill")
fill(h50, h75, color.new(up_color, 85), title = "50-75 Fill")
fill(h0, hm25, color.new(down_color, 95), title = "0-(-25) Fill")
fill(hm25, hm50, color.new(down_color, 90), title = "(-25)-(-50) Fill")
fill(hm50, hm75, color.new(down_color, 85), title = "(-50)-(-75) Fill")
// Bar coloring
barcolor(bar_fill_color)
// Background color for extreme levels
bgcolor(is_extreme_level ? color.new(extreme_color, 90) : na, title = "Extreme Level Background")
// Debug Panel
var DebugPanel panel = DebugPanel.new(table(na), show_debug)
panel.init()
panel.update_row(1, "Raw VFI", str.tostring(raw_vfi, "#.####"), color.orange)
panel.update_row(2, "Smoothed VFI", str.tostring(vfi, "#.####"), current_color)
panel.update_row(3, "Percent Rank", str.tostring(normed_rank, "#.##") + "%",
is_extreme_level ? extreme_color : color.gray)
//panel.update_row(4, "Scaling Factor", str.tostring(kFactor, "#.####"), color.silver)
panel.update_row(4, "LinReg Slope", str.tostring(linreg, "#.####"), smooth_color)
panel.update_row(5, "Extreme Level", is_extreme_level ? "YES" : "NO",
is_extreme_level ? extreme_color : color.green)
// ===== ALERTS =====
alertcondition(is_extreme_level, "VFI Extreme Level",
"VFI has entered extreme territory at {{close}}")
//
// The Viral License - 1.1.0~use-only
//
// Permission is hereby granted, free of charge,
// to anyone obtaining a copy of this software (the 'Recipient', 'You', 'Your'),
// associated documentation files (the 'Software', the 'Indicator'),
// and the source code of the Software, including any inline documentation (the 'Source'),
// to use the Software, and Source, subject to the following conditions:
//
// • The above copyright notice as well as this permission notice (including the next paragraphs)
// shall be included in all copies, or substantial portions of the Software as well as the Source.
//
// • For the purpose of this license, the term 'use' is dvfined as:
// 0) Applying the Indicator to a chart on TradingView
// 1) Reading the Source
// 2) Editing the Source, applying the result to a chart on TradingView for Your use ONLY.
// 3) The use is Yours CANNOT be transfered.
//
// • The Software, the Source, or portions of the Source
// SHALL NOT be distributed without EXPRESS AUTHORIZATION from the Author.
//
// • Commercial use of the Software without PRIOR SIGNED APPROVAL from the Author
// is PROHIBITED, and WILL result in litigation.
//
// • You ACCEPT to STOP using the Software if ANY condition is illegal, or null.
//
// • You UNDERSTAND AND You ACCEPT every condition and its —potential— implications,
// including all limitations layed herein, including the following:
//
// THE SOFTWARE AND THE SOURCE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF,
// OR IN AN CONNECTION WITH, THE SOFTWARE, OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Mediation and Arbitration: THE BELGIAN CENTRE FOR ARBITRATION AND MEDIATION
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment