It produces decent signals if the market is ranging. Not so much if the market is trending.
May be you can improve it.
# sh_WP_V_MA_VWAP_Crossovers
# Created by WP 8/30/24, used some of the concepts below
# https://usethinkscript.com/threads/moving-average-crossovers-for-thinkorswim.229/
# https://usethinkscript.com/threads/vwap-volume-breakout-indicator-for-thinkorswim.573/
# https://usethinkscript.com/threads/increasing-the-value-of-a-variable.11128/#post-97465
# Prints somewhat confirmed VWAP 2SD reversals arrows based on 5, 9 TEMA corssovers (violet arrows).
# 9/20/24 Changed the reversal conditions a bit
# 10/5/24 Added RTH and volume filters 8/30/24
input valuep = close;
input sfastL = 5;
input fastL = 9;
input medL = 20;
input slowL = 50;
input displace = 0;
input showBreakoutSignals = no;
def na = Double.NaN;
# colors forceIndex moving avarages
DefineGlobalColor("sfast", CreateColor(0,204,102)); # bgreen
DefineGlobalColor("fast", CreateColor(230,138,0)); # dorange
DefineGlobalColor("med", CreateColor(45,123,199)); #BBlue
DefineGlobalColor("slow", CreateColor(51,51,0)); #gary/green
#cloor for VWAP and 1.2 and 2 SD bands
DefineGlobalColor("VWAP1", CreateColor(134,0,179));
DefineGlobalColor("VUB1", CreateColor(204,0,102));
DefineGlobalColor("VLB1", CreateColor(85,128,0));
DefineGlobalColor("VUB2", CreateColor(235,70,153));
DefineGlobalColor("VLB2", CreateColor(132,162,78));
# moving averages
input sfastAV = no;
def sfastA = TEMA(valuep, sfastL); #TripleExpotentialMA
plot SFA = If sfastAV Then sfastA else na;
SFA.SetPaintingStrategy(PaintingStrategy.LINE);
SFA.SetDefaultColor(GlobalColor("sfast"));
SFA.SetLineWeight(1);
input fastAV = no;
def fastA = TEMA(valuep, fastL); #TripleExpotentialMA
plot FAMA1 = If fastAV then fastA else na;
FAMA1.SetPaintingStrategy(PaintingStrategy.LINE);
FAMA1.SetDefaultColor(GlobalColor("fast"));
FAMA1.SetLineWeight(1);
input slowAV = yes;
plot slowA = If slowAV Then ExpAverage(valuep, slowL) else Double.NaN; #MovAvgExponential
slowA.SetPaintingStrategy(PaintingStrategy.LINE);
slowA.SetDefaultColor(GlobalColor("slow"));
slowA.SetLineWeight(2);
input medAV = yes;
plot medA = If medAV Then Average(valuep, medL) else Double.NaN; #SimpleMovingAvg
medA.SetPaintingStrategy(PaintingStrategy.LINE);
medA.SetDefaultColor(GlobalColor("med"));
medA.SetLineWeight(2);
#plot DailyVWAP = vwap(period = AggregationPeriod.DAY);
# Start VWAP
#
input numDevDn = -1.92;
input numDevUp = 1.92;
input numDevDn1 = -1.4;
input numDevUp1 = 1.4;
input timeFrame = {default DAY, WEEK, MONTH};
def cap = getAggregationPeriod();
def errorInAggregation =
timeFrame == timeFrame.DAY and cap >= AggregationPeriod.WEEK or
timeFrame == timeFrame.WEEK and cap >= AggregationPeriod.MONTH;
assert(!errorInAggregation, "timeFrame should be not less than current chart aggregation period");
def yyyyMmDd = getYyyyMmDd();
def periodIndx;
switch (timeFrame) {
case DAY:
periodIndx = yyyyMmDd;
case WEEK:
periodIndx = Floor((daysFromDate(first(yyyyMmDd)) + getDayOfWeek(first(yyyyMmDd))) / 7);
case MONTH:
periodIndx = roundDown(yyyyMmDd / 100, 0);
}
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 priceV = volumeVwapSum / volumeSum;
def deviation = Sqrt(Max(volumeVwap2Sum / volumeSum - Sqr(priceV), 0));
plot VWAP = priceV;
VWAP.SetPaintingStrategy(PaintingStrategy.LINE);
VWAP.SetDefaultColor(GlobalColor("VWAP1"));
VWAP.SetLineWeight(1);
plot UpperBand = priceV + numDevUp * deviation;
#UpperBand.SetPaintingStrategy(PaintingStrategy.LINE);
UpperBand.SetStyle(curve.MEDIUM_DASH);
UpperBand.SetDefaultColor(GlobalColor("VUB1"));
UpperBand.SetLineWeight(1);
plot LowerBand = priceV + numDevDn * deviation;
LowerBand.setDefaultColor(GlobalColor("VLB1"));
#LowerBand.SetPaintingStrategy(PaintingStrategy.LINE);
LowerBand.SetStyle(curve.MEDIUM_DASH);
LowerBand.SetLineWeight(1);
def UBpl = no;
def UB1 = priceV + numDevUp1 * deviation;
plot UpperBand1 = If UBpl then UB1 else Double.NaN;
#UpperBand.SetPaintingStrategy(PaintingStrategy.LINE);
UpperBand1.SetStyle(curve.MEDIUM_DASH);
UpperBand1.SetDefaultColor(GlobalColor("VUB2"));
UpperBand1.SetLineWeight(1);
def LBpl = no;
def LB1 = priceV + numDevDn1 * deviation;
plot LowerBand1 = If LBpl then LB1 else Double.NaN;
LowerBand1.setDefaultColor(GlobalColor("VLB2"));
#LowerBand.SetPaintingStrategy(PaintingStrategy.LINE);
LowerBand1.SetStyle(curve.MEDIUM_DASH);
LowerBand1.SetLineWeight(1);
# RTH and Volume filter
def myRTH = secondsFromTime(0945) >= 0 and SecondsTillTime(1545) >= 0;
input length = 5;
def Vol = volume;
def VolAvg = Average(volume, length);
def abVol = Vol > VolAvg;
# Define VWAP 2SD up reversal entry
# close or high in a bullish candle must cross the LowerBand and then the sfastA and fastA moving averages should crossover and align up
# this usually happens in 3-6 periods, a longer period indicates consolidation and a possibillity of continuation (lower) in this case
# define the barNumber of the signal according to the logic presented above and and a period of maximum consolodation (barA <= then 16)
# barA indicates the distance (in periods) from LowerBand crossover to fastA and fastA moving averages crossover and up alignment
DefineGlobalColor("Green1", CreateColor(102,153,0));
def upSH = If high > LowerBand and close > LowerBand and low < LowerBand then BarNumber() else Double.NaN;
def upSH1 = If high[1] > LowerBand[1] and close[1] > LowerBand[1] and low[1] < LowerBand[1] then BarNumber() -1 else Double.NaN;
def upSH2 = If high[2] > LowerBand[2] and close[2] > LowerBand[2] and low[2] < LowerBand[2] then BarNumber() -2 else Double.NaN;
#def upMA = If sfastA > fastA and high > LowerBand and low > ((low[1]+open[1]+close[1])/3) and close > open and high < medA then BarNumber() else Double.NaN;
def upMA = If sfastA > fastA and high > LowerBand and close > LowerBand and high < medA and close > close[1] then BarNumber() else Double.NaN;
#def sUP = If !isNaN(upMA) and barA <= 2 then upMA else Double.NaN;
def sUP = If !isNaN(upMA) and !isNaN(upSH)then upMA else Double.NaN;
def sUP1 = If !isNaN(upMA) and !isNaN(upSH1)then upMA else Double.NaN;
def sUP2 = If !isNaN(upMA) and !isNaN(upSH2)then upMA else Double.NaN;
plot vwDN = if!isNaN(sUP) and myRTH and abVol then low -(5*TickSize()) else na;
vwDN.SetPaintingStrategy(PaintingStrategy.Arrow_UP);
vwDN.SetDefaultColor(GlobalColor("VWAP1"));
vwDN.SetLineWeight(5);
plot vwDN1 = if!isNaN(sUP1) and myRTH and abVol then low - (5*TickSize()) else na;
vwDN1.SetPaintingStrategy(PaintingStrategy.Arrow_UP);
vwDN1.SetDefaultColor(GlobalColor("VWAP1"));
vwDN1.SetLineWeight(5);
plot vwDN2 = if!isNaN(sUP2) and myRTH and abVol then low - (5*TickSize()) else na;
vwDN2.SetPaintingStrategy(PaintingStrategy.Arrow_UP);
vwDN2.SetDefaultColor(GlobalColor("VWAP1"));
vwDN2.SetLineWeight(5);
#AddChartBubble(sUP, low - 0.1, "VB0", GlobalColor("Green1"), no);
#AddChartBubble(sUP1, low - 0.1, "VB1", GlobalColor("Green1"), no);
# Define VWAP 2SD down entry
# First, low in a bearish candle must cross the UpperBand and then sfastA and fastA moving averages should crossover and align down
# This usually happens in 3-6 periods, a longer period indicates consolidation and a possibillity of continuation (upper) in this case
# Define the barNumber of the signal according to the logic presented above and and a period of maximum consolodation (barD <= 16)
# barD indicates the distance (in periods) from UpperBand crossover to fastA and fastA moving averages crossover and down alignment
DefineGlobalColor("Red1", CreateColor(255,26,140));
def dnSH = If low < UpperBand and close < UpperBand and high > UpperBand then BarNumber() else Double.NaN;
def dnSH1 = If low[1] < UpperBand[1] and close[1] < UpperBand[1] and high[1] > UpperBand[1] then BarNumber() -1 else Double.NaN;
def dnSH2 = If low[2] < UpperBand[2] and close[2] < UpperBand[2] and high[2] > UpperBand[2] then BarNumber() -2 else Double.NaN;
def dnMA = If sfastA < fastA and low < UpperBand and close < UpperBand and low > medA and close < close[1] then BarNumber() else Double.NaN;
#def dnMA = If sfastA < fastA and low < UpperBand and high < ((high[1]+open[1]+high[1])/3) and close < UpperBand and low > medA then BarNumber() else Double.NaN;
def sDN = If !isNan(dnMA) and !IsNaN(dnSH) then dnMA else Double.NaN;
def sDN1 = If !isNan(dnMA) and !IsNaN(dnSH1) then dnMA else Double.NaN;
def sDN2 = If !isNan(dnMA) and !IsNaN(dnSH2) then dnMA else Double.NaN;
plot vwUP = if!isNaN(sDN) and myRTH and abVol then high + (5*TickSize()) else na;
vwUP.SetPaintingStrategy(PaintingStrategy.Arrow_DOWN);
vwUP.SetDefaultColor(GlobalColor("VWAP1"));
vwUP.SetLineWeight(5);
plot vwUP1 = if!isNaN(sDN1) and myRTH and abVol then high + (5*TickSize()) else na;
vwUP1.SetPaintingStrategy(PaintingStrategy.Arrow_DOWN);
vwUP1.SetDefaultColor(GlobalColor("VWAP1"));
vwUP1.SetLineWeight(5);
plot vwUP2 = if!isNaN(sDN2) and myRTH and abVol then high + (5*TickSize()) else na;
vwUP2.SetPaintingStrategy(PaintingStrategy.Arrow_DOWN);
vwUP2.SetDefaultColor(GlobalColor("VWAP1"));
vwUP2.SetLineWeight(5);
#AddChartBubble(sDN, high + 0.1, "VS0", GlobalColor("Red1"), yes);
#AddChartBubble(sDN1, high + 0.1, "VS1", GlobalColor("Red1"), yes);
Attachments
Last edited: