Balsam Research
2 min read

Bad Breadth High

Event Studies

It was a pretty remarkable rally to new all time highs last week for both the S&P and the Nasdaq. As I was punching in data over the weekend from Barron’s Market Lab, I was surprised to see negative weekly breadth for both the NYSE and NASDAQ. New 52 week lows actually expanded on the NYSE versus the prior week, even though last week was also a weekly all-time closing high for the S&P. Since I have NYSE breadth data back to the 1940’s, I thought I’d check to see if we’ve ever had all-time highs on expanding new lows coupled with negative breadth.

Although the current market sometimes feels like it’s in uncharted terrority, this setup has been seen 48 times prior to last week. Average returns have been negative four weeks out and even underperformed substantially one year out.

Event study showing negative returns after all-time highs with bad breadth

However, these signals do tend to cluster, so it wouldn’t be surprising at all if the market shrugs it off and grinds higher. If we set a “blackout” period of 4 weeks to prevent repeat observations within that window, 40 prior observations are left out of the original 48. Average returns improve slightly over the next four weeks but are still down on average. Statistical signficance also disappears for all but the 52 week horizon which still substantially underperforms the benchmark.

Event study with 4-week blackout period showing similar negative results

Chart showing bad breadth high events on S&P since 1940s

Code
class BadBreadthHigh : Strategy
{
public static void Run()
{
AsciiBarServer ascii = new AsciiBarServer(@"c:\data\orchestrator", AsciiBarServer.DOHLCV);
var data = ascii.LoadSymbol("SPX Index").Compress(new WeeklyCompression() { IncludePartialPeriod = false, UseFixedDates = true });
var strat = new BadBreadthHigh();
strat.PrimarySeries = data;
strat.RunSimulation();
strat.EventStudyReport();
strat.Chart();
}
protected override void OnStrategyStart()
{
var ascii = new AsciiBarServer(@"c:\data\mktdata\", AsciiBarServer.DC);
var highs = ascii.LoadSymbol("highs").Close;
var lows = ascii.LoadSymbol("lows").Close;
var issues = ascii.LoadSymbol("issues").Close;
var adv = ascii.LoadSymbol("advances").Close;
var dec = ascii.LoadSymbol("declines").Close;
Col1 = Indicators.Highest(Close);
Col2 = lows / issues;
Col3 = (adv - dec) / issues;
Col4 = Cumulative(Col3);
Col4.Name = "NYSE AD Line";
Plot(Col2, 1, Color.Blue, "Column", paneSize: 25f);
Plot(Col4, 2, Color.Purple, paneSize: 25f);
}
protected override void OnBarClose()
{
if (Close.Last == Col1.Last && Col2.Last > Col2.Previous && Col3.Last < 0)
{
SnapEvent();
}
}
}