Moving-Average Alignment Plus Volume: Turning a Classic Setup into One Complete, Backtestable Buy Rule
Moving-average alignment on its own is a description of a trend, not a buy rule. To turn it into something you can backtest and execute mechanically every day, you need to add three things: a volume confirmation (today's volume at least 1.5 times the 20-day average), a "don't chase" guard (price no more than 8% above the 20-day MA, RSI below 70), and an exit written before you buy (a close below the 20-day MA, or a floating loss above 6%).
Key takeaways
- Bullish alignment means the short MA is above the medium, the medium above the long, and price above the MAs — for example MA5 > MA20 > MA50 with price > MA20. It confirms direction; it does not time an entry.
- Alignment alone produces signals that are late and frequent: MAs lag, so alignment appears after much of the move, and once true it stays true for weeks, flagging the stock every day.
- A volume confirmation (vol_vs_avg20d > 1.5) turns a continuous state into a handful of discrete trigger days and demands real money behind the move.
- Guards (price_vs_ma20 < 8, rsi < 70) drop entries that are already extended and would carry an oversized stop.
- The exit belongs in the rule from day one: a close below MA20 (price_vs_ma20 < 0) or a floating loss above 6% (floating_loss_pct > 6), whichever comes first.
What alignment says, and why it is not enough
A moving average is the average close over the last N days: MA5 is roughly a week, MA20 a month, MA50 a quarter. MA5 > MA20 > MA50 with price above MA20 means recent buyers paid more on average than buyers a month ago, who paid more than buyers a quarter ago — the market has kept paying up. It describes a state, not a change: it says "this is an uptrend," not "this is a good moment to get in."
Used alone, it has two problems.
Late. Moving averages lag. By the time MA20 crosses above MA50, price has usually risen 10%–20% off the low. You are buying the middle of the trend, not the start. That is fine, but your stop is further away and your remaining upside smaller than you might assume.
Noisy. Alignment is a persistent condition; a stock may satisfy it for 30 or 60 consecutive sessions. If your buy rule is only "alignment is true," the scanner lists the stock every day. Either you buy a little each day (that is averaging in, not a signal) or you pick a day by feel (which makes the rule pointless). In a backtest, such rules typically show a very large trade count with tiny average gains, and fees eat most of it.
What alignment lacks is a trigger event that converts a continuous state into discrete entry points.
Add a volume confirmation
Volume is the simplest trigger. Require vol_vs_avg20d above 1.5 — today's volume is at least 1.5 times the 20-day average.
This does two jobs. First, within a stretch of alignment, days with 1.5x volume are a minority, so the trigger rate drops immediately. Second, it demands real participation: a rise on thin volume may only mean nobody is selling, while a rise on heavy volume means someone is willing to buy size at this price, and that is more likely to continue.
The 1.5 threshold is a compromise. Too low (1.2) filters almost nothing; too high (3) leaves only news-driven extremes, exactly the days where chasing hurts most. Test 1.3–2.0 in a backtest.
Add a "not already extended" guard
High-volume days come in two kinds: an acceleration in the middle of a trend, and the final surge at its end. The most reliable way to tell them apart is distance from the moving average.
price_vs_ma20 < 8: price no more than 8% above MA20. Your exit is a close below MA20; if you enter 15% above it, your stop distance is 15%. Capping entries at 8% caps the theoretical stop near 8%, which is what makes the 6% floating-loss backstop below coherent.
rsi < 70: a 14-day RSI above 70 usually means the last two weeks ran too fast, and heavy volume there is more likely the last buyers rushing in. It overlaps with price_vs_ma20 but looks at a different window; the pair is sturdier than either alone.
Add one market filter: market_index_vs_ma50_pct > 0, requiring the stock's home index to be above its own 50-day MA. Individual alignments fail far more often when the broad market is falling, and this line removes counter-market signals outright.
Write the exit before you buy
The exit has two doors; whichever opens first is the one you use:
- price_vs_ma20 < 0: a close below the 20-day MA. The logic of alignment is "price above MA20." When that breaks, the reason you bought is gone.
- floating_loss_pct > 6: a floating loss above 6%. This is the fuse, protecting you when MA20 is far away or the stock gaps down.
These are OR conditions and must live in separate groups. Written as AND, the rule would wait for both a break of MA20 and a loss over 6%, which is usually far too late. For why exits have to be written in advance, and why they are so hard to execute, see the stop-loss you can't execute.
Large cap versus volatile small cap
Every number in the rule carries an implicit assumption about volatility.
An index-following large cap (a major HK bank, a mega-cap US tech name): daily moves are mostly 1%–2% and price stays within about 5% of MA20. Here 1.5x volume is a meaningful event, and a 6% backstop equals roughly three to four days of normal movement, so noise rarely trips it. The rule can be used more or less as written.
A volatile small cap: 4%–5% daily moves are common, and three things break. 1.5x volume happens almost weekly, so the threshold may need to be 2.0 or higher. A 6% floating loss is barely more than one day of normal movement, so you may need to widen it to 10% and shrink position size to match. And price_vs_ma20 < 8 is too strict, because these stocks often run 10% or more above MA20 in a perfectly healthy trend.
The conclusion: check the stock's atr14_pct first, then choose the parameter set. Size the position from the stop distance, as described in position sizing.
One complete example (illustrative numbers)
Take a hypothetical HK large cap. All figures below are illustrative and do not describe any real stock.
| Item | Value |
|---|---|
| Today's close | 52.80 |
| MA5 / MA20 / MA50 | 51.90 / 50.20 / 47.60 |
| price_vs_ma20 | +5.2% |
| Today's volume / 20-day average | 28.0M / 16.0M shares → vol_vs_avg20d = 1.75 |
| RSI(14) | 63 |
| Hang Seng vs its MA50 | +2.4% |
Check each line: MA5 > MA20 > MA50 holds; price is 5.2% above MA20, between 0 and 8; volume is 1.75x; RSI is 63; the index is above its 50-day MA. All seven conditions pass and the rule fires a buy signal today.
Entry at 52.80. Both exits are live at once: MA20 is at 50.20, so a break is about -4.9%; the 6% backstop sits at 49.63. The MA20 line is the binding one for now, and it rises as the average rises.
A contrast: two days later, price is 55.00 and MA20 has moved to 50.60, so price_vs_ma20 = +8.7%. Alignment and volume may both still be true, but the guard fails and the rule stays silent. Same move, two days later, and the stop distance has grown from 4.9% to 8.7% — exactly what the guard is for.
Playing it forward (still illustrative): eight sessions later price is 57.10, an 8.1% floating gain, and MA20 has climbed to 51.40. Then a pullback: one day closes at 50.90 while MA20 has reached 52.00, so price_vs_ma20 = -2.1%. The exit triggers, and the trade closes at about -3.6%. It lost money, but the loss stayed inside the range the rule defined in advance. A complete rule does not promise to be right each time, only that each outcome falls within a range you accepted beforehand.
How to set this up in Stock Compass
Below is the full buy + exit strategy, ready to paste. Stock Compass does not connect to a broker or place orders; it scans your own watchlist against these conditions each day and lists what qualifies.
{
"name": "均线多头排列 + 放量",
"market": "hk",
"rules": {
"buy": {
"v": 2,
"outerOp": "OR",
"groups": [
{
"innerOp": "AND",
"conditions": [
{ "indicator": "ma5_above_ma20", "operator": "==", "value": 1 },
{ "indicator": "ma20_above_ma50", "operator": "==", "value": 1 },
{ "indicator": "price_vs_ma20", "operator": ">", "value": 0 },
{ "indicator": "price_vs_ma20", "operator": "<", "value": 8 },
{ "indicator": "vol_vs_avg20d", "operator": ">", "value": 1.5 },
{ "indicator": "rsi", "operator": "<", "value": 70 },
{ "indicator": "market_index_vs_ma50_pct", "operator": ">", "value": 0 }
]
}
]
},
"add": { "v": 2, "outerOp": "OR", "groups": [] },
"trim": { "v": 2, "outerOp": "OR", "groups": [] },
"exit": {
"v": 2,
"outerOp": "OR",
"groups": [
{
"innerOp": "AND",
"conditions": [
{ "indicator": "price_vs_ma20", "operator": "<", "value": 0 }
]
},
{
"innerOp": "AND",
"conditions": [
{ "indicator": "floating_loss_pct", "operator": ">", "value": 6 }
]
}
]
}
}
}
What each line means:
- ma5_above_ma20 == 1: the 5-day MA is above the 20-day MA (booleans use == 1).
- ma20_above_ma50 == 1: the 20-day MA is above the 50-day MA. Together these give MA5 > MA20 > MA50.
- price_vs_ma20 > 0: the close is above the 20-day MA.
- price_vs_ma20 < 8: but no more than 8% above it, to stop you chasing.
- vol_vs_avg20d > 1.5: today's volume exceeds 1.5 times the 20-day average.
- rsi < 70: 14-day RSI has not entered the overbought zone.
- market_index_vs_ma50_pct > 0: the home market index is above its 50-day MA.
- Exit group one, price_vs_ma20 < 0: a close below the 20-day MA.
- Exit group two, floating_loss_pct > 6: a floating loss above 6%. The two groups are joined by OR; either one triggers the exit.
Once saved, backtest it before you use it: look at trade count, win rate, average gain and loss, and maximum drawdown, then decide whether to adjust thresholds.
Common mistakes
- Treating alignment itself as the signal. Without a volume trigger the rule fires every day, and the backtest shows a huge trade count with wafer-thin average gains.
- Writing the two exits as AND. They must be two separate groups (OR). As AND, the exit arrives far too late.
- Dropping the guard. Entering on volume 15% above MA20 puts the stop distance over budget before the trade even starts.
- One parameter set for every stock. Small caps need a higher volume threshold, a wider stop, and a smaller position.
- Counting buy signals but ignoring exit execution. Half of the rule's value is in the exit; in backtests and live trading alike, check whether exits were actually taken as written.
Summary
Bullish moving-average alignment describes a trend state, not an entry moment. To make it a complete buy rule, add three things: a volume trigger (vol_vs_avg20d > 1.5) that turns a continuous signal into discrete ones; guards (price_vs_ma20 < 8, rsi < 70, index above its 50-day MA) that remove extended and counter-market entries; and two OR-joined exits (a break of MA20, or a floating loss over 6%). The numbers are not sacred — a large cap can use them as written, a small cap needs them scaled to its volatility — but every number must be written down, backtested, and executed mechanically each day. For more examples of translating spoken logic into conditions, see turning logic into buy rules.
FAQ
Which moving averages should I use for bullish alignment?
MA5, MA20 and MA50 are a common daily-chart set: about a week, a month and a quarter. Stock Compass exposes ma5_above_ma20, ma10_above_ma20, ma20_above_ma30 and ma20_above_ma50, so you can also build MA10 > MA20 > MA30 for a shorter-term version. Whatever you choose, keep the same set for the exit rule so entry and exit describe the same trend.
Why 1.5 times the 20-day average volume and not some other number?
It is a starting point, not a law. Below about 1.2 the filter removes almost nothing; above about 3 you keep only extreme, news-driven days that are often the worst moment to enter. For most large caps 1.5 marks a genuinely busier-than-usual session. For volatile small caps, where 1.5x happens almost weekly, test 2.0 or higher in a backtest.
Does the rule need both the MA20 exit and the 6% floating-loss exit?
Yes, as two separate OR groups. The MA20 exit follows the trend and rises as the average rises; the 6% line is a fixed fuse for the cases where MA20 is far below entry or the stock gaps down overnight. On most trades the MA20 line triggers first. If you write them as a single AND group the rule waits for both, which usually means a much bigger loss.
Can I use the same rule on US and A-share stocks?
The indicator ids are identical across markets; only the market field and the index behind market_index_vs_ma50_pct change. What differs in practice is volatility and trading costs. Check atr14_pct for each stock before choosing the floating-loss threshold, and remember that daily price limits in the A-share market can delay an exit past the level you intended.
Does Stock Compass buy the stock for me when the rule fires?
No. Stock Compass does not connect to a broker or place orders. It scans your own watchlist against the conditions you saved and shows which stocks qualify today, plus which holdings have hit an exit condition. Whether to act, and how much to buy, remains your decision — position sizing is covered in a separate guide.