Guide · Trading

VCP and bases, described honestly

A base is a pause in a trend where shares change hands. A volatility contraction pattern is a base whose swings get progressively smaller. The structure is real and easy to see. Whether it pays is a separate question, and my own testing says it roughly did not.


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 typeTypical depthTypical durationDefining featureWhere the pivot sits
Flat base10% to 15%5 to 12 weeksShallow, boxy, very little downside slope. Usually forms after a prior breakout has already runThe high of the box
Cup20% to 35%6 to 26 weeksRounded, gradual descent and recovery. A V-shape is not a cup — the rounding is the pointThe left-side high
Cup with handleCup 20% to 35%, handle 8% to 12%7 to 30+ weeksA short downward drift in the upper half of the cup that shakes out weak holders near the highsThe high of the handle
Double bottom20% to 40%7 weeks and upTwo lows with a middle peak, where the second low undercuts the first before recoveringThe middle peak
Ascending baseThree pullbacks of roughly 10% to 20% each9 to 16 weeksA staircase of higher lows through a corrective marketThe high of the third pullback
VCPWhatever the widest contraction isVariableSuccessively shallower pullbacks, each roughly half the previous depthThe 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:

ContractionHighLowDepthReading
T1100.0082.0018.0%First shakeout, widest
T297.0088.309.0%Roughly half of T1
T396.0091.704.5%Roughly half of T2
Pivot96.00Break 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.

LegHighLowDepthAvg volume in the legvs 50-day average
T1$84.50$71.8315.0%2.60M144% — heavy, this is the shakeout
T2$82.10$75.538.0%1.50M83% — participation falling
T3$81.40$78.144.0%0.86M48% — volume dry-up, 52% under average
Breakout3.90M on the pivot day217% — 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.

BufferEntry1R per shareShares at $300 riskR to the $91.00 targetCost vs no buffer
0.00%$81.40$3.50852.74R
0.25%$81.60$3.70812.54R−0.20R
0.50%$81.81$3.91762.35R−0.39R
1.00%$82.21$4.31692.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 modeWhat happensThe tell, before it happens
Undercut and rallyPrice breaks the final low, stops out the obvious holders, then reverses back upThe final contraction's low sits exactly on an obvious prior low that every chart reader can see
Breakout on no volumePivot clears, drifts a few percent, rolls back into the baseBreakout-day volume under about 150% of the 50-day average, with no expansion in the last hour
Wide and looseThe base never actually contracts and the 'pattern' is just a rangeT2 is not at least 25% tighter than T1. If the ratio is 0.9, it is a range
Late-stage failureA textbook base fails immediately after an extended advanceThird or fourth base since the stock left its downtrend, with the base wider than the one before it
Supply overheadBreakout stalls into a shelf of trapped buyers a few percent upA high volume node just above the pivot on the profile, or a prior gap-down level nearby
Drawn to fitThe contractions only exist because you know the outcomeYou 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.

SetupWalk-forward resultVerdict
AVWAP reclaim+0.117R over 4,933 trades on a 129-symbol, 10-year universe, 95% CI +0.057 to +0.174Kept, 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 contractionRoughly breakevenNot traded mechanically
Gap / opening-range-breakout proxy−0.28RDropped
Retired: AVWAP reclaim, first passRoughly twice the row above, on ~100 hand-picked tradesRetired: 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

  1. 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.
  2. 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.
  3. 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.
  4. Treat late-stage bases as a smaller size category, not a normal one, and treat the reason as unverified rather than settled.
  5. 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.
  6. Keep the negative results. A pattern that tests breakeven is information, and it stops you paying for it twice.
  7. 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.

FAQ

Quick answers

What is a VCP in trading?

A volatility contraction pattern is a consolidation in which each successive pullback is shallower than the one before it, typically two to four contractions with each roughly half the depth of the previous. The idea is that supply is being exhausted in measurable steps, so fewer sellers appear at each dip. It is a description of how a range behaves rather than a specific chart shape, so a cup with handle or a flat base can also be a VCP.

How do you count contractions in a base?

Measure each pullback from its local high to its local low as a percentage. A base going 18%, then 9%, then 4.5% is a three-contraction base, usually written 3T. Two to four contractions is normal; if you are counting six, you are almost certainly drawing what you want to see. A workable mechanical rule is that each leg must be at least 25% tighter than the one before it.

What is volume dry-up?

Volume dry-up is the drop in traded volume toward the right edge of a base, often 30% to 50% below the 50-day average during the final contraction. A shallow pullback on very light volume suggests little supply remains, whereas a shallow pullback on heavy volume means sellers are still active and merely being absorbed. In a clean base the depth and the volume fall together, leg by leg.

Where is the buy point in a VCP?

The pivot is the high of the final contraction, and the mechanical entry is a break above it on volume expanding above average. The stop belongs below the low of that final contraction, which makes the structure define the risk and therefore the position size. Any buffer above the pivot should be priced, not assumed.

How much buffer should you add above the pivot?

Price it before you choose it. On a pivot at 81.40 with a stop at 77.90 and a target at 91.00, entering at the pivot gives 2.74R while a 1% buffer gives 2.04R, so the buffer costs 0.70R on every winner and about 19% of the share count. A buffer only pays if it filters out more false breakouts than that cost, which is a testable question rather than a matter of taste.

What are base stages and do late-stage bases fail more?

Stage counting starts at the first base after a stock leaves a correction or downtrend, and increments with each subsequent base. The conventional claim is that third and fourth stage bases fail more often because the move is widely recognised and the accumulation is complete. The mechanism is plausible but I have not measured it on my own universe, so treat it as a cheap precaution rather than a verified statistic.

Why do base breakouts fail?

The common failures are an undercut of the final low that stops out obvious holders before reversing, a breakout on below-average volume that rolls back into the base, a base that never truly contracted, and overhead supply sitting a few percent above the pivot. The largest failure mode is retrospective drawing, since contractions are easy to find on any chart that already went up.

Does the VCP pattern actually work?

In my own walk-forward testing a VCP-style contraction setup came out roughly breakeven, meaning no edge worth sizing after costs. The anchored-VWAP reclaim was the only setup that was not eliminated, at +0.117R over 4,933 trades on a 129-symbol, 10-year universe with a 95% confidence interval of +0.057 to +0.174 - but a risk-matched random entry already captured +0.086R on the same data, so the signal's own contribution is about +0.030R with a confidence interval crossing zero, which is not a validated edge. An earlier, roughly double figure measured over barely a hundred hand-picked trades failed adversarial re-testing and is retired. A gap and opening-range-breakout proxy came out at -0.28R and was dropped. These are backtest results, not live trading claims.