A moving average smooths price; a system decides what to do with it
A moving average replaces a jagged series of observations with a smoother reference. For a 20-bar simple moving average, each of the last 20 completed prices receives equal weight. An exponential moving average gives more weight to recent observations and lets older information decay gradually.
That smoothing can make direction easier to describe, but the line is not a strategy. A strategy must still decide what comparison matters, when it is evaluated, what position follows, and how risk ends.
Three familiar designs are related but not interchangeable:
- A price filter is positive when price is above its moving average.
- A crossover is positive when a faster average is above a slower average.
- A slope rule is positive when one average is rising.
On the same bar, price may be below a still-rising slow average while a fast average remains above it. Each rule is measuring a different combination of level, recent speed, and direction.
Smoothing always creates a trade-off
A fast filter reacts quickly to new prices. It can join a move earlier, but it also changes state whenever short-term noise crosses the reference. A slow filter ignores more noise and changes state less often, but it recognizes turns later.
That delay is not a software defect; it is the consequence of averaging past observations. Every attempt to reduce lag—shorter windows, heavier recent weights, adaptive parameters—also changes sensitivity to noise or introduces a new model.
Moving-average systems are therefore trend implementations, not independent evidence that trends exist. Their research value is that the rule is simple, observable, and capable of expressing a persistence thesis without forecasting an exact future price. Transparent historical tests exist for declared moving-average rules, but their results belong to those constructions and samples rather than to every crossover.
The rule choices that matter
| Choice | Common variants | Research consequence |
|---|---|---|
| Input | Close, midpoint, typical price, or adjusted price | Determines what is actually being smoothed |
| Weighting | Simple or exponential | Changes lag, warm-up, and response to recent observations |
| Trigger | Price/average, fast/slow crossover, or slope | Defines the market state |
| Buffer | Percentage, volatility band, or persistence count | Reduces transitions but delays recognition |
| Decision time | Completed bar or scheduled evaluation | Prevents intrabar hindsight |
| Position | Long/flat, long/short, or scaled | Changes directional and financing exposure |
| Exit | Reverse signal, neutral band, stop, or timeout | Changes whipsaw and tail behavior |
The two window lengths in a crossover should also be understood as a ratio. A 10/20 crossover and a 100/200 crossover both compare a fast window half the length of the slow one, but they operate at very different horizons.
A crossover from observation to trade
Illustrative example. Assume a daily system with a 20-day exponential average and a 100-day exponential average:
- Both averages update only after the daily bar completes.
- The long state begins when the fast average closes at least 0.25% above the slow average. The short state begins at least 0.25% below it. Inside the buffer, the existing state is retained.
- A state change can be acted on only at the next modeled event.
- Exposure is fixed for the baseline. Volatility scaling is tested later as a separate design choice.
- The position closes or reverses only after the opposite buffered condition is known.
Illustrative example. Suppose the slow average is 100 and the fast average moves from 100.10 to 100.35. The positive distance is 0.35%, so the completed observation creates a long state. If the next modeled fill is 100.60, that—not 100.35—is the strategy’s entry reference.
Now suppose the averages repeatedly cross inside the 0.25% band. The strategy does nothing. That can reduce turnover, but it also means the result cannot be attributed to “the 20/100 crossover” alone; it is a buffered state machine.
How to study the filter rather than optimize a picture
Begin by comparing a price-versus-slow-average rule with a fast/slow crossover. Keep the execution time, position size, and costs identical. This reveals whether the extra fast average adds information or merely changes timing.
Next, use a small structured grid:
- a few slow horizons representing short, medium, and long behavior;
- fast windows expressed as stable fractions of the slow window;
- no buffer, a small fixed buffer, and a volatility-scaled buffer; and
- fixed exposure beside risk-scaled exposure.
Inspect transition count, time in market, average delay after major reversals, gross and net results, and drawdowns during sideways periods. A useful parameter surface should change gradually. One profitable island surrounded by failure is not a robust “best setting.”
Make warm-up explicit. A 200-day simple average cannot produce a valid reading after only 30 observations, and silently filling the missing period with a shorter window changes the rule.
Interpreting the result
A moving-average system is doing its job when its behavior matches the declared trade-off. A slow system should trade infrequently, lag turns, and retain long moves. A fast system should react earlier and incur more false transitions. Results that show the opposite deserve a data and timing audit.
Compare performance across trend and range-bound periods, but define those periods without using the strategy’s later P&L. Report long and short legs separately and check whether the system is mostly a long-market exposure.
The most persuasive evidence is not one historically famous pair of windows. It is coherent behavior across nearby filters, later samples, and realistic decision timing.
Why moving-average systems disappoint
- Repeated crossings in a narrow range create whipsaw losses.
- Faster filters can turn small price noise into expensive position changes.
- Slow filters surrender part of both the beginning and end of a move.
- Corporate-action errors or incorrect futures rolls can create false crosses.
- A close-based signal cannot assume an execution before that close is known.
- Changing simple to exponential weighting is a different rule, not a cosmetic chart setting.
Try it in Arizmic
Strategy composition
Build the premise with shipped signals
Turn moving averages into an explicit rule by deciding whether the strategy responds to a crossing event or an ongoing state, then add a separate filter for trend quality or volatility. The recipes make lag and whipsaw visible instead of treating the line itself as a trade.
These are starting structures, not presets or evidence of an edge. Choose one, replace the bracketed decisions, and keep the signal roles separate as you test it.
Composition 01
Crossover with directional-strength confirmation
Event-driven recipe- Moving-Average CrossTransition trigger
- ADX/DMIWhipsaw filter
- Wilder ATRRisk distance
Data: OHLCV Bars
View configuration and complete ruleHide recipe details
Composition 01
Crossover with directional-strength confirmation
Moving-Average Cross
Transition trigger
Moving-Average Cross exposes both the persistent spread and the exact bars where its sign changes.
Configure
- fast_window · [fast window]
- Control short-horizon responsiveness.
- slow_window · [slow window]
- Define the slower trend reference.
Use the output
- cross_up
- Trigger a candidate long only when cross_up is true.
- cross_down
- Trigger a candidate short or long exit only when cross_down is true.
- spread
- Require [spread buffer] if the design needs confirmation beyond a zero crossing.
ADX/DMI
Whipsaw filter
ADX/DMI can reject crosses that occur without meaningful directional strength and can verify that the direction agrees with the proposed side.
Configure
- window · [ADX window]
- Measure strength over a horizon distinct from the fast average.
Use the output
- adx
- Require ADX at or above [minimum strength].
- plus_di
- For a long, require +DI above -DI.
- minus_di
- For a short, require -DI above +DI.
Wilder ATR
Risk distance
ATR supplies a volatility-aware risk distance without changing the crossover’s direction.
Configure
- window · [ATR window]
- Estimate current movement at the intended holding scale.
Use the output
- atr
- Use [ATR multiple] times ATR for the initial risk distance and unit sizing.
Assemble the rule
- Entry
- After bar completion, take a fresh cross only when ADX and DMI confirm the proposed direction.
- Exit
- Exit on the opposite cross, [ATR protection rule], or [maximum holding rule].
- Decision time
- The crossing event belongs to the completed bar; any order decision starts on the next eligible event.
- Sizing
- Derive units from the ATR risk distance and [risk budget], with a hard exposure cap.
Useful variations
- Compare an immediate cross with one- and two-bar spread confirmation.
- Remove the ADX gate to measure the trade-off between lower turnover and missed early trends.
- Test nearby fast/slow pairs while holding the ratio between windows approximately stable.
Keep in view
ADX confirmation adds delay to an already lagging rule. It may improve apparent outcomes simply by skipping trades, so compare like-for-like exposure and trade opportunity.
Composition 02
Persistent EMA state with slope and volatility regime
State-driven recipe- EMADirectional state
- Moving-Average SlopeDirection-quality check
- Volatility RegimeRisk-state gate
Data: OHLCV Bars
View configuration and complete ruleHide recipe details
Composition 02
Persistent EMA state with slope and volatility regime
EMA
Directional state
The EMA spread stays positive or negative between crossings, which makes it suitable for a persistent exposure rule.
Configure
- fast_window · [fast EMA window]
- Set the responsive trend estimate.
- slow_window · [slow EMA window]
- Set the broader reference and keep it above the fast window.
Use the output
- spread
- Hold long while spread is above [positive buffer], short while below [negative buffer], and otherwise flat.
Moving-Average Slope
Direction-quality check
Slope checks whether the smoothed level is actually rising or falling rather than merely remaining on one side after an old crossover.
Configure
- window · [slope average window]
- Choose which trend level is being differentiated.
- slope_lookback · [slope comparison span]
- Control how much change is required before the slope is meaningful.
Use the output
- slope
- Require slope above [positive threshold] for long or below [negative threshold] for short.
Volatility Regime
Risk-state gate
Volatility Regime can keep the persistent trend rule out of states where the declared execution and risk assumptions no longer apply.
Configure
- high_z_threshold · [high-volatility threshold]
- Define the state in which exposure is reduced or blocked.
- low_z_threshold · [low-volatility threshold]
- Define the low-volatility state separately from normal conditions.
Use the output
- volatility_regime
- Apply [normal/low/high regime policy] without using the regime label as direction.
Assemble the rule
- Entry
- Enter when the EMA spread and slope agree and the volatility state is eligible.
- Exit
- Exit when spread returns inside the neutral buffer, slope loses agreement, or the volatility policy forces de-risking.
- Decision time
- Evaluate state only on completed bars and apply any change at the next permitted decision event.
- Sizing
- Use [fixed or volatility-aware sizing] with the same cap across every window comparison.
Useful variations
- Compare zero-spread state with a symmetric neutral buffer.
- Require slope agreement at entry only versus throughout the position.
- Treat high volatility as flat in one variant and reduced size in another.
Keep in view
EMA spread and moving-average slope are related transformations of the same prices. Agreement can reduce noise, but it is not independent evidence and may increase lag materially.
Ask the AI Companion
Draft this strategy
Turn a moving-average crossover idea into a simple draft with each choice explained in ordinary language.
I want to use moving averages to trade meaningful changes in direction in [instrument]. Recommend a sensible starting setup, including the type of moving-average rule, the timeframe, and how responsive the averages should be, and then build that strategy for me. Include appropriate filtering and risk controls, and explain how your design balances responding to a new trend against reacting to ordinary price noise.
Extend it in Marimo
Begin from a retained Study so crossover candidates and parameter neighborhoods remain traceable.
Show how event-driven and state-driven moving-average rules trade off lag, state duration, and clustered whipsaw.
- Bring in
- engine-reported averages, spreads, crossing flags, ADX/DMI, slope, ATR, and volatility state, decision and fill timestamps, positions, turnover, costs, and candidate identifiers
- Build
- price-and-average chart with decision-time cross markers, spread, slope, and strength alignment timeline, whipsaw-cluster table with state duration, turnover, and net outcomes
Interpretation: Inspect whether a slower or more filtered rule genuinely handles ranges better or merely trades less and enters later. Compare exposure time as well as return statistics.
Value origin: Averages, signal outputs, orders, fills, costs, and retained results are engine-reported. Whipsaw clusters, lag intervals, and custom state-duration summaries are notebook-derived.
With Companion: Ask Companion for a reviewed cell set that preserves event timestamps and compares the displayed recipes, then inspect and explicitly apply the diff.
Further reading
- Brock, Lakonishok, and LeBaron, “Simple Technical Trading Rules and the Stochastic Properties of Stock Returns” (1992) — Tests 26 moving-average and trading-range rules on the DJIA from 1897–1986 using several bootstrap null models. It is the historical benchmark for declared rule tests, not clean out-of-sample or cost-adjusted validation.
- Bajgrowicz and Scaillet, “Technical Trading Revisited: False Discoveries, Persistence Tests, and Transaction Costs” (2012) — Re-examines 7,846 technical rules on the DJIA through 2011 and finds that apparent historical winners were not reliably selectable in advance and were offset by low transaction costs in that market and sample.
- Marshall, Nguyen, and Visaltanachoti, “Time Series Momentum and Moving Average Trading Rules” (2017) — Directly compares trailing-return momentum with moving-average rules and shows why closely related constructions can generate signals at different times. Its reported return advantage remains sample-dependent.
- Zakamulin and Giner, “Trend Following with Momentum versus Moving Averages: A Tale of Differences” (2020) — Expresses momentum, SMA, linear-average, and EMA rules as different return-weighting schemes, clarifying their similarity, lag, and parameter sensitivity. Its conclusions depend on an autoregressive model and a specific empirical design.