
This script scores every stock on your TradingView watchlist from 0 to 5 based on five technical conditions. Only trade stocks scoring 4 or 5. Copy the script below, paste it into TradingView's Pine Editor, and follow the setup guide.
What each score means and what to do
Click each condition to see the full logic
Step-by-step — takes less than 5 minutes
TradingView Pro required for the Pine Screener feature. The indicator itself works on any plan — you can manually check the score on individual charts for free.
Copy and paste into TradingView Pine Editor
// Jessie's Simple Screener
// Culgan Wealth | Pine Script v6
// Scores each stock 0-5 across five conditions.
// Score 4-5 = TAKE A LOOK | 3 = NEUTRAL | 0-2 = SKIP
// HOW TO USE: Pine Editor > Add to chart > Star it > Open Screener > Pine Screener > filter Score >= 4
//@version=6
indicator("Jessie's Simple Screener", shorttitle="Jessie Score", overlay=false, max_bars_back=500)
// INPUTS
emaFastLen = input.int(21, "Fast EMA Length", group="EMA", minval=1)
emaSlowLen = input.int(50, "Slow EMA Length", group="EMA", minval=1)
rsiLen = input.int(14, "RSI Length", group="RSI", minval=1)
rsiThresh = input.float(40, "RSI Min Threshold", group="RSI", minval=1, maxval=100)
obvMaLen = input.int(20, "OBV MA Length", group="OBV", minval=1)
volMaLen = input.int(20, "Volume MA Length", group="Volume", minval=1)
swingLen = input.int(10, "Swing Lookback", group="Structure", minval=3)
// COLOURS
C_CYAN = color.rgb(0, 212, 170)
C_GREEN = color.rgb(34, 197, 94)
C_YELLOW = color.rgb(234, 179, 8)
C_ORANGE = color.rgb(249, 115, 22)
C_RED = color.rgb(239, 68, 68)
C_NAVY = color.rgb(13, 20, 33)
C_SLATE = color.rgb(148, 163, 184)
C_LIGHT = color.rgb(203, 213, 225)
C_WHITE = color.rgb(255, 255, 255)
C_BORDER = color.rgb(30, 58, 95)
// CONDITION 1 - Market Structure: Higher Highs and Higher Lows
pivotHigh = ta.pivothigh(high, swingLen, swingLen)
pivotLow = ta.pivotlow(low, swingLen, swingLen)
var float prevHigh1 = na
var float prevHigh2 = na
if not na(pivotHigh)
prevHigh2 := prevHigh1
prevHigh1 := pivotHigh
var float prevLow1 = na
var float prevLow2 = na
if not na(pivotLow)
prevLow2 := prevLow1
prevLow1 := pivotLow
higherHigh = not na(prevHigh1) and not na(prevHigh2) and prevHigh1 > prevHigh2
higherLow = not na(prevLow1) and not na(prevLow2) and prevLow1 > prevLow2
cond1 = higherHigh and higherLow
// CONDITION 2 - EMA Trend Filter: Price above EMA21 and EMA50
emaFast = ta.ema(close, emaFastLen)
emaSlow = ta.ema(close, emaSlowLen)
cond2 = close > emaFast and close > emaSlow and emaFast > emaSlow
// CONDITION 3 - OBV Momentum: OBV above 20-bar MA
obv = ta.obv
obvMa = ta.sma(obv, obvMaLen)
cond3 = obv > obvMa
// CONDITION 4 - RSI Strength: RSI above threshold
rsiVal = ta.rsi(close, rsiLen)
cond4 = rsiVal > rsiThresh
// CONDITION 5 - Volume Surge: Volume above 20-day average
volMa = ta.sma(volume, volMaLen)
cond5 = volume > volMa
// SCORE
score = (cond1 ? 1 : 0) + (cond2 ? 1 : 0) + (cond3 ? 1 : 0) + (cond4 ? 1 : 0) + (cond5 ? 1 : 0)
// SCORE COLOUR
scoreColor = score >= 5 ? C_CYAN : score == 4 ? C_GREEN : score == 3 ? C_YELLOW : score == 2 ? C_ORANGE : C_RED
// CONDITION COLOUR FUNCTION
condColor(c) => c ? color.new(C_CYAN, 20) : color.new(C_RED, 40)
// PLOTS - data window only, no chart clutter
plot(cond1 ? 1 : 0, "1. Market Structure", condColor(cond1), display=display.data_window)
plot(cond2 ? 1 : 0, "2. EMA Trend Filter", condColor(cond2), display=display.data_window)
plot(cond3 ? 1 : 0, "3. OBV Momentum", condColor(cond3), display=display.data_window)
plot(cond4 ? 1 : 0, "4. RSI Strength", condColor(cond4), display=display.data_window)
plot(cond5 ? 1 : 0, "5. Volume Surge", condColor(cond5), display=display.data_window)
// TABLE
var table t = table.new(position.top_right, 2, 7, bgcolor=color.new(C_NAVY, 10), border_color=color.new(C_BORDER, 80), border_width=1, frame_color=color.new(C_CYAN, 60), frame_width=1)
if barstate.islast
table.cell(t, 0, 0, "Jessie's Simple Screener", text_color=C_CYAN, text_size=size.small, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 0, "Culgan Wealth", text_color=C_SLATE, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_right)
table.cell(t, 0, 1, "1. Market Structure", text_color=C_LIGHT, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 1, cond1 ? "YES" : "NO", text_color=cond1 ? C_CYAN : C_RED, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_center)
table.cell(t, 0, 2, "2. EMA Trend Filter", text_color=C_LIGHT, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 2, cond2 ? "YES" : "NO", text_color=cond2 ? C_CYAN : C_RED, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_center)
table.cell(t, 0, 3, "3. OBV Momentum", text_color=C_LIGHT, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 3, cond3 ? "YES" : "NO", text_color=cond3 ? C_CYAN : C_RED, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_center)
table.cell(t, 0, 4, "4. RSI Strength", text_color=C_LIGHT, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 4, cond4 ? "YES" : "NO", text_color=cond4 ? C_CYAN : C_RED, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_center)
table.cell(t, 0, 5, "5. Volume Surge", text_color=C_LIGHT, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 5, cond5 ? "YES" : "NO", text_color=cond5 ? C_CYAN : C_RED, text_size=size.tiny, bgcolor=C_NAVY, text_halign=text.align_center)
scoreLabel = score >= 4 ? str.tostring(score) + "/5 TAKE A LOOK" : score == 3 ? str.tostring(score) + "/5 NEUTRAL" : str.tostring(score) + "/5 SKIP"
table.cell(t, 0, 6, "TOTAL SCORE", text_color=C_WHITE, text_size=size.small, bgcolor=C_NAVY, text_halign=text.align_left)
table.cell(t, 1, 6, scoreLabel, text_color=scoreColor, text_size=size.small, bgcolor=C_NAVY, text_halign=text.align_center)
// BACKGROUND HIGHLIGHT for score 4+
bgcolor(score >= 4 ? color.new(C_CYAN, 95) : na, title="Strong Setup Highlight")
// SCREENER EXPORT
plot(score, "Score", display=display.none)
plot(rsiVal, "RSI", display=display.none)
plot(close / emaSlow * 100, "Price vs EMA50", display=display.none)