A Bottom Detector Backtest

This is a backtest of a bottom detector based on ideas others have posted here. NHNL is used to identify extremely bad days that might indicate a price bottom has been reached with better days ahead. There are different bottom detectors and different portfolio implementations. This is just one. The average gain was 4% over 2 months, but there are few signals (one every three years) and so the increase in CAGR was only about 1%. (An extra 1% over long periods can compound significantly.) The win rate was high (27 out of 33 signals had positive return), but jumping in when the market is fearful raises the possibility of a large loss (a 32% loss in 2008 was narrowly avoided). (I used Excel for calculations, and so don’t have all the fancy gtr1 risk metrics.)

A portfolio using the Bear Catcher [NHNLDiff] is all Cash when [NHNLDiff]=0. Adding a bottom detector moves the portfolio into the market for some of the time it otherwise would be in Cash. A bottom detector signal triggers a buy, which is held until [NHNLDiff]=1. Trading rules:

  1. The only investments are gSPY and Cash.
  2. 100% gSPY when NHNLDiff is 1.
  3. 100% Cash when NHNLDiff is 0, until the bottom detector signals.
  4. 100% gSPY after a bottom detector signal.
  5. Hold until NHNLDiff is 1.

This bottom detector signal looks for a bad day (NHNLny<-25) followed by a better day (NHNLny>=-25 and a price increase). Bottom detector signals when:

  1. Previous day [NHNLny] < -25.
  2. [NHNLny] >= -25.
    and 3. gSPY Price > previous day’s Price.
    [NHNLny] is 52 week NH minus NL of NYSE stocks (excluding ETFs and IPOs) percentage. http://gtr1.net/2013/?~NHNLny:h1::excd.a:et1:styp.a:et10!11!..

Since 1929, there were 47 bottom detector signals, with the most recent being Friday May 13th. Of these, 34 triggered buys (13 had an earlier bottom signal). (The earlier bottom signal always was at a higher price, and so waiting would have had higher returns.) Average gain following a bottom signal buy (until NHNLDiff=1) was 3.7% over 40 market days. This would have increased CAGR from 12.3% to 13.5%.

  Date    gSPY   [NHNLny]  [NHNLDiff]
20220512  9775     -29         0
20220513  10011     -7         0       bottom detector signal
20220516                               buy
    CAGR
  10.0%   gSPY
  12.3%   gSPY using NHNL timing
  13.5%   gSPY using NHNL timing and a bottom detector
  Date      gSPY   [NHNLDiff]  Action   Gain   bars
19291104    2.02       0         Buy
19300124    1.97       1        hold   -2.7%    56
19301113    1.52       0         Buy
19310126    1.52       1        hold    0.6%    49
19310605    1.26       0         Buy
19310625    1.41       1        hold   11.5%    14
19320603    0.47       0         Buy
19320725    0.54       1        hold   13.4%    35
19340731    0.94       0         Buy
19340814    0.99       1        hold    4.5%    10
19370929    1.66       0         Buy
19380111    1.47       1        hold   -11.5%   73
19380405    1.16       0         Buy
19380413    1.24       1        hold    6.4%     6
19400517    1.34       0         Buy
19400620    1.35       1        hold    0.5%    23
19411212    1.32       0         Buy
19420108    1.36       1        hold    2.7%    17
19461014    2.89       0         Buy
19461210    3.05       1        hold    5.7%    40
19470417    2.85       0         Buy
19470617    3.02       1        hold    5.8%    42
19490616    3.14       0         Buy
19490701    3.24       1        hold    3.1%    11
19530917    6.97       0         Buy
19531015    7.24       1        hold    3.9%    19
19571015   14.89       0         Buy
19571203   14.90       1        hold    0.0%    33
19620628   23.21       0         Buy
19620711   24.63       1        hold    6.1%     8
19660825   37.94       0         Buy
19661115   40.10       1        hold    5.7%    56
19690801   49.71       0         Buy
19691016   51.61       1        hold    3.8%    53
19700519   41.48       0         Buy
19700827   45.01       1        hold    8.5%    71
19730524   64.84       0         Buy
19730719   64.63       1        hold   -0.3%    38
19731129   60.03       0         Buy
19740118   59.09       1        hold   -1.6%    34
19740909   44.36       0         Buy
19750110   46.91       1        hold    5.8%    86
19800401   84.29       0         Buy
19800501   87.24       1        hold    3.5%    21
19871029  284.08       0         Buy
19880125  295.33       1        hold    4.0%    59
19900828  412.77       0         Buy
19910124  436.64       1        hold    5.8%   103
19981013  1577.92      0         Buy
19981102  1766.10      1        hold   11.9%    14
20021014  1411.54      0         Buy
20021101  1512.59      1        hold    7.2%    14
20080111  2594.03      0         Buy
20080813  2418.21      1        hold   -6.8%   148
20081125  1627.79      0         Buy
20090402  1605.70      1        hold   -1.4%    87
20110927  2365.20      0         Buy
20111024  2528.16      1        hold    6.9%    19
20150828  4349.89      0         Buy
20151009  4417.59      1        hold    1.6%    29
20160122  4206.92      0         Buy
20160303  4411.83      1        hold    4.9%    28
20181228  5828.72      0         Buy
20190109  6067.35      1        hold    4.1%     7
20200326  6330.96      0         Buy
20200417  6930.60      1        hold    9.5%    15
 
                                 avg    3.7%    40
                                 min    -11%     6
                                 max     13%   148

This system struggled in 2008, with a 7% loss between January and August, and an additional 1% loss between November and the following April. There was a bottom signal near the March 2009 market low, but this was ignored because the previous November bottom signal was still in effect.

A 32% loss was avoided only because NHNLDiff happened to go positive for a few days in August. Some sort of exit rule when the bottom signal is not working (prices are falling) might help, but is hard to justify because only 6 of the 33 signals had negative return (-3% in 1930, -11% in 1938, -0.3% in 1973, -2% in 1974, -7% in 2008, and -1% in 2009). I have not tested exit rules yet.

  Date    gSPY  [NHNLDiff]  Action  reason   Gain
20071018  2832      0        Sell   NHNL=0
20080111  2594      0         Buy   btm det  -8%
20080813  2418      1        hold   NHNL=1   -7%
 
20080819  2383      0        Sell   NHNL=0
20081125  1628      0         Buy   btm det  -32%
20090402  1606      1        hold   NHNL=1   -1%

https://gtr1.net/2013/?~gSPY_NHNL_20130929_rgearyiii:h1::pre…

Notes on tuning. The returns are significantly lower (but still positive) if the bottom detector doesn’t look for a price increase. The returns are slightly higher if buys are done the day of the bottom detector signal (for example on the recent Friday May 13th). Different limits were tested, with the range from -22 to -28 all with Total Return Multiplier about 3 (from 1929 to 2020).

[NHNLny]     Total Return
  limit   Multiplier
  -35        1.94
  -30        2.67
  -29        2.79
  -28        2.90
 **-27        3.24**
 **-26        3.20**
 **-25        3.22**
 **-24        3.09**
 **-23        3.10**
  -22        2.86
  -21        2.67
  -20        1.95
  -15        0.99
  -10        0.92
20 Likes

borisnand:
I used Excel for calculations, and so don’t have all the fancy gtr1 risk metrics.
I’ve been examining the impact of potential long-term and short-term bottom detectors on CAGR using GTR1 for a while. So I took borisnand’s NHNLny signal and used GTR1 to tweak its threshold to maximize CAGR for short-term bottoms (signal applicable over next 21 market days or ~1 month) and for long-term bottoms (signal applicable over next 252 market days or ~52 weeks). The results tabulated below are for rgearyiii back-extended S&P 500 index {!S5T}. All runs start on 19261231 and set friction to 0.15.

In the STBottom run buy or hold occurs when either BCC > 0 OR NHNLny has been less than -28 in the last 21 market days.
http://gtr1.net/2013/?~%5eS5T_STBottom:h1f0.15::BuyHold:gt0:…
In the LTBottom run buy or hold occurs when BCC > 0 OR NHNLny has been less than -56 in the last 252 market days.

Let me know if you see errors in my implementation.

Best regards, Eric

 Statistics are calculated from 19260104 to 20220513 over daily closing portfolio values for a single trading cycle.
Universe backtested: {!S5T}
Friction set to 0.15 for all runs
                 Buy&Hold    BCC         STBottom      LTBottom
                             BCC > 0     BCC > 0  OR   BCC > 0  OR
                                         NHNLny < -28  NHNLny < -28
                                         in last 21md  in last 252md
CAGR:            10.025924   11.885186    12.467578      12.201388
TR:              902913.69  4991417.00   8230498.50     6550753.50
Log2TR:          13.140532   15.607191    16.328711      15.999395
SAWR(20; 0.95):   4.703004    7.225222     7.561042       7.597620
GSD(20):         20.762150   16.718451    17.651146      17.412170
DIGSD(20; 0%):   23.172096   18.161697    19.298712      18.938961
LDD(20; 0%):     13.263360   10.093409    10.690786      10.513021
LDDD3:           13.446321    8.580975     8.852330       8.693167
MDD:            -84.596130  -45.960640   -55.974270     -48.336483
UI(20):          21.703167   12.695241    13.813523      11.810642
Sharpe(20):       0.428300    0.590655     0.602638       0.592370
Beta(20):         1.002458    0.713369    0.775024        0.757777
TI(20):           8.069638   12.901833    12.712817      12.645265
AT:               0.000000    0.892734    1.006920        0.830450
18 Likes

Under LTBottom, last column should read NHNLny < -56.

Thank you both for posting, very nice work!

Would it be possible to show also results starting sometime after the end of the Great Depression?
That singular event affects some statistics, certainly a statistic like MDD.

aussi:
Thanks for the post, but I am wondering about total market cap (NYSE, Nasdaq and OTC). Is there a way to sum marketcap?

GTR1 does not include OTC stocks, but one can easily add ARCA & Nasdaq securities. In fact, the NHNLDiff signal, which appears in both borisnand’s Excel and my GTR1 backtests is for Nasdaq securities, so we currently have a mixed bag. As a quick sensitivity, you can change from excd.a:et1 to excd.a:et1!2!3 in reference screen 1 in the link at the bottom thereby adding ARCA and Nasdaq to NYSE US ordinary shares and REITs for the NHNLny signal, the backtest results don’t change a lot. This is surprising to me because this change markedly increases the StockCount. This question deserves further thought and attention, but my list is loooong already.

I’m not sure what you mean by sum marketcap. Marketcap weighting would seem to defeat the purpose of NHNL signals as market breadth indicators.

tedthedog:
Would it be possible to show also results starting sometime after the end of the Great Depression? That singular event affects some statistics, certainly a statistic like MDD.

In any GTR1 backtest one can examine return results by calendar year or simply change the start date. I post some CAGR by calendar year results at the bottom. But your question prompted me to take another look at several things, so I’ll first ramble on a bit. Feel free to skip to item 6) and the tables if you find yourself nodding off.

  1. Aside from using the same NHNLny signal field my GTR1 URL does not match what borisnand backtested using Excel. (Sorry, I tried, but such a match is currently in my too hard pile.)

  2. borisnand’s observation regarding 40-day returns led me to discover that my GTR1 STBottom results improved slightly when buy or hold occurred for BCC > 0 OR NHNLny < -29 (vs -28) in the last 42 (vs 21) market days (~2 months versus ~1 month).

  3. I changed the bear catchers combined (BCC) screen to the rgearyiii/lohill version. (I’d inadvertently used a modified version in post 283339.)

  4. One should expect the GTR1 NHNLny signal to correlate but not necessarily coincide with platykurtic’s WSJ NHNLny signal for several reasons:
    a) WSJ, BarCharts and StockCharts count new 52-week intraday highs and lows (and counts from those 3 data sources consistently disagree).
    b) In GTR1 both the NHNLDiff and the NHNLny signals in GTR1 are based on new 251-market-day closing highs & lows. (One can use intraday highs & lows in GTR1, but rgearyiii found closing highs & lows worked better for NHNLDiff and I suspect they would for NHNLny or variations thereof.)
    c) 52 weeks seldom corresponds to 251 market.
    d) The NHNLDiff and NHNLny signals generated in GTR1 are for universes restricted to US headquartered ordinary shares and REITs (styp.a = 10!11!18!48).

  5. A virtually endless number of alternative bottom indicators & potential combinations thereof could be investigated. (I’ve got a list somewhere. If I find it, I’ll add TicTok.) But, the mungofitch bottom detectors seem perform well in the real world and, as I understand them, rely primarily on NHNL indicators. So I believe borisnand is on a reasonable path. Certainly platykurtic’s simple bottom detectors have been nice to have. They’ve prompted some timely discussions.

  6. As indicated by the annual CAGR results tabulated below, the current GTR1 NHNLny STBottom signal significantly underperformed B&H in calendar years 1938, 1939, and 1948. I belive borisnand’s results for those years would be better. His reported overall CAGR of 13.5 is better. Anyway my hope is that GTR1 bottom detectors will continue to evolve and improve.

Best regards, Eric


Statistics are calculated from 19260104 to 20220516 over
daily closing portfolio values for a single trading cycle.
Friction: 0.15
                      (a)          (b)
                    {!S5T}       {!S5T}
                             BCC > 0 or
                             NHNLny<-29
                      B&H   in last 42d
           
CAGR:                10.03        12.61  
TR:              993,741.6  9,340,010.0  
Log2TR:              13.28        16.51  
SAWR(20; 0.95):       4.76         7.85  
GSD(20):             20.70        18.11  
DIGSD(20; 0%):       23.10        19.53  
LDD(20; 0%):         13.22        10.81  
LDDD3:               13.39         8.60  
MDD:                -84.60       -47.34  
UI(20):              21.44        12.37  
Sharpe(20):           0.43         0.59  
Beta(20):             1.00         0.82  
TI(20):               8.06        12.31  
AT:                   0.00         0.88  

Total Return for Year Ending
                      (a)          (b)      (b)-(a)
       19261231      10.54        10.54
       19271230      35.49        35.49
       19281231      39.23        39.23
       19291231      -8.54        -8.54
       19301231     -26.07        -6.46      19.61
       19311231     -45.45         2.77      48.22
       19321230      -8.80        31.64      40.44
       19331229      50.51        50.51
       19341231      -1.00        -1.47      -0.47
       19351231      45.06        45.06
       19361231      33.09        33.09
       19371231     -35.95       -23.76      12.18
       19381230      28.56        12.95     -15.61
       19391229      -0.85       -18.85     -18.00
       19401231      -9.67         0.88      10.54
       19411231     -11.51       -13.59      -2.08
       19421231      20.86        21.38       0.52
       19431231      26.81        26.81
       19441229      21.23        21.23
       19451231      36.77        36.77
       19461231      -9.24        -9.60      -0.36
       19471231       4.81        -2.01      -6.82
       19481231       5.22        -4.26      -9.47
       19491230      18.29        21.42       3.13
       19501229      32.75        32.75
       19511231      23.37        23.37
       19521231      18.98        18.98
       19531231      -1.73        -1.58       0.15
       19541231      52.69        52.69
       19551230      31.02        31.02
       19561231       6.30         6.30
       19571231     -10.62       -12.79      -2.17
       19581231      43.75        40.19      -3.56
       19591231      12.37        12.37
       19601230       0.86         0.86
       19611229      27.32        27.32
       19621231      -8.61         4.34      12.95
       19631231      22.59        22.59
       19641231      16.68        16.68
       19651231      12.41        12.41
       19661230     -10.10        -7.93       2.17
       19671229      23.56        19.89      -3.68
       19681231      10.92         3.64      -7.28
       19691231      -8.34         0.77       9.11
       19701231       4.12         9.86       5.74
       19711231      14.50         9.10      -5.40
       19721229      19.15        19.15
       19731231     -14.79       -15.52      -0.73
       19741231     -26.54        12.45      38.99
       19751231      37.01        30.14      -6.87
       19761231      23.97        23.97
       19771230      -7.42        -7.42
       19781229       6.35         6.35
       19791231      18.60        18.60
       19801231      32.58        32.58
       19811231      -4.72         1.30       6.01
       19821231      21.95        29.99       8.04
       19831230      22.36        22.36
       19841231       6.33         5.80      -0.53
       19851231      31.99        31.99       0.00
       19861231      18.26        18.26       0.00
       19871231       5.06         5.06       0.00
       19881230      17.09        18.21       1.12
       19891229      31.38        31.38
       19901231      -3.26        -4.14      -0.89
       19911231      30.56        30.38      -0.18
       19921231       7.74         7.74
       19931231      10.00        10.00
       19941230       1.20        -1.77      -2.97
       19951229      37.58        37.58
       19961231      23.03        23.03
       19971231      33.50        33.50
       19981231      29.16        29.16
       19991231      20.82        20.82
       20001229      -9.39        -9.39
       20011231     -11.61        -4.11       7.49
       20021231     -21.99        -7.91      14.08
       20031231      28.74        23.80      -4.94
       20041231      10.88        10.88
       20051230       5.00         5.00
       20061229      15.78        15.78
       20071231       5.64         5.64
       20081231     -36.64       -17.04      19.60
       20091231      26.18        50.34      24.16
       20101231      14.99        14.99
       20111230       1.74        -0.25      -1.99
       20121231      16.20        16.20
       20131231      32.38        32.38
       20141231      13.67        13.67
       20151231       1.31         0.26      -1.05
       20161230      11.85        14.83       2.98
       20171229      22.04        22.04
       20181231      -4.33        -4.33
       20191231      31.33        31.33
       20201231      18.89        18.89
       20211231      28.34        28.34
       20220516     -15.40       -15.40

(a)
http://gtr1.net/2013/?!!QlpoMTFBWSZTWXQEkF0AA9bfgBAAIgd!2F8D…

11 Likes

I made a gtr1 version with results very close to the OP. There were 33 signals in 96 years, with the bottom detector adding 1.4% to CAGR. The win rate was high (26 of 32 signals had positive return).

Gains are from the bottom signal date to when NHNL turns Bullish, and so vary in length. (Doing the math this way separates out the bottom detector gains from the NHNL gains.)
Average gain was 5% in 41 market days.
Highest gain was 20% in 36 market days following 19320602.
Lowest gain was -11% in 74 days following 19370928.
Longest gain was -8% in 149 days following 20080110.
Shortest gain was 9% in 7 days following 19380404.

This bottom detector has 3 conditions (for example, with a Wednesday bottom):

  1. Two days previous [NHNLny] < -27. (e.g. Monday)
  2. One day previous [NHNLny] >= -27. (e.g. Tuesday)
    and 3. gSPY Price > previous day’s Price. (e.g. Wednesday higher than Tuesday)

{S5T_NHNL_Pop} is https://gtr1.net/2013/?!!QlpoMTFBWSZTWZFZGXEABMRfgFAAIgd!2F8…
https://gtr1.net/2013/?~S5T_NHNL:h1::BCC:et2!3!6!7:BCC:impor…
https://gtr1.net/2013/?~S5T:h1::trp%281,1%29ne-999%7bU:%7b!S…
https://gtr1.net/2013/?~S5T_BCC0:h1::BCC:gt0:BCC:imports%280…

minus_S5T  Screen        CAGR  SAWR  GSD  LDDD3  MDD  UI  Sharpe    From       To     yrs
   3.7     S5T_NHNL_Pop  13.7  8.6   15    6.2   -46  8    0.72   19260105  20220516  96
   2.2     S5T_NHNL      12.3  8.1   14    6.4   -46  7    0.70   19260105  20220516  96
   0.0     S5T           10.0  4.8   21   13.4   -85  21   0.43   19260105  20220516  96
   2.1     S5T_BCC0      12.2  7.6   17    8.3   -44  12   0.61   19260105  20220516  96
 
   2.3     S5T_NHNL_Pop  13.7  8.9   12    4.8   -28  4    0.83   19491230  20220516  72
   0.9     S5T_NHNL      12.3  7.8   11    5.0   -22  5    0.79   19491230  20220516  72
   0.0     S5T           11.4  6.8   16    9.7   -55  11   0.53   19491230  20220516  72
   1.4     S5T_BCC0      12.8  8.6   14    6.5   -34  7    0.69   19491230  20220516  72
 
   1.4     S5T_NHNL_Pop  13.3  8.0   12    5.1   -28  5    0.84   19820517  20220516  40
  -0.1     S5T_NHNL      11.9  7.2   11    5.2   -22  5    0.81   19820517  20220516  40
   0.0     S5T           12.0  5.7   18   10.2   -55  13   0.57   19820517  20220516  40
   1.2     S5T_BCC0      13.2  8.0   15    6.8   -34  8    0.72   19820517  20220516  40
 
   2.2     S5T_NHNL_Pop  11.1  8.6   12    5.2   -28  5    0.86   20020516  20220516  20
   0.5     S5T_NHNL      9.4   8.1   10    5.1   -17  5    0.87   20020516  20220516  20
   0.0     S5T           8.9   6.2   18   11.8   -55  13   0.53   20020516  20220516  20
   2.3     S5T_BCC0      11.2  8.9   14    6.4   -34  5    0.79   20020516  20220516  20

gtr1 details:

  1. Import some fields:
    [NHNLny2]: [NHNLny] lag_days=2
    [NHNLny1]: [NHNLny] lag_days=1
    [sptrp01]: [Total Return % over 1 days; lag=0 days] of ^GSPC

  2. Combine the 3 bottom detector criteria into one number:
    Create [BtmSG2]: [[NHNLny2] < -27 ? 1 : 0]
    Create [UpSG1]: [[NHNLny1] >= -27 ? 1 : 0]
    Create [PricePop]: [[sptrp01] > 0 ? 1 : 0]
    Create [BtmDet]: [[[PricePop] + [UpSG1] + [BtmSG2]] == 3 ? 8 : 0]
    [BtmDet] is 8 on the day of the bottom, and 0 on all other days.

  3. Convert the bottom indicator into a signal using NHNL to limit the lookback:
    Create [NHNLDet]: [[BCC] == 2,3,6,7 ? 1 : 0]
    Create [BtmSignal]: [[Last Value (at step-1) of [[NHNLDet] + [BtmDet]] Not Equal To 0 within 10000 mkt days; lag=0 days] == 8 ? 1 : 0]

See post 261047 for a discussion of sglvne (signal last value not equal to). Example:

  Date    NHNLDet  BtmDet  sum  sglvne0  BtmSignal        note
20200224     1       0      1      1         0            Bull
20200324     0       0      0      1         0            Bear
20200325     0       8      8      8         1            Bottom
20200326     0       0      0      8         1      days after bottom
20200420     1       0      1      1         0            Bull
  1. Buy if NHNL is Bullish OR there was a Bottom Signal. Sell if NHNL is Bearish.
    Create [BuySignal]: [[NHNLDet] + [BtmSignal]]
    Create [BuySell]: [[BuySignal] > 0 ? 1 : [[BCC] == 0,1,4,5 ? -1 : 0]]
    Create [Cash]: [[Last Value (at step-1) of [BuySell] Not Equal To 0 within 10000 mkt days; lag=0 days] == -1 ? 1 : 0]

Example:

  Date    NHNLDet  BtmDet  sum  sglvne0  BtmSignal        note         BuySignal  BuySell  Cash
20200224     1       0      1      1         0            Bull             1         1       0
20200324     0       0      0      1         0            Bear             0        -1       1
20200325     0       8      8      8         1            Bottom           1         1       0
20200326     0       0      0      8         1      days after bottom      1         1       0
20200420     1       0      1      1         0            Bull             1         1       0
15 Likes