ma_crossover
Moving Average Crossover
Golden Cross (bullish): fast MA crosses above slow MA. Death Cross (bearish): fast MA crosses below slow MA.
Signal family
Trend — Signals that fire when price is continuing or reversing an established directional move. Momentum-following by nature.
Parameters
| Name | Description | Default | Range |
|---|---|---|---|
| fast | Fast MA period | 50 | 5–200 |
| slow | Slow MA period | 200 | 20–500 |
Historical context
229,035 triggers on 21,536 tickers, 1989-03-31 → 2026-05-01. Universe: global — all covered exchanges (mcap ≥ $100,000,000, price ≥ $1). Long-only convention: BUY at open T+1, hold the horizon, compare to S&P 500 Equal Weight over the same window.
Methodology footnotes
Benchmarks shown in the detail tables: spxew (S&P 500 Equal Weight — primary, median-stock view, avoids the 2020+ megacap-concentration distortion), spx (S&P 500 cap-weighted, distorted post-2020), msci (MSCI World USD). Per-stock regime tags: trending = ADX(14) ≥ 25, high vol = 20d realized annualized vol ≥ 20%. 1d return = intraday T+1 open→close; 20d = open T+1 to close T+20.
At a glance — alpha vs S&P 500 Equal Weight, global universe
Holding-period sensitivity. Bullish columns: positive = signal worked (long the trigger beat the index). Bearish columns: negative = signal worked (the flagged stock underperformed).
| Horizon | Bullish α | Bearish α |
|---|---|---|
| 5-day | -0.01% | +0.03% |
| 20-day | +0.20% | -0.05% |
| 60-day | +0.16% | +0.24% |
| 1-year | +3.55% | +0.85% |
Bearish: beats random (p=0.015).
Where does MA_CROSSOVER actually fire?
The bucket distribution often reveals what the signal really is, regardless of its textbook label. Heavy concentration in "non-trending + high vol" = it's mostly a chop-market event. Heavy in "trending + low vol" = it picks up the smooth grinds. Read the chart before the alpha numbers — context shapes everything that follows.
Does it work in every regime?
Trigger alpha split by the host stock's own regime on the trigger date — trending or ranging, high-vol or low-vol. The 20d alpha you'd actually capture if you took the trade. Bars matching your direction's "right" sign (positive for bullish, negative for bearish) = the signal worked in that regime; opposite sign = avoid it there. A signal with one strong-positive bar and three flat ones isn't a "20d alpha" signal — it's a "20d alpha when the stock is X" signal.
Does it work in every era?
A multi-year average can hide major instability. The sample splits into three windows: 2015–2019 (pre-COVID), 2020–2022 (pandemic + 2022 bear), and 2023+ (post-ZIRP + AI megacap rally). All three matching your direction's "right" sign = the signal is durable. One era doing all the work = a regime-specific edge that may not repeat. The bigger the variance across eras, the smaller the position you should run.
↑ Bullish triggers
| Bench | Metric | 1d | 5d | 20d | 60d | 252d |
|---|---|---|---|---|---|---|
| spxew | Stock % | +0.00% | +0.14% | +0.69% | +2.02% | +13.37% |
| Bench % | +0.03% | +0.16% | +0.62% | +1.88% | +9.82% | |
| Alpha % | -0.04% | -0.01% | +0.20% | +0.16% | +3.55% | |
| Median alpha | -0.10% | -0.33% | -0.96% | -2.47% | -6.05% | |
| Hit rate (α>0) | 47.7% | 46.6% | 45.4% | 43.2% | 42.4% | |
| p (naive) | <0.001 | 0.4653 | <0.001 | 0.0151 | <0.001 | |
| p (HAC) | <0.001 | 0.4655 | <0.001 | 0.0415 | <0.001 | |
| N | 109,789 | 105,519 | 105,348 | 103,501 | 91,322 | |
| spx | Stock % | +0.00% | +0.14% | +0.69% | +2.02% | +13.37% |
| Bench % | +0.01% | +0.22% | +0.99% | +3.01% | +14.40% | |
| Alpha % | -0.02% | -0.07% | -0.21% | -1.01% | -1.20% | |
| Median alpha | -0.09% | -0.41% | -1.38% | -3.74% | -11.18% | |
| Hit rate (α>0) | 47.7% | 45.8% | 43.4% | 40.1% | 37.3% | |
| p (naive) | 0.0297 | 0.0003 | <0.001 | <0.001 | <0.001 | |
| p (HAC) | 0.0305 | 0.0003 | <0.001 | <0.001 | 0.0169 | |
| N | 110,777 | 107,245 | 106,920 | 104,949 | 92,545 | |
| msci | Stock % | +0.00% | +0.14% | +0.69% | +2.02% | +13.37% |
| Bench % | +0.04% | +0.22% | +0.84% | +2.59% | +11.78% | |
| Alpha % | -0.04% | -0.05% | -0.06% | -0.55% | +1.35% | |
| Median alpha | -0.12% | -0.40% | -1.23% | -3.31% | -8.69% | |
| Hit rate (α>0) | 47.1% | 46.0% | 44.1% | 41.2% | 39.9% | |
| p (naive) | <0.001 | 0.0050 | 0.1036 | <0.001 | <0.001 | |
| p (HAC) | <0.001 | 0.0051 | 0.1097 | <0.001 | 0.0070 | |
| N | 110,459 | 106,960 | 106,702 | 104,528 | 92,127 |
Permutation null detail — all horizons × each benchmark
| Horizon | Bench | Observed lift | Null mean | Null 95% CI | pperm |
|---|---|---|---|---|---|
| 1d | spxew | +0.09% | +0.08% | [+0.06%, +0.09%] | 0.020 |
| 1d | spx | +0.09% | +0.08% | [+0.07%, +0.10%] | 0.139 |
| 1d | msci | +0.10% | +0.09% | [+0.07%, +0.10%] | 0.149 |
| 5d | spxew | +0.38% | +0.34% | [+0.30%, +0.38%] | 0.025 |
| 5d | spx | +0.37% | +0.36% | [+0.32%, +0.40%] | 0.249 |
| 5d | msci | +0.38% | +0.36% | [+0.33%, +0.40%] | 0.204 |
| 20d | spxew | +1.31% | +1.12% | [+1.04%, +1.18%] | 0.005 |
| 20d | spx | +1.12% | +1.15% | [+1.07%, +1.22%] | 0.746 |
| 20d | msci | +1.16% | +1.16% | [+1.09%, +1.23%] | 0.577 |
| 60d | spxew | +2.28% | +2.38% | [+2.24%, +2.50%] | 0.905 |
| 60d | spx | +1.87% | +2.45% | [+2.31%, +2.57%] | 1.000 |
| 60d | msci | +1.89% | +2.47% | [+2.34%, +2.59%] | 1.000 |
| 252d | spxew | +6.02% | +4.62% | [+4.41%, +4.89%] | 0.005 |
| 252d | spx | +5.41% | +5.01% | [+4.79%, +5.27%] | 0.005 |
| 252d | msci | +5.55% | +4.96% | [+4.76%, +5.23%] | 0.005 |
Example triggers on US large-caps (2023+, mcap ≥ $30B)
Six recent bullish MA_CROSSOVER triggers on US mega-caps. Top three: the signal's best outcomes. Bottom three: the worst. Extreme outliers (|α| > 25%) excluded. The three best and three worst are still tail outcomes by construction — read them as the range, not the typical result.
Strongest outcomes (what MA_CROSSOVER looks like when it works)
Weakest outcomes (what MA_CROSSOVER looks like when it fails)
Stock-regime quadrants (2×2 per-stock, 20d alpha detail table)
| Quadrant | N | Stock % (spxew) | Bench % (spxew) | Alpha % (spxew) | p (HAC) | Stock % (spx) | Bench % (spx) | Alpha % (spx) | p (HAC) | Stock % (msci) | Bench % (msci) | Alpha % (msci) | p (HAC) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Trending + Low vol Clean directional grind, low whipsaw | 10,037 | +0.30% | +0.39% | -0.05% | 0.5184 | +0.30% | +0.86% | -0.52% | <0.001 | +0.30% | +0.67% | -0.32% | <0.001 |
| Trending + High vol Crisis selloff or parabolic rally | 57,317 | +0.97% | +0.59% | +0.54% | <0.001 | +0.97% | +1.00% | +0.06% | 0.3158 | +0.97% | +0.84% | +0.23% | 0.0002 |
| Non-trending + Low vol Quiet chop, summer doldrums | 10,996 | +0.42% | +0.49% | -0.02% | 0.7301 | +0.42% | +0.87% | -0.41% | <0.001 | +0.42% | +0.71% | -0.25% | <0.001 |
| Non-trending + High vol Classical "whipsaw zone" for momentum | 35,850 | +0.54% | +0.74% | -0.09% | 0.1860 | +0.54% | +1.04% | -0.41% | <0.001 | +0.54% | +0.90% | -0.28% | <0.001 |
Sub-period breakdown table (20d alpha)
| Period | N | Alpha % (spxew) | p (HAC) | Alpha % (spx) | p (HAC) | Alpha % (msci) | p (HAC) |
|---|---|---|---|---|---|---|---|
| 2015-2019 2015-01-01 → 2020-01-01 | 27,578 | -0.72% | <0.001 | -1.08% | <0.001 | -0.80% | <0.001 |
| 2020-2022 2020-01-01 → 2023-01-01 | 36,368 | +0.49% | <0.001 | +0.66% | <0.001 | +0.72% | <0.001 |
| 2023-2026 2023-01-01 → 2099-01-01 | 50,218 | +0.48% | <0.001 | -0.37% | <0.001 | -0.21% | 0.0006 |
↓ Bearish triggers negative alpha = signal was right (stock underperformed market)
| Bench | Metric | 1d | 5d | 20d | 60d | 252d |
|---|---|---|---|---|---|---|
| spxew | Stock % | +0.00% | +0.30% | +1.32% | +3.70% | +12.54% |
| Bench % | +0.05% | +0.24% | +1.39% | +3.50% | +11.73% | |
| Alpha % | -0.06% | +0.03% | -0.05% | +0.24% | +0.85% | |
| Median alpha | -0.09% | -0.20% | -0.80% | -1.72% | -7.00% | |
| Hit rate (α>0) | 47.6% | 47.7% | 45.9% | 44.9% | 41.0% | |
| p (naive) | <0.001 | 0.1289 | 0.1097 | <0.001 | <0.001 | |
| p (HAC) | <0.001 | 0.1325 | 0.1132 | 0.0007 | 0.0165 | |
| N | 110,300 | 106,246 | 104,802 | 102,404 | 92,156 | |
| spx | Stock % | +0.00% | +0.30% | +1.32% | +3.70% | +12.54% |
| Bench % | +0.03% | +0.29% | +1.56% | +3.91% | +14.95% | |
| Alpha % | -0.03% | -0.02% | -0.22% | -0.20% | -2.36% | |
| Median alpha | -0.07% | -0.27% | -1.00% | -2.31% | -10.55% | |
| Hit rate (α>0) | 48.0% | 47.1% | 44.9% | 43.3% | 37.4% | |
| p (naive) | <0.001 | 0.3064 | <0.001 | 0.0006 | <0.001 | |
| p (HAC) | <0.001 | 0.3120 | <0.001 | 0.0033 | <0.001 | |
| N | 111,434 | 107,675 | 106,456 | 103,697 | 93,782 | |
| msci | Stock % | +0.00% | +0.30% | +1.32% | +3.70% | +12.54% |
| Bench % | +0.06% | +0.29% | +1.38% | +3.48% | +12.49% | |
| Alpha % | -0.06% | -0.01% | -0.06% | +0.26% | -0.12% | |
| Median alpha | -0.11% | -0.27% | -0.85% | -1.83% | -8.16% | |
| Hit rate (α>0) | 47.4% | 47.0% | 45.5% | 44.6% | 39.8% | |
| p (naive) | <0.001 | 0.4279 | 0.0495 | <0.001 | 0.4394 | |
| p (HAC) | <0.001 | 0.4323 | 0.0524 | 0.0001 | 0.7317 | |
| N | 110,535 | 106,722 | 105,468 | 103,175 | 92,761 |
Permutation null detail — all horizons × each benchmark
| Horizon | Bench | Observed lift | Null mean | Null 95% CI | pperm |
|---|---|---|---|---|---|
| 1d | spxew | +0.06% | +0.08% | [+0.06%, +0.09%] | 0.050 |
| 1d | spx | +0.08% | +0.08% | [+0.07%, +0.10%] | 0.184 |
| 1d | msci | +0.08% | +0.09% | [+0.07%, +0.11%] | 0.169 |
| 5d | spxew | +0.38% | +0.34% | [+0.31%, +0.37%] | 0.995 |
| 5d | spx | +0.37% | +0.36% | [+0.32%, +0.39%] | 0.821 |
| 5d | msci | +0.38% | +0.36% | [+0.33%, +0.40%] | 0.781 |
| 20d | spxew | +1.00% | +1.10% | [+1.02%, +1.17%] | 0.015 |
| 20d | spx | +1.06% | +1.13% | [+1.06%, +1.20%] | 0.025 |
| 20d | msci | +1.10% | +1.15% | [+1.08%, +1.22%] | 0.080 |
| 60d | spxew | +2.41% | +2.36% | [+2.24%, +2.47%] | 0.771 |
| 60d | spx | +2.70% | +2.43% | [+2.30%, +2.55%] | 1.000 |
| 60d | msci | +2.74% | +2.45% | [+2.33%, +2.57%] | 1.000 |
| 252d | spxew | +4.17% | +4.58% | [+4.32%, +4.77%] | 0.005 |
| 252d | spx | +4.94% | +4.97% | [+4.73%, +5.18%] | 0.328 |
| 252d | msci | +4.86% | +4.92% | [+4.69%, +5.10%] | 0.279 |
Example triggers on US large-caps (2023+, mcap ≥ $30B)
Six recent bearish MA_CROSSOVER triggers on US mega-caps. Top three: the signal's best outcomes. Bottom three: the worst. Extreme outliers (|α| > 25%) excluded. The three best and three worst are still tail outcomes by construction — read them as the range, not the typical result.
Strongest outcomes (what MA_CROSSOVER looks like when it works)
Weakest outcomes (what MA_CROSSOVER looks like when it fails)
Stock-regime quadrants (2×2 per-stock, 20d alpha detail table)
| Quadrant | N | Stock % (spxew) | Bench % (spxew) | Alpha % (spxew) | p (HAC) | Stock % (spx) | Bench % (spx) | Alpha % (spx) | p (HAC) | Stock % (msci) | Bench % (msci) | Alpha % (msci) | p (HAC) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Trending + Low vol Clean directional grind, low whipsaw | 8,610 | +0.21% | +0.81% | -0.52% | <0.001 | +0.21% | +1.05% | -0.80% | <0.001 | +0.21% | +0.94% | -0.68% | <0.001 |
| Trending + High vol Crisis selloff or parabolic rally | 42,788 | +2.19% | +1.98% | +0.17% | 0.0063 | +2.19% | +2.21% | -0.04% | 0.5391 | +2.19% | +1.94% | +0.22% | 0.0004 |
| Non-trending + Low vol Quiet chop, summer doldrums | 13,530 | +0.38% | +0.70% | -0.29% | <0.001 | +0.38% | +0.91% | -0.51% | <0.001 | +0.38% | +0.82% | -0.41% | <0.001 |
| Non-trending + High vol Classical "whipsaw zone" for momentum | 49,902 | +1.03% | +1.13% | -0.08% | 0.1217 | +1.03% | +1.25% | -0.20% | <0.001 | +1.03% | +1.12% | -0.09% | 0.0619 |
Sub-period breakdown table (20d alpha)
| Period | N | Alpha % (spxew) | p (HAC) | Alpha % (spx) | p (HAC) | Alpha % (msci) | p (HAC) |
|---|---|---|---|---|---|---|---|
| 2015-2019 2015-01-01 → 2020-01-01 | 29,173 | -0.41% | <0.001 | -0.55% | <0.001 | -0.40% | <0.001 |
| 2020-2022 2020-01-01 → 2023-01-01 | 37,771 | -0.42% | <0.001 | -0.19% | 0.0027 | +0.08% | 0.1981 |
| 2023-2026 2023-01-01 → 2099-01-01 | 47,844 | +0.50% | <0.001 | -0.03% | 0.5612 | +0.05% | 0.3571 |
Methodology and caveats
How to read. Entry at open of T+1 (one trading day after the signal fires on close of T). 20d = open T+1 to close T+20. Alpha = stock return − benchmark return over the same window (Convention A, single-sided, textbook). For bullish triggers, POSITIVE alpha = signal was right. For bearish triggers, NEGATIVE alpha = signal was right (stock underperformed market). No sign-flipping; the direction of the bet determines what "good" looks like. Per-stock regime is each stock's own ADX(14) and RV(20) at the trigger date — not market-wide state.
Three p-values, three robustness tests. (a) p_naive: scipy one-sample t-test on winsorized alphas. Optimistic because overlapping 20d windows on the same ticker inflate effective N. (b) p_hac: Newey-West HAC with lag = horizon — corrects for the overlap and is the academic-finance standard. (c) p_perm: one-sided fraction of 200 random-date null iterations falling in the “signal was right” tail (mean ≥ observed for bullish; mean ≤ observed for bearish). Tests whether the signal beats random date selection at all. A signal that clears all three (pnaive, phac, pperm all < 0.05) has real information; a signal that fails pperm has not beaten random timing whatever the t-test says — and because the test is one-sided, a pperm up at its 1.000 ceiling is not "no edge" but inverted edge: every random draw served the claimed direction better than the trigger dates did.
Caveats. (i) Universe reflects today's active tickers; delisted losers pruned → survivorship bias. (ii) Mcap ≥ $100M filter uses today's snapshot, not point-in-time — mild lookahead on which stocks enter the sample, not on returns. (iii) Means and p-values use winsorized alphas (1/99 percentile) to prevent data errors from dominating. Medians and hit rates use raw data. (iv) Zero transaction costs assumed. Realistic bid-ask + commissions remove 20–40bps from 20d alpha on US large-caps, more on small-cap. Sub-20bps alpha is noise in practice. (v) Past performance does not predict future results.
How to use this
1 · When to reach for this signal
Use Moving Average Crossover bullish as a long-side screening tile. Bullish 20d alpha is +0.20% and beats random (permutation test, 200 iterations). Bearish 20d alpha is -0.05% and beats random , but sits below the ~20bps cost floor from the caveats — screening context, not a standalone edge.
These verdicts are 20-day holds vs S&P 500 Equal Weight. Longer horizons can differ in either direction — check the permutation detail tables below before extrapolating.
2 · When it works — the setups that drive it
- Best bullish setup: Trending + High vol — alpha +0.54% / 20d on 57,317 historical triggers.
- Best bearish setup: Trending + Low vol — alpha -0.52% / 20d on 8,610 historical triggers.
- Best era for bullish: 2020-2022 — alpha +0.49% / 20d on 36,368 triggers.
- Best era for bearish: 2020-2022 — alpha -0.42% / 20d on 37,771 triggers.
3 · When it fails — common false positives
- Weakest bullish cell: Non-trending + High vol — alpha -0.09% / 20d on 35,850 triggers.
- Weakest bearish cell: Trending + High vol — alpha +0.17% / 20d on 42,788 triggers.
- Worst era for bullish: 2015-2019 — alpha -0.72% / 20d on 27,578 triggers.
- Worst era for bearish: 2023-2026 — alpha +0.50% / 20d on 47,844 triggers.
Signal-specific failure patterns
4 · Pairing inside a screen
The statements below describe how this signal relates to others by construction — which indicator family it belongs to, and where same-family redundancy might reduce the independence of evidence inside a Daily Report. These are taxonomic classifications drawn from standard technical-analysis texts; they are not pairing backtests. Measured pair results — same-day co-fires put through the pair backtest — follow under “Measured pairings” below.
Trend-follower family
Moving-average crossover signals are derived from the intersection of two price moving averages at different lookbacks and are classified as trend-following (Murphy, Technical Analysis of the Financial Markets, 1999; Kirkpatrick & Dahlquist, Technical Analysis, 3rd ed. 2015). This construction overlaps with MACD, which is the difference of two EMAs (Appel, Technical Analysis: Power Tools for Active Investors, 2005); stacking MA crossover with MACD in the same direction produces correlated rather than independent evidence.
Measured pairings — Bonferroni survivors
Beyond the literature pairings above, these are the same-day co-fire combinations involving Moving Average Crossover that cleared the pair backtest's Bonferroni cut on the full 2016–2026 sample (549 pairs × 5 horizons = 2,745 hypotheses), on universes filtered to ADV ≥ $5M, price ≥ $5 and market cap ≥ $100M. That cut is two-sided: it asks only whether the co-fire's α is reliably different from zero, in either direction, so a pair can survive by reliably underperforming — every row below happens to be positive on the full sample, but that is not what the test asked. The same run holds out 2023+: the Test columns are that held-out window, printed for every row with enough held-out co-fires to measure, so a survivor that did not repeat out of sample is visible rather than hidden. All α figures here are for holding the stock long after the co-fire — no shorting assumed, and no sign flip for bearish legs. So positive α means the co-fire was followed by outperformance and negative α by underperformance, whichever way either leg points — a bearish leg does not flip the reading. Survivors are rare by design — absence of a pair here means it did not clear the cut, not that it was untested. Ranked by held-out (2023+) α. Historical tendencies, not recommendations.
China A-shares
| Pair (same-day co-fire, long) | Full α | Test α (2023+) | Test N | p_perm test |
|---|---|---|---|---|
| ma_crossover bearish + weekly_change bullish | +3.90% | +7.89% | 249 | 0.002 |
| ma_crossover bearish + weekly_change bearish | +4.75% | +6.71% | 584 | 0.002 |
| failed_double_bottom bullish + ma_crossover bearish | +4.44% | +5.28% | 38 | 0.054 |
| bollinger bullish + ma_crossover bearish | +1.64% | +3.62% | 428 | 0.002 |
| hh_hl_streak bullish + ma_crossover bearish | +2.54% | +3.44% | 244 | 0.002 |
| ma_crossover bullish + macd bearish | +2.20% | +2.49% | 436 | 0.002 |
| cci bearish + ma_crossover bullish | +1.65% | +2.10% | 743 | 0.002 |
| ma_crossover bearish + new_20d_low bearish | +1.19% | +1.38% | 1,372 | 0.002 |
8 of this universe's 138 surviving pairs involve this signal · α vs 83188.HK.
China A-share survivor α runs large but skews toward small-caps, where trading costs and thin liquidity claim a large share of any measured edge — screening context, not a capturable spread.
What would likely rescue this signal
This block calls out the data or conditions that could turn a technically weak signal into a usable one in a composite screen. Based on signal mechanics and the observed failure patterns above; individual combinations are not yet backtested.
- Use as confirmation filter, not entry trigger — The signals natural home is as a regime gate: take MACD bullish trades only when the 50DMA is above the 200DMA, or take RSI bearish only during death-cross regime. Layered onto other triggers, MA crossover improves precision without its own weak short-horizon returns doing damage.
- Volume confirmation for bearish death cross — Death crosses on expanding volume are more decisive than on contracting volume (the latter is often a late-stage rollover that is about to bounce). A filter requiring volume above 1.2x the 20d average during the week the cross prints would sharpen the bearish signal.
- Faster MA parameters — A formal parameter grid search (20/50, 50/150, 50/200, 100/200) would reveal whether the lag issue can be reduced by going faster without losing too much signal-to-noise.
See also Why technical-only signals don't survive on their own for the broader argument.
5 · Before you act — a 5-point checklist
- Normal trading day? Rule out earnings (within ±3 days), ex-dividend, or known corporate-action dates — the signal is almost certainly reading noise, not momentum, in those windows.
- Where is price vs its own 50 / 200 DMA? A trend signal is only as credible as the underlying trend it claims to confirm. Check the 200DMA orientation before acting.
- What's the sector breadth doing? An isolated signal in a broadly down-trending sector is a lower-confidence setup than one firing with the rest of its peer group.
- Is ADV20 enough for your size? If the trigger is on a $500M name and you want to move $1M notional, you're the tape. Consider adv20d ≥ 5% of your intended position.
- What invalidates you? Define a price level (for longs: a close below the trigger-day low; for shorts: close above the trigger-day high) and honor it. The backtest alpha is an average; any one trade can be at either tail.
Execution notes
MA crossover is a lagging structural indicator — not a timing signal. Best use: regime gate that tells you which side of the market structure favors your other triggers. The 1-year alpha numbers are the headline; the 20-day numbers are noise around a structural state. Entry open T+1 if traded directly.
See a live screen of this signal
Curated Daily Reports that screen for this signal, refreshed at the open, midday and close — free to view, no account needed: