What is a base?
A base is a sideways or corrective range that interrupts a prior advance. Mechanically it is a transfer: holders who bought lower and want out sell into buyers who are willing to pay today's price. The range persists until one side runs out of inventory or patience.
Three things describe any base and you should be able to state all three before calling something a base:
- Depth — the percentage from the high of the base to its lowest low. A 12% base and a 45% base are not the same object.
- Duration — how many bars or weeks the range has lasted. Short bases after a long advance are usually late-stage.
- Prior trend — a base only means anything after an advance. A sideways range after a nine-month decline is a downtrend resting.
The base-type taxonomy
"Base" is a family, not a shape. The conventional depth and duration ranges below come from the published O'Neil and Minervini literature rather than from my own measurements, and I have flagged them that way deliberately — they are the definitions people use, not results I have verified on my universe.
| Base type | Typical depth | Typical duration | Defining feature | Where the pivot sits |
| Flat base | 10% to 15% | 5 to 12 weeks | Shallow, boxy, very little downside slope. Usually forms after a prior breakout has already run | The high of the box |
| Cup | 20% to 35% | 6 to 26 weeks | Rounded, gradual descent and recovery. A V-shape is not a cup — the rounding is the point | The left-side high |
| Cup with handle | Cup 20% to 35%, handle 8% to 12% | 7 to 30+ weeks | A short downward drift in the upper half of the cup that shakes out weak holders near the highs | The high of the handle |
| Double bottom | 20% to 40% | 7 weeks and up | Two lows with a middle peak, where the second low undercuts the first before recovering | The middle peak |
| Ascending base | Three pullbacks of roughly 10% to 20% each | 9 to 16 weeks | A staircase of higher lows through a corrective market | The high of the third pullback |
| VCP | Whatever the widest contraction is | Variable | Successively shallower pullbacks, each roughly half the previous depth | The high of the final contraction |
The VCP is orthogonal to the rest of that list rather than a competitor to it. A cup with handle whose handle is meaningfully tighter than the cup's right side is a two-contraction VCP. A flat base that tightens from 14% to 7% to 3.5% is a three-contraction VCP that happens to fit inside a box. Treat VCP as a description of how the range behaves, and the taxonomy above as a description of what shape it draws.
What makes it a VCP
The volatility contraction pattern, popularised by Mark Minervini, is a base in which each successive pullback is smaller than the one before it. The idea is that supply is being exhausted in measurable steps: fewer sellers appear at each pullback, so each dip gets shallower.
A worked count on a hypothetical base:
| Contraction | High | Low | Depth | Reading |
| T1 | 100.00 | 82.00 | 18.0% | First shakeout, widest |
| T2 | 97.00 | 88.30 | 9.0% | Roughly half of T1 |
| T3 | 96.00 | 91.70 | 4.5% | Roughly half of T2 |
| Pivot | 96.00 | — | — | Break above the T3 high |
That is a 3T base: three contractions, each about half the previous depth. Two to four contractions is the usual count. More than five and you are almost certainly drawing the ones you want to see.
A second count, with the volume attached
The first example is clean because I made it clean. Here is a fuller one with the volume figures, which is the half most write-ups leave out. Assume a 50-day average volume of 1.80M shares and a nine-week base.
| Leg | High | Low | Depth | Avg volume in the leg | vs 50-day average |
| T1 | $84.50 | $71.83 | 15.0% | 2.60M | 144% — heavy, this is the shakeout |
| T2 | $82.10 | $75.53 | 8.0% | 1.50M | 83% — participation falling |
| T3 | $81.40 | $78.14 | 4.0% | 0.86M | 48% — volume dry-up, 52% under average |
| Breakout | — | — | — | 3.90M on the pivot day | 217% — expansion confirms the move |
Depth halves each leg (15.0, 8.0, 4.0) and volume falls monotonically with it (144%, 83%, 48%). That co-movement is what a real contraction looks like. If T3 were 4% deep on 130% of average volume, the price side would still qualify and the pattern would still be wrong, because plenty of stock is still changing hands at that level — it is being absorbed today, not exhausted.
Volume dry-up
The volume side of the pattern matters as much as the price side. Through a genuine contraction, volume should fall away toward the right edge of the base. The shorthand is VDU, volume dry-up: the final contraction trades on notably below-average volume, often 30% to 50% under the 50-day average.
The reasoning is straightforward. If the last pullback is shallow and almost nobody traded it, there is very little supply left at that price. A shallow pullback on heavy volume says the opposite: plenty of people are still selling, they are just being absorbed for now.
This is also where a volume profile earns its keep, because it answers the question a daily volume histogram cannot: at which prices inside the base did the inventory accumulate. A base whose point of control sits near its lows has most of its supply below the pivot. A base whose point of control sits just under the pivot has a wall of recent buyers who will be roughly flat on a small pullback, and flat holders sell.
Base stages, and why late ones fail
Stage counting starts at the first base that forms after a stock emerges from a correction or a downtrend. That is stage one. The base that forms after the stage-one breakout has run and consolidated is stage two, and so on. The count resets when the stock undercuts its prior base low or the general market takes a real correction.
- Stage 1 — the least crowded. Few people are watching, the move has not been written about, and the institutional accumulation that drives the eventual advance is often still incomplete.
- Stage 2 — still reasonable. The trend is established, which is a genuine positive, and the pattern is not yet obvious to everyone.
- Stage 3 — deteriorating. The story is known, the chart is in newsletters, and the buyers who were going to buy have largely bought.
- Stage 4 and beyond — routinely late. Bases here tend to be wider and looser, because the supply arriving is from holders taking profits rather than from weak hands being shaken out.
The stage-failure claim is conventional wisdom that I have not measured on my own universe, and I am not going to present borrowed statistics as though they were mine. The mechanism is plausible and the rule is cheap to follow — treat late-stage bases as a smaller size category. But if it matters to your process, tag base stage in your journal and compute your own expectancy per stage rather than trusting the folklore or trusting me.
The pivot, the buffer, and what a buffer costs
The pivot is the high of the final contraction. The mechanical entry is a break above it, ideally on volume expanding well above average, because a breakout without volume is a price move without participation.
Entry = pivot + small buffer
Stop = below the low of the final contraction
1R = entry − stop
Size = (account × risk %) ÷ 1R
Note the ordering. The structure defines the stop, the stop defines 1R, and 1R defines the size. Tight final contractions are attractive precisely because they make 1R small, which lets you take a normal-sized position without oversizing risk. The arithmetic is in the R-multiple guide and the sizing mechanics in position sizing per trade.
The buffer question — how far above the pivot to trigger — gets argued about constantly and almost never quantified. It is quantifiable. Take the second worked base above: pivot $81.40, stop $77.90, a $300 risk budget, and an illustrative target of $91.00 at the prior structural high.
| Buffer | Entry | 1R per share | Shares at $300 risk | R to the $91.00 target | Cost vs no buffer |
| 0.00% | $81.40 | $3.50 | 85 | 2.74R | — |
| 0.25% | $81.60 | $3.70 | 81 | 2.54R | −0.20R |
| 0.50% | $81.81 | $3.91 | 76 | 2.35R | −0.39R |
| 1.00% | $82.21 | $4.31 | 69 | 2.04R | −0.70R |
A 1% buffer costs 0.70R on every winner and 19% of the share count. That is not a rounding error, it is most of a typical edge. The buffer is therefore a filter with a priced ticket: it only pays if it removes enough one-tick pokes that would have become −1R losses to cover 0.70R on everything it lets through. At an illustrative 40% win rate, a 0.25% buffer costs 0.40 × 0.20R = 0.08R per trade taken, so it needs to convert roughly 8% of your would-be trades from −1R into no-trade just to break even.
I do not have a measured answer to whether it does. Neither does anyone quoting a buffer at you. The point of writing it this way is that it turns a preference into a testable number, and a testable number is the only kind that can ever be settled.
Encoding it mechanically
If a pattern cannot be written down as code, it cannot be tested, and if it cannot be tested you are trading a story. Here is a workable encoding — deliberately blunt, because a definition with six tunable knobs will fit anything you point it at:
def contractions(bars, avg_vol_50):
swings = zigzag(bars, pct=3.0) # local highs and lows, 3% threshold
legs = pairs(swings) # [(high, low), ...] most recent last
depths = [(h - l) / h for h, l in legs]
n_ok = 2 <= len(depths) <= 4
tighten = all(depths[i+1] < depths[i] * 0.75
for i in range(len(depths) - 1))
vdu = mean(vol_in_leg(legs[-1])) < 0.70 * avg_vol_50
pivot = legs[-1][0]
return (n_ok and tighten and vdu), pivot
Every constant in that block is a place to overfit: the 3% zigzag threshold, the 0.75 tightening ratio, the 0.70 VDU ratio, the 2-to-4 leg count. Four knobs on a few thousand trades will find something, which is exactly the failure the backtest overfitting guide is about. Fix the constants from the literature before you run anything, and if you must tune them, tune on one slice and test on another.
Failure modes and the tell that precedes each
| Failure mode | What happens | The tell, before it happens |
| Undercut and rally | Price breaks the final low, stops out the obvious holders, then reverses back up | The final contraction's low sits exactly on an obvious prior low that every chart reader can see |
| Breakout on no volume | Pivot clears, drifts a few percent, rolls back into the base | Breakout-day volume under about 150% of the 50-day average, with no expansion in the last hour |
| Wide and loose | The base never actually contracts and the 'pattern' is just a range | T2 is not at least 25% tighter than T1. If the ratio is 0.9, it is a range |
| Late-stage failure | A textbook base fails immediately after an extended advance | Third or fourth base since the stock left its downtrend, with the base wider than the one before it |
| Supply overhead | Breakout stalls into a shelf of trapped buyers a few percent up | A high volume node just above the pivot on the profile, or a prior gap-down level nearby |
| Drawn to fit | The contractions only exist because you know the outcome | You found the base by looking at a chart that had already broken out |
The last row is not a joke and it is not rare. It is the dominant failure mode in every pattern-based method, and the only defence is to define the pattern before you look at the outcome, then apply the definition mechanically to a universe you did not choose after the fact.
What my own testing said
This is the part most write-ups omit. I built a screener and a no-lookahead backtest engine, then ran my swing setups through walk-forward testing rather than an in-sample fit. The VCP-style contraction setup came out roughly breakeven. Not a disaster, not an edge — after costs there was nothing there worth sizing.
| Setup | Walk-forward result | Verdict |
| AVWAP reclaim | +0.117R over 4,933 trades on a 129-symbol, 10-year universe, 95% CI +0.057 to +0.174 | Kept, but not a validated edge. A risk-matched random entry captured +0.086R on the same data, so the signal's own contribution is about +0.030R with a confidence interval that crosses zero |
| VCP-style contraction | Roughly breakeven | Not traded mechanically |
| Gap / opening-range-breakout proxy | −0.28R | Dropped |
| Retired: AVWAP reclaim, first pass | Roughly twice the row above, on ~100 hand-picked trades | Retired: failed my own adversarial re-test. The number itself is withdrawn so nobody quotes it back at me as a result |
Read the top row carefully, because it is the one that gets misquoted. The +0.117R is real and the confidence interval excludes zero, but a risk-matched random entry on the same universe already produced +0.086R. That residual is not a business, and it is not something I would size against. The setup survived in the sense that it was not eliminated; it did not survive in the sense of being proven.
Breakeven does not mean the pattern is fake. It means my mechanical encoding of it, on my universe, over my test window, did not produce an edge. Discretionary traders who read context, liquidity, and market environment may do better. But if you cannot express a setup mechanically, you also cannot prove it works, and the honest position is to say so rather than to sell the ambiguity.
Two filters I expected to rescue it — a market-regime filter and a normalised-momentum-lag filter — were tested on the same data and cut expectancy, so both were rejected. That is worth dwelling on: the two most obvious improvements made it worse, which is the usual outcome and the reason adding filters to a losing setup is not a plan. How the testing was run →
How to use bases anyway
- Use the structure for risk definition, which it is genuinely good at. The final contraction gives you a tight, non-arbitrary invalidation, and that is the whole subject of the stop loss placement guide.
- Do not use the structure as a standalone edge claim until you have tested your version of it on your universe. Mine tested breakeven; yours might not, and that is exactly the point.
- Tag every base trade with base type, contraction count, base stage, and whether VDU was present, then compute expectancy per tag after 30-plus trades. TradeLog does this offline and locally.
- Treat late-stage bases as a smaller size category, not a normal one, and treat the reason as unverified rather than settled.
- Pair the pattern with something that carries independent information — a cost-basis anchor or a profile level — rather than stacking three variations of the same price observation.
- Keep the negative results. A pattern that tests breakeven is information, and it stops you paying for it twice.
- If a term here was unfamiliar, the glossary has short definitions for pivot, POC, VDU, and R.
Educational content, not financial advice. No live profit-and-loss figures are claimed anywhere on this site; backtest and walk-forward results are always labelled as such. Full terms: /terms.html
Tools referenced in this guide
- Swing Screener — the screener and no-lookahead backtest engine behind the walk-forward results.
- TradeLog — tag base trades by contraction count and get expectancy per tag, offline and local.
- Walk-forward testing guide — why in-sample pattern studies flatter every chart pattern.