Idea in brief
Qullamaggie trades stocks that have already risen sharply. The rise comes in steps: a move, a pause, a move. The task is to buy at the start of the next step. The stock has gained 30-100% in one to three months, then spends two weeks to two months building a base: lows rise, the range narrows, volume dries up, price holds on rising 10- and 20-day averages. On the breakout day, Qullamaggie buys through the high of the first 1-, 5- or 60-minute candle and places the stop at the low of the day.
The stop should be no wider than the stock's average daily range (ADR or ATR), ideally a third or half of it. After 3-5 days, a third to a half of the position is sold, the stop moves to breakeven, and the rest is held until the first close below the 10-day average. The win rate is low, and the money comes from rare trades that make dozens of times the risk.
Both parts of the source are retellings by Jack Corsellis: a breakdown of the strategy and a separate video on scanning and execution. Stock selection across the whole universe is moved to a separate rule at the end of the "Rules" section. The signal is described for a single stock.
Why it might work
The authors explain it through momentum and demand. A stock that has risen more than the market attracts buyers, and after a pause the move often continues. A tight base on falling volume means there are few sellers. A short narrow candle before the breakout gives a close stop, so the trade is asymmetric from the start: the risk is a fraction of ADR, the potential is several ADRs.
The NASDAQ regime filter rests on the observation that breakouts work en masse during periods of broad market growth. According to Qullamaggie, every year has three to six months when the method makes almost nothing, and then it is better to sit in cash.
All result figures belong to Qullamaggie and Jack. They cannot be verified from statements, and Jack's study was done in hindsight on breakouts picked by eye.
Rules
Market regime (author)
// daily bars of the NASDAQ Composite
N10 = EMA(NasdaqClose, 10)
N20 = EMA(NasdaqClose, 20)
N50 = SMA(NasdaqClose, 50)
// the author talks about the 10- and 20-day average without naming the type. Finetiq: EMA, as Jack uses
RegimeOK = N10 > N20 AND N10 > N10[1] AND N20 > N20[1] // ideally also N20 > N50
RegimeOff = N10 < N20 AND N10 < N10[1] AND N20 < N20[1] // author: high failure rate, do not trade long
// Finetiq: new entries only when RegimeOK
// community (Jack): NASDAQ monthly close above the monthly 10-period average
// Jack calls it EMA 10, the line on Jack's Excel chart is an SMA (index-ema-regime). Test both
Setup on a single stock
ADRpct = 100 * (Average(High / Low, 20) - 1)
// author: average daily range in % over 20 days without gaps; Finetiq: formula
BaseHigh = Highest(High, 60)
BaseLen = number of bars after the BaseHigh bar
Rally = BaseHigh / (low over the 60 bars before the BaseHigh bar) - 1
BigMove = Rally >= 30% // author: 30-100% or more in 1-3 months
BaseOK = BaseLen >= 10 AND BaseLen <= 40 // author: base from 2 weeks to 2 months
HigherLows = low of the second half of the base > low of the first half // author: higher lows; Finetiq: method
Surf = Close > EMA(Close, 20) on at least 80% of base bars
AND Close > SMA(Close, 50) // author: base on rising 10/20, sometimes 50; almost never buys below the 50-day
// Finetiq: 80%
Tight = High - Low < 0.5 * Average(High - Low, 20) // author: narrow trigger bar; Finetiq: threshold
DryUp = Volume < Average(Volume, 30) // author: volume dries up; Finetiq: comparison with the 30-day average
Setup = BigMove AND BaseOK AND HigherLows AND Surf AND Tight AND DryUp
Pivot = High of the trigger bar // community (Jack): the high of the last narrow candle
// variant for testing: Pivot = BaseHigh
Entry and stop (author)
// the day after Setup, intraday data
IF RegimeOK
ORH = High of the first N-minute candle, N = 1, 5 or 60 // the first 60-minute candle is effectively 30 minutes long
BUY STOP at MAX(ORH, Pivot) // Finetiq: if ORH is below the pivot, wait for the pivot
StopLoss = low of the day at the time of entry // author: low of the day
RiskPct = (EntryPrice - StopLoss) / EntryPrice * 100
IF RiskPct > ADRpct THEN CANCEL // author: stop no wider than ADR
// author: ideal is 1/3-1/2 ADR; community (Jack): keeps 1/2-2/3 ADR
IF EntryPrice - Close[1] > ATR(20) THEN CANCEL // author: do not buy if the stock has moved more than ATR on the day
// Finetiq: ATR 20
// community (Jack, second video): daily approximation without intraday data
BUY STOP at Pivot LIMIT Pivot * 1.005 (up to 1.01)
StopLoss = Low of the trigger bar
Position size (author)
RiskMoney = Equity * 0.5% // author: usually 0.3-0.5%, 1-2% on a small account
Shares = RiskMoney / (EntryPrice - StopLoss)
Shares * EntryPrice <= 25% * Equity // author: no more than 25% of the account in one stock
// author: take only trades with a real potential of 10R or more. This cannot be checked mechanically.
// Finetiq: proxy ADRpct >= 3%; community (Jack): the stock's ADR at least 1.5-2 times the ADR of QQQ
Trade management (author)
// after 3-5 days sell a third to a half, move the stop on the rest to breakeven
IF BarsSinceEntry = 3 AND the position is in profit // Finetiq: day 3, "in profit" condition
SELL 1/2 AT NEXT BAR OPEN
StopLoss = EntryPrice
// community (Jack), free roll: SELL 1/3 LIMIT at EntryPrice + 2R or SELL 1/2 LIMIT at EntryPrice + 1R.
// The locked-in profit equals the risk on the remaining part
// the rest: the first close below the average, not an intraday touch
IF Close < EMA(Close, 10) THEN EXIT AT NEXT BAR OPEN // fast stocks, always 10 for beginners
// slow stocks: EMA 20; community (Jack): EMA 21
// Finetiq: execution at the next day's open; variant for testing: minutes before the close
Stock selection (a separate rule)
// calculated across the whole US stock universe after the close, the result goes to a watchlist
// Qullamaggie: three scans over 1, 3 and 6 months; dollar volume, ADR% and gain in the top 7% of all stocks
// community (Jack), example of a 3-month scan:
Close > 1 AND Close > SMA(Close, 200) AND Close > SMA(Close, 50)
AND Average(Volume, 50) > 100 000
AND 3-month gain > 50%
// community (Jack): sorted by 3-month RS rank, 99 = best. In Jack's database about 64 stocks out of 5000
// the signal above is calculated on each stock from the list separately
Parameters
| Parameter | Value | Source |
|---|---|---|
| Regime | NASDAQ: 10 above 20, both rising | author |
| Type of regime averages | EMA | Finetiq |
| Prior rally | 30% or more in 1-3 months | author |
| Base length | 10-40 trading days | author |
| Base averages | EMA 10 and 20, SMA 50 | author |
| Share of bars above EMA 20 | 80% | Finetiq |
| Narrow bar | range less than 0.5 of the 20-day average | Finetiq |
| Entry | ORH of the first 1, 5 or 60-minute candle | author |
| Stop | low of the day | author |
| Maximum stop | 20-day ADR%, ideally 1/3-1/2 | author |
| Chase filter | daily move no more than ATR | author |
| Limit in the daily version | 0.5-1% above the pivot | community (Jack) |
| Risk per trade | 0.3-0.5% | author |
| Account share per stock | up to 25% | author |
| 10R potential proxy | ADR% of 3% or more | Finetiq |
| Partial exit | 1/3-1/2 after 3-5 days, stop to breakeven | author |
| Partial exit day | 3 | Finetiq |
| Trailing stop | close below EMA 10 (slow stocks: 20-21) | author; EMA 21 community (Jack) |
| Scan | price > $1, above SMA 50 and 200, volume > 100,000, gain > 50% over 3 months | community (Jack) |
What to test
- Regime filter. Run the signal without the filter, with the 10/20 NASDAQ rule and with Jack's monthly average (EMA 10 and SMA 10). Jack's 90% figure shows when breakouts happen, not when they are profitable. Compare the average trade in each regime.
- ORH versus a daily entry. Entry on the 1, 5 and 60-minute candle versus a buy stop at the pivot. Look at stop width in fractions of ADR and at the share of skipped trades where the stop was wider than ADR. Jack shows that on 60 minutes the stop often exceeds ADR.
- Trailing stop. EMA 10 versus EMA 21 and SMA 50. Compare not only the average move but also time in the trade. On Jack's 60 best setups, the EMA 10 exit gave an average of +98% in 26 days, EMA 21 +148% in 45 days, SMA 50 +194% in 72 days.
- Partial exit. Half after 3 days versus a free roll (a third at 2R) and versus holding the whole position until the trailing stop. With a win rate of 20-30%, a partial exit changes the shape of the distribution a lot.
- Neighborhood of the setup filters. Rally of 30%, 50% and 100%; base of 10-40 and 15-60 days; narrow bar threshold of 0.4, 0.5 and 0.7. If trades and results change sharply, the base formalization is overfitted.
- Survivorship bias and costs. The scan picks the best stocks. A test on today's stock list inflates the result, so you need history that includes delisted stocks. Add slippage on breakout stop orders and on gaps through the stop.
- Long losing streaks. With a 25% win rate, a streak of 10 losses in a row is normal. Calculate the maximum streak and the drawdown at 0.5% and at 1% risk.
Platform notes
TradingView (Pine Script)
- A strategy trades only the chart symbol. A universe scan, the top 7% and RS rank cannot be reproduced in a Pine backtest. The signal can be tested on a preselected list of stocks one at a time, but such a list already contains survivorship bias.
- NASDAQ regime on daily bars:
request.security("NASDAQ:IXIC", "D", expr[1], lookahead = barmerge.lookahead_on). - ORH needs years of 1- or 5-minute data for many stocks. The depth of intraday history on TradingView is limited by the subscription plan, so for a long test only the daily approximation remains.
- Partial exit:
strategy.exitwithqty_percent. If the entry and the low of the day are hit by one candle, you needuse_bar_magnifier = true.
MultiCharts and TradeStation (EasyLanguage)
- Scanning and ranking across the universe are done in the portfolio module (TradeStation Portfolio Maestro, MultiCharts Portfolio Trader). Check whether the data includes delisted stocks.
- The NASDAQ Composite is added as a second data stream on the stock chart. For ORH, the daily stream runs together with the intraday one, and
Timeis the bar's close time: the first one-minute candle after 09:30 hasTime = 931. Buy next bar at X stoplives for one bar, so on the breakout day it has to be sent on every bar. Stop as a price:Sell next bar at StopLoss stop.- On TradeStation intraday bars, the full volume has historically been stored in
Ticks, whileVolumemay contain only up volume. Use daily bars for the drying volume filter.
MetaTrader 5 (MQL5)
- Brokers offering CFDs on US stocks usually have a few hundred large stocks. Fast stocks with an ADR of 3% or more, where the method works, are often missing, and a scan across the whole universe is impossible.
- CFDs have only tick volume. The average volume and drying volume filters cannot be reproduced on it.
- Brokers usually do not offer the NASDAQ Composite. The NAS100 CFD is the Nasdaq-100, so the regime based on it is approximate.
- Convert the 09:30 ET open to the broker's server time, accounting for daylight saving time. At some brokers, pre-market quotes get into the daily bars of stocks, and the low of the day comes out different.
Where the idea can break
- Qullamaggie's results come from stream screenshots via a retelling, and there are no audited statements. Jack's videos advertise MarketSmith and Jack's own scanning platform.
- The author judges base quality by eye, and Jack even uses star ratings. Our formalization through rally, length and a narrow bar may select very different charts from those an experienced trader would pick.
- The scan picks the best stocks by past return. Without history that includes delisted stocks, the backtest will look noticeably better than reality.
- A win rate of 20-30% means long losing streaks. The result rests on a few trades of 20-50R, and a short sample may not contain any of them.
- Jack's study of 500 breakouts was done in hindsight: stops were placed by eye and breakouts were selected after the fact.
- The ORH entry needs intraday data for hundreds of stocks and fast execution. The daily approximation gives a different stop and a different set of trades.