← All posts Engineering & Postmortem

I built a market digest. Then I asked it about my own portfolio.

May 2026

My E*TRADE was down ~2% on the day. NVDA, OKLO, MSFT, BRK-B — nothing dramatic, just the slow drip that makes you want to look at it. So I opened the AI-and-stocks digest I've been building for the last few months, bitinforming, and asked it what was going on with my holdings.

It gave me a market briefing. Generic, well-written, useless. Three movers, none of them touched my portfolio. The dominant theme of the day was "power" with 12 stories running 7× their baseline — but the digest never connected that to OKLO, the small modular reactor stock I own whose entire product thesis is SMRs power AI datacenters. The day's #1 paper was literally "Designing Datacenter Power Delivery Hierarchies for the AI Era." OKLO wasn't mentioned anywhere.

Useful failure. I wrote down what was wrong, fixed it in one session, and the fixes were more interesting than I expected.

What the audit turned up

Bug 1 — Hidden track record

There was a 142KB JSON file on disk called track_record.json — forward-return attribution for every signal the digest had ever flagged. The internal dashboard read it. Readers couldn't see it. A recommendation engine hiding its own scoreboard.

Bug 2 — Keyword surface area

The keyword→ticker map had OKLO under nuclear, smr, small modular reactor, fusion. None of which appear verbatim in arXiv abstracts about datacenter power. So on the day SMRs were the obvious thesis, the SMR play stayed invisible.

Bug 3 — Wrong audience

The daily output was 23KB of text aimed at "operators, investors, and engineers" simultaneously — which means it served none of them well.

Three bugs, one underlying mistake: I'd built a market-wide briefing when the wedge is a personal one.

Fix #1: Watchlist mode

A DIGEST_TICKERS=NVDA,OKLO,MSFT,BRK-B env. The digest now opens with a "Your Watchlist Today" section: holdings with live prices, items that touched your tickers ranked by impact, and an explicit no coverage today on BRK-B so you know nothing showed up.

After the fix, my morning question got an actual answer:

## Your Watchlist Today
- Holdings: NVDA $222.03 (-1.46%), OKLO $57.49 (-7.65%),
            MSFT $419.05 (-0.68%), BRK-B $483.62 (+0.19%)
- MSFT, NVDA, OKLO — Designing Datacenter Power Delivery
  Hierarchies for the AI Era (impact 137.71)
- MSFT, NVDA — Offline Semantic Guidance for Vision-Language-
  Action Policy Distillation (impact 67.7)
- No coverage today: BRK-B

Fix #2: Surface the track record honestly

The dashboard already had 523 of 652 calls scored over 365 days against SPY. Aggregate: 51.4% 5-day hit rate, +7.59% average 20-day alpha, 75% win rate on the 20-day window. I added a five-line block above the executive brief with those numbers and named two trades: the top call (RKLB +68.7%) and the worst call (TER -20.5%).

The instinct is to omit losers. The version that survives skeptical readers names them.

Fix #3: The bug I didn't expect

The dashboard also runs a deterministic backtest — buy one position per day at the close, hold 5 trading days, equal-dollar size, SPY benchmark. It had been quietly reporting -1.86% alpha for weeks. I'd been ignoring it because "the signal is right, the strategy code is just naive."

It wasn't naive. It was wrong in a structural way I didn't see until I looked.

The rule said "take the first listed ticker on the top-impact item." My keyword map looked like this:

ai:
  - NVDA
  - MSFT
  - GOOGL
artificial intelligence:
  - NVDA
  - MSFT
  - GOOGL

Dict order is insertion order, which is intent order — but also market-cap order. Almost every AI-themed item triggers ai first, and ai returns NVDA at position 0. So "first listed ticker" was "NVDA" for ~70% of days. The backtest had been buying NVDA every day. It looks like SPY because it kind of is SPY.

The fix is one function:

MEGA_CAP = {"AAPL","MSFT","GOOGL","GOOG","META",
            "NVDA","AMZN","TSLA","BRK-B"}

def _pick_thesis_ticker(tickers):
    for t in tickers:
        if t.upper() not in MEGA_CAP:
            return t
    return tickers[0]

First non-mega-cap. Mega-caps stay in the ticker list for the briefing — they get the signal exposure — but the trade goes to the smaller-cap thesis play, because that's the entire point of reading bitinforming over reading the Wall Street Journal.

Over the same 53 trading days the backtest moved from:

+12.32%
Strategy return (before)
+14.18%
SPY benchmark
-1.86%
Alpha (before)

to:

+19.06%
Strategy return (after)
+14.27%
SPY benchmark
+4.79%
Alpha (after)

The sample is 20 closed trades, n=52 on the 20-day alpha — small enough that it may not survive a regime change. The engineering point doesn't depend on it.

The trade list is more interesting too: OKLO -26% (brutal), RKLB +68% (made the month), MDB +14%, ISRG twice for losses. The strategy now has actual dispersion because it's actually betting on theses instead of cloning the index.

What I'd take from this

Three things, none specific to stocks.

Takeaways
  1. Aggregators that don't answer "what about mine?" are newspapers, not tools. The wedge is always personal — your code, your tickers, your patients, your customers. The market-wide briefing is the funnel artifact, not the product.
  2. Track record is the cheapest trust lever a recommender will ever have, and almost everyone hides it. A model that names its losers reads as ten times more credible than one that lists its wins.
  3. The default ordering of every keyword/category/tag list in your codebase is a strategy choice. If you sorted alphabetically, you picked alphabetical bias. If you sorted by insertion, you picked the bias of whoever was paying attention first. The same shape of bug shows up in news ranking, social feeds, and search relevance. Worth checking which one you accidentally chose.

The product is at bitinforming.com. The code that drives it is the kind of thing one person can hold in their head, which is the only reason I caught the mega-cap bias before someone with a real portfolio did.

Trade your plan, not the headline.

Bitinforming Intelligence Briefing More notes →