Skip to content

Field note No. 03 · Intermediate

Indicators, and the 200-day moving average

What technical indicators measure, how to test one honestly, and a century of daily data on the most famous of them.

Revised September 202615 min read11 references

Educational material only. Not investment advice.

Contents
  1. 01Indicators and rules
  2. 02The main families
  3. 03How to evaluate an indicator
  4. 04The 200-day rule on a century of data
  5. 05Where the result comes from
  6. 06Lookback, execution and costs
  7. 07What the literature says
  8. 08Implications
  9. —References

Abstract

Defines the main indicator families (trend, momentum, volatility, mean reversion, breadth) and six checks for testing any of them, then analyses the rule 'hold the US market above its 200-day moving average, otherwise T-bills' on daily data from 1927 to 2026: returns, drawdowns, time invested, switches, whipsaw, results by decade and in the deepest drawdowns, sensitivity to the lookback, to one day of execution delay and to costs, with the code that produced every number.

Key takeaways

  • An indicator is a function of past prices; the rule, the execution lag and the costs decide whether it is worth anything.
  • On US data from 1927 to 2026, the 200-day rule raised the Sharpe ratio and limited the deepest drawdowns to between a quarter and three-fifths of the market's, at the price of frequent whipsaw.
  • The return advantage belongs to the years before 1990; since then the rule has returned less than the market, while keeping its risk advantage.
  • Every lookback from 50 to 300 days behaves similarly on Sharpe ratio; 200 is not special.
  • One day of execution delay and 10 bp a switch erase the return advantage; the Sharpe and drawdown advantages survive.

Before you start

  • Field note 01 on anomalies and multiple testing
  • Daily returns, compounding and drawdowns
  • Reading Python with pandas

A technical indicator turns a price history into a number, and a rule turns the number into a position. The idea is old, the vocabulary is large and the evidence is mixed. This note defines the main families precisely, sets out how to test one without fooling yourself, and then takes the most widely quoted of them, the 200-day moving average of the US stock market, through a full, reproducible analysis on 99 years of daily data.

Indicators and rules

Write Pt for the closing price (or total-return index) on day t. An indicator is a function It = f(Pt, Pt−1, …) of prices up to and including the close of t. A rule maps the indicator to an exposure wt+1 held over the next day. Everything that goes wrong in practice happens in the space between those two sentences: which close the indicator uses, when the order can execute, and what the trade costs. Figure 1 shows the chain; the notation is the one used throughout the series.

Figure 1From price to profit and loss
Signal chain: prices, indicator, rule, target exposure, order, fill, position, P and LDecided at the close of day tRealised over day t + 1PricesP₀ … PₜIndicator Iₜe.g. Pₜ / SMA₂₀₀Rulewₜ₊₁ = 1 if Iₜ > 1OrderΔw, at the closeFillprice, cost, delayP&Lwₜ₊₁ · rₜ₊₁ − cost
The indicator and the rule use data up to the close of day t. The order executes at that close at the earliest; the position then earns day t + 1's return. Using day t's close to earn day t's return is look-ahead.

The main families

Most indicators in use belong to five families. Each has a standard definition; the differences between implementations (a simple or exponential average, a close or a typical price, the smoothing of Wilder’s averages) matter less than the lookback and the execution around it.

FamilyCanonical indicatorDefinitionTypical use
TrendSimple / exponential moving averageSMAₙ = mean of the last n closes; EMA with α = 2/(n+1)Price above average: hold; crossovers of a fast and a slow average
MomentumRate of change (ROC)Pₜ / Pₜ₋ₙ − 1Sign of the past year's return (time-series momentum)
VolatilityAverage true range (ATR); realised volatilityWilder's average of max(high − low, |high − prev close|, |low − prev close|); stdev of returnsPosition sizing and stops rather than direction
Mean reversionRelative strength index (RSI)100 − 100 / (1 + avg gain / avg loss), Wilder smoothingFade short-term extremes (below 30, above 70)
BreadthShare of constituents above their own 200-day average; advance–decline lineCounts across the index's membersConfirms or contradicts the index's own trend

The ATR and RSI are due to Wilder (1978); breadth needs constituent-level data, which is why it is described here but not computed.

The trend and momentum families are two views of the same thing: a price above its n-day average has, roughly, risen over the last n days. Time-series momentum, which Field note 01 (Market anomalies) reviews, is the academic name for the second view.1 Volatility indicators are the input to Field note 02 (Volatility targeting). Wilder introduced the RSI and the ATR,2 and the RSI’s mean-reversion logic is the short-term reversal of Field note 01 (Market anomalies) in another form. Figure 2 draws four of the families on the same days.

Figure 2Four indicator families on the same episodes
Episode
Trend: index with its 200-day SMA and 50-day EMA (log scale)Momentum: 252-day rate of changeMean reversion: 14-day RSI (30 / 70 bands)Volatility: 21-day realised, annualised1.5k2k2.5k0%20%40%60%80%-50%0%50%30702007-072008-012008-072009-012009-072010-01
US market total-return index200-day SMA50-day EMABelow the 200-day SMA
US market total-return index (Kenneth R. French Data Library). Indicators are computed on the full history and then cut to the episode, so every value uses only data up to its own date. Shaded: the index below its 200-day average.
site_research/fieldnotes/indicators.py
def sma(price: pd.Series, n: int) -> pd.Series:
    """Simple moving average of the last n closes."""
    return price.rolling(n, min_periods=n).mean()


def ema(price: pd.Series, n: int) -> pd.Series:
    """Exponential moving average with span n (alpha = 2 / (n + 1))."""
    return price.ewm(span=n, adjust=False, min_periods=n).mean()


def roc(price: pd.Series, n: int) -> pd.Series:
    """Rate of change over n periods (time-series momentum)."""
    return price / price.shift(n) - 1.0


def rsi(price: pd.Series, n: int = 14) -> pd.Series:
    """Wilder's relative strength index: 100 - 100 / (1 + avg gain / avg loss)."""
    d = price.diff()
    gain = d.clip(lower=0.0).ewm(alpha=1.0 / n, adjust=False, min_periods=n).mean()
    loss = (-d.clip(upper=0.0)).ewm(alpha=1.0 / n, adjust=False, min_periods=n).mean()
    return 100.0 - 100.0 / (1.0 + gain / loss)


def realised_vol(ret: pd.Series, n: int = 21, periods: int = 252) -> pd.Series:
    """Annualised standard deviation of the last n returns."""
    return ret.rolling(n, min_periods=n).std(ddof=1) * np.sqrt(periods)
Each function returns a series aligned to the prices; the value at t uses prices up to and including t.

How to evaluate an indicator

Indicators are easy to compute and easy to overrate. Six checks separate a result from an artefact; the analysis that follows applies each of them.

  1. Look-ahead. A signal computed from the close of day t cannot earn day t’s return. The error is common because in a vectorised backtest it is one missing shift, and it is flattering: on the rule below it adds 8.7% a year.
  2. Execution lag. Even correctly lagged, a rule that trades “at the close” assumes the signal is known in time to send a market-on-close order. Test one day later as well; the difference measures how much the result depends on precise timing.
  3. Costs. Charge every switch. A rule that trades a few times a year looks cheap until the switches cluster in volatile, wide-spread markets.
  4. Whipsaw. Count round trips that reverse within weeks, and measure what they cost. They are the price of a trend rule, and they are paid in exactly the range-bound markets where the rule adds nothing.
  5. Regime dependence. Report results by decade and by episode, not only in aggregate. A century-long average can be one decade’s result in disguise.
  6. Multiple testing. The 200-day lookback is famous because it has been examined for decades, which is itself a form of selection. Show the whole neighbourhood of lookbacks, and read Field note 01 (Market anomalies) on deflating the best of many trials.

The 200-day rule on a century of data

The rule is the simplest trend rule there is: at each close, hold the US stock market if its total-return index is above its 200-day simple moving average, otherwise hold one-month Treasury bills; trade at that close. The data are the daily CRSP value-weighted US market total return and the one-month T-bill return from the Kenneth R. French Data Library,3 1927-05-05 to 2026-08-31 after a year of warm-up. That is the broad US market rather than the S&P 500 or the SPY exchange-traded fund, which only exists since 1993: a long daily S&P 500 history is not freely licensed. As a check, the 200-day regime computed on the S&P 500 price index (FRED, 2017-07-12 to 2026-08-31) agreed with the regime on the CRSP series on 98.5% of 2,297 days.

Annual return
11.5%
buy and hold 10.2%
Sharpe ratio
0.73
buy and hold 0.46
Worst drawdown
-34%
buy and hold -84%
Time invested
72%
5.7 switches a year
wt+1 = 1 if Pt > SMA200(P)t, else 0;    rt+1rule = wt+1 rt+1 + (1 − wt+1) rt+1bill − c |Δwt+1|
the rule, decided at the close of day t, held over day t + 1
Figure 3The 200-day rule, a century of daily data
Execution
Cost per switch
Hysteresis band
Window

The 200-day rule compounded at 11.5% a year against 10.2% for buy and hold, with a worst drawdown of -33.6% against -84.1%, invested 72% of the time and switching 5.7 times a year.

Growth of 1 (log scale); shaded while the rule holds T-bills1101001k10kDrawdown from the running peak-80%-60%-40%-20%0%1930194019501960197019801990200020102020
Buy and hold (the market index)Its 200-day moving average200-day moving-average ruleRule in T-bills
1927-05-05 to 2026-08-31Buy and hold200-day rule
Annual return10.2%11.5%
Annual volatility17.5%11.5%
Sharpe ratio (excess of T-bills)0.460.73
Worst drawdown-84.1%-33.6%
Worst day-17.4%-9.2%
Time in the market100%72%
Switches a year0.05.7

US market total return (CRSP value-weighted, via the Kenneth R. French Data Library); the rule holds one-month T-bills when out. The moving average is computed on the total-return index. Cost is charged per unit of exposure switched.

US market total return and one-month T-bills, Kenneth R. French Data Library, 1927-05-05 to 2026-08-31. Top: growth of one unit, with the market’s own moving average and the periods the rule spent in bills. Bottom: drawdowns. The lookback, execution, cost, band and window are live; the default reproduces the numbers above.

The headline is real but needs reading carefully. The rule earned a higher return than the market with two-thirds of its volatility, so its Sharpe ratio was materially higher (0.73 against 0.46), and its worst drawdown was -34% against -84%. It achieved that by being out of the market 28% of the time and switching 5.7 times a year. Two cautions apply before any of these numbers is quoted. The return advantage comes from the years before 1990 (next section); and the 200-day drawdown is the best, not the typical, result among the lookbacks tested (Figure 4). The case trading at the close that produced the signal is also the optimistic one: the next-close row below is the conservative reading.

site_research/examples/sma200.py
import sys
from pathlib import Path

import pandas as pd

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from fieldnotes import backtest, data, indicators  # noqa: E402

d = data.market_daily()                          # daily total return, T-bill return
price = (1 + d["mkt"]).cumprod()                 # total-return index
signal = indicators.sma_regime(price, 200)       # 1 above the 200-day average, else 0

rule = backtest.run(d["mkt"], signal, d["rf"], lag=1)                       # trade at the signal's close
hold = backtest.run(d["mkt"], pd.Series(1.0, index=d.index), d["rf"])

start = d.index[252]                             # one year of warm-up for every lookback
for name, res in (("buy and hold", hold), ("200-day rule", rule)):
    r = res[res.index >= start]
    print(name, {k: round(float(v), 4) for k, v in
                 backtest.stats(r["ret"], d["rf"][r.index], weight=r["weight"]).items()})
The complete computation of the headline row, using the functions listed in this note and in Field note 02. It prints the table's first two columns.
site_research/fieldnotes/indicators.py
def sma_regime(price: pd.Series, n: int = 200, band: float = 0.0) -> pd.Series:
    """1 when the close is above its n-day SMA, else 0, decided at each close.

    band > 0 adds hysteresis: switch IN only above sma * (1 + band) and OUT only below
    sma * (1 - band); in between, keep yesterday's state. band = 0 is the plain rule.
    """
    m = sma(price, n)
    up, down = price > m * (1 + band), price < m * (1 - band)
    state = pd.Series(np.nan, index=price.index)
    state[up] = 1.0
    state[down] = 0.0
    state[m.isna()] = 0.0
    return state.ffill().fillna(0.0)

Where the result comes from

By period

PeriodMarket, annual returnRule, annual returnMarket, SharpeRule, SharpeMarket, worst drawdownRule, worst drawdown
1927 to 19527.1%11.8%0.390.80-84%-34%
1953 to 198911.5%13.7%0.510.90-48%-16%
1990 to 202611.0%9.2%0.520.58-55%-29%

Each period compounded from one on its first day.

The century-long return advantage belongs to the years before 1990, and mostly to the first quarter-century: from 1927 to 1952 the rule compounded at 11.8% against 7.1%. From 1953 to 1989 it was ahead by 2.2 percentage points, and since 1990 it has returned less than the market (9.2% against 11.0%). What held in every period is the risk profile: a higher Sharpe ratio and a much smaller worst drawdown.

By decade

DecadeMarket, annual returnRule, annual returnMarket, worst drawdownRule, worst drawdownRule, switches
1927-2914.9%23.9%-44%-17%5
1930-39-0.4%8.4%-80%-34%67
1940-499.1%10.1%-31%-15%58
1950-5918.2%16.7%-21%-12%58
1960-698.3%10.3%-28%-9%45
1970-796.1%10.7%-48%-16%63
1980-8916.8%18.8%-33%-15%34
1990-9917.9%15.8%-22%-14%42
2000-09-0.4%2.4%-55%-29%96
2010-1913.6%8.0%-20%-22%58
2020-2615.5%12.2%-34%-19%36

Each decade compounded from one on its first day; the first and last are partial.

The rule beat the market in the decades of long bear markets, the 1930s, the 1970s and the 2000s, and lagged it in strong, steady ones: the 1950s, the 1990s, so far the 2020s and, most of all, the 2010s, when it returned 8.0% a year against 13.6%. Its drawdowns were smaller in almost every decade. Anyone who adopted the rule in 2010 on the strength of the previous eighty years would have spent ten years underperforming and been right to ask whether it had stopped working.

In the deepest drawdowns

Market peakTroughRecoveredMarketRule, worst in the same span
1929-09-031932-07-081945-02-06-84%-34%
2007-10-092009-03-092012-02-28-55%-22%
2000-03-242002-10-092006-10-23-49%-29%
1973-01-111974-10-031976-12-28-48%-14%
1968-11-291970-05-261971-04-27-37%-9%

This is where the rule earns its reputation: in the five deepest market drawdowns its own worst loss over the same span was between a quarter and three-fifths of the market’s. The mechanism is simple: a decline deep enough to matter lasts long enough to take the index below its average, and the rule steps aside for the rest of it.

Whipsaw

The cost of that protection is whipsaw. Of 281 round trips (an exit and the next re-entry), 247 (88%) were out of the market for 60 trading days or less, and on average the market rose 1.2% more than T-bills while those quick round trips were out. The worst are listed below; the largest, from 1939-08-18 to 1939-09-06, missed 7.8% in 15 trading days.

First day outFirst day back inDays outMissed, net of bills
1939-08-181939-09-06157.8%
2000-04-172000-04-1926.9%
1932-10-111932-10-1316.9%
1933-03-181933-04-20276.0%
2010-06-072010-06-1674.8%
1933-10-201933-10-2434.4%

Lookback, execution and costs

The lookback

Figure 4 repeats the analysis for every lookback from 50 to 300 days in steps of ten. The Sharpe ratio ranges from 0.68 to 0.84 and the annual return from 11.1% to 12.2%; every lookback beats buy and hold on Sharpe ratio, and 200 days is not special. That flatness is reassuring, with a caveat: every lookback shares the same few bear markets, so the 26 results are far from 26 independent confirmations. The worst drawdown, by contrast, jumps around, because it is decided by how a handful of crashes happened to line up with each average. At 200 days it was -34%, the best of the 26 (tied with another lookback); the median across lookbacks was -41%. Quote the median, not the famous number.

Figure 4Sensitivity to the lookback
Sharpe ratio by lookback (buy and hold dashed)0.00.20.40.60.8Worst drawdown by lookback (buy and hold: -84%, off this scale)-50%-40%-30%-20%-10%0%50 d100 d150 d200 d250 d300 d
Sharpe ratioWorst drawdown●200 daysBuy and hold (Sharpe panel)
Every lookback from 50 to 300 trading days, same data and conventions as Figure 3. Computed by the Python build, not in the browser.

Execution and costs

VariantAnnual returnSharpeWorst drawdownWorst daySwitches a year
Buy and hold10.2%0.46-84%-17.4%0
Rule, trade at the signal's close11.5%0.73-34%-9.2%5.7
Rule, trade at the next close10.6%0.66-39%-17.4%5.7
Rule, next close and 10 bp per switch10.0%0.61-41%-17.4%5.7
Rule with look-ahead (wrong)20.2%1.37-25%-9.2%5.7
Rule, 10 bp per switch10.9%0.68-34%-9.2%5.7
Rule, 25 bp per switch10.0%0.61-37%-9.2%5.7
Rule, ±1% band11.0%0.69-36%-9.2%2.5
Rule, ±2% band11.1%0.70-43%-9.2%1.5

Costs are charged per unit of exposure switched. The band switches in only above the average by the band and out only below it by the band.

Four things in this table matter. First, look-ahead multiplies the return by 1.75: the error is not a rounding matter. Second, one day of delay costs 0.9 percentage points a year and changes the worst day from -9.2% to -17.4%. The worst-day change is a single date: the index closed below its average on Friday 16 October 1987, so selling at that close avoided Monday’s -17.4%, and selling at Monday’s close took all of it. That one day explains only part of the annual difference; the rest is spread across hundreds of switches, each a day late. Third, one day of delay and 10 bp a switch together remove the return advantage entirely (10.0% against 10.2%), while the Sharpe ratio and drawdown still favour the rule. Fourth, a band cuts the switches by more than half; at 1% it costs a little return, and at 2% it also deepens the worst drawdown to -43%, so a band is a cost decision, not a free improvement.

What the literature says

The evidence on technical rules is long and divided. Fama and Blume found that simple filter rules on individual stocks did not beat buy and hold once costs were counted.4 Brock, Lakonishok and LeBaron tested moving-average and trading-range rules on the Dow Jones index from 1897 to 1986 and found returns after buy signals that standard time-series models could not explain.5 Sullivan, Timmermann and White then corrected for the full universe of rules that could have been tried: the best rule remained significant in the original sample but not in the decade that followed.6 Lo, Mamaysky and Wang gave chart patterns a statistical footing and found that some carried incremental information,7 and Park and Irwin’s survey concluded that the positive results cluster in older samples and weaken with better controls for data snooping and costs.8

For asset allocation, Faber popularised a monthly version of this note’s rule, a 10-month average applied to several asset classes, and reported equity-like returns with much smaller drawdowns;9 Zakamulin examined the real-life performance of moving-average and momentum timing rules and found the out-of-sample advantage smaller and concentrated in bear markets.10 The wider trend-following literature puts the same idea across many markets.1,11 This note’s result sits comfortably inside that literature: protection in long declines, a price paid in whipsaw and in strong bull markets, and returns that depend on the period.

Implications

  1. Treat a trend indicator as a risk overlay first: its robust property is avoiding the middle of long declines.
  2. Lag every signal, test one day later as well, and distrust any result that hinges on a single close.
  3. Charge realistic costs per switch, and consider a band or a monthly check if switches cluster.
  4. Report the whole neighbourhood of lookbacks and the per-decade table, not a single number.
  5. Decide in advance how long the rule may lag the market, remembering the 2010s, before concluding that it has stopped working.

References

  1. Moskowitz, T. J., Ooi, Y. H., & Pedersen, L. H. (2012). Time series momentum. Journal of Financial Economics, 104(2), 228-250.
  2. Wilder, J. W. (1978). New concepts in technical trading systems. Trend Research, Greensboro, NC.
  3. French, K. R. (2026). Data Library: Fama/French factors (daily) and momentum factor (daily). Tuck School of Business, Dartmouth College. https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html (retrieved September 2026).
  4. Fama, E. F., & Blume, M. E. (1966). Filter rules and stock-market trading. Journal of Business, 39(1), Part 2, 226-241.
  5. Brock, W., Lakonishok, J., & LeBaron, B. (1992). Simple technical trading rules and the stochastic properties of stock returns. Journal of Finance, 47(5), 1731-1764.
  6. Sullivan, R., Timmermann, A., & White, H. (1999). Data-snooping, technical trading rule performance, and the bootstrap. Journal of Finance, 54(5), 1647-1691.
  7. Lo, A. W., Mamaysky, H., & Wang, J. (2000). Foundations of technical analysis: Computational algorithms, statistical inference, and empirical implementation. Journal of Finance, 55(4), 1705-1765.
  8. Park, C.-H., & Irwin, S. H. (2007). What do we know about the profitability of technical analysis? Journal of Economic Surveys, 21(4), 786-826.
  9. Faber, M. T. (2007). A quantitative approach to tactical asset allocation. Journal of Wealth Management, 9(4), 69-79.
  10. Zakamulin, V. (2014). The real-life performance of market timing with moving average and time-series momentum rules. Journal of Asset Management, 15(4), 261-278.
  11. Hurst, B., Ooi, Y. H., & Pedersen, L. H. (2017). A century of evidence on trend-following investing. Journal of Portfolio Management, 44(1), 15-29.