Fundamental: Piotroski F-Score
systemic:core-pfsIndicatorsfunction1 crInputs
| Name | Type | Description |
|---|---|---|
| Year Lag (4 for quarterly data) | integer | How many grid positions back each signal compares against, walked positionally (not by calendar date — see the module description). |
| Net Income | floatarray | Trailing-twelve-month net income. |
| Cash Flow From Operations | floatarray | Trailing-twelve-month operating cash flow. |
| Total Assets | floatarray | | Property | Value | |
| Long-Term Debt | floatarray | | Property | Value | |
| Current Assets | floatarray | | Property | Value | |
| Current Liabilities | floatarray | | Property | Value | |
| Shares Outstanding | floatarray | | Property | Value | |
| Gross Profit | floatarray | Trailing-twelve-month gross profit. |
| Revenue | floatarray | Trailing-twelve-month revenue, in dollars (not per-share). |
Outputs
| Name | Type | Description |
|---|---|---|
| F-Score | floatarray | The Piotroski fundamental-quality score, 0–9. |
The Piotroski F-Score (Joseph Piotroski, 2000) grades a company's fundamental health on a 0–9 scale, built from nine binary tests spanning profitability, leverage/liquidity, and operating efficiency — each comparing the current period against the same period one year (year_lag periods) earlier.
| Category | Signals |
|---|---|
| Profitability (4) | ROA positive · Cash flow from operations positive · ROA improved YoY · Accruals (CFO > Net Income) |
| Leverage & Liquidity (3) | Long-term debt ratio improved YoY · Current ratio improved YoY · No new shares issued |
| Operating Efficiency (2) | Gross margin improved YoY · Asset turnover improved YoY |
Each test that passes contributes one point.
Interpreting the Score
| F-Score | Reading |
|---|---|
| 8 – 9 | Strong fundamentals |
| 3 – 7 | Mixed / average |
| 0 – 2 | Weak fundamentals |
Piotroski's own research applied the score within a value-stock universe (high book-to-market) to separate future winners from losers — pair it with a valuation filter for that use case, or use it standalone as a quality screen.
Year-over-Year Mechanics
Every signal compares index i against index i − year_lag, walked positionally across the input grid — it does not look for "the same fiscal quarter a year ago" by date, it looks year_lag positions back. On a quarterly TTM grid (the EDGAR nodes' cadence), year_lag = 4 compares each quarter to four quarters earlier.
This is a deliberate choice: compacting the series down to only its observed (non-null) datapoints before lagging would silently compare against whichever quarter happens to be four observed slots back — the wrong fiscal quarter whenever an intervening quarter is missing. Comparing by raw position instead means a missing quarter costs you that one comparison (both its own score and any later score that would have lagged into it), never a mismatched comparison.
The first year_lag positions of every series have no prior period to compare against and are always null.
Missing Data — All-or-Nothing
The F-Score follows the honest-null doctrine: if any of the nine signals cannot be determined at a position — a missing input at i or at i − year_lag, or a zero/negative denominator — the entire score at that position is null. A partial sum (e.g. "6 out of the 7 determinable signals") would silently change what the 0–9 scale means; the module never does this.
Denominator guards (each requires the value to be strictly positive at both i and i − year_lag): Total Assets (ROA, leverage, and turnover signals), Current Liabilities (current-ratio signal), Revenue (gross-margin and turnover signals).
In live execution the module returns exactly one datapoint — the newest position — which is null when it cannot be determined (including whenever fewer than year_lag datapoints have been served).
The Leverage Signal's Zero-Debt Corner
The long-term-debt signal uses a strict less-than comparison (LTD/TA at i less than at i − year_lag), matching Piotroski's original formulation. If a company carries zero long-term debt in both periods, the ratio is 0 in both — 0 < 0 is false, so this signal scores 0, not 1. A debt-free company does not get free credit here; it needs to demonstrate an actual reduction to earn the point.
Wiring
From Stock: Income and Cash Flow (TTM): ni → Net Income, cfo → Cash Flow from Operations, gp → Gross Profit. From Stock: Balance Sheet (Quarter-End): ta → Total Assets, ltd → Long-Term Debt, ca → Current Assets, cl → Current Liabilities. From Stock: Fundamentals: shr → Shares Outstanding. All already trailing-twelve-month or point-in-time as appropriate. Select the same company on every node — mixing issuers across nodes silently produces a nonsense score.
Build Revenue with a Multiply module: rps (revenue per share) × shr (shares outstanding).
Coverage note: ltd is not published for every covered ticker (it depends on which EDGAR concept the company tags) — the F-Score is null wherever it is unavailable, same as any other missing input.
Related Modules
- ALTZ / ALTZDP — Altman Z-Score family (bankruptcy risk)
- GRAHAM — Graham Number (fair-value benchmark)