# Breakaway Momentum (Breadth Thrust)
# defined: 10d sma advances > 1.97 x 10d sma declines.
# article: https://www.walterdeemer.com/bam.htm
#
# Desmond Reversals
# defined: 1 or more 90% downvolume day(s) [panic selling] followed by 90% upvolume day or 2 80+% upvolume days [panic buying]
# article: https://data.bloomberglp.com/assets/sites/2/2014/01/Desmond-report.pdf
#
# Whaley Thrusts
# defined:
# - breath thursts (ADT): 5day cumulative advance/total issues crossing above 75 [whaley1] or crossing below 25 [whaley2]
# - volume thrusts (UDT): 5day cumulative upvolume/total volume crossing above 77.8 [whaley3] or crossing below 16.4 [whaley4]
# - sprice thrusts (SPT): 5day cumulative SP500 price % change of +10.05% [whaley5] or -13.85% [whaley6]
# article: http://docs.mta.org/pdfs/dowaward-2010.pdf
#
# Zweig Thrust
# defined: 10d ema advances crosses above 4.0 and 6.1 within 10 trading days
# article: https://www.seeitmarket.com/did-zweig-breadth-thrust-indicator-flash-buy-signal-for-stock-market/
# sourcecode: @ClarenceCarr
#
declare upper;
input thrustType = {default "Breakaway", "Desmond", "Whaley|ADT", "Whaley|UDT", "Whaley|SPT", "Zweig"};
input exchange = {default NYSE, NASDAQ, SnP500, Nasdaq100, Russell2000, Dow30, AMEX};
input signalType = {"Off", default "Bubble", "VerticalLine"};
input signalLabel = {"Date", "Type", default "Type|Date"};
input showLabels = no;
input showClouds = yes;
input tradeDays = 60;
input showExtLine = yes;
def advanceI;
def declineI;
def advanceV;
def declineV;
switch (exchange) {
case NYSE:
advanceI = close("$ADVN");
declineI = close("$DECN");
advanceV = close("$UVOL");
declineV = close("$DVOL");
case NASDAQ:
advanceI = close("$ADVN/Q");
declineI = close("$DECN/Q");
advanceV = close("$UVOL/Q");
declineV = close("$DVOL/Q");
case SnP500:
advanceI = close("$ADVSP");
declineI = close("$DECLSP");
advanceV = close("$UVOLSP");
declineV = close("$DVOLSP");
case Nasdaq100:
advanceI = close("$ADVND");
declineI = close("$DECLND");
advanceV = close("$UVOLND");
declineV = close("$DVOLND");
case Russell2000:
advanceI = close("$ADVRL");
declineI = close("$DECLRL");
advanceV = close("$UVOLRL");
declineV = close("$DVOLRL");
case Dow30:
advanceI = close("$ADVI");
declineI = close("$DECLI");
advanceV = close("$UVOLI");
declineV = close("$DVOLI");
case AMEX:
advanceI = close("$ADVA");
declineI = close("$DECA");
advanceV = close("$UVOLUS");
declineV = close("$DVOLUS");
}
def aCount = if isnan(advanceI) then aCount[1] + 1 else 0;
def dCount = if isnan(declineI) then dCount[1] + 1 else 0;
def addI = if isnan(advanceI) then GetValue(advanceI, aCount) else advanceI;
def decI = if isnan(declineI) then GetValue(declineI, dCount) else declineI;
def totI = addI+decI;
def addIR = addI/totI;
def decIR = decI/totI;
def aVCount = if isnan(advanceV) then aVCount[1] + 1 else 0;
def dVCount = if isnan(declineV) then dVCount[1] + 1 else 0;
def addV = if isnan(advanceV) then GetValue(advanceV, aVCount) else advanceV;
def decV = if isnan(declineV) then GetValue(declineV, dVCount) else declineV;
def totV = addV + decV;
def addVR = addV/totV;
def decVR = decV/totV;
def SPChg = 100 * (close("SPX") / close("SPX")[1] - 1);
def advnDecl;
def mean;
def weak;
def thrust;
switch (thrustType){
case "Breakaway":
advnDecl = round(average(addIR,10) - 1.97*average(decIR,10),2);
mean = 0;
weak = Double.NaN;
thrust = Double.NaN;
case "Desmond":
advnDecl = if addVR > decVR then round(addVR*100,2) else round(-decVR*100,2);
mean = 0;
weak = -80;
thrust = 80;
case "Whaley|ADT":
advnDecl = round(sum(addI,5)/sum(totI,5),3)*100;
mean = 50;
weak = 25;
thrust = 75;
case "Whaley|UDT":
advnDecl = round(sum(addV,5)/sum(totV,5),3)*100;
mean = 50;
weak = 16.4;
thrust = 77.8;
case "Whaley|SPT":
advnDecl = round(sum(SPChg,5),2);
mean = 0;
weak = -13.85;
thrust = 10.05;
case "Zweig":
advnDecl = round(ExpAverage(addIR,10),3);
mean = 0.5;
weak = 0.4;
thrust = 0.61;
}
# -- plots
def ADExpAvg = if IsNaN(close) then double.nan else if IsNaN(advnDecl) then mean else advnDecl;
# -- signals
# breakaway signal
def breakaway = average(addIR,10) crosses above 1.97*average(decIR,10);
def breakaway2 = average(addIR,20) crosses above 1.72*average(decIR,20); # jan 2019 addendum
# desmond
def desmond1 = advnDecl[1]<=-90 and advnDecl>=90;
def desmond2 = advnDecl[2]<=-90 and advnDecl[1]>=80 and advnDecl>=80;
# whaley signal
def whaley1 = advnDecl crosses above thrust; #whaley1,3,&5
def whaley2 = advnDecl crosses below weak; #whaley2,4,&6
# zweig signal
def maxDays = 10;
def zCount = if advnDecl >= Weak then zCount[1] + 1 else 0;
def zweig = advnDecl crosses above Thrust and zCount <= maxDays;
def signal =
if thrustType == thrustType."breakaway" then (breakaway or breakaway2) else
if thrustType == thrustType."desmond" then (desmond1 or desmond2) else
if thrustType == thrustType."whaley|ADT" then (whaley1 or whaley2) else
if thrustType == thrustType."whaley|UDT" then (whaley1 or whaley2) else
if thrustType == thrustType."whaley|SPT" then (whaley1 or whaley2) else
if thrustType == thrustType."Zweig" then Zweig else
double.nan;
AddVerticalLine(signalType == signalType."VerticalLine" and signal,
(if signalLabel != signalLabel."Date" then
" " + thrustType + ", " else ", ")
+
(if GetMonth()==1 then " Jan " else
if GetMonth()==2 then " Feb " else
if GetMonth()==3 then " Mar " else
if GetMonth()==4 then " Apr " else
if GetMonth()==5 then " May " else
if GetMonth()==6 then " Jun " else
if GetMonth()==7 then " Jul " else
if GetMonth()==8 then " Aug " else
if GetMonth()==9 then " Sep " else
if GetMonth()==10 then " Oct " else
if GetMonth()==11 then " Nov " else
" Dec ")
+ getdayofmonth(getyyyymmdd()) + ", " + asprice(getyear())
+ (if thrustType == thrustType."Zweig" then " (" + zCount + " days)" else " ")
, globalcolor("signal"), 1);
Addchartbubble(signalType == signalType."Bubble" and signalLabel != signalLabel."Date" and signal, low, thrustType + (if breakaway2 then "2" else ""), globalcolor("signal"), 0);
Addchartbubble(signalType == signalType."Bubble" and signalLabel != signalLabel."Type" and signal, low,
(if GetMonth()==1 then "Jan " else
if GetMonth()==2 then "Feb " else
if GetMonth()==3 then "Mar " else
if GetMonth()==4 then "Apr " else
if GetMonth()==5 then "May " else
if GetMonth()==6 then "Jun " else
if GetMonth()==7 then "Jul " else
if GetMonth()==8 then "Aug " else
if GetMonth()==9 then "Sep " else
if GetMonth()==10 then "Oct " else
if GetMonth()==11 then "Nov " else
"Dec ")
+ getdayofmonth(getyyyymmdd()) + ", " + asprice(getyear())
, color.light_gray, 0);
# -- clouds
def cond1 = if isnan(close) then double.nan else if signal or signal[1] then double.positive_INFINITY else Double.NaN;
def cond2 = if !showClouds then double.nan else double.negative_infinity;
AddCloud(cond1, cond2, globalcolor("signal"));
# zweig signal window
def ccross = advnDecl crosses above weak;
def ccloud = Sum(ccross, maxdays);
def value3 = if ccloud then double.positive_INFINITY else Double.NaN;
#AddCloud(if thrustType != thrustType."Zweig" then double.nan else value3, value2, color.light_gray);
# -- trade window
# sourcecode: @Pipsinger, bacontrading.com
Rec SignalBar = if barnumber() == 1 then double.nan else CompoundValue(1,if Signal then 0 else SignalBar[1] + 1,0);
def cond3 = if SignalBar <= tradeDays then double.positive_INFINITY else double.nan;
AddCloud(cond3, cond2, color.light_gray);
# -- thrust candles
# sourcecode: https://funwiththinkscript.com/adding-space-between-candles/
def o = open;
def h = high;
def l = low;
def c = close;
# up candles
def UpO;
def UpH;
def UpL;
def UpC;
if o <= c and signal
then {
UpO = o;
UpH = h;
UpL = l;
UpC = c;
} else {
UpO = Double.NaN;
UpH = Double.NaN;
UpL = Double.NaN;
UpC = Double.NaN;
}
AddChart(high = UpH, low = UpL, open = UpC, close = UpO, type = ChartType.CANDLE, growcolor = globalcolor("signal"));
AddChart(high = UpH, low = UpL, open = UpO, close = UpC, type = ChartType.CANDLE, growcolor = globalcolor("candlebody"));
# down candles
def DnO;
def DnH;
def DnL;
def DnC;
if o > c and signal
then {
DnO = o;
DnH = h;
DnL = l;
DnC = c;
} else {
DnO = Double.NaN;
DnH = Double.NaN;
DnL = Double.NaN;
DnC = Double.NaN;
}
AddChart(high = DnH, low = DnL, open = DnO, close = DnC, type = ChartType.CANDLE, growcolor = globalcolor("signal"));
AddChart(high = DnH, low = DnL, open = DnC, close = DnO, type = ChartType.CANDLE, growcolor = globalcolor("candlebody"));
# -- colors
defineglobalcolor("average", CreateColor(8,65,93)); #darker blue
#defineglobalcolor("average", CreateColor(0,102,153)); #blue
defineglobalcolor("candlebody", createcolor(25,25,25));
defineglobalcolor("signal", color.dark_orange);
defineglobalcolor("extLine", color.light_gray);
# -- labels
AddLabel(showLabels, " " + thrustType + " ", globalcolor("average"));
AddLabel(showLabels, " " + (if thrustType == thrustType."whaley|SPT" then "SnP500" else exchange) + " ", globalcolor("average"));
# breakaway labels
def ADRI =
if addI == 0 then 0 else
if decI == 0 then 0 else
if addI > decI then round(addI/decI,1) else round(-decI/addI, 1);
def ADRV =
if addV == 0 then 0 else
if decV == 0 then 0 else
if addV > decV then round(addV/decV,1) else round(-decV/addV, 1);
AddLabel(showLabels and thrustType == thrustType."breakaway",
if ADRI == 0 then " Iss: TILT " else
" Iss: " + ADRI + ":1 ", if addIR > decIR then color.uptick else if addIR < decIR then color.downtick else color.gray);
AddLabel(showLabels and thrustType == thrustType."breakaway", " " + round(addIR,2)*100 + "% ", if addIR > decIR then color.uptick else color.gray);
AddLabel(showLabels and thrustType == thrustType."breakaway", " " + round(decIR,2)*100 + "% ", if addIR > decIR then color.gray else color.downtick);
# desmond labels
AddLabel(showLabels and thrustType == thrustType."desmond",
if ADRV == 0 then " Vol: TILT " else
" Vol: " + ADRV + ":1 ", if addVR > decVR then color.uptick else if addVR < decVR then color.downtick else color.gray);
AddLabel(showLabels and thrustType == thrustType."desmond", " " + round(addVR,2)*100 + "% ", if addVR > decVR then color.uptick else color.gray);
AddLabel(showLabels and thrustType == thrustType."desmond", " " + round(decVR,2)*100 + "% ", if addVR > decVR then color.gray else color.downtick);
# whaley labels
AddLabel(showLabels and thrustType == thrustType."whaley|ADT", " " + ADExpAvg + "% ", if signal then globalcolor("signal") else globalcolor("average"));
AddLabel(showLabels and thrustType == thrustType."whaley|UDT", " " + ADExpAvg + "% ", if signal then globalcolor("signal") else globalcolor("average"));
AddLabel(showLabels and thrustType == thrustType."whaley|SPT", " " + ADExpAvg + "% Chg ", if signal then globalcolor("signal") else globalcolor("average"));
# zweig labels
AddLabel(showLabels and thrustType == thrustType."Zweig", " " + ADExpAvg * 100 + "% stocks ", if signal then globalcolor("signal") else if adexpavg crosses above Weak then color.magenta else globalcolor("average"));
AddLabel(showLabels and thrustType == thrustType."Zweig" and zCount <= maxDays, " AD >= Weak: " + zcount + " days ", color.light_gray);
#AddLabel(showLabels and thrustType == thrustType."Zweig" and zCount <= maxDays, " Signal Window: " + (10-zCount) + (if (10-zCount)<=1 then " day left" else " days "), if (10-zCount)<=2 then color.downtick else color.light_gray);
AddLabel(showLabels and thrustType == thrustType."Zweig" and zweig, " Thrust ", globalcolor("signal"));
# signal label
AddLabel(signal, " Alert ", globalcolor("signal"));
# -- extLine
def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(close), 0, barNumber));
def colorAvg = if isnan(close) then colorAvg[1] else if signal then 1 else 0;
def extend = if barNumber == 1 then Double.NaN else if barNumber == barCount then close
else if barNumber == barCount then Double.NaN else extend[1];
plot extLine = extend;
extLine.SetStyle(Curve.SHORT_DASH);
extLine.AssignValueColor(if colorAvg == 1 then globalcolor("signal") else globalcolor("extLine"));
#extLine.HideBubble();
extLine.HideTitle();
extLine.SetHiding(!showExtLine);