Indicator · Pine Script v5 · Own pane

Minervini Qualifier

by regalouisei· code credited to Lantzwat

Calculates Mark Minervini Trend Template criteria to identify stocks in strong uptrends.

View on GitHub

GitHub stars2on the repository
Pine versionv5runs as is
Lines of code191
Settings8inputs
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

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

minervini-qualifier.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Lantzwat

//@version=5
indicator("Minervini Qualifier", "MQ")

// From Mark Minervini's book "Trade Like a Stock Market Wizard"
// Trend Template
// 1. The current stock price is above both the 150-day (30-week) and the 200-day 
// (40-week) moving average price lines.
// 2. The 150-day moving average is above the 200-day moving average.
// 3. The 200-day moving average line is trending up for at least 1 month (preferably 
// 4–5 months minimum in most cases).
// 4. The 50-day (10-week) moving average is above both the 150-day and 200-day 
// moving averages.
// 5. The current stock price is trading above the 50-day moving average.
// 6. The current stock price is at least 30 percent above its 52-week low. (Many of 
// the best selections will be 100 percent, 300 percent, or greater above their 
// 52-week low before they emerge from a solid consolidation period and mount 
// a large scale advance.)
// 7. The current stock price is within at least 25 percent of its 52-week high (the 
// closer to a new high the better).
// 8. The relative strength ranking (as reported in Investor’s Business Daily) is no 
// less than 70, and preferably in the 80s or 90s, which will generally be the case 
// with the better selections 

RefTickerId = input.symbol("SP:SPX+NASDAQ_DLY:NDX+DJ:DWCPF", title="Reference index", tooltip = "e.g. SPX/NDX/RUT/DWCPF or combinations of it")
bCriteria = input.bool(true,"Show qualifiying criterias seperately")
bStrength = input.bool(true,"Calculate relative strength")
bSMA      = input.bool(true,"Show SMA lines")
bBuysell  = input.bool(true,"Draw verical buy signal lines")

var table infoTable = table.new(position.top_right, 1, 2, border_width = 0)
f_fillCell(_table, _column, _row, _value) =>
    _cellText = str.tostring(_value, "#.##")
    table.cell(_table, _column, _row, _cellText, text_color = color.yellow)
f_fillCell2(_table, _column, _row, _value) =>
    _cellText = _value
    table.cell(_table, _column, _row, _cellText, text_color = color.yellow)

bShowText = input(false, "ShowLabel")
_label(bool showlabel, float yPosition, string Name) =>
    var TEXTCOLOR = color.new(color.white,50)
    if barstate.islast and showlabel
        offset = str.length(Name)/2 + 1
        var _label = label.new(bar_index+offset, y=yPosition-2, text=Name, color=color.white, textcolor=TEXTCOLOR, style=label.style_none, size=size.tiny, textalign=text.align_left, text_font_family=font.family_monospace) 
        label.set_x(_label, bar_index+offset)


// SMA/EMA Calculation
s_close = request.security(syminfo.tickerid, 'D', close)

low_of_52week   = ta.lowest(s_close,260)
high_of_52week  = ta.highest(s_close,260)

//sma5            = ta.sma(s_close,5)
sma20           = ta.sma(s_close, 20)
sma50           = ta.sma(s_close, 50)
sma150          = ta.sma(s_close, 150)
sma200          = ta.sma(s_close, 200)

//Condition 1: Current Price > 150 SMA and > 200 SMA
condition_1 = s_close > sma150 and s_close > sma200

// # Condition 2: 150 SMA > 200 SMA
condition_2 = sma150 > sma200

// # Condition 3: 200 SMA trending up for at least 1 month, enhanced for 5 months
condition_3             = ta.rising(sma200,30) //sma200 > sma200[30] //sma200 > sma200[10] and sma200[10] > sma200[20] and sma200[20] > sma200[30]
condition_3_enhanced    = ta.rising(sma200,5*30) //condition_3 and sma200[30] > sma200[60] and sma200[60] > sma200[90] and sma200[90] > sma200[120] and sma200[120] > sma200[150]

// # Condition 4: 50 SMA> 150 SMA and 50 SMA> 200 SMA
condition_4 = sma50 > sma150 and sma50 > sma200 

// # Condition 5: Current Price > 50 SMA
condition_5 = s_close > sma50

// # Condition 6: Current Price is at least 30% above 52 week low
condition_6         = s_close >= (1.3 * low_of_52week) // 30% above 52 week low
condition_6_plus    = s_close >= (1.7 * low_of_52week) // 70% above 52 week low

// # Condition 7: Current Price is within 25% of 52 week high
condition_7 = s_close >= (0.75 * high_of_52week)

condition_minervini          = condition_1 and condition_2 and condition_3          and condition_4 and condition_5 and condition_6 and condition_7
condition_minervini_light    = condition_1 and condition_2 and condition_3          and condition_4 and                 condition_6 and condition_7
condition_minervini_enhanced = condition_1 and condition_2 and condition_3_enhanced and condition_4 and condition_5 and condition_6 and condition_7

condCol = condition_minervini_light ? condition_minervini ? condition_minervini_enhanced ? color.new(color.blue,0) : color.new(color.green, 0) : color.new(color.yellow, 0) : na

// draw vertical line when SMA20 crossover and the conditions are fullfilled
buy = ta.crossover(s_close,sma20) and condition_minervini_light
plot(bBuysell and buy ?  28 : na,color=color.new(color.green,50), linewidth=1,style = plot.style_histogram)
plot(bBuysell and buy ? -45 : na,color=color.new(color.green,50), linewidth=1,style = plot.style_histogram)

// calculate and draw envelope curve with condition matching fillcolor
lb = last_bar_index < 200 ? last_bar_index : 200
range_m = sma20-s_close
factor = 20 / (ta.highest(range_m,lb)-ta.lowest(range_m,lb))
range_m := range_m * factor
condCol2 = range_m < 0 ? color.new(color.blue,0) : color.new(color.red,50)
mp1 = plot(range_m ,        title = "SMA20 + conditions match", color=condCol2, linewidth=2)
mp2 = plot(range_m * -1 ,   title = "SMA20 + conditions match", color=condCol2, linewidth=2)
fill(mp1, mp2, color=condCol)

// Plot flatline SMAs
FirstlineSMA = input.int(20,"First line SMA")
sma20a = ta.sma(s_close,FirstlineSMA)
//plot(bSMA ? 32 : na, color = (sma5 - sma20) > 0? color.blue : color.red, linewidth = 3, title = "SMA5/SMA20 crossover")
plot(bSMA ? 28 : na, color = sma20a < s_close ? color.green : color.red, linewidth = 3, title = "SMA20 or so")
plot(bSMA ? 24 : na, color = sma50  < s_close ? color.green : color.red, linewidth = 3, title = "SMA50")
plot(bSMA ? 20 : na, color = sma150 < s_close ? color.green : color.red, linewidth = 3, title = "SMA150")
plot(bSMA ? 16 : na, color = sma200 < s_close ? color.green : color.red, linewidth = 3, title = "SMA200")

// Plot Minervini condition lines
plot (bCriteria ? -15 : na, linewidth = 3, title = "close>150MA and >200MA"      , color = condition_1 ? color.new(color.blue,0) : color.new(color.red,0))
plot (bCriteria ? -20 : na, linewidth = 3, title = "150MA>200MA"                 , color = condition_2 ? color.new(color.blue,0) : color.new(color.red,0))
plot (bCriteria ? -25 : na, linewidth = 3, title = "200MA uptrending 1+month"    , color = condition_3 ? color.new(color.blue,0) : color.new(color.red,0))
plot (bCriteria and condition_3_enhanced ? -25 : na, linewidth = 6, title = "200MA uptrending 5+month", color = condition_3_enhanced ? color.new(#2521f3, 0) : color.new(color.red,0))
plot (bCriteria ? -30 : na, linewidth = 3, title = "50MA>150MA and 50MA>200MA"   , color = condition_4 ? color.new(color.blue,0) : color.new(color.red,0))
plot (bCriteria ? -35 : na, linewidth = 3, title = "close>50MA"                  , color = condition_5 ? color.new(color.green,0) : color.new(color.red,0))
plot (bCriteria ? -40 : na, linewidth = 3, title = "close 30%+ above 52-week low", color = condition_6 ? color.new(color.blue,0) : color.new(color.red,0))
plot (bCriteria and condition_6_plus ? -40 : na, linewidth = 6, title = "close 70%+ above 52-week low", color = condition_6_plus ? color.new(color.green, 0) : color.new(color.red,0))
plot (bCriteria ? -45 : na, linewidth = 3, title = "close within 25% 52-week high", color = condition_7 ? color.new(color.blue,0) : color.new(color.red,0))

// Create label next to the lines to ease identification
//_label(bShowText, 32, "SMA5/SMA20 crossover")
_label(bShowText, 28, "SMA20 ")
_label(bShowText, 24 ,"SMA50 ")
_label(bShowText, 20 ,"SMA150")
_label(bShowText, 16 ,"SMA200")
_label(bShowText, -15, "close>150MA and >200MA" )
_label(bShowText, -20, "150MA>200MA " )
_label(bShowText, -25, "200MA uptrending 1+month" )
_label(bShowText, -30, "50MA>150MA and 50MA>200MA " )
_label(bShowText, -35, "close>50MA " )
_label(bShowText, -40, "close 30%+ above 52-week low" )
_label(bShowText, -45, "close within 25% 52-week high " )

if not timeframe.isdaily
    f_fillCell2(infoTable, 0, 1, "only valid on daily timeframes")

// Calculate relative strength, just one way to calculate it
// value > 100, better performance compared to reference index
// value < 100, worse performance compared to reference index 
// ...over the period of one year, last quarter double counted

quarter_performance(closes, n) =>
    length  = math.min(last_bar_index, (252/4))
    start   = (n-1) * length
    stop    = n * length
    pct_cum = 0.0
    for i=start to stop -1
        pct_cum := pct_cum + closes[i]
    pct_cum

strength(closes) =>
    quarters1 = quarter_performance(closes ,1)
    quarters2 = quarter_performance(closes ,2)
    quarters3 = quarter_performance(closes ,3)
    quarters4 = quarter_performance(closes ,4)
    ret = 0.4*quarters1 + 0.2*quarters2 + 0.2*quarters3 + 0.2*quarters4
    ret

relative_strength(closes, ref_close) =>
    rs_stock = strength(closes)
    rs_ref   = strength(ref_close)
    rs  = (1 + rs_stock) / (1 + rs_ref) * 100
    rs := math.round(rs,2)
    rs


s_ref_close = request.security(RefTickerId, 'D', close)
relStrength = 0.0
if bStrength
    s_close_pct = (s_close - s_close[1]) / s_close[1]
    s_ref_close_pct = (s_ref_close - s_ref_close[1]) / s_ref_close[1]
    relStrength := relative_strength(s_close_pct,s_ref_close_pct)
    f_fillCell(infoTable, 0, 0, relStrength)

// alerts ----------------------------------------------

alertcondition(condition_minervini and not condition_minervini[1],"MQ - All Miverini conditions match", "All Minervini conditions match")
alertcondition(condition_minervini_light and not condition_minervini_light[1],"MQ - Miverini (light) conditions match", "All Minervini light conditions matched")
alertcondition(not condition_minervini_light and condition_minervini_light[1],"MQ - Miverini conditions unmatch", "At least one Minervini condition doesn't match")

alertcondition(buy,"MQ - buy signal", "SMA20 crossover and Minervini conditions match")

UptrendAlert = input.int(70, "Alertcondition when close xx% above 52week low", minval = 30)
Percent_above_52weeklow = ((s_close * 100) / low_of_52week) - 100 // Strong uptrend signal when close is 70%+ above 52week low 
alertcondition(Percent_above_52weeklow >= UptrendAlert, "MQ - in strong uptrend mode", "close is xx% (70% default value) above 52week low")

Overview

Minervini Qualifier evaluates key conditions based on 50-day, 150-day, and 200-day Simple Moving Averages, 52-week high and low price ranges, and relative strength against a customizable reference index. The indicator plots qualifying criteria, SMA lines, and vertical signal markers in a separate pane alongside an onscreen summary table. Inputs allow toggling individual criteria displays, adjusting SMA parameters, and choosing reference benchmark tickers.

Details

Published by

regalouisei on GitHub

Code credit

Lantzwat, as written in the script's header

Type

Indicator, Pine Script v5

Draws

Separate pane below the chart

Category

Trend, Moving averages, Screeners & dashboards

Markets

Stocks

Timeframes

H4 and above

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
Reference indexsymbolSP:SPX+NASDAQ_DLY:NDX+DJ:DWCPFRefTickerId
Show qualifiying criterias seperatelybooltruebCriteria
Calculate relative strengthbooltruebStrength
Show SMA linesbooltruebSMA
Draw verical buy signal linesbooltruebBuysell
ShowLabelboolfalsebShowText
First line SMAint20FirstlineSMA
Alertcondition when close xx% above 52week lowint70UptrendAlert
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

218 stars

Multi-Timeframe Analysis Suite calculates trend direction and momentum conditions across five user-selected timeframes using moving averages, RSI, and Stochastic oscillators. It evaluates moving average slope and oscillator levels to compute trend alignment, m

Indicator v6 Screeners & dashboardsTrend
Updated 3 months ago · None stated GitHub repository of Multi-Timeframe Analysis Suite

KamaFama

by Mastaaa1987
141 stars

KamaFama is an indicator that translates a Freqtrade trading strategy into Pine Script for visualization. It combines Kaufman Adaptive Moving Average (KAMA), MAMA/FAMA calculations derived via Hilbert Transform, Williams %R, and correlation trend filters to ev

Indicator v6 Moving averagesOscillators & momentum
Updated 6 weeks ago · MIT GitHub repository of KamaFama
10 stars

This indicator combines SuperGuppy exponential moving average ribbons with SuperTrend pivot points in a separate pane screener. It classifies up to twenty assets as neutral, long, strong long, short, or strong short. Fast and slow EMA stacks define trend align

Indicator v4 TrendMoving averages
Updated 4 years ago · MIT GitHub repository of SuperGuppySTPPScreener
9 stars

This indicator functions as a multi-pair forex screener, drawing output in a separate pane. It fetches price data across major currency pairs using security functions based on a user-selected resolution timeframe. It processes these market feeds with short, me

Indicator v4 Screeners & dashboardsTrend Repaints
Updated 5 years ago · None stated GitHub repository of AG Screener (Phill_I Request)

MTF WaveTrend Opportunity Hunter calculates multi-timeframe momentum and confluence scores using WaveTrend across custom Regime, Setup, Trigger, and Context timeframes. It plots a net confluence score histogram, multi-layer heat ribbons, an RRG-style Rotation

Indicator v6 TrendOscillators & momentum
Updated yesterday · MIT GitHub repository of MTF WaveTrend Opportunity Hunter [WavesUnchained]

Snagprofit WMA

by dearvn
4 stars

Snagprofit WMA is a multi-timeframe trend indicator that calculates a 125-period Weighted Moving Average across the 1-minute, 5-minute, 15-minute, and 1-hour timeframes alongside a local 50-period Simple Moving Average. It identifies momentum signals when pric

Indicator v5 Moving averagesTrend Repaints
Updated 4 years ago · None stated GitHub repository of Snagprofit WMA

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