Balsam Research
2 min read

Stability Breeds Instability

Event Studies

The past five month rally in the S&P has been remarkable not just for the magnitude but also for its persistence. Prior to today, we experienced 110 consecutive trading days with less than a 2% close-to-close drawdown in the cash S&P. This is fairly extraordinary, having occurred only six times prior since 1928. Today that streak was broken with a -1.23% selloff for a whopping -2.04% drawdown off the closing high.

So what happens when a streak is broken? Typically there is modest follow through to the downside over the next several days.

Event study showing modest downside follow-through after stability streak breaks

But sometimes that streak can end in a dramatic fashion. In 2018 a 124 day streak culminated in Volmageddon the following day when the VIX exploded and several inverse VIX exchange traded products in turn imploded. This was a classic example of Hyman Minsky’s maxim that stability breeds instability.

If we look at all rolling 110 day periods in the S&P since 1928 a -2% drawdown is the 99th percentile. The median drawdown is -8.11% and the average is -10.71%. Market commentators often talk about a “healthy correction”. For people who have been lulled into complacency from this long uptrend, it will feel anything but healthy if we revert to the norm. Today’s afternoon sell-off is a good reminder that it would be wise to recalibrate expectations for what is “normal” when it comes to S&P corrections.

Distribution of 110-day rolling S&P drawdowns showing 2% is 99th percentile

Code
class RollingDrawdown : Strategy
{
public static void Run()
{
AsciiBarServer server = new AsciiBarServer(@"c:\data\orchestrator", AsciiBarServer.DOHLC);
var data = server.LoadSymbol("SPX Index");
var strat = new RollingDrawdown();
strat.PrimarySeries = data;
strat.RunSimulation();
strat.EventStudyReport();
strat.Chart();
}
protected override void OnStrategyStart()
{
base.OnStrategyStart();
int lookback = 110;
Col1 = new TimeSeries(Dates);
Col1.Name = "Rolling max drawdown";
Col1.MaxBarsBack = lookback - 1;
for (int x = lookback - 1; x < PrimarySeries.Count; x++)
{
var sub = PrimarySeries.Subset(PrimarySeries.Dates[x - lookback + 1], PrimarySeries.Dates[x]);
var dd = DrawdownCollection.Calculate(sub.Close);
Col1[x] = dd.MaxPercent.Percent;
}
Plot(Col1, 1, Color.Blue, "Column");
}
private bool _flag;
protected override void OnBarClose()
{
base.OnBarClose();
if (CrossAbove(Col1, -0.02).Last)
{
//rolling drawdown now > -2% (i.e. extremely low)
_flag = true;
}
if (_flag && CrossBelow(Col1, -0.02).Last)
{
//now drawdown back below -2%
SnapEvent();
_flag = false;
}
}
}