learn-value-investing-with-phoebe / Analyst session 1 of 10
Learn Value Investing with Phoebe · Analyst session 1 of 10

Owner earnings from the filings

Every US public company files its annual accounts with the SEC, and since 2009 the numbers inside those filings are tagged so a program can read them. Tonight we read them. Four large companies in four different industries, Caterpillar, Exxon Mobil, Johnson & Johnson and Procter & Gamble, each with fifteen to nineteen fiscal years of tagged facts. From those facts we build Buffett's owner earnings the only way the filings allow: net income, plus depreciation and amortisation, minus all capital spending, per share. Then we spend as long on where that approximation lies as on how to compute it. No share prices anywhere. Educational, not investment advice.

🟡 Analyst Analysts, finance and data people who want to read a business from its filings Python, standard library only 45 min
0-3 · Welcome 3-18 · Facts, the formula, where it lies 18-40 · Build-along: owner earnings for four filers 40-45 · Q&A
Part 0

Where we start

The Owner track teaches the reasoning on a constructed business. The ten Analyst sessions do it on real ones. Each session takes one piece of the reasoning, owner earnings, normalising, returns on capital, discounting, reverse discounting, sensitivity, base rates, durability, the memo, and puts it on the same four companies' filings, so that by the bench in session 10 every number is one you have built yourself. Reading the three statements is not taught here; it lives in Finance: Reading the Numbers ↗. Here the statements are inputs.

🎫 Clear all three quiz questions to stamp your passport Live = presented in the 45 minutes Self-study = the full depth, after class ★ Build-along = everyone builds

Educational, not investment advice. Four company names appear because their filings are public and long. Nothing here says whether to buy, hold or sell any of them, and no market price, ticker or price chart appears on any page. The figures come from SEC XBRL company facts; during this build the SEC's own server refused the build machine, so the same records were read from a public mirror and spot-checked against the SEC's API. The source map records which values were checked.

★ What you walk out with tonight. A thirty-line Python reader for any US filer's annual facts, owner earnings per share for four companies across fifteen to nineteen years, the sentence that explains why Johnson & Johnson's owner earnings sit above its net income while Exxon Mobil's sat far below for five years, and a list of the three places the approximation is wrong before anyone uses it in a valuation.

Part 1 · covers XBRL company facts

A filing is a pile of tagged facts

5 min live

A 10-K is a long document for people. Underneath, every number in its financial statements carries a tag: which concept it is (net income, capital expenditure), which period it covers, which unit, and which filing reported it. The SEC publishes all of a company's tagged facts as one file per company, called company facts. The same year's net income appears in three successive 10-Ks, because each one shows three years, and if the company restated it, the later filings carry the new number.

ONE YEAR, THREE FILINGS, ONE ROW Caterpillar's fiscal 2014 net income, as the company facts file holds it 10-K filed 2015 FY2014 net income 3,695 10-K filed 2016 FY2014 net income 2,452 10-K filed 2017 FY2014 net income 2,452 THE SIEVE 10-K, full year only latest filing wins first concept that has the year a restatement, kept FY2014 · net income 2,452 million (as restated) one row per year, per concept: net income, D&A, capex, cash flow, shares Millions of dollars. The restated number is the one later filings stand behind; the original is kept in the source map.
🔍 Click to zoom - the same year can carry two values; a reader has to choose one, and say which
LiveWhat a fact is, and the four choices a reader makes3 min▶

A fact is a concept name, a value, a unit, a start and end date, the form that reported it and the date it was filed. Turning a pile of facts into one row per fiscal year forces four choices, and every one of them changes numbers. Which form: 10-K annual reports only, not quarterly 10-Qs. Which period: full years only, between 330 and 380 days, which drops the quarters and year-to-date figures that 10-Ks also carry. Which filing: the latest, so restatements win. Which concept: companies change tags over time, so a reader keeps a short preference list per field and takes the first one that has the year.

One more choice bites quietly. Johnson & Johnson's fiscal year is 52 or 53 weeks, and three of its years ended on 3 January. Labelled by the calendar year of the end date, fiscal 2009 collides with fiscal 2010 and silently overwrites it. A year that ends in the first ten days of January belongs to the year before.

Self-studyThe tags that changed under our feet3 min▶

Caterpillar tagged its profit as NetIncomeLoss until fiscal 2010 and as NetIncomeLossAvailableToCommonStockholdersBasic from 2011. Its capital spending moved from PaymentsToAcquireProductiveAssets (to 2017) to PaymentsToAcquirePropertyPlantAndEquipment (from 2018); the two agree exactly in the years both appear. Exxon Mobil stopped tagging diluted shares after 2013 and tags basic shares since, which it reports as the same number, so its usable run starts in 2011. A reader that knows only one tag per field returns four years for Caterpillar and three for Exxon and calls it data.

The full concept map, every fallback and every restated value is in the source map. The habit is to print, for each field, which concept fed which years, before trusting any total.

Real world

Caterpillar's fiscal 2014, two numbers. Caterpillar's 10-K filed in 2015 reported fiscal 2014 profit of 3,695 million dollars. Later 10-Ks show 2,452 million for the same year, after the company changed how it accounts for pension costs and restated earlier years. Nothing about 2014's factories or customers changed. A five-year average that started from the first number and one that started from the second differ by about 250 million a year before anyone has made a single judgment.

Part 2 · covers the owner earnings formula

Net income, plus D&A, minus capex

5 min live

Buffett's 1986 letter defines owner earnings as reported earnings, plus depreciation, depletion, amortisation and certain other non-cash charges, less the average annual capital spending the business needs to keep its competitive position and its unit volume. The filings give us the first two terms directly. They do not give us the third: a cash flow statement reports all capital spending, and does not say how much of it was to stand still and how much was to grow.

CATERPILLAR, FISCAL 2024, FROM PROFIT TO OWNER EARNINGS millions of dollars, from 10-K facts 10,792 net income +2,153 plus D&A -1,988 minus all capex 10,957 owner earnings / 489.4m $22.39 per share diluted shares All capex is subtracted, growth spending included, because the filing does not separate it. That is the approximation.
🔍 Click to zoom - the brass minus box is the term Buffett called a guess; the filing gives us an upper bound for it
LiveWhy subtracting all capex is the conservative choice3 min▶

Total capital spending is the spend to stand still plus the spend to grow. Subtracting all of it removes some money the owners chose to reinvest, so the figure is lower than Buffett's owner earnings for any business that is expanding. For a valuation, erring low is the safer direction, and it has one more virtue: it is computed from the filing, not from a guess. The honest name for what we compute is owner earnings, all-capex approximation, and every page and the bench label it so.

The opposite error is the one Buffett warned about in the same 1986 letter: adding depreciation back to profit and calling the result cash flow, with no capital spending subtracted at all. That number hides the money a business must keep pouring in. It is the most common shortcut in a pitch deck.

Self-studyWhy operating cash flow is not owner earnings either3 min▶

Operating cash flow already adds back depreciation, and it also moves with working capital: when a company collects faster or pays suppliers slower, operating cash rises without the business earning more. We store operating cash flow in the sample so you can compare, but the owner-earnings formula here starts from net income, as Buffett's does. Working capital and why cash and profit diverge belong to Finance: Reading the Numbers ↗.

Real world

Exxon Mobil, when capex ran far above depreciation. Buffett's 1986 letter names the oil industry as the case where required capital spending exceeds depreciation, so reported earnings overstate owner earnings. Exxon's filings show the pattern: in fiscal 2011 net income was 41,060 million dollars, depreciation, depletion and amortisation 15,583 million and capital spending 30,975 million, so net income per share was 8.42 dollars and owner earnings per share 5.27. From 2011 to 2015 its capital spending ran between about 1.5 and 2.2 times its depreciation every year. Some of that was growth, and our approximation cannot tell how much.

Part 3 · covers where the approximation lies

Three places the number is wrong

5 min live

A number you computed carefully is still wrong in known ways, and the analyst's job is to name them before anyone else uses it. For these four filers there are three, and each moves owner earnings in a direction you can state.

LAST FISCAL YEAR, DOLLARS PER SHARE hatched = net income per share · brass = owner earnings per share, all-capex approximation 18.81 17.63 6.70 6.15 11.03 12.13 6.62 6.11 Caterpillar FY25 Exxon Mobil FY25 J&J FY25 P&G FY26 D&A above capex 1 · growth capex subtracted: too low for a growing business · 2 · Caterpillar's capex tag leaves out leased equipment: too high 3 · one-off years left in: a single year can be wildly off in either direction, which is Analyst session 2
🔍 Click to zoom - J&J is the one where owner earnings beat profit; the reason is amortisation of acquired intangibles, not a better business
LiveGrowth capex, leased equipment, and one-off years4 min▶

Growth capex subtracted. Every dollar spent to grow is counted as if it were spent to stand still, so a growing company looks worse than it is. Direction: too low.

Caterpillar's leased equipment. The capital spending tag Caterpillar uses covers its own plant and equipment and leaves out equipment its finance arm buys to lease to customers, while the depreciation tag includes depreciation on that leased fleet. So depreciation is added back for assets whose purchase is never subtracted. Direction: too high, for Caterpillar only. A careful analyst finds the leasing spend in the cash flow statement and subtracts it; we leave it, label it, and keep the reader of our numbers informed.

One-off years. Exxon's fiscal 2020 net loss of 22,440 million came with 46,009 million of depreciation, depletion and amortisation that included large write-downs; J&J's fiscal 2023 net income of 35,153 million included a gain from separating its consumer health business. A single year's owner earnings can be off in either direction by more than the business earns in a normal year. Normalising across a cycle is Analyst session 2.

Self-studyWhy J&J's owner earnings sit above its net income2 min▶

J&J's depreciation and amortisation, 7,503 million in fiscal 2025, was well above its capital spending of 4,832 million. A large part of that amortisation is the write-down, year by year, of intangible assets it acquired, which is a charge with no cash leaving that year and no capital spending to replace it. Adding it back is what the formula says to do. Whether those acquired intangibles will need to be "re-bought" through future acquisitions to keep the business where it is, is exactly the guess Buffett's term (c) asks for, and the filing cannot make it for you.

Real world

An unusual repeat in J&J's share count. J&J's diluted weighted-average shares are tagged as 2,429.4 million for both fiscal 2024 and fiscal 2025. The SEC's own company-concept data shows the same figure for both years, so it is what the filing says, and we keep it rather than "correct" it. It is the kind of thing a reader notices only by printing every row before computing anything.

Build-along

Owner earnings for four filers, from the facts

★ 22 min · everyone builds

Python 3, standard library only. The reader fetches a company's facts from the SEC with a descriptive User-Agent carrying your name and contact, which the SEC requires, and stays well under its limit of ten requests a second. If the SEC refuses your network, as it refused the build machine, the source map names the public mirror these pages used. The printed figures below are the ones the bench recomputes.

FOUR STEPS, AND THE CHECK AFTER EACH 1 · fetch company facts, one file 2 · sieve 10-K, full year, latest 3 · join four fields on fiscal year 4 · per share (NI + D&A - capex) / sh check: how many facts? zero means a blocked fetch check: concept per year tags change over time check: missing years a gap breaks an average check: every row one-offs jump out An empty result is not an empty company. A blocked request returns a page of HTML, and a reader must fail loudly on it.
🔍 Click to zoom - the check under each step is the part that catches the defects in Part 3

Step 1 · Fetch one company's facts. Set a User-Agent with your own name and email. The CIK is the SEC's ten-digit company number, zero padded.

★ Step 1 · fetchimport json, time, urllib.request from datetime import date UA = "your-name your-email@example.com" # the SEC asks for a name and a contact def companyfacts(cik): url = f"https://data.sec.gov/api/xbrl/companyfacts/CIK{cik}.json" req = urllib.request.Request(url, headers={"User-Agent": UA}) time.sleep(0.2) # stay well under 10 requests a second return json.load(urllib.request.urlopen(req))

Step 2 · Sieve to one value per fiscal year. 10-K and 10-K/A only, full-year periods only, the latest filing wins, and a 52/53-week year ending in early January belongs to the year before. The first concept in the list that has a year wins.

★ Step 2 · the sievedef annual(facts, concepts, unit="USD"): out = {} for concept in concepts: node = facts["facts"]["us-gaap"].get(concept) if not node: continue best = {} for f in node["units"].get(unit, []): if f["form"] not in ("10-K", "10-K/A") or f["fp"] != "FY" or "start" not in f: continue s, e = date.fromisoformat(f["start"]), date.fromisoformat(f["end"]) if not 330 <= (e - s).days <= 380: continue fy = e.year - 1 if (e.month == 1 and e.day <= 10) else e.year if fy not in best or f["filed"] > best[fy][0]: best[fy] = (f["filed"], f["val"]) for fy, (_, v) in best.items(): out.setdefault(fy, v) return out

Step 3 · Name the concepts, with fallbacks. These lists are the ones that cover all four filers' full runs.

★ Step 3 · the concept listsCONCEPTS = { "ni": ["NetIncomeLoss", "NetIncomeLossAvailableToCommonStockholdersBasic"], "da": ["DepreciationDepletionAndAmortization", "DepreciationAndAmortization"], "capex": ["PaymentsToAcquirePropertyPlantAndEquipment", "PaymentsToAcquireProductiveAssets"], "sh": ["WeightedAverageNumberOfDilutedSharesOutstanding", "WeightedAverageNumberOfSharesOutstandingBasic"], }

Step 4 · Join on fiscal year and divide by shares. Only years where all four fields exist survive the join.

★ Step 4 · owner earnings per sharedef owner_earnings(cik): f = companyfacts(cik) got = {k: annual(f, c, "shares" if k == "sh" else "USD") for k, c in CONCEPTS.items()} years = sorted(set.intersection(*[set(v) for v in got.values()])) rows = [] for y in years: oe = got["ni"][y] + got["da"][y] - got["capex"][y] rows.append((y, got["ni"][y] / got["sh"][y], oe / got["sh"][y])) return rows

Step 5 · Run it for the four filers. The last row for each, as these pages computed it:

★ Step 5 · run, and what it printedfor cik, name in [("0000018230", "Caterpillar"), ("0000034088", "Exxon Mobil"), ("0000200406", "Johnson & Johnson"), ("0000080424", "Procter & Gamble")]: y, ni, oe = owner_earnings(cik)[-1] print(f"{name:18} FY{y} net income/share {ni:6.2f} owner earnings/share {oe:6.2f}") Caterpillar FY2025 net income/share 18.81 owner earnings/share 17.63 Exxon Mobil FY2025 net income/share 6.70 owner earnings/share 6.15 Johnson & Johnson FY2025 net income/share 11.03 owner earnings/share 12.13 Procter & Gamble FY2026 net income/share 6.62 owner earnings/share 6.11

Step 6 · Print every row, and find the one-offs. Loop over all the rows for one filer and look. You should see Exxon's fiscal 2020 owner earnings per share at 1.47 with net income per share at -5.25, J&J's fiscal 2017 at 1.33 and fiscal 2023 at 14.88, and Caterpillar's fiscal 2016 at 3.18. Write one line per jump saying whether it is the business or an accounting event; Analyst session 2 decides what to do with them.

★ Step 6 · look before averagingfor y, ni, oe in owner_earnings("0000034088"): print(y, round(ni, 2), round(oe, 2)) # your notes, one line per jump: # 2020 ______________________________________________ # 2022 ______________________________________________

Keep the label with the number. Wherever these figures travel, they travel as "owner earnings, all-capex approximation, from 10-K facts, latest filing", with the known errors listed. A figure that loses its label becomes a fact in somebody else's deck.

Homework

Before Analyst session 2

30 min
  1. Run the reader for a fifth company you know, and print which concept fed which years for every field. Note any tag change and any missing year.
  2. Compare capex with D&A for each year of one filer. Mark the years where capex ran above D&A and write one sentence on why.
  3. Find one restatement by printing every filing's value for one year of one concept. Which filing would you trust, and why?
  4. Write the label for your fifth company's owner earnings: the approximation, its direction of error, and any company-specific gap like Caterpillar's leased equipment.
Check yourself

Three questions

Clear all three and Analyst session 1 gets stamped in your passport.

1 · Caterpillar's fiscal 2014 net income appears as 3,695 million in one 10-K and 2,452 million in later ones. What does a careful reader do?

The restated figure is the one the company now stands behind. Using it is a choice with a consequence, so it is recorded with the original. A backtest that wants to know what was knowable at the time would make the other choice, and should say so.

2 · Owner earnings here are net income plus D&A minus all capital expenditure. In which direction is that wrong for a growing company?

The filing reports total capex, not the maintenance part. Subtracting all of it understates owner earnings for an expanding business. It is the conservative error, and it has to be labelled.

3 · Johnson & Johnson's fiscal 2025 owner earnings per share (12.13) sit above its net income per share (11.03). Why?

The formula adds D&A and subtracts capex; when the first is bigger, owner earnings beat profit. Whether that amortisation is truly free, or will have to be "re-bought" through acquisitions, is the guess the filing cannot make.

Sources covered

What this session teaches, and where it came from

✓Owner earnings definition; (c) must be a guess; the oil industry as the case where capex exceeds D&A; the "cash flow" fallacyBuffett, W., Berkshire Hathaway shareholder letter, 1986, appendix (read at source)
✓Every filer figure: net income, D&A, capex, shares; 18.81 / 17.63, 6.70 / 6.15, 11.03 / 12.13, 6.62 / 6.11; Caterpillar FY2024 bridge; the restatementSEC EDGAR XBRL company facts, read from a public mirror after the SEC refused the build machine; computed, with two values per filer spot-checked against the SEC's own API
✓The SEC's User-Agent requirement and ten-requests-a-second guidelineSEC fair-access policy, as printed on the SEC's own refusal page during this build
◐Caterpillar's leased equipment, J&J's acquired intangiblesNamed as gaps; the leasing spend is not subtracted and the intangibles are not adjusted
◐Reading the three statements, working capitalTaught in Finance: Reading the Numbers; linked, not re-taught

Every fact on this page, and its verification tier, is recorded in the course's source map.

Analyst session 1 cheat sheet · pin this

A fact has six partsConcept, value, unit, start and end, form, filed date.
The sieve10-K, full year, latest filing wins, first concept that has the year.
Owner earnings, all-capex(Net income + D&A - all capex) / diluted shares. Too low for a grower.
Print the concept per yearTags change. One tag per field returns three years and calls it data.
Three known errorsGrowth capex subtracted, missing capex lines, one-off years.
Fail loudlyA blocked fetch is HTML, not an empty company.