Adam Burich Open to work

← Portfolio

2026 · Ongoing · Personal investing project

Silly Prices Holdings

Solo · July–August 2026 · ~15.7k lines of Python across 31 modules · 337 commits · 410 tests

Built on the old Buffett and Graham idea that quality companies sometimes trade at silly prices. Keep a pre-vetted list of wonderful businesses, wait for a temporary dislocation, buy at a real margin of safety, and hold. The software's job is to make each of those steps mechanical, reproducible, and honest about when it doesn't know.

The idea

Most "buy the dip" systems buy things that are down. Most things that are down are down for a reason. The discipline here is to separate the two: only businesses that pass hard quality gates are eligible at all, "cheap" is measured against each company's own history rather than the market's, and every candidate has to survive a written diagnosis of whether the damage is temporary before anything is bought. Nothing is bought to flip.

The whole pipeline is standard-library Python over free data — SEC EDGAR's XBRL company facts and Yahoo prices — with a disk cache in front of both (24 hours for EDGAR, 12 for prices, about three requests a second to the SEC). The universe is the full S&P 500 plus three foreign ADRs (TSMC, ASML, Novo Nordisk): 507 names, re-rated daily.

A GitHub Actions job rebuilds and publishes the board every evening. A separate daily cloud routine has Claude work through the judgment queues, and commits its verdicts to the repo — so the board is just a re-render of committed data, and any verdict can be traced back to the exact prompt that produced it.

  1. EligibilityHard quality gates computed from primary SEC filings.
  2. ScreenDown meaningfully, and valued in the bottom of its own history.
  3. DiagnoseClaude: temporary dislocation or permanent decline?
  4. ValueA rule-based buy line, with a stricter cash-flow floor beneath it.
  5. AcquireA weekly ladder of up to three lots, each only at a lower price.
  6. HoldSell only on a broken thesis or egregious overvaluation.

01Quality gates from raw XBRL

Every gate is computed from the company's own filings, with current-period figures built as trailing twelve months from 10-Qs rather than stale annual numbers.

GateBarNotes
Piotroski F-Score≥ 7A criterion that can't be computed counts as 0 — deliberately strict. Returns n/a if fewer than 5 of 9 are computable.
ROIC vs. WACC> 9%After-tax EBIT over invested capital, at the company's own tax rate. Fails on three consecutive declines. Returns n/a if only half the debt is tagged, rather than guessing.
Altman Z> 2.99Skipped for ADRs, where it would mix a USD market cap with a local-currency balance sheet; distress disqualifier waived for utilities and REITs.
Beneish M< −2.22Earnings-manipulation screen; missing inputs get neutral values and are listed.
Balance sheet & dilution—Debt/EBITDA < 3.0×, gross profit/assets > 15%, cash flow > net income, share count up ≤ 1% over five years, no two consecutive revenue declines.

The F-Score bar earned its place in the backtest: without it, the system bought Citigroup in October 2007 and rode it most of the way down. A bar of 5 would have refused it.

02What "cheap" means

For each company the pipeline builds about ten fiscal years of EV/EBIT, P/E, and P/FCF, each priced at that year's fiscal year-end. The buy line is the 5th percentile of the company's own EV/EBIT history, applied to current EBIT — so the target rises as the business grows. It started at the 20th percentile; a backtest grid showed the deepest entries winning every sell-side comparison, and the line moved.

Each name gets one rating: BUY at or below the line, CLOSE within 8%, WATCH within 25%, RICH beyond — or one of the refusals: FLAGGED (cheap, but a value-trap disqualifier fired or the diagnosis wasn't "temporary"), GATED (failed the F-Score), NO-VALUE (history too short, too erratic, or median multiple above 40×), and AVOID. A strict cash-flow DCF (9% discount rate, growth at 70% of the company's own, capped at 3–8%) is shown as a deeper floor when it sits below the line.

One multiple doesn't fit every business, so a few names get a different lens:

03The qualitative half, automated

Cheap isn't enough; the question that actually matters is why it's cheap. When a name enters the buy zone, Claude researches it with web search and returns a structured verdict:

classification   temporary | permanent | uncertain
confidence       low | medium | high
cause            what happened
moat_status      intact | eroding | unclear
five_questions   q1–q5, all must be "yes" for temporary
disqualifiers_fired, key_risks, recommendation, summary
narrative        with cited sources, shown on the board

Only temporary can proceed to a buy; uncertain fails safe. Each verdict records the provider, the model, and a hash of the prompt. Verdicts are reused for a week (90 days for "permanent") unless something happens first — a new SEC filing, a 12% price move, crossing the buy line, or a change in the disqualifiers — so the model is re-asked when the facts change, not on a timer. Two newer queues follow the same shape: an exit review for held names that deliberately withholds cost basis and P&L from the model, and an informational "is this expensive price earned?" check.

04Data quality is most of the work

XBRL is messy, and every mistake in it becomes a wrong rating. A selection of what the git log records fixing:

05Keeping score on itself

A backtest of about 400 configurations on point-in-time S&P 500 data from 1998 to 2026 gave the shape the system is built around: names the funnel would have bought beat the market by a median +3.9% over five years, the value traps it rejected lagged by −10.9%, and naive "down 30%" dip-buying lagged by −23.9%. Mechanical thesis-break selling lost in every configuration tested, so it isn't used.

The same work also produced the results that keep the claims modest. Out of sample, the configuration rankings barely held (a rank correlation of 0.24 between training and test; the training winner placed 16th of 24). And a blinded audit — could Claude diagnose anonymized filings without recognizing the company? — failed all three rounds, which means the verdicts can't be assumed free of hindsight. Going forward, a paper portfolio built on paper-broker tracks every buy, and a "graveyard" report checks whether the names the diagnosis rejected actually do worse than the ones it accepted.

06The board

The public board shows each name's rating, buy line, and verdict with its citations, with a slider to narrow the universe to the largest N companies and a what-if slider for the buy percentile. The header carries a market-regime label built from volatility, credit spreads, and unemployment data. The deploy has two independent guards — a per-file publish list and a final check that refuses to ship if a position table appears — so the paper holdings never reach the public page.

Stack

Python (standard library only) · SEC EDGAR XBRL · Yahoo Finance · GitHub Actions · GitHub Pages · Claude (daily cloud routine) · paper-broker

A personal, long-term investing project and my own methodology. Not investment advice.