How the Short Term Reversal Effect Works: QuantConnect Implementation Guide

The short-term reversal effect exploits the empirical observation that stocks underperforming over the past week tend to rebound while those outperforming over the past month tend to decline, implemented in the awesome-systematic-trading repository as a weekly rebalanced long/short strategy using 5-day and 20-day rolling returns.

The paperswithbacktest/awesome-systematic-trading repository provides a complete QuantConnect implementation of this well-documented market anomaly. The algorithm systematically captures mean-reversion in equity prices by combining a liquidity-filtered universe with precise rolling-window calculations and disciplined weekly rebalancing.

Understanding the Short Term Reversal Anomaly

The short-term reversal effect describes a predictable pattern where extreme short-term price movements partially reverse over subsequent periods. Academic research shows that stocks experiencing negative returns over a one-week horizon typically bounce back, while stocks with strong one-month performance often give back gains. This phenomenon is generally attributed to liquidity shocks, temporary price pressure, and investor overreaction that subsequently corrects.

In the QuantConnect implementation found in static/strategies/short-term-reversal-in-stocks.py, the strategy translates this behavioral bias into a systematic trading rule. The algorithm maintains a 100-capitalization-weighted universe, ranks constituents by recent performance, and constructs a market-neutral portfolio that rebalances every fifth trading day.

Universe Construction and Data Management

Liquidity and Capitalization Filtering

The algorithm begins with a two-stage filtering process to ensure tradeable capacity and reduce computational overhead. In the CoarseSelectionFunction method, the code first isolates the 500 most liquid U.S. equities using self.coarse_count = 500 as an initial screen. From this liquid subset, the algorithm selects the 100 largest securities by market capitalization, defined by self.top_by_market_cap_count = 100.

This approach approximates the academic specification of trading the largest 100 companies while adding a practical liquidity safeguard. The coarse-fine selection pattern ensures that the intensive rolling-window calculations and return rankings occur only on securities that can realistically absorb institutional position sizes.

Rolling Window Implementation

Each candidate symbol receives a dedicated SymbolData instance that maintains a 21-day rolling window of closing prices. The window length is deliberately set to period = 21 to accommodate both the 5-day weekly return and the approximate 20-day monthly return calculations without constantly requesting historical data.

During initialization, the algorithm warms up these windows via History requests. Within CoarseSelectionFunction, the method updates each symbol's rolling window daily with the latest close price, ensuring that return calculations always reference synchronized, refreshed data points rather than stale values.

Signal Generation and Performance Metrics

Weekly Return Calculation

The weekly return metric identifies the most immediate underperformers. In the SymbolData class, the weekly_return() method calculates the five-day performance using the formula:

def weekly_return(self) -> float:
    # 5-day look-back

    return self.closes[0] / self.closes[5] - 1

This calculation divides today's close (index 0) by the close from five trading days prior (index 5), subtracting one to yield the percentage change. The 5-day window specifically targets the short-term price pressure effect documented in reversal literature.

Monthly Return Calculation

Conversely, the monthly return captures longer-term overreaction. The monthly_return() method leverages the full window capacity:

def monthly_return(self) -> float:
    # full period (≈20 trading days)

    return self.closes[0] / self.closes[self.period - 1] - 1

Using index self.period - 1 (20), this calculation measures performance from 20 trading days ago to the present. The algorithm uses this metric to identify potential short candidates—stocks that have risen substantially over the past month and are statistically likely to experience mean reversion.

Portfolio Construction and Execution

Long and Short Selection Logic

The FineSelectionFunction method implements the dual-ranking system. For the long portfolio, the algorithm selects the 10 symbols with the lowest weekly returns (the worst recent performers), stored in self.stock_selection = 10.

For the short portfolio, the code identifies the 10 symbols with the highest monthly returns, explicitly excluding any symbols already selected for the long side. This exclusion prevents conflicting exposures and ensures pure long/short separation. The selection logic uses Python's sorted function with lambda keys to rank the month_perf and week_perf dictionaries efficiently.

Weekly Rebalancing Mechanism

The strategy executes trades only once per week through a custom scheduling mechanism. The Selection method acts as a daily trigger that increments a counter (self.day) and sets self.selection_flag = True specifically on the fifth trading day of each week. This flag gates the execution logic inside OnData, preventing excessive turnover and transaction costs from daily signal changes.

When the flag activates, the algorithm liquidates positions no longer in the long or short lists and establishes equal-weighted holdings. The allocation applies 1/len(self.long) weight to each long position and -1/len(self.short) weight to each short, creating a dollar-neutral structure. The leverage is set to 5× per security, resulting in approximately 100% long and 100% short notional exposure after accounting for the equal weights.

Risk Management and Implementation Nuances

Transaction Cost Modeling

High-frequency reversal strategies are notoriously sensitive to trading frictions. The implementation addresses this through a CustomFeeModel class that overrides GetOrderFee to apply a 0.005% transaction cost on every trade. This realistic cost assumption helps validate whether the theoretical alpha survives actual market execution, as small-cap reversal effects often diminish when bid-ask spreads and commissions are factored into backtests.

Data Validation and Error Handling

The algorithm includes defensive programming to handle missing or insufficient data. Before computing returns, the code checks for empty history responses and skips symbols lacking the required 21 data points. This prevents runtime exceptions during the warm-up phase or when corporate actions create data gaps in the rolling windows.

Leverage and Exposure Constraints

Each security is configured with 5× leverage via SetLeverage(5), allowing the strategy to take meaningful sized positions without requiring excessive capital. The equal-weighting scheme ensures that no single position dominates the risk profile, while the 100-long/100-short structure maintains approximate beta neutrality against broader market movements.

Summary

  • The short-term reversal effect captures mean reversion in weekly and monthly equity returns by going long on recent losers and short on recent winners.
  • The QuantConnect implementation filters a 500-stock liquid universe down to the top 100 by market cap before calculating 5-day and 20-day rolling returns using a 21-day window.
  • The FineSelectionFunction ranks securities to create 10-long and 10-short portfolios, while the Selection method triggers rebalancing only on the fifth trading day each week.
  • Risk controls include a 0.005% custom fee model, 5× leverage limits per security, and explicit checks for missing historical data.
  • The full implementation resides in static/strategies/short-term-reversal-in-stocks.py within the paperswithbacktest/awesome-systematic-trading repository.

Frequently Asked Questions

What is the optimal lookback period for capturing the short-term reversal effect?

The algorithm uses a 5-day lookback for weekly returns and a 20-day lookback for monthly returns, matching classic academic specifications for short-term reversal anomalies. These horizons balance the need to capture temporary price pressure against the risk of holding positions too long and missing the reversal window. The 21-day rolling window size provides sufficient buffer to calculate both metrics simultaneously without additional data requests.

How does the algorithm prevent excessive turnover and transaction costs?

The strategy employs a weekly rebalancing flag (self.selection_flag) that only activates on the fifth trading day of each week, ensuring positions remain static for at least four full market days. Additionally, the CustomFeeModel applies a 0.005% transaction cost to simulate realistic slippage, which helps validate that the reversal alpha exceeds trading frictions. This conservative approach is essential because high-frequency reversal strategies can see profits eroded by bid-ask spreads without proper timing constraints.

Why does the strategy filter for the 500 most liquid stocks before selecting by market cap?

The liquidity pre-filter (self.coarse_count = 500) ensures that the algorithm only considers securities capable of absorbing institutional trade sizes without excessive market impact. While the academic literature often specifies the largest 100 companies by capitalization, the additional liquidity screen prevents the inclusion of large-cap stocks with thin trading volumes. This two-stage filtering maintains the spirit of the strategy—trading large, stable companies—while improving practical executability in live trading environments.

Can the short-term reversal strategy be applied to asset classes other than equities?

Yes, the repository includes static/strategies/short-term-reversal-with-futures.py, which adapts the same rolling-window logic and weekly rebalancing framework to futures contracts. The reversal effect has been documented across multiple asset classes including commodities, currencies, and fixed income, though the specific lookback periods and leverage constraints may require adjustment based on the volatility and roll dynamics of the specific futures markets being traded.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →