FSCORE-Enhanced Short-Term Reversal Strategy on Large-Cap Stocks

Log in to collect

Onsite backtest IDE

Quant Buffet native backtest IDE

Edit and run Quant Buffet Python for FSCORE-Enhanced Short-Term Reversal Strategy on Large-Cap Stocks in the browser. Results update live with equity, drawdown, and metrics charts. Allowed: backtest.data, backtest.engine, backtest.metrics, numpy, pandas. Define ASSETS and make_on_day(prices). Shortcut: Ctrl+Enter. API docs →

Ready — edit code, then Run backtest.
IDE · 44 lines
Quant Buffet syntax cheat sheet (copy / insert)

Paste these fragments into the editor. The sandbox rejects QuantConnect, os, and network libraries.

Required imports
Only these libraries are allowed in the sandbox.
from __future__ import annotations

import numpy as np
import pandas as pd

from backtest.data import load_daily_prices
from backtest.engine import EngineConfig, PortfolioEngine
from backtest.metrics import compute_metrics
ASSETS list (whitelisted ETFs)
Module-level list. Tickers must be in the Quant Buffet whitelist.
ASSETS = ["SPY", "QQQ", "TLT", "GLD", "BIL"]
make_on_day contract
Must return (on_day, ready). on_day calls engine.set_target_weights.
def make_on_day(prices: pd.DataFrame):
    cols = [c for c in ASSETS if c in prices.columns]
    sma = prices[cols].rolling(200, min_periods=200).mean()
    state = {"last": None}

    def on_day(engine: PortfolioEngine, dt: pd.Timestamp) -> None:
        if sma.loc[dt].isna().all():
            return
        key = (dt.year, dt.month)
        if state["last"] == key:
            return
        state["last"] = key
        long = [
            s for s in cols
            if pd.notna(prices.at[dt, s]) and pd.notna(sma.at[dt, s])
            and prices.at[dt, s] > sma.at[dt, s]
        ]
        weights = {} if not long else {s: 1.0 / len(long) for s in long}
        engine.set_target_weights(dt, weights)

    ready = sma.dropna(how="all").index.min() if sma.notna().any().any() else None
    return on_day, ready
Set target weights
Weights should sum to about 1.0. Empty dict = 100% cash.
engine.set_target_weights(dt, {"SPY": 0.60, "BIL": 0.40})

Live backtest performance

CAGR
1.44%
Sharpe
0.17
Max DD
-36.97%
Vol
14.04%
Sortino
0.26
Beta
0.55
Up days
45%

Run the backtest to populate charts.

Export to your platform

Transform Quant Buffet lab code (ASSETS + make_on_day / PortfolioEngine) into native classes for a third-party IDE — then copy and paste.

Run in: QuantConnect Cloud or LEAN CLI · QCAlgorithm with Equity securities and monthly rebalance.

Detected pattern: Mean reversionAssets: SPY, TLT, GLD, BIL
# Generated from Quant Buffet → QuantConnect LEAN
# Strategy: FSCORE-Enhanced Short-Term Reversal Strategy on Large-Cap Stocks
# Detected pattern: Mean reversion
# Source uses Quant Buffet lab APIs (ASSETS + make_on_day / PortfolioEngine).
# Review fees, data, and risk before live trading — educational export only.

from AlgorithmImports import *


class QuantBuffetExport(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2010, 1, 1)
        self.SetCash(100000)
        tickers = ["SPY", "TLT", "GLD", "BIL"]
        self.symbols = []
        for t in tickers:
            if "-" in t:  # crypto proxy e.g. BTC-USD
                self.symbols.append(self.AddCrypto(t.replace("-USD", ""), Resolution.Daily).Symbol)
            else:
                self.symbols.append(self.AddEquity(t, Resolution.Daily).Symbol)
        self.Schedule.On(
            self.DateRules.MonthStart(self.symbols[0]),
            self.TimeRules.AfterMarketOpen(self.symbols[0], 30),
            self.Rebalance,
        )
        # Logic: Buy when return z-score < -1 over 20 days.

    def Rebalance(self):
        import numpy as np
        picks = []
        for symbol in self.symbols:
            hist = self.History(symbol, 20 + 5, Resolution.Daily)
            if hist.empty: continue
            close = hist["close"]
            if hasattr(close, "unstack"):
                close = close.unstack(level=0).iloc[:, 0]
            rets = close.pct_change().dropna()
            if len(rets) < 20: continue
            window = rets.iloc[-20:]
            z = (window.iloc[-1] - window.mean()) / (window.std() or 1e-9)
            if z < -1:
                picks.append(symbol)
        w = 1.0 / len(picks) if picks else 0.0
        for symbol in self.symbols:
            self.SetHoldings(symbol, w if symbol in picks else 0.0)

Exported code uses the platform’s native classes and libraries. Install dependencies in your third-party IDE, then run. Validate before live trading.

Academic paper

Noise Trading, Slow Diffusion of Information, and Short-Term Reversals: A Fundamental Analysis Approach

AuthorsZhaobo Zhu; Licheng Sun; Min Chen

Institute
  • Audencia Business School
  • Shenzhen University
  • GHDominion University College
  • Old Dominion University
  • San Francisco State University
  • ?San Francisco State University - Department of Accounting

Screenshot from the original paper

Screenshot from the original paper

Strategy in a nutshell

The investment universe consists of common stocks (share code 10 or 11) listed in NYSE, AMEX, and NASDAQ exchanges. Stocks with prices less than $5 at the end of the formation period are excluded.

The range of FSCORE is from zero to nine points. Each signal is equal to one (zero) point if the signal indicates a positive (negative) financial performance. A firm scores one point if it has realized a positive return-on-assets (ROA), positive cash flow from operations, a positive change in ROA, a positive difference between net income from operations (Accrual), a decrease in the ratio of long-term debt to total assets, a positive change in the current ratio, no-issuance of new common equity, a positive change in gross margin ratio and lastly a positive change in asset turnover ratio. Firstly, construct a quarterly FSCORE using the most recently available quarterly financial statement information.

Monthly reversal data are matched each month with a most recently available quarterly FSCORE. The firm is classified as a fundamentally strong firm if the firm’s FSCORE is greater than or equal to seven (7-9), fundamentally middle firm (4-6) and fundamentally weak firm (0-3). Secondly, identify the large stocks subset – those in the top 40% of all sample stocks in terms of market capitalization at the end of formation month t. After that, stocks are sorted on the past 1-month returns and firm’s most recently available quarterly FSCORE. Take a long position in past losers with favourable fundamentals (7-9) and simultaneously a short position in past winners with unfavourable fundamentals (0-3). The strategy is equally weighted and rebalanced monthly.

Economic rationale

There are three reasons to use FSCORE. Firstly, FSCORE is a comprehensive metric of a firm’s fundamental strength, because this score synthesizes information from nine signals along three dimensions of a firm’s financial performance (profitability, change in financial leverage and liquidity, and change in operational efficiency). Secondly, the fundamental information is gathered directly from the financial statements, which obviates the measurement error problem. And lastly, FSCORE is a nonparametric measure, compared with a parametric approach, FSCORE is more robust and helps to reduce concerns over potential estimation biases. Results support the hypothesis that short-term reversals are influenced by both noise trading and investor underreaction to fundamental information. Also results from regression analysis suggest that both noise trading and fundamental information significantly influence stock returns on the short horizon. No doubt, there is a conclusion that investor underreaction to fundamental information coupled with noise trading can explain the observed empirical patterns in short-term reversals. Moreover, results indicate that the bid-ask spread cannot be the main source of the profitability for short-term reversals, and the results are not particularly sensitive to alternative definitions of fundamental strength. Last but not least, simple short-term reversal and industry-adjusted reversal strategies fail to be profitable in the presence of transaction costs; however, fundamental anchored reversal strategies are economically profitable even in the presence of transaction costs.

Backtest performance

Annualised return1.44%
Volatility14.04%
Beta0.55
Sharpe ratio0.17
Sortino ratio0.26
Maximum drawdown-36.97%
Win rate45%