Skip to content

Price Deviation & ROE Filter (US Market)

Strategy Overview

This strategy combines price momentum with a fundamental quality filter:

  1. 60-Day Momentum: Compute the price change over the last 60 trading days and select the top 30 stocks by this metric.
  2. ROE Filter: Only keep stocks with a positive ROE (Return on Equity), excluding companies that are currently unprofitable.

The portfolio rebalances monthly.

from finlab import data
from finlab.backtest import sim
from finlab.market import USMarket

data.set_market('us')

close = data.get('price:adj_close')
close = close[close.index.dayofweek < 5]  # remove weekends

# Compute ROE from financial statements
net_income = data.get('us_income_statement:netIncome')
equity = data.get('us_balance_sheet:totalStockholdersEquity')
roe = net_income / equity

# Top 30 by 60-day momentum, filtered by positive ROE
position = ((close / close.shift(60)).is_largest(30) & (roe > 0))

# Backtest with monthly (M) rebalancing
report = sim(position, resample='M', market=USMarket(), fee_ratio=0.001, tax_ratio=0)
report.display()

Key Parameters

  • close / close.shift(60): Computes the 60-day price ratio (i.e., 1 + return over 60 trading days). This captures approximately one quarter of momentum, balancing between short-term noise and long-term mean reversion.
  • is_largest(30): Selects the 30 stocks with the highest 60-day returns. Concentrating on the top performers tilts the portfolio toward momentum.
  • roe > 0: A simple profitability screen. By requiring positive ROE, the strategy avoids speculative or distressed companies whose price surges may be driven by short squeezes or speculative trading rather than fundamental improvement.
  • us_income_statement:netIncome and us_balance_sheet:totalStockholdersEquity: US financial statement data fields used to compute ROE directly, since point-in-time ROE is not available as a pre-computed field.
  • resample='M': Monthly rebalancing aligns with the frequency of new financial data availability and keeps transaction costs reasonable.

Expected Behavior

This is a momentum strategy with a fundamental guard rail. Pure momentum strategies can load up on speculative names that have surged on hype; the ROE filter removes unprofitable companies, steering the portfolio toward stocks where price momentum is supported by actual earnings. The 60-day lookback captures intermediate-term trends and avoids the reversal effects that plague very short-term momentum. Monthly rebalancing gives positions time to play out while periodically refreshing the portfolio as new earnings data arrives.