What happens when strong stocks gap down at the open? A well-known trading strategy is to buy the gap, expecting mean reversion. This post uses Zipline to explore down gaps and finds a profitable strategy based on selling, not buying, the gap.
Buy the gap?
Buying stocks that gap down is a common trading strategy. The reasoning behind the strategy is that bad news causes traders to enter sell orders overnight which execute in tandem at the open, causing a temporary liquidity shock which drives down the opening price. The selling pressure immediately exhausts itself, however, leading the stock to recover through the remainder of the session. The strategy typically targets stocks in an uptrend, expecting that traders will buy the dip.
I use Zipline with QuantRocket's 1-minute US stock data to backtest a buy-on-gap strategy. I first screen the daily universe of 8,000 listed stocks using the following criteria:
- common stocks only (no ETFs, ADRs, or preferred shares)
- liquid stocks only (top 10% by dollar volume)
- closed above their 20-day moving average
mavg = SimpleMovingAverage( window_length=20, inputs=[EquityPricing.close]) are_common_stocks = SecuritiesMaster.usstock_SecurityType2.latest.eq( "Common Stock") are_liquid = AverageDollarVolume(window_length=30).percentile_between(90, 100) are_above_mavg = EquityPricing.close.latest > mavg pipeline = Pipeline( screen=( are_common_stocks & are_liquid & are_above_mavg ) )
For the stocks that pass the screen, I use intraday data to identify which stocks gapped down at least 1 standard deviation below the prior day's low:
today_opens = data.current(context.candidates.index, 'open') prior_lows = context.candidates["prior_low"] stds = context.candidates["std"] # find stocks that opened sufficiently below the prior day's low gapped_down = today_opens < (prior_lows - stds) assets_to_buy = context.candidates[gapped_down]
I buy the stocks 1 minute after the open and hold until the close, resulting in the following equity curve:
Sell the gap
The performance of the buy-on-gap strategy is so bad, it suggests a good strategy. Why not simply reverse the sign of the trade and go short instead of long?
I reverse the rules and indeed find a profitable strategy. From 2014-2020, the Sharpe ratio is 1.30 and the annual return is 10%:
Experimenting with parameters, I make two observations:
- The strategy works better on large-cap stocks than on small-cap stocks. Perhaps this is because small-cap stocks are more subject to liquidity shocks, which tend to mean-revert.
- Entering positions 5-10 minutes after the open works better than entering immediately after the open. This suggests that some mean reversion occurs immediately after the open before the stock continues falling.
Big gaps vs small gaps
If a sell-on-gap strategy works better than a buy-on-gap strategy, why is the buy-on-gap strategy so well-known?
Most buy-on-gap strategies utilize a rule to limit the size of the down gap, but it turns out that I inadvertently omitted such a rule in my original backtest. As a result, my original strategy targeted large down gaps.
I revise the buy-on-gap strategy to target smaller down gaps by requiring that stocks not only closed above their 20-day moving average the prior day, but also open above the moving average on the day of the down gap. This produces a positive equity curve:
The difference in price action following small gaps vs large gaps makes intuitive sense. A small down gap leaves the uptrend intact; thus the gap is a buying opportunity. In contrast, a large down gap violates the uptrend and often signals more serious trouble; moreover, because of the prior uptrend, the stock that is now in trouble has room to keep falling.
Stocks tend to recover after small down gaps and keep dropping after large down gaps. This knowledge can be used to develop trading strategies on both the long and short side.
This post also demonstrates the serendipity of quantitative research. Sometimes you discover useful trading ideas by accident while exploring a different idea. Even implementation errors occasionally provide helpful insights into how markets behave.
Explore this research on your own
This research was created with QuantRocket. Clone the sell-gap repository to get the code and perform your own analysis.
quantrocket codeload clone 'sell-gap'