Volume Split Buy vs Sell + Labels
A very popular script that has been passed around since before I was with TDA/TOS is a study that breaks down volume into buy vs sell volume. I had a client who had a handful of specific additions that he wanted made to this, to match what he had see online somewhere
Here is the starting script that splits the volume bars:
declare on_volume;
def O = open;
def H = high;
def C = close;
def L = low;
def V = volume;
def Buying = V * (C - L) / (H - L);
def Selling = V * (H - C) / (H - L);
# Selling Volume
plot SV = Selling;
SV.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
SV.SetDefaultColor(Color.RED);
SV.HideTitle();
SV.HideBubble();
SV.SetLineWeight(5);
# Total Volume
plot TV = buying + selling;
TV.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
TV.SetDefaultColor(Color.GREEN);
TV.HideTitle();
TV.HideBubble();
TV.SetLineWeight(5);
Here is everything I added to the original:
# 6 and 30 Volume SMA's
input ShortSmartAvgLength = 6;
plot ShortSmartAvg = Average(volume(), ShortSmartAvgLength);
shortsmartavg.setLineWeight(4);
shortSmartAvg.setstyle(curve.short_DASH);
input LongSmartAvgLength = 30;
plot LongSmartAvg = Average(volume(), LongSmartAvgLength);
longSmartAvg.setLineWeight(4);
longSmartAvg.setstyle(curve.long_DASH);
# Daily Volume Label
def dailyvolavg = Average(volume(period = AggregationPeriod.DAY), LongSmartAvgLength);
def DailyVolumeRatio = 100 * (volume(period = AggregationPeriod.DAY) / dailyvolavg);
input UnusualVolumeThreshold = 200;
AddLabel(yes, "Today: " + volume(period = AggregationPeriod.DAY), (if DailyVolumeRatio >= UnusualVolumeThreshold then Color.GREEN else if DailyVolumeRatio <= 99.99 then Color.RED else Color.GRAY));
# Current Bar Volume Label
def CurrentBarVolumeRatio = 100 * (volume() / LongSmartAvg);
AddLabel(yes, "CurBar: " + volume(), (if CurrentBarVolumeRatio >= UnusualVolumeThreshold then Color.GREEN else if CurrentBarVolumeRatio < 100 then Color.RED else Color.GRAY));
# Current Bar Sell % label
def SVpercent = Round(100 * (SV / TV), 0);
AddLabel(yes, "CurBarSell: " + SVpercent + "%", (if SVpercent >= 55 then Color.RED else if SVpercent <= 45 then Color.GREEN else Color.gray));
# 6 and 30 buy/sell ratio average labels
def SellValueShortAverage = Average(SVpercent, ShortSmartAvgLength);
def SellValueLongAverage = Average(SVpercent, LongSmartAvgLength);
AddLabel(yes, "6BarAvgSell " + Round(SellValueShortAverage, 1) + "%", (if SellValueShortAverage <= 45 then Color.GREEN else if SellValueShortAverage >= 55 then Color.RED else Color.gray) );
AddLabel(yes, "30BarAvgSell " + Round(SellValueLongAverage, 1) + "%", (if SellValueLongAverage <= 45 then Color.GREEN else if SellValueLongAverage >= 55 then Color.RED else Color.gray) );
# Smart Volume SMA's color settings(based on buy/sell ratio average ^)
ShortSmartAvg.assignvalueColor(if SellValueShortAverage < 50 then Color.dark_green else Color.dark_red);
LongSmartAvg.assignvaluecolor(if SellValueLongAverage < 50 then Color.dark_green else Color.dark_red);
# Relative Volume Spike Vertical lines
def RVol_Spike = CurrentBarVolumeRatio >= UnusualVolumeThreshold;
AddVerticalLine(RVol_Spike, "RVol " + SVpercent + "%", if SVpercent <= 25 then Color.dark_GREEN else if SVpercent >= 75 then Color.dark_RED else Color.GRAY);
That was a lot all at once, let's scroll down to learn more about what we have added:
First of all the client wanted 2 different moving averages, a 6 and 30 period length. They are also color coded based on the average of buy volume vs sell volume over that period. The line will be red when over that timeframe there has been more sell volume on average, and vice versa for more buy volume
Next we added labels for today's total volume as well as the total volume of the current candle we are on (5 minute shown here). They will change colors based on if the volume is exceeding the unusual volume threshold (set at 200% the average). Here the daily candle is in between 100 and 200% of the average, so it's grey. The current 5 minute bar is more than 200% of the average, so its label is lit up green for stronger volume. If the volume were to be below the average, it would be red for weak volume.
Next are labels for the current bar Sell percentage, and well as labels for both the 6 and 30 period moving averages and the sell % over those time frames. They are also color coded based on if there was more sell or buy volume over those periods. Shown in this picture the current candle has more sell volume (in red). However there has been more buy volume over both the 6 and 30 period timeframes, so they are shown in green.
Lastly, any time that the volume is at least 200% of the longer average, they wanted a dotted line to be painted on the chart, with a label marking the sell % of that candle. It is also color coded for volume on that candle being overly biased toward buys or sells. The first line is red since that candle is almost all sell volume, the second was more even between buy and sell volume, and the third was mostly buy volume.
Once we put it all together, we have all 5 labels, the 2 moving averages with their color coding, and the vertical lines painted any time there's a volume spike.
Here is the script all together:
declare on_volume;
def O = open;
def H = high;
def C = close;
def L = low;
def V = volume;
def Buying = V * (C - L) / (H - L);
def Selling = V * (H - C) / (H - L);
# 6 and 30 Volume SMA's
input ShortSmartAvgLength = 6;
plot ShortSmartAvg = Average(volume(), ShortSmartAvgLength);
shortsmartavg.setLineWeight(4);
shortSmartAvg.setstyle(curve.short_DASH);
shortSmartAvg.hidetitle();
input LongSmartAvgLength = 30;
plot LongSmartAvg = Average(volume(), LongSmartAvgLength);
longSmartAvg.setLineWeight(4);
longSmartAvg.setstyle(curve.long_DASH);
longSmartAvg.hidetitle();
# Selling Volume
plot SV = Selling;
SV.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
SV.SetDefaultColor(Color.RED);
SV.HideTitle();
SV.HideBubble();
SV.SetLineWeight(5);
# Total Volume
plot TV = buying + selling;
TV.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
TV.SetDefaultColor(Color.GREEN);
TV.HideTitle();
TV.HideBubble();
TV.SetLineWeight(5);
# Daily Volume Label
def dailyvolavg = Average(volume(period = AggregationPeriod.DAY), LongSmartAvgLength);
def DailyVolumeRatio = 100 * (volume(period = AggregationPeriod.DAY) / dailyvolavg);
input UnusualVolumeThreshold = 200;
AddLabel(yes, "Today: " + volume(period = AggregationPeriod.DAY), (if DailyVolumeRatio >= UnusualVolumeThreshold then Color.GREEN else if DailyVolumeRatio <= 99.99 then Color.RED else Color.GRAY));
# Current Bar Volume Label
def CurrentBarVolumeRatio = 100 * (volume() / LongSmartAvg);
AddLabel(yes, "CurBar: " + volume(), (if CurrentBarVolumeRatio >= UnusualVolumeThreshold then Color.GREEN else if CurrentBarVolumeRatio < 100 then Color.RED else Color.GRAY));
# Current Bar Sell % label
def SVpercent = Round(100 * (SV / TV), 0);
AddLabel(yes, "CurBarSell: " + SVpercent + "%", (if SVpercent >= 55 then Color.RED else if SVpercent <= 45 then Color.GREEN else Color.gray));
# 6 and 30 buy/sell ratio average labels
def SellValueShortAverage = Average(SVpercent, ShortSmartAvgLength);
def SellValueLongAverage = Average(SVpercent, LongSmartAvgLength);
AddLabel(yes, "6BarAvgSell " + Round(SellValueShortAverage, 1) + "%", (if SellValueShortAverage <= 45 then Color.GREEN else if SellValueShortAverage >= 55 then Color.RED else Color.gray) );
AddLabel(yes, "30BarAvgSell " + Round(SellValueLongAverage, 1) + "%", (if SellValueLongAverage <= 45 then Color.GREEN else if SellValueLongAverage >= 55 then Color.RED else Color.gray) );
# Smart Volume SMA's color settings(based on buy/sell ratio average ^)
ShortSmartAvg.assignvalueColor(if SellValueShortAverage < 50 then Color.dark_green else Color.dark_red);
LongSmartAvg.assignvaluecolor(if SellValueLongAverage < 50 then Color.dark_green else Color.dark_red);
# Relative Volume Spike Vertical lines
def RVol_Spike = CurrentBarVolumeRatio >= UnusualVolumeThreshold;
AddVerticalLine(RVol_Spike, "RVol " + SVpercent + "%", if SVpercent <= 25 then Color.light_GREEN else if SVpercent >= 75 then Color.light_RED else Color.GRAY);