99-day signal

By my estimation, the market is getting awfully close to 99 days without a new high.

Last high price:
S&P500: December 28
DJIA: Jan 4
NASDAQ: November 19

So, the S&P is about a week away, the DJIA is 2 weeks away, and the NASDAQ has passed the 99 day threshold.

Is that a correct reading of the tea leaves?

2 Likes

Last high price:
S&P500: December 28

not quite when counting intraday highs and market days

.SPX last 99 day High Pri on Jan-7

GD_

1 Like

By my estimation, the market is getting awfully close to 99 days without a new high..

Classic 99-Day DBE:
https://stockcharts.com/h-sc/ui?s=%24SPX&p=D&yr=1&am…

You can iterate the signal time length down to where it “signals” to see how many days it’s been. This link shows that if you’d chosen 58-Day DBE, it would have signaled today:
https://stockcharts.com/h-sc/ui?s=%24SPX&p=D&yr=1&am…

(And remember, it tracks market days, not calendar days.)

Tails

1 Like

This is a good illustration that basing any timing signal off a single day price and especially an intraday day price can trigger at dramatically different dates.

However, Robbie in post 278450 in reference to today’s intraday high:

This comes up every single time DBE fires, or doesn’t fire, and the answer is always the same: The version used by the Bear Catchers Combined (BCC) URL that lohill uses to post signals does not use intra-day highs–it uses closing prices only. . . As I’m sure people can guess, DBE was tested both using closing prices and intra-day high prices (from 1962, when they become available for ^GSPC), and closing prices worked a tiny bit better. Testing this again just now, I get SAWR(20, 0.95) = 8.20 for closing prices (with ^S5T as the investment) and SAWR(20, 0.95) = 8.09 using intra-day high prices.

RAMc

6 Likes

I’m showing 99 day closing high as 4791.19 on 27 Dec 2021.
That’s 64 days. Maybe closing in but I wouldn’t call it particularly close.

2 Likes

I’m showing 99 day closing high as 4791.19 on 27 Dec 2021.

It looks like it closed a little higher than that later on 29 Dec, and also on 3 Jan 2022 (at 4796.56)
https://stockcharts.com/h-sc/ui?s=%24SPX&p=D&yr=0&am…

Tails

2 Likes

I’m showing 99 day closing high as 4791.19 on 27 Dec 2021.

It looks like it closed a little higher than that later on 29 Dec, and also on 3 Jan 2022 (at 4796.56)
https://stockcharts.com/h-sc/ui?s=%24SPX&p=D&yr=0&am…

Tails

By cracky, you’re right. Missed it by “that much.” All the numbers in the column start running together. I sure there’s an instruction I can input into the spreadsheet that goes directly to the highest value in a column

This is a good illustration that basing any timing signal off a single day price and especially an intraday day price can trigger at dramatically different dates.

Calling those very small backtested differences “dramatically different” is a bit of a stretch don’t you think? The signal would not be very reliable if it mattered that much. Your correct of course that GTR1 uses different Prices than jim used in his original test.

On that note I was wrong about the IntraDay date 01/07/22 actually should be 01/04/22 and that was only 5 market days later than closing price of 12/28/22.

GD_

1 Like

I sure there’s an instruction I can input into the spreadsheet that goes directly to the highest value in a column

Yes. Several, depending on just what you want to do.

=max([range]) will give you the highest value.
Then something like =lookup(…) can show you the date corresponding to that value. I imagine that’s probably what you want.

Oops, no. I keep making that mistake. lookup requires the lookup range to be sorted. Obviously, that’s not the case here. You have to use =match() to find the row of the match, then =index() and/or =offset() to get the date.
Assuming col A has the dates and col B has the values.

1 Like

I sure there’s an instruction I can input into the spreadsheet that goes directly to the highest value in a column

You have to use =match() to find the row of the match, then =index() and/or =offset() to get the date.
Assuming col A has the dates and col B has the values.

If(Price=Max(99d_range),(Date)

Works for me.

GD_

1 Like

Thank you both. Here’s the one I found noodling around

=MAX(bxx:bxxx) “b” and "xx…"is the column & cell range containing daily S&P500 closing. The date of course is always right next to it.

It looks like it has been 60 days since the last new high.

FWIW, both of the two variants I track are currently on track to go bearish about May 27.
Barring a rally, of course.

The original thesis behind the model was that it was tracking the broad market’s mood,
so trying it on multiple indexes might be better to develop a single market-wide consensus signal
rather than trying to make a separate signal to trade each separate index.
i.e., I don’t personally have any reason to think it works on the Nasdaq alone.
Do that test before putting much weight on the time since the Nasdaq peak date in November.

Though peaks tend to coincide pretty often, so it probably works in backtest to some extent.
The signals are so rare (about one per year) that even the entire history of the Nasdaq isn’t really going to give great statistical support for tuning.

Jim

21 Likes

The “99-day” signal for the Nasdaq is maximized using parameters 107 and 134, i.e. a new 107d high in the last 134d. CAGR was 12.5% on the data I used.

I’ve placed Python code for this on Github:
https://github.com/jcmiii

John

5 Likes

The “99-day” signal for the Nasdaq is maximized using parameters 107 and 134, i.e. a new 107d high in the last 134d. CAGR was 12.5% on the data I used.

Though again, recall that this is very hard to tune well. Too few signals per year, too little Nasdaq history.
I imagine that if you do a height map of the performance of all the possible parameter pairs tested, it is very bumpy and you’ve in effect picked the top of one spike.

Perhaps it might be worthwhile to fit a low-order curve (sphere, say, or at most ellipsoid) through that height
field and take the high point, as a way to get the middle of the mound of toast.
(and, as a secondary suggestion, to consider a metric other than raw CAGR as the thing to optimize.
I like DDDD3 on the inflation-adjusted portfolio total return value calculated on rolling years.
This will tend to give a very good CAGR, but sometimes a less brittle result)

FWIW, the original 99 day figure was tuned back to the 1930s, and the lookback and timeout were pinned to the same value
to reduce the degrees of freedom even further, to try to get maximum robustness and minimal overtuning to a particular historical market peak.
The goal was maximum robustness–“probably pretty good in all market conditions”–not highest backtest return.
It has generally met its goal of identifying the bull market stretches.

Since my kick-off post, SPY has returned (non annualized) 265.2% in total during the bullish stretches and 6.9% in the bearish stretches.
(up to a little while ago–I haven’t updated all my figures lately)
Most of the returns were during the bits marked “safe to be in the market”.
As a long/cash portfolio strategy you’d have done worse than buy and hold, so in that sense it’s a failure as a market timing tool.
But at least the loss in CAGR was dwarfed by the reduction in portfolio “risk”.
I believe the pre-credit-crunch peak real total return portfolio value was exceeded 2009-12-22 instead of 2013-05-08 with buy and hold.

Jim

14 Likes

The title Dying Bullish Euphoria implies a gradual decline rather than an exact death date.
I just ran a few tests varying the lookback from 70 to 140 days over the 19251231 to present period.
From my limited 8 samples it shows an amazingly smooth mound of toast around 100 days. Being one of those older guys I like the SAWR as the parameter of choice for optimization which fortunately also coincides with the optimum CAGR.

                      70         80         90         99        110        120        130        140
          CAGR:      9.6       10.4       11.4       11.8       11.3       10.9       11.2       11.0
            TR:  705,718  1,356,663  3,345,837  4,436,268  3,015,240  2,087,112  2,815,967  2,202,124
        Log2TR:     12.8       13.7       15.0       15.4       14.9       14.3       14.8       14.4
SAWR(20; 0.95):      6.0        6.0        7.6        8.0        7.4        5.9        6.6        5.9
       GSD(20):     15.2       15.2       14.5       14.3       14.6       14.5       14.5       14.8
 DIGSD(20; 0%):     17.1       17.1       16.4       16.3       16.5       16.6       16.7       17.1
   LDD(20; 0%):      9.8        9.7        9.1        9.0        9.2        9.3        9.3        9.6
         LDDD3:     10.3        9.8        7.9        7.5        8.0        8.4        7.8        8.2
           MDD:    -55.0      -56.1      -43.4      -45.0      -52.1      -49.1      -50.6      -48.1
        UI(20):     15.5       15.0       10.2        9.6       11.6       11.5       10.7       11.9
    Sharpe(20):      0.5        0.5        0.6        0.7        0.6        0.6        0.6        0.6
      Beta(20):      0.6        0.6        0.5        0.5        0.5        0.5        0.5        0.5
        TI(20):     12.1       13.2       16.2       17.1       16.0       15.6       16.3       15.5
            AT:      1.1        0.9        0.8        0.8        0.7        0.7        0.6        0.5

RAMc

15 Likes

Those drawdowns are still very hard to swallow. Guessing these are from the 1929- area.

Those drawdowns are still very hard to swallow.

FWIW the DBE drawdowns are twice as high for smallcap(10yr) than LargeCap(10yr) indices.

Maybe that’s why the 3-way combinations like BCC works better(with MI) than a stand alone DBE timing signal for risk control.

GD_

1 Like

…if you do a height map of the performance of all the possible parameter pairs tested, it is very bumpy…

I actually did make a heat map in Excell for 75 <= M <= 200 and 75 <= N <= 300. I just added that to the github repository in case anyone wants to check it out (https://github.com/jcmiii). It’s actually not too spiky, but kind of mesa-like moving up the M axis around M=107, which is one of the optimal parameters. You could move over to say M=140, N=192 and be standing in the middle of the mesa surrounded by returns in the 11-12% range.

S&P has max CAGR with M=122, N=214. But if you require M=N, then indeed 99 is optimal.

Where I have found the “99-day” rule most useful lately is in conjunction with NHNL. If NHNL triggers within a few days of a new high the possibility of a significant drop is more likely. This dual signal triggered in the Covid drop and in our current drop. And, if there are no new highs lately (e.g. 99 days) then a NHNL trigger also becomes more meaninful.

John

4 Likes

johnIII:
The “99-day” signal for the Nasdaq is maximized using parameters 107 and 134, i.e. a new 107d high in the last 134d. CAGR was 12.5% on the data I used.

Below are GTR1 results for the rgearyiii/lohill version (no new 98d high in the last 99d) and the johnIII version (no new 107d high in the last 134d).

The first table is for the default 19251231 rgearyiii/lohill start date, and the second is for the 19500103 S&P 500 index start date.

All results are for the S&P 500 Index {!GSPC}. This may not be fair because johnIII’s post 282986 refers to the Nasdaq. His github data file is, however, clearly for the S&P 500 Index.

Anyway, the rgearyiii/lohill parameters are clearly superior for the S&P 500 Index.

Eric


Statistics are calculated from 19251231 to 20220401 over
daily closing portfolio values for a single trading cycle.

                 rgearyiii/
                 lohill      johniii
                 No New      No New
                 98d High    107d High
                 in Last     in Last
                 99 days     134 days

CAGR:            8.758137    7.516901
TR:              322219.8    106716.1
Log2TR:          11.65428    10.06091
SAWR(20; 0.95):  5.701741    3.889494
GSD(20):         14.38714    15.57587
DIGSD(20; 0%):   16.33856    17.75172
LDD(20; 0%):     9.414463    10.43575
LDDD3:           8.446873    10.34551
MDD:             -45.8895    -63.8789
UI(20):          11.32058    19.34567
Sharpe(20):      0.456418    0.353414
Beta(20):        0.512518    0.581334
TI(20):          11.77692    8.639092
AT:              0.581986    0.405312

Statistics are calculated from 19500103 to 20220401 over
daily closing portfolio values for a single trading cycle.

                 rgearyiii/
                 lohill      johniii
                 No New      No New
                 98d High    107d High
                 in Last     in Last
                 99 days     134 days

CAGR:            10.00194    9.355503
TR:              97076.08    63410.5
Log2TR:          9.924458    9.310851
SAWR(20; 0.95):  7.40186     5.797071
GSD(20):         12.80827    13.53472
DIGSD(20; 0%):   14.48591    15.23977
LDD(20; 0%):     8.119977    8.66655
LDDD3:           6.740932    7.967209
MDD:             -33.925     -33.925
UI(20):          6.380389    8.180449
Sharpe(20):      0.522979    0.45547
Beta(20):        0.646074    0.706217
TI(20):          9.684815    8.131117
AT:              0.512702    0.34642
4 Likes