
This is the third strategy in my series testing whether backtested strategies hold up over extended periods. This one comes from Zura Kakushadze's "151 Trading Strategies" book - specifically Strategy #1: Standardized Unexpected Earnings (SUE).
What This Strategy Does:
The SUE strategy exploits post-earnings announcement drift (PEAD). It calculates the change in quarterly EPS from its value four quarters ago, computes the standard deviation of this change over the prior eight quarters, and derives a SUE score by dividing the change by the standard deviation. Each month, it sorts the universe by SUE and goes long on the top 5% with the highest positive earnings surprises. Monthly rebalancing captures persistence in earnings momentum.
Based on the foundational research by Foster, Olsen and Shevlin (1984) and replicated by Hou, Xue and Zhang (2018).
5-Year Backtest (2021-2026) - "Focused Fluorescent Pink Falcon":
- Sharpe Ratio: 0.635
- PSR: 23.050%
- Sortino: 0.752
- CAGR: 23.576%
- Net Profit: 173.363%
- Max Drawdown: 28.9%
- Win Rate: 67%
- Total Orders: 225
- End Equity: $2,733,631 (from $1M)
18-Year Backtest (2007-2026) - "Maximum Fundamental Data Coverage":
- Sharpe Ratio: 0.442
- PSR: 0.495%
- Sortino: 0.485
- CAGR: 13.619%
- Net Profit: 1,009.312%
- Max Drawdown: 63.9%
- Win Rate: 65%
- Total Orders: 976
- End Equity: $11,093,124 (from $1M)
Key Observations:
1. Like the Drawdown Regime Gold Hedge, this strategy survives the extended test with meaningful returns. $1M to $11M over 18 years at 13.6% CAGR is solid.
2. The Sharpe dropped from 0.635 to 0.442 - less degradation than many strategies I have tested, suggesting some genuine alpha from PEAD.
3. However, the max drawdown jumped from 28.9% to a brutal 63.9%. The 2008-2009 crisis decimated the strategy - if you were running this live, you would have lost nearly two-thirds of your capital.
4. PSR dropped from 23.05% to 0.495%, again raising questions about statistical significance over the longer window.
5. QC flags this as "Likely Overfitting" with 23 parameters detected.
Lessons Learned:
- Academic anomalies like PEAD can generate real alpha, but surviving a financial crisis matters enormously
- A 63.9% drawdown would be psychologically devastating in live trading, even if the strategy eventually recovers
- The strategy needs risk management overlays (stop losses, position sizing limits) before it could be traded live
- Comparing 5-year vs 18-year results tells a much more honest story about what to expect
Full code below. Would love to hear ideas on reducing the drawdown while preserving the earnings momentum alpha.
# 151-1 Standardized Unexpected Earnings
# From 151 Trading Strategies book by Zura Kakushadze
#
# Strategy: Uses standardized unexpected earnings (SUE) to identify stocks with significant earnings surprises.
# Calculates quarterly earnings changes, computes standard deviations, and derives SUE scores.
# Ranks stocks by SUE and takes long positions in the top 5% with highest positive surprises.
# Monthly rebalancing captures persistence in earnings momentum.
# Based on research showing post-earnings announcement drift.
#region imports
from AlgorithmImports import *
from universe import TopStandardizedUnexpectedEarningsUniverseSelectionModel
from alpha import MonthlyLongAlphaModel
#endregion
class StandardizedUnexpectedEarningsAlgorithm(QCAlgorithm):
'''Step 1. Calculate the change in quarterly EPS from its value four quarters ago
Step 2. Calculate the st dev of this change over the prior eight quarters
Step 3. Get standardized unexpected earnings (SUE) from dividing results of step 1 by step 2
Step 4. Each month, sort universe by SUE and long the top quantile
Reference:
[1] Foster, Olsen and Shevlin, 1984, Earnings Releases, Anomalies, and the Behavior of Security Returns,
The Accounting Review. URL: https://www.jstor.org/stable/pdf/247321.pdf?casa_token=KHX3qwnGgTMAAAAA:
ycgY-PzPfQ9uiYzVYeOF6yRDaNcRkL6IhLmRJuFpI6iWxsXJgB2BcM6ylmjy-g6xv-PYbXySJ_VxDpFETxw1PtKGUi1d91ce-h-V6CaL_SAAB56GZRQ
[2] Hou, Xue and Zhang, 2018, Replicating Anomalies, Review of Financial Studies,
URL: http://theinvestmentcapm.com/HouXueZhang2019RFS.pdf
'''
_undesired_symbols_from_previous_deployment = []
_checked_symbols_from_previous_deployment = False
def initialize(self):
months_count = self.get_parameter("months_count", 36) # Number of months of rolling window object
# Set backtest start date and warm-up period
WARM_UP_FOR_LIVE_MODE = self.get_parameter("warm_up_for_live_mode", 1)
MORNING_STAR_LIVE_MODE_HISTORY = timedelta(30) # US Fundamental Data by Morningstar is limited to the last 30 days
if self.live_mode:
self.set_warm_up(MORNING_STAR_LIVE_MODE_HISTORY)
else: # Backtest mode
now = datetime.now()
self.set_end_date(now)
if WARM_UP_FOR_LIVE_MODE: # Need to run a backtest before you can deploy this algorithm live
# The universe selection model will quit 30-days before the current day
self.set_start_date(now - MORNING_STAR_LIVE_MODE_HISTORY)
else: # Regular backtest - using maximum available fundamental data
self.set_start_date(2007, 1, 1) # Extended to earliest available Morningstar fundamental data
self.set_warm_up(timedelta(31 * (months_count+1)))
self.set_cash(1_000_000)
self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
self.set_security_initializer(BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)))
self.settings.minimum_order_margin_portfolio_percentage = 0
self.universe_settings.data_normalization_mode = DataNormalizationMode.RAW
self.universe_settings.schedule.on(self.date_rules.month_start())
self.add_universe_selection(TopStandardizedUnexpectedEarningsUniverseSelectionModel(
self,
self.universe_settings,
self.get_parameter("coarse_size", 50), # Number of stocks to return from Coarse universe selection
self.get_parameter("top_percent", 0.05), # Percentage of symbols selected based on SUE sorting
self.get_parameter("months_eps_change", 12), # Number of months of lag to calculate eps change
months_count,
WARM_UP_FOR_LIVE_MODE
))
self.add_alpha(MonthlyLongAlphaModel())
self.settings.rebalance_portfolio_on_security_changes = False
self.settings.rebalance_portfolio_on_insight_changes = False
self._month = -1
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(self._rebalance_func))
self.add_risk_management(NullRiskManagementModel())
self.set_execution(ImmediateExecutionModel())
def _rebalance_func(self, time):
if self._month != self.time.month and not self.is_warming_up and self.current_slice.quote_bars.count > 0:
self._month = self.time.month
return time
return None
def on_data(self, data):
# Exit positions that aren't backed by existing insights.
# If you don't want this behavior, delete this method definition.
if not self.is_warming_up and not self._checked_symbols_from_previous_deployment:
for security_holding in self.portfolio.values():
if not security_holding.invested:
continue
symbol = security_holding.symbol
if not self.insights.has_active_insights(symbol, self.utc_time):
self._undesired_symbols_from_previous_deployment.append(symbol)
self._checked_symbols_from_previous_deployment = True
for symbol in self._undesired_symbols_from_previous_deployment[:]:
if self.is_market_open(symbol):
self.liquidate(symbol, tag="Holding from previous deployment that's no longer desired")
self._undesired_symbols_from_previous_deployment.remove(symbol)
Ney Torres
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!