On this page
Overview
In this tutorial I build the VScore indicator for ThinkOrSwim, a free study that measures how far the close is from the volume weighted average price (VWAP) in standard deviations. A VScore of 1 means price is 1 standard deviation above that mean, and -2 means it is 2 below. I build it from the code of ThinkOrSwim's built-in VWAP study and our free anchored VWAP study.
This page covers two builds. The lower VScore plots the score in its own panel, with trend clouds, a price label and arrows for pullbacks to the mean. The upper VScore, from a second video, draws the same levels as prices on your chart. Both are for traders who want to know whether a stock has pulled back far enough to matter.
Key Takeaways
- The VScore indicator is the close minus VWAP, divided by the VWAP standard deviation. Readings above 5 or below -5 reset to 0.
- On charts of 1 hour and longer, the VScore measures from a VWAP anchored at the anchorDate input (20210101 in the download). Below 1 hour, it uses each day's VWAP.
- The lower VScore shades a green or red cloud over the zone it spent the most bars in over the last barsGoBack bars: 90 in the download, 120 in the video.
- A bullish VScore arrow needs a winning cloud above 0, a VScore at or below 0.3 after a bar above 0, and a CCI above -100.
- The upper VScore plots the mean and the 1, 2 and 3 standard deviation levels as prices and judges trend by adding +1 or -1 per bar over the last 30 bars.
What Is the VScore?
The VScore is a z-score of price against the volume weighted average price. A z-score says how far a value is from its average, counted in standard deviations. Here the average is VWAP and the value is the close of each bar.
A VScore of 0 means the close sits on VWAP. A reading of 1 means price is 1 standard deviation above it, and -2 means 2 below, so you can compare today's stretch with past pullbacks. For a broader look at VWAP and other volume studies, see our article on the best volume indicators for ThinkOrSwim.

How the VScore Calculates the Mean and the Deviation
The VScore indicator reuses the math in ThinkOrSwim's built-in VWAP study. Each bar adds to three running totals: volume, volume times VWAP, and volume times VWAP squared. From those, the code gets the volume weighted average price (price) and its standard deviation (deviation), the same one the built-in study uses for its bands.
This step’s code is free with an account. Create one or sign in.
Read the VScore line as the close minus VWAP, divided by the deviation.
Multiplying (price - close) by -1 flips the sign, so a close above VWAP gives a positive score. If the result is above 5 or below -5, the code resets it to 0, since a reading that far out means something unusual is happening on that bar.
Which VWAP the VScore Measures From
The VScore picks the start of its VWAP from the chart's aggregation period:
This step’s code is free with an account. Create one or sign in.
When the period changes, the running totals start over from that bar.
| Chart timeframe | VWAP the VScore measures from | What the line looks like |
|---|---|---|
| Below 1 hour | That day's VWAP, which starts over every day | More jagged |
| 1 hour and longer | A VWAP anchored at the anchorDate input | Smoother |
The anchor logic comes from our free anchored VWAP indicator. In the video I compared two copies of the study with different anchor dates. The one anchored to a recent date was jagged and told me little, so I moved the anchor back to August 1, 2018.
Pick a date far enough back to show the mean over about a year. The download uses January 1, 2021 (20210101).
What the Lower VScore Plots
The lower VScore indicator draws the score as one line in its own panel, on a fixed scale from -3 to +3 standard deviations. These are the plots in the download:
| Plot | Value | Color in the code |
|---|---|---|
| VScore | The score | Set in the settings panel (yellow in the video) |
| zero | 0, the mean | Line weight 3 (white in the video) |
| one, negOne | +1 and -1 | Light gray |
| two | +2 | Light green |
| negTwo | -2 | Pink |
| three | +3 | Green |
| negThree | -3 | Light red |
| posInt, negInt | +0.3 and -0.3 | Cyan |
The two 0.3 lines mark the area I'd consider close to the mean.

The Price Label
The VScore price label reads like "Price at [1] SD: 425.7". It turns a standard deviation level into a price: the level times the deviation, plus VWAP. If you're new to labels, our AddLabel tutorial covers the function.
This step’s code is free with an account. Create one or sign in.
Choose the level with the devStop input: One, Two, Three, Zero, NegOne, NegTwo, NegThree or Custom.
Custom uses the customDev input, 0.15 by default, added on 10/6/19. If you take a bounce at the mean and want to exit at 1 standard deviation, set devStop to One to see the exit price ahead of time. Set it to NegOne to see a stop price.
The Trend Clouds
Six counters record which zone the VScore is in on each bar: 0 to 1, 1 to 2, 2 to 3, and the same three zones below 0. These are the three above 0:
This step’s code is free with an account. Create one or sign in.
Each counter is 1 on a bar in its zone and 0 everywhere else.
The cloud code adds up each counter over the last barsGoBack bars and shades the zone with the highest count, the winning zone. Zones above 0 shade light green and zones below 0 shade light red. If two zones tie, no cloud plots. A panel that stays green reads as strength.

The Arrows and Alerts
The VScore arrows mark a reversion to the mean in the direction of the winning cloud. The table shows each condition as it reads in the download.
| Condition | Bullish arrow | Bearish arrow |
|---|---|---|
| Winning cloud | Above 0 (0 to 1, 1 to 2 or 2 to 3) | Below 0 |
| VScore on this bar | 0.3 or below | 0.3 or above |
| VScore on the previous bar | Above 0 | Below 0 |
| CCI | Above -100 | Below 100 |
| Where it plots | Up arrow at -2 | Down arrow at +2 |
| Alert, when soundAlertsOn is yes | VScore crosses from above 0 to 0 or below | VScore crosses from below 0 to 0 or above |
The CCI check rules out heavy selling pressure behind a bullish arrow, or heavy buying pressure behind a bearish one. In the video I started the bullish test at 0 and moved it to 0.3 to give it room. At 0, Apple's chart would have shown only a handful of arrows.
A note on the download: the bearish test reads 0.3 or above, the same +0.3 as the bullish side, so a bearish arrow needs the VScore to jump from below 0 to +0.3 or higher. The mirror of the bullish test is -0.3 or above, which is the value I use for the wide bearish scan in the scans video.
The upper study has the same +0.3 test. To match, change VScore >= 0.3 to VScore >= -0.3 in the BearSignal line.
How to Build the Lower VScore in ThinkOrSwim
The lower VScore build starts from two pieces of existing code, and these are the steps I follow in the video. The finished study is in the download if you'd rather skip the build, and our guide on how to import a study into ThinkOrSwim shows how to add it.
- Create a new study, paste in the code of ThinkOrSwim's built-in VWAP study, and name it VScore.
- Copy in the top of our anchored VWAP code (the anchorDate input and postAnchorDate) and delete its anchor time lines and plot.
- Replace periodIndx with the aggregation check, so charts under 1 hour use the daily VWAP and longer charts use the anchor date.
- Delete the VWAP and band plots at the bottom, keep
priceanddeviation, and add the VScore plot. - Plot the 0, 1, 2, 3, -1, -2 and -3 lines, plus the two 0.3 lines.
- Add the devStop input, the switch that turns it into chosenDev, the stop price, and the label with a showStopLabel input.
- Add the six zone counters, the barsGoBack input and the cloud code, and declare the study lower.
- Add the BullSignal and BearSignal plots with ARROW_UP and ARROW_DOWN at line weight 3, then style the lines.
Here's the lower VScore video:
Lower VScore Settings
| Input | Default in the download | What it does |
|---|---|---|
| anchorDate | 20210101 | Start of the anchored VWAP on charts of 1 hour and longer. I used 20180801 in the video. |
| barsGoBack | 90 | Bars the clouds count over. I used 120 in the video. |
| showStopLabel | yes | Shows or hides the price label. |
| devStop | One | The standard deviation level the label prices. |
| customDev | 0.15 | The level the label uses when devStop is Custom. |
| soundAlertsOn | no | Turns on the Bullish VScore Entry and Bearish VScore Entry alerts. |
How to Build the Upper VScore
The upper VScore indicator plots the same standard deviation levels as prices on the main chart. I built it in a second video, from a member request, so you can read support and resistance as prices. On a United States Steel (X) chart in that video, the -3 standard deviation level sat at $12.32.

- Copy the lower VScore code into a new study, name it (I used TI_VScore_Upper) and change it to declare upper.
- Change
plot VScoretodef VScore, since the score itself no longer plots. - Turn each level into a price with the label formula: the level times the deviation, plus price.
- Delete the 0.3 lines, the cloud code, the label, devStop, chosenDev, showStopLabel and customDev.
- Set the anchor date to 20210101 and color the lines: white zero at weight 3, light gray for 1 and -1, light green and light red for 2 and -2, green and red for 3 and -3.
- Add the counter and trend logic below, switch both arrows to 1 or 0 with Boolean arrow painting strategies, and add the trend to the alerts.
This step’s code is free with an account. Create one or sign in.
On hourly and longer charts, the zero line is the anchored VWAP itself.
The Card-Counting Trend
The upper VScore measures trend with a basic card-counting system. Each bar scores +1 when the VScore is at or above 0 and -1 when it is below. Sum adds the scores over the last barsGoBack bars, 30 by default. A total of 0 or more is a positive trend, and below 0 is a negative trend.
This step’s code is free with an account. Create one or sign in.
On a 30-bar lookback, the trend total runs from -30 to +30.
The Upper Arrows
The upper arrows keep the VScore and CCI tests from the lower study and swap the cloud check for positiveTrend or negativeTrend.
This step’s code is free with an account. Create one or sign in.
The 0.3 is a hard-coded, arbitrary number, so change it or the CCI test if you want to experiment.
The BearSignal line uses negativeTrend, a VScore of 0.3 or above after a bar below 0 (the same +0.3 test noted for the lower study), and CCI below 100. BOOLEAN_ARROW_UP and BOOLEAN_ARROW_DOWN draw an arrow on price when the plot is 1 and nothing when it is 0.
Here's the upper VScore video:
Lower vs Upper VScore
The upper VScore is the lower VScore moved onto the price chart, with the same VWAP math and the same VScore formula.
| Feature | Lower VScore | Upper VScore |
|---|---|---|
| Where it plots | Its own panel below price | On the price chart |
| Levels shown as | Standard deviations, -3 to +3 | Prices |
| Trend measure | Winning-zone cloud | Sum of +1 and -1 per bar |
| Default barsGoBack | 90 | 30 |
| Price label | Yes, set with devStop | Not needed, the levels are prices |
| Arrows | At -2 and +2 in the panel | On the candles |
You can run both at once. On JPMorgan (JPM) in the upper video, the upper and lower studies both plotted a bullish arrow, a confluence of two different signals.
How to Scan for the Upper VScore Signal
The upper VScore scan is one line of thinkScript that calls the study by name and reads its BullSignal plot. Use the name you saved the study under:
This step’s code is free with an account. Create one or sign in.
To add it as a scan filter:
- Open the Scan tab and click Add filter. In the video I note that a custom study filter needs a live account, not paperMoney.
- Choose Study, pick Custom from the dropdown, and switch to the thinkScript Editor tab.
- Type the line above and click OK. ThinkOrSwim shows a prompt that the filter is now linked to your study.
- Run the scan. In the video it returned 31 symbols from my watchlist of weeklies.
The linked filter uses the anchor date inside the study. In the video I note that a daily scan has about 1 year of data, so anchoring to January 1 of the current year works best. Later edits to the study don't carry into the filter: click its edit icon to update the date.
The 4 lower VScore scans are built in our V-Score scans tutorial.
VScore Examples from the Videos
The VScore examples in the two videos follow one pattern: a trend away from VWAP, then a pullback toward it. Each example is from the day I recorded.
- The S&P. On the opening chart, the VScore read about 1 standard deviation away from the mean. From February it held above 0 until June 3rd, when it reverted to the mean.
- Apple (AAPL). The VScore pulled back to the mean near a pivot point under green clouds, a bullish arrow plotted, and price went up afterward.
- Home Depot (HD). The 0.3 line acted more as support than the zero line did. The daily chart showed cleaner signals than a lower timeframe, where the line uses the daily VWAP.
- United States Steel (X). Anchored to January 1, 2021, X had one earlier pullback to VWAP and was in a second one when I recorded. The upper scan found it that day.
- JPMorgan (JPM). Since January 1, 2021, price had stayed mostly above VWAP. As it pulled back toward VWAP, a bullish arrow plotted, and the 1 standard deviation line, the nearest level in the bullish direction, sat at $159.78.
How I Use the VScore
The VScore indicator tells me whether price has pulled back far enough toward its volume weighted mean to matter. I read the clouds or the trend sum for direction, then watch for the score to revert toward 0 that way.
A common use from the video: catch the reversion back to 0, the mean, use it as a bounce, and time exits at the first, second or third standard deviation. Set devStop to the level you're targeting and the label shows that price before you enter.
Different timeframes have different sensitivities. In the video a 4-hour chart is much smoother than an intraday chart.
An arrow is a read on a pullback, not an entry by itself. Decide where the stop goes first, such as the -1 standard deviation price from the label, and size the position so a stop-out costs a small, fixed share of your account. More free studies are on our indicators page.
VScore on real charts
Drawn from real daily bars with the code on this page, through Oct 20, 2026. The VScore is how many standard deviations the close sits from a VWAP anchored at the anchorDate input, January 1, 2021 in the download. Our daily bars carry no intraday VWAP, so each day stands in with its typical price, (high + low + close) / 3, the same price the Anchored VWAP study uses.
SPY against its 2021 VWAP

On Oct 20, 2026 SPY closed at $769.05, a VScore of 2.51: 2.51 standard deviations above a VWAP of $493.64 that started on January 4, 2021. A long anchor makes the bands wide; move the anchor to a recent low or high to measure a shorter move.
A pullback arrow that worked: XLRE, Apr 6, 2026

I picked these two by rule among the 14 ETFs: the most recent first arrow of a run that closed higher 10 trading days later, and the most recent that did not. XLRE closed at $41.76 on Apr 6, 2026 and at $44.64 ten days later, +6.9%.
One that did not: XLRE, Nov 26, 2025

XLRE closed at $41.47 on the arrow and at $40.80 ten days later, -1.6%.
By the numbers
Daily bars for SPY, QQQ, IWM, DIA and 10 sector ETFs, Feb 16, 2021 to Oct 20, 2026, all anchored at January 1, 2021. A run of arrows on back-to-back bars counts once, on its first bar, and the arrows did about as well as any day. Arrows bunch up when price drifts near the VWAP, since every bar that stays between 0 and 0.3 after a bar above 0 qualifies.
Full thinkScript code
Create a free account or sign in to copy all 221 lines and download the file.
Download
Download both the Upper and Lower VScore indicators for ThinkOrSwim. The download is a .zip with two folders. Lower Study has TI_VScore_LowerSTUDY.ts and a .txt file with 4 ThinkOrSwim shared links for scans: bull signal and bear signal (more filter criteria), and wide bull and wide bear (less filter criteria). Upper Study has TI_VScore_UpperSTUDY.ts and a .txt file with a bullish and a bearish scan link. To open a scan link, click Setup in ThinkOrSwim, choose Open shared item and paste it in. If you haven't added a custom study before, here's how to import an indicator into your ThinkOrSwim platform.
Questions
What is the VScore indicator?
The VScore indicator measures how many standard deviations the close is from the volume weighted average price. A reading of 0 means price is on VWAP, 1 means 1 standard deviation above it, and -2 means 2 below. Our free version adds a price label, trend clouds and pullback arrows.
How is the VScore calculated?
The code keeps running totals of volume, volume times VWAP and volume times VWAP squared, which give the volume weighted average price and its standard deviation. The VScore is the close minus that average, divided by the deviation. Readings above 5 or below -5 reset to 0.
What anchor date should I use for the VScore?
Pick a date far enough back to show the mean over about a year. In the video I used August 1, 2018, and the download uses 20210101. For the upper VScore scan, anchor to January 1 of the current year, since a daily scan has about 1 year of data.
Why does the VScore look jagged on intraday charts?
On charts below 1 hour, the VScore measures from each day's VWAP, which starts over every day, so the line moves more. On hourly, 4-hour and daily charts it measures from the VWAP anchored at the anchorDate input, which gives a smoother line and cleaner signals.
What do the green and red clouds on the VScore mean?
The clouds shade the standard deviation zone the VScore spent the most bars in over the last barsGoBack bars. Green means that zone is above 0, so price has mostly traded above VWAP, and red means it is below 0. Bullish arrows need a green cloud and bearish arrows a red one.
How do I see the price at a standard deviation level?
Open the lower VScore settings and change the devStop input to One, Two, Three, Zero, NegOne, NegTwo or NegThree, or to Custom to use the customDev value. The label then shows the price at that level, so you can plan a target or stop before you enter.
What is the difference between the upper and lower VScore?
The lower VScore plots the score in its own panel on a -3 to +3 scale, with trend clouds, a price label and arrows. The upper VScore draws the same levels as prices on the chart, measures trend by adding +1 or -1 per bar over 30 bars, and puts its arrows on the candles.
How do I scan for VScore signals in ThinkOrSwim?
For the upper VScore, add a Custom study filter in the Scan tab and type one line: plot signal = TI_VScore_Upper().BullSignal; using the name of your study. The download also has shared links for 4 lower VScore scans and 2 upper VScore scans that you can open with Setup, Open shared item.
Get each new indicator by email
One email on Sundays with the week's new tool and its code. A free account also unlocks every .txt download.
No credit card. Unsubscribe anytime.
Fair Value Gap
False Breakout Scanner
Heiken Ashi Trend



Stock Volatility Box
Futures Volatility Box
ORB Setups
Squeeze Setups
V-Score Scans
Bollinger Bands Reversal
Reversion to 50-Day Moving Average
Supply Demand Edge
Market Pulse
Simple Breakout Tool