Case study

InvestingAssistant

An investment simulator that attempts to beat buy-and-hold of a global index fund.

Decisions this project turns on — 10 of 18

ADR-0002The algorithm picks, the owner observes, and two buy-and-hold benchmarks are the baraccepted 2026-09-02
ADR-0003One window is every six-month span starting on a stored trading day, with the non-overlapping count alongsideaccepted 2026-09-02
ADR-0004No frontend here; this repository publishes endpoints and Alfred builds the dashboardaccepted 2026-09-02
ADR-0007Stamp duty and a flat broker fee are charged on every trade, benchmark included, and results are cash in handaccepted 2026-09-02
ADR-0009A Phase 2 event is a scheduled results announcement, one per day, by headline words and a before-07:30 gateaccepted 2026-09-02
ADR-0010The drift test holds for N = 5 trading days, direction from the sign of the jump, and the first Tesco answer is recorded with the dividend caveataccepted 2026-09-02
ADR-00112019 to 2023 is the tune stretch and 2024-01-01 onward is held back, fixed before any tuningaccepted 2026-09-02
ADR-0014Phase 2 closes on three companies of different kinds, answer no drift; the FTSE 100 fetch moves to Phase 4accepted 2026-09-05
ADR-0017Phase 3's second question runs; "combined" means the results-day trade is taken only when 12-1 is risingaccepted 2026-09-06
ADR-0018Phase 3 closes on both answers no; picking by past trend across a universe is Phase 4's testaccepted 2026-09-06

Where it started

I started building my InvestingAssistant in Feb 2026 as a scaffold with the one route, GET /price/{ticker}. It sat on the shelf for seven months. Fable 5.1 launched and I decided that it would be a good choice of project to test the model out.

The main focus is learning the stock market and the financial domain in general. Starting off as an experimental tool which collects data from a number of sources, news, past prices and hopefully some social trending down the line. Using these sources it will analyse them and make informed decisions on whether to issue buy, hold or sell on UK shares. All of this is simulated with a virtual bankroll against buy-and-hold over the same dates. When the simulator reports a winning strategy the experiment is a success, if not then looks like buy-and-hold was the winning strategy all along.

The first version had three parts: the algorithm, me picking shares based on findings and the benchmark. I decided there was no point in me picking too as it would only blur the main question, can my algorithm beat the index?

I had set up the repo’s CLAUDE.md to forbid one-shotting features and multi-phase planning. I added some instructions that every concept implemented gets explained to me with the added bonus of me having to explain the concept in my own words before the build commences. It’s a slow build and a lot of commits (25 on 2026-09-02!) and why the reasoning was already written beforehand.

The decision

The bar came before any signal was introduced ([ADR-0002]). Two benchmarks, both kept: 100% VWRP.L, an accumulating global equity fund, and a 60/40 blend with VAGP.L, global bonds. Beating the blend but not the full fund is a weaker result and would be reported as one.

A win in this experiment is at least 2 percentage points over both, and after costs, in more than half of the rolling six month windows I test. I had written “match or beat”, but this doesn’t take into account costs like brokerage fees, so when it matches and subtracting the fees, it’s a loss. The 2 points seems like a good benchmark in itself as professional managers who beat their index do it by 1 to 3 points a year, and most do not.

Following on from this, I put costs before any strategy ([ADR-0007]). Buying a share in the UK pays 0.5% stamp duty and an exchange-traded fund (ETF) pays none. A broker charges a flat fee each way, £5 as a stand-in. That’s to not discount that the benchmark also has an exit fee too, so both sides are judged as cash in hand. So, a round trip on a share costs ~0.6% which is the number every signal has to clear first.

Windows needed a rule of their own ([ADR-0003]). Every six month span starting on a stored trading day counts one, which over the seven years that I have ingested gives a total of 1,669 windows that overlap almost entirely. I had rejected counting only the non-overlapping ones (as it would be too coarse, and the answer moves with an arbitrary first day) and a random sampling (a blurred copy that keeps the overlap). Every fraction reported carries the non-overlapping count beside, about 14, as the sample size.

The one I am most pleased with is the split ([ADR-0011]). 2019 to 2023 tunes and 2024 onwards is held back, written down before any tuning, because picking a parameter from the full table is already tuning.

What it buys

The first signal gave its answer; no, and it’s recorded as such. Phase 2 tested post-earnings-announcement drift on Tesco. Results announcements are pulled from the RNS feed via Investegate ([ADR-0009]), 31 events over seven years, four a year, every one released between 07:00 and 07:02. Buy at that day’s close, sell five trading days later ([ADR-0010]), against both benchmarks over the same days, after costs.

On the held-back windows, good news won 1 event of 6 and sat at a median 2.10 points behind VWRP.L. Bad news reversed. Only 1 event of 5 kept falling, and the typical one finished 0.91 points ahead of VWRP.L. On 2025-04-10 Tesco fell 6.15% on the day and rose 12.7% over the next five sessions. The reversal was a different anomaly from the one tested, 14 events on a single company does not stand on its own, so I made a note of it and left it at that.

Where it’s going

Phase 2 closed on three different kinds of companies, Tesco, AstraZeneca and Games Workshop, with the answer no drift in general ([ADR-0014]). Phase 3 asked whether a past-price trend does any better. I learned about the 12-1 momentum rule, holding the share while the last year’s return is positive and sit in cash when it is not, subtracted from plain old holding on every company and on both stretches. I used it as a filter on the results-day trade. It left good news winning the same half of events, 8 of 16 vs 10 of 20 ([ADR-0017]). Both answers are no now, and I closed phase 3 on that ([ADR-0018]).

Phase 4 is next, the model building. First the full FTSE 100 fetch from the RNS feed with prices and dividends. Then I can simulate buying, holding and selling across the whole index, judging it against the 547 held-back windows, 5 of these share no days. Relative momentum, ranking shares against each other, is still untested until that fetch exists. Phase 4 is a pivotal (and arguably the biggest phase) part of this experiment, if it reports a winning strategy I keep building and using the trust gained in the numbers I will use my own money starting with phase 6. If not, the build is shelved again (and for good this time).

I decided to not build a front end for this experiment and only expose the endpoints ([ADR-0004]) for Alfred to proxy the live API from InvestingAssistant’s data.

As I had created the repo early 2026, this predated my ADR obsession. So I had to write a full eleven ADRs retroactively in one sitting on 2026-09-02. Six more have followed since, one per decision, written when it was needed. Each of them following an InvestingAssistant rule I had in place forced me to either give my own reasoning or take the decision on trust.

Decision numbers, statuses and dates are read from InvestingAssistant/docs/adr/ at sync time, not typed here.