Volume Spread Analysis (VSA) Reversal Indicator for ThinkorSwim

BenTen

BenTen

Administrative
Staff
VIP
This is an indicator that signal potential reversals from the Volume Spread Analysis indicator. You will see a label that says, "Buy @ $X.X" for calls or "Sell @ $X.X" for short. Alert system is included.



thinkScript Code
Rich (BB code):
# SJ_VSA_Reversals 

declare lower; 


# Arguments 

def length = 40; 

def displace = 0; 

def volumeEMALength = 30; 

def narrowSpreadFactor = 0.7; 

def wideSpreadFactor = 1.5; 

def aboveAvgVolfactor = 1.5; 

def ultraHighVolfactor = 2; 

def highCloseFactor = 0.70; 

def lowCloseFactor = 0.25; 

def GdojiFactor = 0.2; # C_RP 

def WickFactor = 0.1; # C_RP 

def shortTermLength = 5; #C_RP 

def midTermLength = 15; #C_RP 

def longTermLength = 40; #C_RP 

input colorBars = {false, default true}; #C_RP 

input trendText = {false, default true}; 

input volumeDefinitions = { false, default true }; 

input alerts = { default false, true }; 


# Calculations 

rec spread = high - low; 

def median = (high + low ) / 2; 

rec avgVolume = compoundValue(volumeEMALength, ExpAverage(volume, volumeEMALength), Double.NaN); 

# Calculate Volume moving average and it's standard deviation 

rec sAvgVolume =  compoundValue(volumeEMALength, Average(volume, volumeEMALength), Double.NaN); 

def sAvgVolumeSTD = stdev(sAvgVolume, volumeEMALength); 

# check if the vloume has been decreasing in the past two days. 

def isTwoDaysLowVol = (volume < volume[1] && volume[0] < volume[2]); 

# Calculate Range information 

def avgSpread = WildersAverage(spread, volumeEMALength)[0]; 

rec isWideSpreadBar = (spread > (wideSpreadFactor * avgSpread)); 

rec isNarrowSpreadBar = (spread < (narrowSpreadFactor * avgSpread)); 

 

# Price information 

rec isUpBar = close > close[1]; 

rec isDownBar = close < close[1]; 

 

# Check if the close is in the Highs/Lows/Middle of the bar. 

# C_RP 20100809  

# original code - def x1 = if (close == low) then avgSpread else (spread / (close - low)); 

def x1 = if (high==low) then 2.0 else if (close == low) then 2.65 else (spread / (close - low)); 

# C_RP try the line below with various divisors totalSum result in a minimum of 2.3 on a spread of 1 pip instead of using a fixed 2.3 as in the line above 

# def x1 = if (high==low) then 2.0 else if (close == low) then (spread / 0.43 ) else (spread / (close - low)); 

def isUpCloseBar = (x1 < 2); 

def isDownCloseBar = (x1 > 2); 

def isMidCloseBar = (x1 < 2.2 && x1 > 1.8); 

def isVeryHighCloseBar = (x1 < 1.35); 

# C_RP 20100809 added isVeryLowCloseBar 

def isVeryLowCloseBar = (x1 >= 2.65); 


# Trend Definitions 


rec fiveDaysSma = compoundValue(5, Average(close, 5)[0], Double.NaN); 

def LongTermTrendSlope = LinearRegressionSlope(price = fiveDaysSma, length = longTermLength)[0]; # 40 

def MiddleTermTrendSlope = LinearRegressionSlope(price = fiveDaysSma, length = midTermLength)[0]; # 15 

def ShortTermTrendSlope = LinearRegressionSlope(price = fiveDaysSma, length = shortTermLength)[0]; # 5 


#  VSA Definitions 



# upTHRUST - CRITERIA      

# utbar 

rec isUpThrustBar = isWideSpreadBar && isDownCloseBar &&  ShortTermTrendSlope > 0 && middleTermTrendSlope > 0; #C_RP added positive middleTermTrendSlope requirement to filter out upThrusts in trends that are only short term. Consider adding longTermTrendSlope requirement as well. 

# utcond1 

def upThrustConditionOne = (isUpThrustBar[1] && isDownBar); 

# utcond2 

def upThrustConditionTwo = (isUpThrustBar[1] && isDownBar[0] && volume > volume[1]); 

# utcond3 

def upThrustConditionThree = (isUpThrustBar[0] && volume > 2 * sAvgVolume[0]); 

# scond1 

rec isConfirmedUpThrustBar = (upThrustConditionOne OR upThrustConditionTwo OR upThrustConditionThree); 

# scond 

rec isNewConfirmedUpThrustBar = (isConfirmedUpThrustBar[0] && !isConfirmedUpThrustBar[1]); 

# Two Period UpThrust Bar 

rec isTwoPerUpT = isUpBar[1] && isWideSpreadBar[1] &&  isDownBar[0] && isDownCloseBar[0] && !isUpThrustBar[0] && (absValue(open[1] - close[0]) < (GdojiFactor * spread[1])) ; 

# Three Period UpThrust Bar 

rec isThreePerUpT = isUpBar[2] && isWideSpreadBar[2] &&  isDownBar[0] && isDownCloseBar[0] && !isUpThrustBar[0] && (absValue(open[2] - close[0]) < (GdojiFactor * spread[2])) ; 


# GRAVESTONE DOJI - CRITERIA   

#  C_RP 20100816 

# rec isGraveDojiBar = (spread > avgSpread) && (open == low) && (close == low); totally strict Gravestone Doji. Revised version below identifies a candle with above average spread, a real body smaller than 20% of the spread, and a lower wick less than 10% of the spread as a Gravestone Doji pictured as a white triangle above the candle. 

rec isGraveDojiBar = (spread > avgSpread) && (absValue(open - close) < (GdojiFactor * spread)) &&  ((absValue(close - low) < (WickFactor * spread)) or (absValue(open - low) < (WickFactor * spread))); # less strict Gravestone Doji 


# LIKELY REVERSAL - CRITERIA  

#  trbar 

def reversalLikelyBar = (volume[1] > sAvgVolume[0] && isUpBar[1] && isWideSpreadBar[1] && isDownBar[0] && isDownCloseBar && isWideSpreadBar[0] && LongTermTrendSlope > 0 && high == Highest(high, 10)[0]); 


# PSEUSO-upTHRUST - CRITERIA              

# hutbar 

rec isPseudoUpThrustBar = (isUpBar[1] && (volume[1] > aboveAvgVolfactor * sAvgVolume[0]) && isDownBar[0] && isDownCloseBar && !isWideSpreadBar[0] && !isUpThrustBar[0]); 

# hutcond 

def pseudoUpThrustConfirmation = (isPseudoUpThrustBar[1] && isDownBar[0] && isDownCloseBar && !isUpThrustBar[0]); 


# FAILED-upTHRUST - CRITERIA 

# C_RP Failed UpThrustConfirmation or pseudoUpThrustConfirmation occurs when the close of bar following such confirmation is not lower than the close of the confirmation bar 

rec isFailedUpThrustConfirmation = (isNewConfirmedUpThrustBar[1] or pseudoUpThrustConfirmation[1]) && close[0] >= close[1]; 


# WEAKNESS BAR - CRITERIA 

# tcbar 

def weaknessBar = (isUpBar[1] && high[0] == Highest(high, 5)[0] && isDownBar[0] && (isDownCloseBar OR isMidCloseBar) && volume[0] > sAvgVolume[0] && !isWideSpreadBar[0] && !isPseudoUpThrustBar[0]); 


# DOWNTREND STRENGTH (MARKET WEAKNESS) - CRITERIA 

# stdn, stdn0, stdn1, stdn2 

def strengthInDownTrend =  (volume[0] > volume[1] && isDownBar[1] && isUpBar[0] && (isUpCloseBar OR isMidCloseBar) && ShortTermTrendSlope < 0 && MiddleTermTrendSlope < 0); 

def strengthInDownTrend0 = (volume[0] > volume[1] && isDownBar[1] && isUpBar[0] && (isUpCloseBar OR isMidCloseBar) && ShortTermTrendSlope < 0 && MiddleTermTrendSlope < 0 && LongTermTrendSlope < 0);

def strengthInDownTrend1 = (volume[0] > (sAvgVolume[0] * aboveAvgVolfactor) && isDownBar[1] && isUpBar[0] && (isUpCloseBar OR isMidCloseBar) && ShortTermTrendSlope < 0 && MiddleTermTrendSlope < 0 && LongTermTrendSlope < 0); 

def strengthInDownTrend2 = (volume[1] < sAvgVolume[0] && isUpBar[0] && isVeryHighCloseBar && volume[0] > sAvgVolume[0] && ShortTermTrendSlope < 0); 


# CONFIRMATION DOWNTREND STRENGTH (MARKET WEAKNESS) - CRITERIA 

rec bycond1 = (strengthInDownTrend OR strengthInDownTrend1); 

# bycond 

def isStrengthConfirmationBar = (isUpBar[0] && bycond1[1]); 

# bycond2 C_RP UpClose on higher volume with all slopes down adds extra strength 

def isStrengthConfirmationBar2 = (isUpBar[0] && isUpCloseBar[0] && volume[0] > volume[1] && longtermtrendslope < 0 && bycond1[1]); 


# FAILED DOWNTREND STRENGTH (MARKET WEAKNESS) - CRITERIA 

# Failed strength in downtrend signal force a follow-up bar that closes below mid-point of confirmaton bar C_RP 

def isFailedStrengthSignal = (isStrengthConfirmationBar[1] or isStrengthConfirmationBar2[1] or strengthinDownTrend2[1])&& close[0] <= (close[1] - (spread[1]/2)); 


# STOPPING VOLUME AT BOTTOM (LIKELY REVERSAL) - CRITERIA 

# stvol 

def stopVolBar = low[0] == Lowest(low, 5)[0] && (isUpCloseBar OR isMidCloseBar) && volume[0] > aboveAvgVolfactor * sAvgVolume[0] && LongTermTrendSlope < 0; 


# STOPPING VOLUME AT TOP (LIKELY REVERSAL) - CRITERIA 

# C_RP stvol at highs - the opposite of stvol 

def stopVolBarHighs = high[0] == Highest(high, 5)[0] && (isDownCloseBar OR isMidCloseBar) && volume[0] > aboveAvgVolfactor * sAvgVolume[0] && LongTermTrendSlope > 0; 


# NO DEMAND - CRITERIA 

# ndbar, nsbar 

def noDemandBar = (isUpBar[0] && isNarrowSpreadBar[0] && isTwoDaysLowVol && isDownCloseBar); 

# C_RP 20100809 


# NO SUPPLY - CRITERIA 

# def noSupplyBar = (isDownBar[0] && isNarrowSpreadBar[0] && isTwoDaysLowVol && isDownCloseBar); 

def noSupplyBar = (isDownBar[0] && isNarrowSpreadBar[0] && isTwoDaysLowVol && isUpCloseBar); 


# TEST FOR SUPPLY - CRITERIA 

# lvtbar, lvtbar1, lvtbar2 

rec supplyTestBar = (isTwoDaysLowVol && low[0] < low[1] && isUpCloseBar); 


# TEST FOR SUPPLY IN AN UPTREND - CRITERIA 

def supplyTestInUpTrendBar = (volume[0] < sAvgVolume[0] && Low[0] < Low[1] && isUpCloseBar && LongTermTrendSlope > 0 && MiddleTermTrendSlope > 0 && isWideSpreadBar[0]); 


# SUCCESSFUL FIRST TEST FOR SUPPLY - CRITERIA 

def successfulSupplyTestBar = (supplyTestBar[1] && isUpBar[0] && isUpCloseBar); 


# SUCCESSFUL SECOND TEST FOR SUPPLY - CRITERIA 

def successfulSupplyTestBar2 = (successfulsupplyTestBar[1] && isUpBar[0] && x1 <= 2 && volume[0] > volume[1]); # C_RP x1 finds Mid and UpCloseBars 


# DISTRIBUTION - CRITERIA             

# dbar 

def distributionBar = (volume[0] > ultraHighVolfactor * sAvgVolume[0] && isDownCloseBar && isUpBar[0] && ShortTermTrendSlope > 0 && MiddleTermTrendSlope > 0 && !isConfirmedUpThrustBar[0] && !isUpThrustBar[0]); 


# EFFORT TO MOVE UP - CRITERIA  

# eftup, eftupfl, eftdn 

def effortToMoveUpBar = (high[0] > high[1] && low[0] > low[1] && Close[0] > Close[1] && Close[0] >= ((high[0] - low[0]) * highCloseFactor + low[0]) && spread[0] > avgSpread && volume[0] > volume[1]); 


# FAILED EFFORT TO MOVE UP - CRITERIA 

def failedEffortUpMove = (effortToMoveUpBar[1] && (isUpThrustBar[0] OR upThrustConditionOne OR upThrustConditionTwo OR upThrustConditionThree)); 


# EFFORT TO DOWN - CRITERIA 

def effortToMoveDownBar = ( ((high[0] < high[1]) OR (isWideSpreadBar && volume[0] > 1.5 * sAvgVolume[0]))  && low[0] < low[1] && close[0] < close[1] && Close[0] <= ((high[0] - low[0]) * lowCloseFactor + low[0]) && spread[0] > avgSpread && volume[0] > volume[1]); 

#C_RP old code - def effortToMoveDownBar = (high[0] < high[1] && low[0] < low[1] && close[0] < close[1] && Close[0] <= ((high[0] - low[0]) * lowCloseFactor + low[0]) && spread[0] > avgSpread && volume[0] > volume[1]); 


#  PLOT DEFINITIONS 


plot uSMA = Average(volume[-displace], length); 

uSMA.SetDefaultColor(GetColor(2)); 

uSMA.SetLineWeight(1); 

uSMA.HideTitle(); 

uSMA.HideBubble(); 

plot dSMA = Average(-volume[-displace], length); 

dSMA.SetDefaultColor(GetColor(2)); 

dSMA.SetLineWeight(1); 

dSMA.HideTitle(); 

dSMA.HideBubble(); 

plot ZeroLine = 0; 

ZeroLine.SetDefaultColor(GetColor(2)); 

ZeroLine.SetLineWeight(1); 

ZeroLine.HideTitle(); 

ZeroLine.HideBubble(); 

def Condition1 = shortTermTrendSlope > 0 and MiddleTermTrendSlope > 0 and longtermtrendslope > 0; 

def Condition2 = shortTermTrendSlope > 0 and MiddleTermTrendSlope > 0 and longtermtrendslope < 0; 

def Condition3 = shortTermTrendSlope > 0 and MiddleTermTrendSlope < 0 and longtermtrendslope < 0; 

def Condition4 = shortTermTrendSlope < 0 and MiddleTermTrendSlope < 0 and longtermtrendslope < 0; 

def Condition5 = shortTermTrendSlope < 0 and MiddleTermTrendSlope > 0 and longtermtrendslope > 0; 

def Condition6 = shortTermTrendSlope < 0 and MiddleTermTrendSlope < 0 and longtermtrendslope > 0; 


# Candle definitions 





def SafeReversal = double.nan; 

# plot null = double.nan; 



# SELECTED REVERSAL CONDITIONS 


# LIKELY REVERSAL AT THE TOP #1 

# (Top - Red DownArrow) 

def ConditionDown1 = if isNewConfirmedUpThrustBar && (upThrustConditionTwo or upThrustConditionThree) then (high + 4 * tickSize()) else Double.NAN; 


# (Top - Red Triangle) 

def ConditionDown2 = if isNewConfirmedUpThrustBar && upThrustConditionOne then (high + 2 * tickSize()) else Double.NAN; 


# (Middle - Magenta Circle) 

def ConditionDown3 = if effortToMoveDownBar && !(shortTermTrendSlope < 0 && MiddleTermTrendSlope < 0 && longTermTrendSlope < 0) then (median) else  

Double.NAN; 


AddChartBubble(ConditionDown1 && ConditionDown2 && ConditionDown3,  Volume, concat("Sell @ $", Close), Color.Red, Yes); 

Alert(ConditionDown1 && ConditionDown2 && ConditionDown3, concat("Sell @ $", Close), Alert.BAR, Sound.Chimes); 

# AddChartBubble(ConditionDown2, Volume, "Reversal Alert", Color.Red, Yes); 


# LIKELY REVERSAL AT THE TOP #2 

# (Top - Red Circle) 

def ConditionDown4 = if reversalLikelyBar then (high + 6 * tickSize()) else Double.NAN; 


# (Top - Yellow circle) 

def ConditionDown5 = if stopVolBarHighs then (high + 7 * tickSize()) else Double.NAN; 


AddChartBubble(ConditionDown1 && ConditionDown4 && ConditionDown5, Volume, concat("Sell @ $", Close), Color.Red, Yes);  

Alert(ConditionDown1 && ConditionDown4 && ConditionDown5, concat("Sell @ $", Close), Alert.BAR, Sound.Chimes); 

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

# LIKELY REVERSAL AT THE BOTTOM #1 

# (Bottom - Green Arrow Up) #1 

def ConditionUp1 = if isStrengthConfirmationBar then (low - 4 * tickSize()) else Double.NAN; 


# (Bottom - Green Arrow Up) #2 

def ConditionUp2 = if isStrengthConfirmationBar2 then (low - 7 * tickSize()) else Double.NAN; 


# (Middle - Green Circle) 

def ConditionUp3 = if effortToMoveUpBar then (median) else Double.NAN; 


AddChartBubble(ConditionUp1 && ConditionUp2 && ConditionUp3, Volume, concat("Buy @ $", Close), Color.Green, Yes);  

Alert(ConditionUp1 && ConditionUp2 && ConditionUp3, concat("Buy @ $", Close), Alert.BAR, Sound.Bell); 


# LIKELY REVERSAL AT THE BOTTOM #2 

# (Bottom - Green Circle) 

def ConditionUp4 = if stopVolBar then (low - 2 * tickSize()) else Double.NAN; 


# (Bottom - Green Triangle) 

def ConditionUp5 = if strengthInDownTrend2 then (low - 3 * tickSize()) else Double.NAN; 


AddChartBubble(ConditionUp4 && ConditionUp5, Volume, concat("Buy @ $", Close), Color.Green, Yes);  

Alert(ConditionUp4 && ConditionUp5, concat("Buy @ $", Close), Alert.BAR, Sound.Bell);
Shareable Link
http://tos.mx/O04FPQ

&#127873; If you're new here. Consider joining our free Discord chatroom.

 
Last edited:
T

Tesh01

New member
I imported the study but Labels are not showing up for me.

 
Last edited:
BenTen

BenTen

Administrative
Staff
VIP
@Tesh01 They don't often give you Buy or Sell signals since it has to follow set rules and until then it won't alert you of anything (The reason being so we don't have to see a lot of false signals). Furthermore, I found it best to use on the 5min chart (for day trading) and daily (for swings) with pre-market turn off.

 
Last edited:
M

max

New member
Hm, I put that on AMZN chart also but I don't have the signal as on your chart. And also I have that indicator on the bottom (in the lower panel) and it shows only 3 lines like "Bollinger Band" and nothing more

 
Last edited:
BenTen

BenTen

Administrative
Staff
VIP
@max Left click on your screen, click Chart scale > check Fit Studies. In the indicator's setting, go ahead and untick all the plots for the bands.

 
Last edited:
S

San

New member
VIP
@BenTen , Just i try to load this indicator and i notice same as Max comment, I see only 3 line in lower band and i don't see any buy or sell signal as well as i have set chart scale > check fit Studies no luck. When you find time please verify.

 
Last edited:
BenTen

BenTen

Administrative
Staff
VIP
@San On which ticker and timeframe?

 
Last edited:
S

San

New member
VIP
@BenTen The indicator "Volume Spread Analysis (VSA) Reversal Indicator" and i used AMZN and time frame 3/5 /15mts as well 1 day time frame.


 
Last edited:
S

San

New member
VIP
@San , Never mind. I did below to look like your chart . I have enable Chart Scale > Fit study and Fit study market and indicator disable show plot u/d SMA and Zero line then move this indicator to chart window.

 
Last edited:
J

J-guy2point0

New member
Has anyone been able to create a scan for this?

 
Last edited:

Top