| Overall Statistics |
|
Total Orders 1999 Average Win 0.03% Average Loss -0.02% Compounding Annual Return 7.874% Drawdown 6.000% Expectancy 0.476 Start Equity 100000000 End Equity 107821873.96 Net Profit 7.822% Sharpe Ratio 0.063 Sortino Ratio 0.069 Probabilistic Sharpe Ratio 12.388% Loss Rate 44% Win Rate 56% Profit-Loss Ratio 1.62 Alpha 0.003 Beta 0.001 Annual Standard Deviation 0.049 Annual Variance 0.002 Information Ratio -1.068 Tracking Error 0.119 Treynor Ratio 2.754 Total Fees $28864.94 Estimated Strategy Capacity $4200000.00 Lowest Capacity Asset BSQR RP1305HZ49K5 Portfolio Turnover 0.74% Drawdown Recovery 71 |
# region imports
from AlgorithmImports import *
from typing import List
from math import isfinite
# endregion
class FundamentalSnapshot:
def __init__(
self,
formation_date: datetime,
file_date: datetime,
period_ending_date: datetime,
income_before_extraordinary_items: float,
total_assets: float,
industry_code: int,
market_cap: float,
business_country_id: str,
primary_exchange_id: str,
security_type: str,
is_primary_share: bool,
) -> None:
self.formation_date = formation_date
self.file_date = file_date
self.period_ending_date = period_ending_date
self.income_before_extraordinary_items = income_before_extraordinary_items
self.total_assets = total_assets
self.industry_code = industry_code
self.market_cap = market_cap
self.business_country_id = business_country_id
self.primary_exchange_id = primary_exchange_id
self.security_type = security_type
self.is_primary_share = is_primary_share
self.average_assets = None
self.return_on_assets = None
self.market_excluded_return_on_assets = None
self.industry_excluded_return_on_assets = None
self.industry_market_intercept = None
self.industry_market_slope = None
self.industry_market_residual = None
self.industry_earnings_beta = None
self.market_earnings_beta = None
self.is_beta_eligible = False
self.market_return_on_assets_component = None
self.industry_return_on_assets_component = None
self.idiosyncratic_return_on_assets_component = None
class IdiosyncraticProfitabilityAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2023, 1, 1)
self.set_end_date(2023, 12, 31)
self.set_cash(100_000_000)
self.set_warm_up(timedelta(days=5 * 365))
self.settings.min_absolute_portfolio_target_percentage = 0
self.settings.minimum_order_margin_portfolio_percentage = 0
self._snapshots = {}
self._panels = {}
self._eligible_snapshots = []
self._bottom_quintile = []
self._top_quintile = []
self._portfolio_weights = {}
self._selected_symbols = []
self._pending_weights = None
self._pending_formation_date = None
self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
self._formation_rule = FuncDateRule(
"QuarterlyFormation",
self._get_formation_dates,
)
self.universe_settings.resolution = Resolution.DAILY
self.universe_settings.schedule.on(self._formation_rule)
self._universe = self.add_universe(self._select_assets)
self.schedule.on(
self.date_rules.every_day("SPY"),
self.time_rules.after_market_close("SPY", 1),
self._execute_rebalance,
)
def _get_formation_dates(
self,
start: datetime,
end: datetime,
) -> List[datetime]:
hours = self.securities[self._spy].exchange.hours
dates = []
current = start.date()
while current <= end.date():
if current.month in (2, 5, 8, 11) and hours.is_date_open(current):
next_trading_day = hours.get_next_trading_day(current)
if next_trading_day.month != current.month:
dates.append(datetime.combine(current, datetime.min.time()))
current += timedelta(days=1)
return dates
def _previous_calendar_quarter_end(self, period_end: datetime) -> datetime:
previous_quarter = {
3: (period_end.year - 1, 12),
6: (period_end.year, 3),
9: (period_end.year, 6),
12: (period_end.year, 9),
}
year, month = previous_quarter[period_end.month]
last_day = 31 if month in (3, 12) else 30
return datetime(year, month, last_day)
def _is_usable_roa_record(self, snapshot: FundamentalSnapshot) -> bool:
return (
snapshot.return_on_assets is not None
and isfinite(snapshot.income_before_extraordinary_items)
and isfinite(snapshot.average_assets)
and isfinite(snapshot.return_on_assets)
)
def _update_excluded_roas(self) -> None:
records_by_period = {}
for symbol, symbol_snapshots in self._snapshots.items():
for period_end, snapshot in symbol_snapshots.items():
snapshot.market_excluded_return_on_assets = None
snapshot.industry_excluded_return_on_assets = None
if self._is_usable_roa_record(snapshot):
records_by_period.setdefault(period_end, []).append(
(symbol, snapshot)
)
for records in records_by_period.values():
market_total_ib = sum(
snapshot.income_before_extraordinary_items
for _, snapshot in records
)
market_total_average_assets = sum(
snapshot.average_assets for _, snapshot in records
)
industry_records = {}
for symbol, snapshot in records:
industry_records.setdefault(snapshot.industry_code, []).append(
(symbol, snapshot)
)
for _, snapshot in records:
market_excluded_ib = (
market_total_ib - snapshot.income_before_extraordinary_items
)
market_excluded_average_assets = (
market_total_average_assets - snapshot.average_assets
)
if market_excluded_average_assets != 0:
snapshot.market_excluded_return_on_assets = (
market_excluded_ib / market_excluded_average_assets
)
peers = industry_records[snapshot.industry_code]
if len(peers) < 5:
continue
industry_total_ib = sum(
peer.income_before_extraordinary_items for _, peer in peers
)
industry_total_average_assets = sum(
peer.average_assets for _, peer in peers
)
industry_excluded_ib = (
industry_total_ib - snapshot.income_before_extraordinary_items
)
industry_excluded_average_assets = (
industry_total_average_assets - snapshot.average_assets
)
if industry_excluded_average_assets != 0:
snapshot.industry_excluded_return_on_assets = (
industry_excluded_ib / industry_excluded_average_assets
)
def _update_panels(self) -> None:
self._panels = {}
for symbol, symbol_snapshots in self._snapshots.items():
panel = []
for period_end in sorted(symbol_snapshots):
snapshot = symbol_snapshots[period_end]
if (
snapshot.return_on_assets is None
or snapshot.market_excluded_return_on_assets is None
or snapshot.industry_excluded_return_on_assets is None
):
continue
panel.append(snapshot)
self._panels[symbol] = panel[-20:]
def _update_industry_market_regressions(self) -> None:
for panel in self._panels.values():
for snapshot in panel:
snapshot.industry_market_intercept = None
snapshot.industry_market_slope = None
snapshot.industry_market_residual = None
if len(panel) < 10:
continue
market_mean = sum(
snapshot.market_excluded_return_on_assets for snapshot in panel
) / len(panel)
industry_mean = sum(
snapshot.industry_excluded_return_on_assets for snapshot in panel
) / len(panel)
market_sum_squared_deviation = sum(
(snapshot.market_excluded_return_on_assets - market_mean) ** 2
for snapshot in panel
)
if market_sum_squared_deviation == 0:
continue
market_industry_covariance = sum(
(snapshot.market_excluded_return_on_assets - market_mean)
* (snapshot.industry_excluded_return_on_assets - industry_mean)
for snapshot in panel
)
slope = market_industry_covariance / market_sum_squared_deviation
intercept = industry_mean - slope * market_mean
for snapshot in panel:
fitted_industry_roa = (
intercept
+ slope * snapshot.market_excluded_return_on_assets
)
snapshot.industry_market_intercept = intercept
snapshot.industry_market_slope = slope
snapshot.industry_market_residual = (
snapshot.industry_excluded_return_on_assets
- fitted_industry_roa
)
def _solve_three_by_three(
self,
matrix: List[List[float]],
vector: List[float],
) -> List[float]:
augmented = [
matrix[row][:] + [vector[row]] for row in range(3)
]
for column in range(3):
pivot_row = max(
range(column, 3),
key=lambda row: abs(augmented[row][column]),
)
if augmented[pivot_row][column] == 0:
return []
augmented[column], augmented[pivot_row] = (
augmented[pivot_row],
augmented[column],
)
pivot = augmented[column][column]
augmented[column] = [value / pivot for value in augmented[column]]
for row in range(3):
if row == column:
continue
factor = augmented[row][column]
augmented[row] = [
augmented[row][index] - factor * augmented[column][index]
for index in range(4)
]
return [augmented[row][3] for row in range(3)]
def _update_own_roa_regressions(self) -> None:
for panel in self._panels.values():
for snapshot in panel:
snapshot.industry_earnings_beta = None
snapshot.market_earnings_beta = None
snapshot.is_beta_eligible = False
if (
len(panel) < 10
or any(
snapshot.industry_market_residual is None
for snapshot in panel
)
):
continue
industry_residuals = [
snapshot.industry_market_residual for snapshot in panel
]
market_roas = [
snapshot.market_excluded_return_on_assets for snapshot in panel
]
own_roas = [snapshot.return_on_assets for snapshot in panel]
observation_count = len(panel)
matrix = [
[
observation_count,
sum(industry_residuals),
sum(market_roas),
],
[
sum(industry_residuals),
sum(value ** 2 for value in industry_residuals),
sum(
industry_residuals[index] * market_roas[index]
for index in range(observation_count)
),
],
[
sum(market_roas),
sum(
industry_residuals[index] * market_roas[index]
for index in range(observation_count)
),
sum(value ** 2 for value in market_roas),
],
]
vector = [
sum(own_roas),
sum(
industry_residuals[index] * own_roas[index]
for index in range(observation_count)
),
sum(
market_roas[index] * own_roas[index]
for index in range(observation_count)
),
]
coefficients = self._solve_three_by_three(matrix, vector)
if not coefficients:
continue
industry_beta = coefficients[1]
market_beta = coefficients[2]
is_eligible = abs(industry_beta) <= 3 and abs(market_beta) <= 3
for snapshot in panel:
snapshot.industry_earnings_beta = industry_beta
snapshot.market_earnings_beta = market_beta
snapshot.is_beta_eligible = is_eligible
def _update_current_quarter_components(self) -> None:
for panel in self._panels.values():
for snapshot in panel:
snapshot.market_return_on_assets_component = None
snapshot.industry_return_on_assets_component = None
snapshot.idiosyncratic_return_on_assets_component = None
if (
not snapshot.is_beta_eligible
or snapshot.industry_earnings_beta is None
or snapshot.market_earnings_beta is None
or snapshot.industry_market_residual is None
):
continue
market_component = (
snapshot.market_earnings_beta
* snapshot.market_excluded_return_on_assets
)
industry_component = (
snapshot.industry_earnings_beta
* snapshot.industry_market_residual
)
snapshot.market_return_on_assets_component = market_component
snapshot.industry_return_on_assets_component = industry_component
snapshot.idiosyncratic_return_on_assets_component = (
snapshot.return_on_assets
- market_component
- industry_component
)
def _form_idiosyncratic_quintiles(self) -> None:
self._eligible_snapshots = []
self._bottom_quintile = []
self._top_quintile = []
for symbol, panel in self._panels.items():
if not panel:
continue
snapshot = panel[-1]
if (
not snapshot.is_beta_eligible
or snapshot.idiosyncratic_return_on_assets_component is None
or not isfinite(snapshot.idiosyncratic_return_on_assets_component)
or not isfinite(snapshot.market_cap)
or snapshot.market_cap <= 0
or snapshot.business_country_id != "USA"
or snapshot.primary_exchange_id not in ("NYS", "ASE", "NAS")
or snapshot.security_type != "ST00000001"
or not snapshot.is_primary_share
):
continue
self._eligible_snapshots.append((symbol, snapshot))
self._eligible_snapshots.sort(
key=lambda item: item[1].idiosyncratic_return_on_assets_component
)
quintile_size = len(self._eligible_snapshots) // 5
if quintile_size == 0:
return
self._bottom_quintile = self._eligible_snapshots[:quintile_size]
self._top_quintile = self._eligible_snapshots[-quintile_size:]
def _calculate_portfolio_weights(self) -> None:
self._portfolio_weights = {}
if not self._bottom_quintile or not self._top_quintile:
return
bottom_market_cap = sum(
snapshot.market_cap for _, snapshot in self._bottom_quintile
)
top_market_cap = sum(
snapshot.market_cap for _, snapshot in self._top_quintile
)
if bottom_market_cap <= 0 or top_market_cap <= 0:
return
for symbol, snapshot in self._bottom_quintile:
self._portfolio_weights[symbol] = (
-0.5 * snapshot.market_cap / bottom_market_cap
)
for symbol, snapshot in self._top_quintile:
self._portfolio_weights[symbol] = (
0.5 * snapshot.market_cap / top_market_cap
)
def _select_final_constituents(self) -> None:
self._selected_symbols = list(self._portfolio_weights)
def _execute_rebalance(self) -> None:
if (
self._pending_weights is None
or self._pending_formation_date is None
):
return
selected_count = len(self._pending_weights)
priced_weights = {
symbol: weight
for symbol, weight in self._pending_weights.items()
if self.securities[symbol].price != 0
}
zero_price_excluded_count = selected_count - len(priced_weights)
executable_weights = {}
for symbol, weight in priced_weights.items():
quantity = self.calculate_order_quantity(symbol, weight)
if quantity != 0:
executable_weights[symbol] = (weight, quantity)
zero_quantity_excluded_count = len(priced_weights) - len(executable_weights)
target_symbols = set(executable_weights)
liquidated_holding_count = sum(
1
for holding in self.portfolio.values()
if holding.invested and holding.symbol not in target_symbols
)
target_long_weights = [
weight
for weight, _ in executable_weights.values()
if weight > 0
]
target_short_weights = [
weight
for weight, _ in executable_weights.values()
if weight < 0
]
long_weight_sum = sum(target_long_weights)
short_weight_sum = sum(target_short_weights)
self.log(
"FORMATION_SUMMARY "
f"date={self._pending_formation_date:%Y-%m-%d} "
f"selected={selected_count} "
f"zero_price_excluded={zero_price_excluded_count} "
f"zero_quantity_excluded={zero_quantity_excluded_count} "
f"executable={len(executable_weights)} "
f"target_longs={len(target_long_weights)} "
f"target_shorts={len(target_short_weights)} "
f"long_weight={long_weight_sum:.10f} "
f"short_weight={short_weight_sum:.10f} "
f"net_weight={long_weight_sum + short_weight_sum:.10f} "
f"gross_weight={long_weight_sum - short_weight_sum:.10f} "
f"departed_holding_liquidations={liquidated_holding_count}"
)
for symbol, (_, quantity) in executable_weights.items():
self.market_on_open_order(symbol, quantity)
for holding in self.portfolio.values():
if holding.invested and holding.symbol not in target_symbols:
self.market_on_open_order(holding.symbol, -holding.quantity)
self._pending_weights = None
self._pending_formation_date = None
def on_end_of_algorithm(self) -> None:
invested_holdings = [
holding for holding in self.portfolio.values() if holding.invested
]
final_long_count = sum(
1 for holding in invested_holdings if holding.quantity > 0
)
final_short_count = sum(
1 for holding in invested_holdings if holding.quantity < 0
)
self.log(
"FINAL_HOLDINGS_SUMMARY "
f"longs={final_long_count} shorts={final_short_count} "
f"invested={len(invested_holdings)}"
)
def _select_assets(self, fundamentals: List[Fundamental]) -> List[Symbol]:
formation_date = self.time
for fundamental in fundamentals:
statements = fundamental.financial_statements
file_date = statements.file_date.three_months
period_ending_date = statements.period_ending_date.three_months
if period_ending_date.month not in (3, 6, 9, 12):
continue
if file_date < period_ending_date or file_date > formation_date:
continue
snapshot = FundamentalSnapshot(
formation_date,
file_date,
period_ending_date,
statements.income_statement.net_income_continuous_operations.three_months,
statements.balance_sheet.total_assets.three_months,
fundamental.asset_classification.morningstar_industry_code,
fundamental.market_cap,
fundamental.company_reference.business_country_id,
fundamental.company_reference.primary_exchange_id,
fundamental.security_reference.security_type,
fundamental.security_reference.is_primary_share,
)
symbol_snapshots = self._snapshots.setdefault(fundamental.symbol, {})
symbol_snapshots[period_ending_date] = snapshot
if len(symbol_snapshots) > 20:
del symbol_snapshots[min(symbol_snapshots)]
prior_period = self._previous_calendar_quarter_end(period_ending_date)
if prior_period in symbol_snapshots:
prior_snapshot = symbol_snapshots[prior_period]
average_assets = (
snapshot.total_assets + prior_snapshot.total_assets
) / 2
if isfinite(average_assets) and average_assets != 0:
snapshot.average_assets = average_assets
snapshot.return_on_assets = (
snapshot.income_before_extraordinary_items / average_assets
)
self._update_excluded_roas()
self._update_panels()
self._update_industry_market_regressions()
self._update_own_roa_regressions()
self._update_current_quarter_components()
self._form_idiosyncratic_quintiles()
self._calculate_portfolio_weights()
self._select_final_constituents()
selector_output = [] if self.is_warming_up else self._selected_symbols
if not self.is_warming_up and self._selected_symbols:
self._pending_weights = self._portfolio_weights.copy()
self._pending_formation_date = formation_date
return selector_output
SPEC = "# Idiosyncratic Profitability — Quintile Hedge Portfolio on the Firm-Specific Component of ROA\n\n**Deutsche Bank \"Academic Insights\" (AI October 2025), item #81 — \"Cash equities — Accountancy #8: Idiosyncratic Profitability\" (p.277).**\n**Underlying paper:** Han, Jackson & Monroe, *\"Excess Returns on Idiosyncratic Profitability: Evidence from a Hedge Portfolio Strategy\"*, Australian Journal of Management, forthcoming (SSRN 4890319). Disaggregation method from Jackson, Plumlee & Rountree (2018), Review of Financial Studies. Sample CRSP/Compustat 1977–2023. No author code published.\n\nImplement the **full method** below. Do not build a reduced version, and do not substitute total profitability (plain ROA) for the disaggregated idiosyncratic component — the paper shows plain ROA carries no significant return premium while the idiosyncratic component does.\n\n---\n\n## Structured brief (for the QC Assistants)\n\n**Concept.** Disaggregate each firm's quarterly return on assets (ROA) into three additive components — a market component, an industry component, and a firm-idiosyncratic component — using firm-specific earnings betas estimated from the past twenty quarters. Rank firms on the idiosyncratic component (IdiosROA), hold a hedge portfolio long the top quintile and short the bottom quintile, value-weighted within legs, refreshed each quarter when the new quarter's accounting data has become available for the full cross-section.\n\n**Why the pattern exists.** The market and industry components of a firm's profitability are easy for investors to verify and anticipate: macroeconomic and industry-level information is abundant, and common information reaches prices as peer firms announce earnings. The idiosyncratic component — the ex-post earnings outcome of the firm's own strategic response to competitive pressure — is the opposite: it is harder to verify, less persistent (competition and imitation erode firm-specific advantage), and costlier to analyze, and capital markets systematically discount uniqueness in firm strategy because evaluating a unique strategy is expensive. Investors therefore make systematic expectation errors about exactly this component: they underreact to strategy-driven performance. Consistent with mispricing rather than risk, the premium loads on no standard factor (alphas survive CAPM, Fama-French 3/5/6-factor, and Hou-Xue-Zhang q-factor models), plain ROA and the market/industry components carry no premium, and sophisticated investors (institutions, analysts) concentrate their holdings monotonically in the high-IdiosROA quintiles.\n\n**Investment universe.** US common stocks listed on NYSE, AMEX, or NASDAQ with an industry classification and quarterly financial statements. Only firms whose fiscal quarters end in March, June, September, and December (calendar-quarter reporters). A firm-quarter enters only if its industry has at least five member firms that quarter, the firm has at least ten of the past twenty quarters of data available to estimate its earnings betas, and its estimated market and industry betas are both no larger than 3 in absolute value.\n\n**Signal.** IdiosROA — the firm-idiosyncratic component of quarterly ROA, i.e. what remains of ROA after removing the fitted market and industry components implied by the firm's own historical sensitivities (exact procedure below).\n\n**Portfolio construction & rebalance.** Quarterly. At the end of February, May, August, and November (two months after each calendar quarter-end, so that essentially all firms have reported), re-estimate the disaggregation on the just-completed quarter, sort all eligible firms into quintiles on the signed magnitude of IdiosROA (equal-count quintiles of the eligible cross-section), and hold: LONG the top quintile, SHORT the bottom quintile, value-weighted by market capitalization within each leg, legs of equal gross size (long 0.5, short 0.5 of portfolio value — total gross exposure 1x, dollar-neutral). Hold until the next quarterly refresh. Trading decisions are made after the close of the formation day; orders fill at the next market open.\n\n**Reference.** Han, Miaodi, Andrew B. Jackson & Gary S. Monroe (2025), SSRN 4890319 — §3.1 (disaggregation), §3.2 (sample), §4.2 (trading strategy), Appendix 1 (variable definitions). Jackson, Plumlee & Rountree (2018), RFS — the earnings-beta disaggregation method.\n\n---\n\n## Implementation specifics from the source paper\n\nNotation: firm i, industry j, calendar quarter t. All accounting inputs are quarterly (single-quarter, not trailing-twelve-month) values.\n\n1. **Quarterly profitability.**\n\n$$\nROA_{i,t} = \\frac{IB_{i,t}}{\\tfrac{1}{2}\\left(AT_{i,t} + AT_{i,t-1}\\right)}\n$$\n\n where `IB` is quarterly income before extraordinary items (quarterly net income from continuing operations) and `AT` is total assets; the denominator is the average of beginning and ending total assets.\n\n2. **Firm-excluded market and industry ROA.** For each firm-quarter, compute the market-level and industry-level ROA *excluding the firm itself* (this prevents large firms from mechanically loading on themselves):\n\n$$\nROA^{M}_{i,t} = \\frac{\\sum_k IB_{k,t} - IB_{i,t}}{\\sum_k AT_{k,t} - AT_{i,t}}, \\qquad\nROA^{I}_{i,j,t} = \\frac{\\sum_{k \\in j} IB_{k,t} - IB_{i,t}}{\\sum_{k \\in j} AT_{k,t} - AT_{i,t}}\n$$\n\n The market sum runs over all sample firms in quarter t; the industry sum runs over the members of firm i's industry j. Industry = the six-digit GICS level, an intermediate granularity of roughly 60–70 industries; where GICS itself is unavailable, use the data provider's industry-group classification of comparable granularity. Each `AT` in these sums is the same beginning/ending average used in item 1. An industry-quarter must contain at least five firms; otherwise its member firm-quarters are excluded.\n\n3. **Two-step earnings-beta estimation.** For each firm at each quarterly refresh, using the trailing twenty quarters of the three series above (minimum ten non-missing quarters; the firm is excluded this quarter if fewer):\n\n Step 1 — orthogonalize industry to market. Regress the firm's industry-ROA series on its market-ROA series and keep the residual series, which is the pure-industry component stripped of market effects (common market/industry information is attributed to the market):\n\n$$\nROA^{I}_{i,j,t} = \\beta_0 + \\beta_1 \\, ROA^{M}_{i,t} + \\epsilon_{i,j,t}\n$$\n\n Step 2 — earnings betas. Regress the firm's own ROA series on the orthogonalized industry residual and the market ROA:\n\n$$\nROA_{i,t} = \\beta_0' + \\beta_1' \\, \\hat{\\epsilon}_{i,j,t} + \\beta_2' \\, ROA^{M}_{i,t} + \\epsilon'_{i,t}\n$$\n\n The slopes are the firm's industry earnings beta (beta_1') and market earnings beta (beta_2'). Exclude the firm this quarter if either |beta_1'| > 3 or |beta_2'| > 3.\n\n4. **Component construction.** Apply the estimated betas to the current quarter's values, and define the idiosyncratic component as the remainder so the three components sum exactly to total ROA:\n\n$$\nMktROA_{i,t} = \\hat{\\beta}_2' \\, ROA^{M}_{i,t}, \\qquad\nIndROA_{i,t} = \\hat{\\beta}_1' \\, \\hat{\\epsilon}_{i,j,t}, \\qquad\nIdiosROA_{i,t} = ROA_{i,t} - MktROA_{i,t} - IndROA_{i,t}\n$$\n\n where the current quarter's orthogonalized industry value is the Step-1 residual evaluated at quarter t.\n\n5. **Formation timing (reporting lag).** The disaggregation for the calendar quarter ending in month M is performed at the end of month M+2 (end of February, May, August, November), by which point essentially all calendar-quarter reporters have filed. Use each firm's most recently *reported* quarterly statements as of the formation date — never statements whose public release date is after the formation date. Portfolio decisions are made after the close of the formation day; the rebalance fills at the next market open. Positions are held unchanged until the next quarterly formation.\n\n6. **Sort and weights.** At each formation, rank all eligible firms by the signed value of IdiosROA and cut into five equal-count quintiles. LONG every firm in the top quintile, SHORT every firm in the bottom quintile. Within each leg, weight positions by market capitalization (value-weighted). Scale the legs to +0.5 and −0.5 of portfolio value: total gross exposure 1x, net exposure 0. A firm that delists mid-quarter leaves the book at its delisting (no special handling beyond the platform's delisting processing).\n\n---\n"
# === CLIENT-DIRECTED OVERRIDE (2026-07-27) - supersedes: execution treatment for selected constituents that have no tradable price at rebalance - directed change: In the rebalance function, check whether each selected security price is zero; do not submit an order for a selected security whose price is zero. ===
# === CLIENT-DIRECTED OVERRIDE (2026-07-27) - supersedes: any temporary starting-cash scaling used to force small selected targets into nonzero share quantities - directed change: Keep starting cash at $100,000,000. ===
# === CLIENT-DIRECTED OVERRIDE (2026-07-27) - supersedes: the requirement to submit an order for every selected nonzero-price constituent when its exact value-weight target rounds to zero shares - directed change: Explicitly exclude and report selected nonzero-price constituents whose built-in calculated order quantity is zero; do not force a minimum one-share order. ===