The Psychology of Volume

mashume

Expert
VIP
Lifetime
New Indicator... Maybe.

Link

http://tos.mx/xSDbRO5

Introduction

In a field of financial analysis that has seen an explosion of tinkerers, like myself, there seems likely to have been someone who tried this before. I have not found their efforts, but then again I haven't looked all that hard. Sometime we reinvent the wheel. Such is the nature of this game of trying to make a few cents in the markets.

With that in mind, I present a new take on trying to recognize trends and important points in volume analysis, and the effects that that change can have as it applies to potential levels of support, accumulation, and distribution.

I would also like to ask the community if this is indeed a new approach, or if this has been tried and failed before. The wisdom of the many is indeed vast, though often unasked.

The Indicator

Origins
This started as the Psychological Line Indicator. For those who know it, feel free to skip down to the Modifications section below.

The PLI is arrived at by taking the number of bars that were up bars over the last n bars and calculating the ratio of that number to n:

Code:
(1.) PLI = (count up bars in last n / n) x 100

This is an interesting indicator in that it ignores the price information in bars and only considers the direction moved, and gives an interesting picture of market movement.

Volume
Volume is as an important indicator of trend strength, and the idea to combine volume and movement is not a new one. Many have tried to combine volume and price movement into a strength or momentum or force indicator. Some are more successful than others. This one may or may not be an improvement on any of them.

Starting with a sum of the volume for up bars and dividing by the total volume gave a satisfyingly simple plot.

Code:
(2.) UpVolVSTotalVolume = sum(volume for up bars in last n bars) / Total Volume last n bars

This plotted over the PLI provided little insight as the two tracked nearly identically for some tickers and varied widely for others. The theory I started working on is that when up the ratio of up-candle volume to total volume outpaces the ratio of up-candles to total bars (n), then there the number of people buying in hoping the price will go up is larger than the number of people holding or selling out of positions. This is perhaps a simplistic view. If the up volume on up candles does not move up as much as the PLI for the bar, then the interest in pushing the price higher is absent, and while the close was up, it was not supported on strong volume.

Calculating Deviation between PLI and UpVolume
The difference between these two is then calculated as a ratio:

Code:
(3.) Indicator = (VolPLIMod - PLI) / (PLI)) * 100

Several attempts at refining the ratio of up volume to total volume were tried. Particular interest was given to scenarios which followed on from the thought that only the volume between the open and the high (of an up bar, so the close is necessarily between the open and the high) actually contributes to pushing the price higher, only that volume is considered 'strong' up-candle volume. Strong upward volume was calculated this way:

Code:
(4.) StrongFraction = (high - open) / (high - low)
(5.) Strong Up Volume = sum (volume x StrongFraction)
This number was then used in the same way as (2.) above as the numerator for the calculation of the Indicator (3.)

Some attempts were made to remove 'weak' portions of volume from the total volume, but all of them turned out to be poorer than this method. They are included in the indicator code for those who wish to pursue this avenue and make potential improvements to the signals given by this indicator.

Though it is not intended to be used as a stand-alone indicator, the Indicator plot crossovers were used to assess timing by backtesting a strategy. This was a long-only test, with no short positions entered. The entry condition was a crossover above zero, along with the two bars preceding the positive value being both negative (to reduce chop).

SPY was chosen for the first test at a timeframe of 1 year at 1 day. With a setting of n=12, a total profit of $2,501 was realized. When set to n=13, the total profit was $2,496. Each of those was on a standard lot size of 100 which did not get reintroduced into the position.

Trading TSLA on a 30 day 30 minute chart without extended-trading-hours, again at 100 shares per trade, 17 trades resulted in $21,298 gross profit with n=15.

There is obviously some bias in tuning the back testing, and you may need to find a value that works for whatever ticker you are trading. The indicator was not intended to deliver signals all alone, but in combination with others or as a confirmation to other signals.

Eye Candy

RFgQthP.png


Analysis
The most interesting point in the chart above is the set of positive (green) histogram bars just to the left of the cursor vertical line, about halfway across the image. This shows a divergence in price movement and an influx of volume on positive bars, possibly presaging the move upward that happens at the green histogram bars about 3/4 of the way across the image. The red histogram bars on the far left, or the far right indicate a lack of interest, possibly. The ones on the left are an indication of the larger fall that will come, and the ones on the right in the non-trending marked show that there is a general outflow compared to price. I'd be getting out of this if I were in.

Backtesting
EddZkHo.png

Strategy Backtest 1, SPY 1Y1D n=12

UJoVtv2.png

Strategy Backtest 2, TSLA 30D30m n=15

The Indicator Code

Code:
#####################################################
#       Psychological Volume Expectation
#
#           2021-01-12.V1     @mashume
#      Released under GPL V3 as applicable
#        to the UseThinkScript Community
#              http://tos.mx/xSDbRO5
#####################################################

declare lower;

input n = 15;
input smoothing = 10;

# Uncomment this if you want to see where the indicator starts the current calculations
# def bar = barnumber();
# addverticalLine(bar == highestall(if !isNan(open) then bar else double.nan ) - n, "BACK LIMIT", color.Blue);

def isUpCandle = if close > open then 1 else 0;

plot PLI = (sum(isUpCandle, n) / n) * 100;
PLI.SetDefaultColor(getColor(3));
PLI.SetLineWeight(2);

plot PLIMA = SimpleMovingAvg(PLI, smoothing);
PLIMA.SetDefaultColor(getColor(8));
PLIMA.Hide();

plot Center = 50;
Center.SetDefaultColor(getColor(7));
Center.SetStyle(CURVe.MEDIUM_DASH);

plot Warning = 80;
Warning.SetDefaultColor(getColor(5));
Warning.SetStyle(CURVE.SHORT_DASH);

plot Opportunity = 20;
Opportunity.SetDefaultColor(getColor(6));
Opportunity.SetStyle(CURVE.SHORT_DASH);

def isUpVolSimple = if close > open then Volume else 0;

plot VolPLI = (sum(isUpVolSimple, n) / sum(Volume, n)) * 100;
VolPLI.SetDefaultColor(getColor(4));
# VolPLI.SetStyle(CURVE.POINTS);
VolPLI.SetLineWeight(2);

####################################
#
#    These are experimental alternate calculation methods for volume
#    which incorporate the idea of strength or conviction
#
# def isUpVol = if close > open then Volume * ((high - open) / (high - low)) else 0;
# def UpCandleDnVol = if close > open then Volume * ((open - low) / (high - low)) else 0;
# def DnCandleUpVol = if close < open then Volume * ((high - open)/(high - low)) else 0;
# def VolPLIMod = (sum(isUpVol, n) / (sum(Volume, n) - (sum(UpCandleDnVol, n) + sum(DnCandleUpVol)))) * 100;
# VolPLIMod.SetStyle(CURVE.SHORT_DASH);
#
####################################


plot Indicator = (((VolPLI - PLI) / PLI) * 100);
Indicator.SetPaintingStrategy(PaintingStrategy.histogram);
Indicator.SetLineWeight(3);
Indicator.AssignValueColor(if Indicator >= 0 then getColor(9) else getColor(5));

plot cent = 100;
cent.setdefaultcolor(getColor(7));
cent.hide();

plot VolPLIMA = SimpleMovingAvg(VolPLI, n);
VolPLIMA.SetDefaultColor(getColor(9));
VolPLIMA.SetStyle(CURVE.MEDIUM_DASH);
VolPLIMA.Hide();

plot IndicatorMA = MovAvgExponential(Indicator, floor(n/2));
IndicatorMA.SetDefaultColor(getColor(4));
IndicatorMA.SetLineWeight(1);
IndicatorMA.Hide();

AddLabel(Indicator > Indicator[1], "Rising Sentiment Volume", getColor(9));
AddLabel(Indicator < Indicator[1], "Falling Sentiment Volume", getColor(5));

AddLabel(PLI > 80, "PLI Line Warning", getColor(5));
AddLabel(PLI < 20, "PLI Line Opportunity", getColor(9));

plot StartBuy = if Indicator crosses above 0 and indicator [2] < 0 then -20 else double.nan;
StartBuy.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
StartBuy.SetDefaultColor(GetColor(9));
StartBuy.Hide();

plot StartSell = if Indicator crosses below 0 and indicator[2] > 0 then 20 else double.nan;
StartSell.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
StartSell.SetDefaultColor(GetColor(5));
StartSell.Hide();
 
Last edited:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

@mashume thank you for sharing this. I enjoyed reading your thought process. Do you think there could be a successful strategy for shorting as well?
 
@mashume thank you for sharing this. I enjoyed reading your thought process. Do you think there could be a successful strategy for shorting as well?
I don't see why it wouldn't work that way. The indicator should be symmetrical about the zero line, that is there shouldn't be a bias toward overly positive or negative signals.

This is the original strategy implementation:

Code:
# Psychological Line Strategy

input n = 15;

def isUpCandle = if close > open then 1 else 0;
def PLI = (sum(isUpCandle, n) / n) * 100;
def isUpVolSimple = if close > open then Volume else 0;
def VolPsy = (sum(isUpVolSimple, n) / sum(Volume, n)) * 100;
def Indicator = (((VolPsy - PLI) / (PLI)) * 100);

def Entry = if Indicator > 0 and Indicator[1] < 0 and Indicator[2] < 0 and PLI < 80 then 1 else Double.NaN;
def Exit = if Indicator < 0 and Indicator[1] > 0 then 1 else Double.NaN;

AddOrder(OrderType.BUY_TO_OPEN, Entry == 1, tickColor = Color.DARK_GREEN, arrowColor = Color.BLACK);
AddOrder(OrderType.SELL_TO_CLOSE, Exit == 1, tickColor = Color.DARK_RED, arrowColor = Color.BLACK);

You could modify the buy and sell like this:

Code:
def ShortEntry = if Indicator < 0 and Indicator[1] > 0 and Indicator[2] > 0 and PLI > 20 then 1 else Double.NaN;
def ShortExit = if Indicator > 0 and Indicator[1] < 0 then 1 else Double.NaN;

AddOrder(OrderType.SELL_TO_OPEN, ShortEntry == 1, tickColor = Color.DARK_GREEN, arrowColor = Color.BLACK);
AddOrder(OrderType.BUY_TO_CLOSE, ShortExit == 1, tickColor = Color.DARK_RED, arrowColor = Color.BLACK);
You will want to adjust the PLI level in the short entry variable to see what works. I took a guess at 20 which mirrors the long strategy.

As I noted in the first post, the n value is of critical importance, so play with it. I've seen it work well with values from n=9 to n=21, though the sweet spot seems to be between 12 and 15 normally.

happy trading,
mashume

EDIT -- I had neglected to change the AddOrder conditions for ShortEntry and ShortExit. That is now correct
 
Last edited:
@mashume Can a scanner be made out of this?
In your scanner, edit as thinkscript and paste this in. Adjust variables as necessary (n, and the PLI_min value in the Entry condition).

Code:
script PSY_Local {
input n = 14;
input PLI_min = 50;

def isUpCandle = if close > open then 1 else 0;
def isUpVolSimple = if close > open then Volume else 0;
def VolPsy = (sum(isUpVolSimple, n) / sum(Volume, n) ) * 100;
def PSY = (sum(isUpCandle, n) / n) * 100;;
def Indicator = (((VolPsy - psy) / (Psy)) * 100);

plot Entry = if Indicator > 0
    and Indicator[1] < 0
    and PSY < PLI_min
    and volume[1] > 1.5 * SimpleMovingAvg(volume[2], 30)
then 1 else double.nan;}

plot Entry = PSY_Local();
I notice this one that I was playing with at some point also had a volume condition, looking for stocks that had at least 150% of their recent volume level. Take it out or leave it in as you see fit.

happy trading.
-mashume
 
Last edited:
Thanks, Mashume! Creative and fun! Question: is there any significance to the two line plots that you don't have hidden? Or do we only really care about the histogram plot direction/magnitude? Thanks.
 
Thanks, Mashume! Creative and fun! Question: is there any significance to the two line plots that you don't have hidden? Or do we only really care about the histogram plot direction/magnitude? Thanks.
I think I have several moving averages in there, for the PLI line, the PLI Volume line, and the histogram. They were there as I started looking for patterns, and because the first PLI indicator description had a moving average in the description. It seems that they slowed it down unnecessarily, though as moving averages do, they smooth the data.

I left them out of laziness. And because I thought some folks might like them. ;-)

-mashume
 
@mashume This could be a good alternative to typical accumulation/distribution. Great work! I will use this a confirmation tool with BTD or squeeze setups and report my stats once I have a handful of them. I feel like folks in this forum need to give more attention this one :)
 
@mashume This could be a good alternative to typical accumulation/distribution. Great work! I will use this a confirmation tool with BTD or squeeze setups and report my stats once I have a handful of them. I feel like folks in this forum need to give more attention this one :)
You can lead a horse...
;-)

I've got another variant version of this in the works that I hope to have ready for you all in the near future.


EDIT:
Here's a link to the thread with the variant I was talking about:

https://usethinkscript.com/threads/price-action-deviance-from-expectation.5427/#post-51029

There is a reasonable explanation of it in the first post in that thread.

-mashume
 
Last edited:
@mashume I have really enjoyed trading with one of your indicators and I take notice of your posts whenever I am on here. In the screenshot above entitled "Eye Candy," what is the indicator you are using in the upper panel, the one with the brown line at 98.58?

Thanks much for the great work you do.
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
470 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top