Build the VScore trading indicator which helps you understand and plot price behavior in relation to its standard deviation, using the VWAP bands.

  • 6/23/21 - Upper VScore Indicator for ThinkOrSwim Added to the Downloads (Scans also included, for new bullish and bearish signals).
  • 10/6/19 - Feature Added -- Ability to Set Custom Standard Deviation Value in Label

The VScore is a free trading indicator that helps you understand and plot price behavior in relation to its standard deviation, and distance from the Volume Weighted Average Price (VWAP).

VScore Indicator - Breakdown

There are 3 key things that the VScore helps you do:

  1. Understand Trend: Whether you’re predominantly above or below the mean provides you context around price action from a given date and time.
  2. Reversion to the Mean: Easily spot a reversion to the mean using the z-score distance between price and VWAP (down to a single stock price)
  3. Support and Resistance: Upper and lower standard deviations representing support and resistance are visually obvious, and statistically relevant.

You can anchor our VScore to any particular date, and use the tool to understand whether we’ve pulled back enough to a place where the symbol has usually found support, or where resistance has generally presented itself.

The VScore is a derivative of the z-score, which measures the volatility in prices for different securities and indexes, when compared against the volume weight average price (VWAP).

As an example, using the VScore, you can get a more accurate reading on what direction an index may head in next. This could help you, as a trader/investor, identify potential buying opportunities in stocks with retests of key standard deviation levels.

How to Identify Trend With the VScore

Additionally, with a common anchor point (such as the beginning of every hear ie. January 1, 2021), you have a quick and easy method to evaluate stocks, ETFs and futures on a relative basis:

  1. The ones that have been predominantly above 0 represent stocks trading above the volume weighted average price, suggesting strength.
  2. The ones that have been predominantly below 0 represent stocks trading below the volume weighted average price, suggesting weakness.
  3. The ones that have been chopping from positive to negative levels representing stocks with no clear trend, suggesting chop.

This information can be combined with other indicators, such as the Edge Signals or Squeeze Course indicators, to pinpoint exact reversal zones, supported by momentum. 

In statistics, a Z-score is a number that describes how far your score is from the average score of some group. For example, if someone has a Z-score of one, it means they have one standard deviation above the mean (read: average).

Z Score in Trading
Source: Investopedia

The z-score is a measure of the magnitude of deviation in an asset's value from mean. It's important for traders and statisticians to understand these deviations to better predict price, as well as classify trades by risk.

The mean is the average value of a set, and in the case of the VScore ThinkOrSwim indicator, it's in the price of the anchored VWAP (usually anchored to either the beginning of the current year, or 1 year prior to the current date).

The standard deviation tells you how much values typically vary from the mean; a higher deviation indicates that values are more spread out than those with lower deviations (i.e., more tightly clustered around the mean).

The Upper VScore Indicator is an updated tutorial in 2021, that builds upon the original idea of calculating the zscore distance between price action and its anchored VWAP. Instead of having the indicator plot on the lower panel, the Upper VScore plots directly with price action.

Upper VScore Indicator

This allows you to visually understand where price action is, relative to its historical statistical distance. The upper version of the indicator also allows you to combine and layer on any other indicators that you'd normally be using.

In contrast, the Lower VScore Indicator may be more straightforward for traders who like to spot divergences alongside price action. The indicator is cleaner on the charts, and can be anchored to any date or time that is visible on your ThinkOrSwim charts.

Lower VScore Indicator

You can find examples of some of our favorite trade setups below, using winning combinations of indicators that add an edge.

First and foremost, our VScore indicator is completely free.

The following is all included as part of the download folder for this tutorial:

  1. Upper VScore Indicator for ThinkOrSwim
  2. Lower VScore Indicator for ThinkOrSwim

In addition to the VScore Indicator, we have also built VScore scans, which are 100% free as well, and available for you to download here:

  1. Bullish VScore Trend Continuation Scan
  2. Bearish VScore Trend Continuation Scan

The following is all included as part of the download folder for this tutorial:

There are a few different stores online that have their own versions (both paid and free)...

There are also quite a few different free versions for different platforms, like TradingView and ProRealTime.

But there were no free versions for ThinkOrSwim.

So... we built one! 

And, as usual, we worked on finding ways to make ours better. 

Here are some bells & whistles that we've added to our version of the VScore ThinkOrSwim indicator:

  • Translate Standard Deviation Cryptic Code into Real-World Prices
  • Automatically Switch Between End of Day and Intraday V-Scores
  • Easily Plan Entries, Exits, and Stops All Ahead of Time
  • Identify "Winning Standard Deviation" Trend With Colors
  • Clear Buy/Sell Signals Using Reversion to Mean
  • Alerts Included

You can follow along the tutorial below, learn more about our setups, and download the final versions of the indicator. 

Build the Lower VScore Indicator (thinkscript):

Let's start with the Lower VScore Indicator first, which will be our baseline for the upper version of the indicator as well.


One piece of code that you will need to get started is the Anchored VWAP code, which is available here, for free.

The calculation for the V-Score, using the thinkscript format is included below for copy/paste:

plot VScore = if (((price - close)*(-1))/deviation) > 5 or (((price - close)*(-1))/deviation) < -5 then 0 else (((price - close)*(-1))/(deviation));

The code for the clouds, which help you determine which area the V-Score spends the most time in-between is included below:

def cloud1;
def cloud2;
if Sum(zeroAndOne, barsGoBack) > Sum(OneAndTwo,barsGoBack) and Sum(zeroAndOne, barsGoBack) > Sum(twoAndThree,barsGoBack) and Sum(zeroAndOne, barsGoBack) > Sum(negZeroAndOne,barsGoBack) and Sum(zeroAndOne, barsGoBack) > Sum(negoneAndTwo,barsGoBack) and Sum(zeroAndOne, barsGoBack) > Sum(negtwoAndThree,barsGoBack){
cloud1 = zero;
cloud2 = one;
else if Sum(OneAndTwo, barsGoBack) > Sum(zeroAndOne,barsGoBack) and Sum(OneAndTwo, barsGoBack) > Sum(twoAndThree,barsGoBack) and Sum(OneAndTwo, barsGoBack) > Sum(negZeroAndOne,barsGoBack) and Sum(OneAndTwo, barsGoBack) > Sum(negoneAndTwo,barsGoBack) and Sum(OneAndTwo, barsGoBack) > Sum(negtwoAndThree,barsGoBack){
cloud1 = one;
cloud2 = two;
else if Sum(twoAndThree, barsGoBack) > Sum(zeroAndOne,barsGoBack) and Sum(twoAndThree, barsGoBack) > Sum(oneAndTwo,barsGoBack) and Sum(twoAndThree, barsGoBack) > Sum(negZeroAndOne,barsGoBack) and Sum(twoAndThree, barsGoBack) > Sum(negoneAndTwo,barsGoBack) and Sum(twoAndThree, barsGoBack) > Sum(negtwoAndThree,barsGoBack){
cloud1 = two;
cloud2 = three;
else if Sum(negZeroAndOne, barsGoBack) > Sum(zeroAndOne,barsGoBack) and Sum(negZeroAndOne, barsGoBack) > Sum(oneAndTwo,barsGoBack) and Sum(negZeroAndOne, barsGoBack) > Sum(twoAndThree,barsGoBack) and Sum(negZeroAndOne, barsGoBack) > Sum(negoneAndTwo,barsGoBack) and Sum(negZeroAndOne, barsGoBack) > Sum(negtwoAndThree,barsGoBack){
cloud1 = zero;
cloud2 = negOne;
else if Sum(negoneAndTwo, barsGoBack) > Sum(zeroAndOne,barsGoBack) and Sum(negoneAndTwo, barsGoBack) > Sum(oneAndTwo,barsGoBack) and Sum(negoneAndTwo, barsGoBack) > Sum(twoAndThree,barsGoBack) and Sum(negoneAndTwo, barsGoBack) > Sum(negZeroAndOne,barsGoBack) and Sum(negoneAndTwo, barsGoBack) > Sum(negtwoAndThree,barsGoBack){
cloud1 = negOne;
cloud2 = negTwo;
else if Sum(negtwoAndThree, barsGoBack) > Sum(zeroAndOne,barsGoBack) and Sum(negtwoAndThree, barsGoBack) > Sum(oneAndTwo,barsGoBack) and Sum(negtwoAndThree, barsGoBack) > Sum(twoAndThree,barsGoBack) and Sum(negtwoAndThree, barsGoBack) > Sum(negZeroAndOne,barsGoBack) and Sum(negtwoAndThree, barsGoBack) > Sum(negOneAndTwo,barsGoBack){
cloud1 = negTwo;
cloud2 = negThree;
else {
cloud1 = Double.nan;
cloud2 = Double.nan;
AddCloud(cloud1, cloud2, color.light_red, color.light_green);

Code if you would like to add alerts every time the V-Score triggered a bullish or bearish entry is included below:

input soundAlertsOn = yes; Alert((cloud1 == one or cloud2 == one or cloud1 == two or cloud2 == two or cloud1 == three or cloud2 == three) and (VScore <= 0 and VScore[1] > 0) and (SoundAlertsOn), "Bullish VScore Entry", Alert.BAR); Alert((cloud1 == negOne or cloud2 == negone or cloud1 == negtwo or cloud2 == negtwo or cloud1 == negthree or cloud2 == negthree) and (VScore >= 0 and VScore[1] < 0)and (SoundAlertsOn), "Bearish VScore Entry", Alert.BAR);

Build the Upper VScore Indicator (thinkscript):

Next, we'll move on to building an Upper VScore indicator, leveraging much of the code from above. The key difference between the two lines in how they plot on our charts (and thus, formatting code).


Here is the complete upper study's thinkScript code:

declare upper;
input anchorDate = 20210101;
input barsGoBack = 30;

def postAnchorDate = if GetYYYYMMDD() >= anchorDate then 1 else 0;

def yyyyMmDd = getYyyyMmDd();
def periodIndx = if getAggregationPeriod() < AggregationPeriod.HOUR then yyyyMMDD else postAnchorDate;
def isPeriodRolled = compoundValue(1, periodIndx != periodIndx[1], yes);

def volumeSum;
def volumeVwapSum;
def volumeVwap2Sum;

if (isPeriodRolled) {
volumeSum = volume;
volumeVwapSum = volume * vwap;
volumeVwap2Sum = volume * Sqr(vwap);
} else {
volumeSum = compoundValue(1, volumeSum[1] + volume, volume);
volumeVwapSum = compoundValue(1, volumeVwapSum[1] + volume * vwap, volume * vwap);
volumeVwap2Sum = compoundValue(1, volumeVwap2Sum[1] + volume * Sqr(vwap), volume * Sqr(vwap));
def price = volumeVwapSum / volumeSum;
def deviation = Sqrt(Max(volumeVwap2Sum / volumeSum - Sqr(price), 0));

def VScore = if (((price - close)*(-1))/deviation) > 5 or (((price - close)*(-1))/deviation) < -5 then 0 else (((price - close)*(-1))/(deviation));
plot zero = (0)*(deviation) + (price);
plot one = (1)*(deviation) + (price);
plot two = (2)*(deviation) + (price);
plot three = (3)*(deviation) + (price);
plot negOne = (-1)*(deviation) + (price);
plot negTwo = (-2)*(deviation) + (price);
plot negThree = (-3)*(deviation) + (price);


def zeroAndOne = if VScore > zero and VScore <= one then 1 else 0;
def oneAndTwo = if VScore > one and VScore <= two then 1 else 0;
def twoAndThree = if VScore > two and VScore <= three then 1 else 0;

def negZeroAndOne = if VScore > negOne and VScore < zero then 1 else 0;
def negOneAndTwo = if VScore > negTwo and VScore <= negOne then 1 else 0;
def negTwoAndThree = if VScore > negThree and VScore <= negTwo then 1 else 0;

def counter = if VScore >= 0 then 1 else if VScore < 0 then -1 else 0;
def trend = Sum(counter, barsGoBack);
def positiveTrend = if trend >= 0 then 1 else 0;
def negativeTrend = if trend < 0 then 1 else 0;

plot BullSignal = if positiveTrend and (VScore <= 0.3 and Vscore[1] >0) and CCI() > -100 then 1 else 0;

plot BearSignal = if negativeTrend and (VScore >= 0.3 and Vscore[1] < 0) and CCI() < 100 then 1 else 0;


input soundAlertsOn = no;
Alert(positiveTrend and (VScore <= 0 and VScore[1] > 0) and (SoundAlertsOn), "Bullish VScore Entry", Alert.BAR);
Alert(negativeTrend and (VScore >= 0 and VScore[1] < 0)and (SoundAlertsOn), "Bearish VScore Entry", Alert.BAR);

Trade Setup #1: Fades with the VScore

Sample Trade Plan (2021)


  • Price must hit either the upper or lower Volatility Box zones
    • For Futures: the zone is defined as in between the cyan entry line and outer edge of the clouds
    • For Stocks: the zone is defined as the beginning of the clouds to the outer edge of the clouds
  • VScore must retest a previous support or resistance level, above or below at least the 2 Standard Deviation levels
  • Bonus: Oversold or overbought confirmation using the Edge Signals indicator


  • Option 1: Volatility Box zone, ranging from aggressive to conservative entries
  • Option 2: VScore Standard Deviation price level for previous standard deviation


  • Option 1: Volatility Box target line
  • Option 2: VScore retest of subsequent standard deviation price values


  • Outside of Volatility Box clouds

Trade Setup #2: VScore Trend Continuation

Sample Trade Plan (2021)


  • Checkpoint 1:
    Using at least a 30 "bar go-back" period, the clouds must signal a clear trend:
    • If green, focus on bullish setups only
    • If red, focus on bearish setups only
  • Checkpoint 2:
    Entry trigger, in the direction of the trend (example triggers below):
    • Slingshot Squeeze
    • Squeeze Signals
    • Edge Signals
    • Acceleration Trend Switch via Market Pulse
    • Simple Breakout Tool
  • Bonus: Oversold or overbought confirmation using the Edge Signals indicator


  • Option 1: Closing price of the candle with the entry trigger (ie. Slingshot Squeeze fires today, and the closing price is the price used for trade entry)
  • Option 2: If price is extended, use a pullback zone, such as a previous support on the VScore as the "ideal entry price" (or your favorite moving average / Market Pulse)


  • Option 1: Wait for squeeze to fire and exit based on backtester results
  • Option 2: VScore retest of previous resistance levels, using specific prices to set exit points


  • Option 1: VScore trend reversing into bearish territory
  • Option 2: Break of previous support / resistance levels (using both price and/or VScore standard deviations)
Table of Contents
    Add a header to begin generating the table of contents

    Trade Like a Pro, With the Pros