← Writing

I have Claude write up my portfolio every morning

I know nothing about finance but I do have a portfolio. For twenty days I had forecasts written and scored. Mostly I learned a word: baseline.

·13 min read

Also available in Turkish This post is a translation.

Contents
  1. First I had to settle this: Claude does not do arithmetic
  2. The file layout
  3. What a forecast looks like
  4. So what is a baseline
  5. Why it was rubbish
  6. Is the point forecast worth anything
  7. There was also a 74.5%
  8. How the system changed, day by day
  9. The most useful file: the error log
  10. Why I wrote the analysis plan first
  11. The part that has nothing to do with finance
  12. At the end of twenty days

I know nothing about finance. I do have a portfolio, with gold in it, a technology fund, participation accounts. For months I had been looking at the balance and thinking “it went up” or “it went down”, and that was all. I did not know what moved what.

One morning I tried this: have Claude take a photograph of my portfolio every day, write down what would happen next, and score it the following day. The goal was not to get rich. The goal was to learn, through my own money, what actually moves what.

It ran for twenty days. The forecasts were not the valuable part.

  • 20
    days
  • 148
    scored forecasts
  • 53
    correction records
  • 0
    positive findings

First I had to settle this: Claude does not do arithmetic

What I noticed on day one was this. If you ask a language model “how much did my portfolio go up”, it gives you a number. The number looks reasonable. But that number was not calculated, it was produced.

So I split the work in two from the start. Claude is the side that thinks, code is the calculator. I wrote the border between them down and never broke it again.

fetch_market.py pulls dated prices from APIs cross checks them never fills a gap Claude scans the news writes forecast and rationale does no arithmetic pt.py stores and matches computes the error metric never goes online the border is deliberately sharp: the only box a hallucination can enter is the middle one
I set this split up on 1 August. The left and right boxes never interpret anything, and the middle box never does arithmetic.

I had the right hand rule from day one. I had to add the left hand one on 5 August, because the most productive source of error in the model turned out not to be arithmetic: it was treating an undated number seen in a search result as true. Reading a price is no longer Claude’s job either.

The file layout

Everything is a flat file. No database, no interface. The reason is simple: when I open this folder a year from now, I want to be able to understand what I did.

data/
  portfolio.json            asset definitions
  snapshots/2026-08-21.json prices and portfolio value for the day
  forecasts/2026-08-21.json forecasts, evidence, market state
  resolutions.jsonl         outcomes, append only
  evidence/2026-08-21.md    the raw news note for the day, with sources
  narrative/2026-08-21.md   the commentary that goes into the report
  reviews/on-kayit.md       analysis plan: which test, which n, which threshold
  holdings/2026-08-21.json  the real assets inside the funds

The folder that helped me most turned out to be evidence. Every morning Claude scans the news and writes that day’s note with its sources. What sits there is not the forecast but the reasoning behind it.

One example. The note from 1 August contains this line:

While the geopolitical risk premium pushes gold up, the same event pushes it down through the oil, inflation, Fed hike, real rate channel. The two forces largely cancel each other.

Gold price Geopolitical escalation risk premium pushes up The same event oil, inflation, Fed hike, real rates the two forces cancel out point near zero, band wide
This is where I learned what moves what. The sentence "war broke out, so gold goes up" is wrong in this picture.

Another line changed how I read my own balance more than anything else:

The controlled slide of the Turkish lira gives every lira denominated asset a steady upward push of roughly 0.07% a day. So “my portfolio is up 2% this month” and “I got richer” are not the same sentence. Before measuring it, I did not know those were different.

What a forecast looks like

Every forecast has five parts: a point value, an 80% band, a probability of going up, a rationale, and the event that would falsify it. The last one is the most useful, because the next day I get to ask “did the thing that would break this happen” instead of “was I right”.

{
  "asset": "gram_altin",
  "horizon": "1d",
  "target_date": "2026-08-24",
  "base_price": 7039.39,
  "point_pct": 0.15,
  "low_pct": -1.85,
  "high_pct": 2.15,
  "p_up": 0.53,
  "confidence": "low",
  "rationale": "Today's quote already carries the move since Wednesday, and it cannot be counted twice. What is left is the Friday US session and the Sunday open. In an asset that ran 5.9% in three days, profit taking into the weekend is a real risk."
}

Once written, the record is sealed. When the target day arrives, pt.py matches it against what happened and scores it. The scoring side is not a language model, because letting it fill in its own report card would be absurd.

Pricesscript pulls Newsevery day, no exception Forecastrationale and falsifier Seal Scorecode does it the same order every morning, no step skipped
This order is the one thing that did not change across twenty days. Everything that did change is in the table further down.

So what is a baseline

Now to the thing I actually learned.

At the end of the first week Claude told me this: the forecasts beat the naive baseline 70% of the time, p < 0.001. I was pleased. But I did not know what the word baseline meant, only that it sounded good.

I learned later. A baseline is the dumbest answer you could give without thinking at all. In price forecasting the dumbest answer is “tomorrow it stays where it is today”. The model has to beat that, otherwise its thinking is worth nothing.

That made sense. The problem is that this dumb answer is not equally dumb under all conditions.

Why it was rubbish

On 12 August I looked at the measurement window. Every weekly move that landed inside it was positive. Twenty out of twenty.

20 of 20 observations positive average +5.78%
The market went one way for the whole window. Claude had also written 86.5% of its forecasts as positive.

In a window like that, beating “no change” is not skill. Any small positive number beats it mechanically. What I was measuring was not the model’s foresight but the direction the market happened to be going.

So the headline I had been proud of in week one was measuring nothing.

The fix was to put three dumb answers in place of one. One of them genuinely dumb, the other two a little harder.

BaselineMeaningBeatenRatep
Naivetomorrow stays the same104/1480.703< 0.001
Driftit moves like the last 5 days on average86/1280.672< 0.001
Momentumit moves as much as it did yesterday93/1280.727< 0.001
All threebeating all of them at once50/1280.3910.995

It beats each of them one at a time. It cannot beat them together: 39.1%, which is worse than flipping a coin.

A baseline you can beat by accident is not a baseline.

Is the point forecast worth anything

Comparing against baselines is still a gentle exam. The harder question is whether the number the model gives is better than giving no number at all.

To measure that I compared two things per asset. First, the spread of the forecast errors. Second, the spread I would get if I made no forecast and just said the average for that asset.

0 forecast is worse forecast is better A1−2.5% A2−4.3% A3−0.9% A4+15.8% A5+0.6% A6−3.8%
In five of six there is no gain, and in three the forecast is worse than a constant number. The single exception is A4, where there are only 14 observations, so most likely noise.

This has a practical consequence, and it is what actually convinced me. If the forecast does not reduce the spread, then the width of the confidence band comes from the volatility of the market rather than from my ignorance. That band does not narrow by collecting more data. The expectation that “if I improve the model a bit the bands will tighten” turned out, in measured form, to be wrong.

There was also a 74.5%

On the same dataset the direction hit rate came out at 74.5%. Three out of four forecasts called the right direction.

That was very tempting as a headline. I did not use it, because it is the same trap wearing a different coat: in a window where most days are up, saying “up” scores well and hides the fact that you know nothing.

The measure that cleans this up compares the probabilities against simply counting how many of the recent days were up.

Brier score, lower is better model 0.208 simple count 0.194 "how many of the recent days were up" The gap model behind
Counting the recent days scored better than the probabilities the model produced.

How the system changed, day by day

The forecasts did not work, but the system got a little less wrong every day. Most of the changes came after an error.

DayWhat happenedWhat changed
1 AugFirst recordI took a fund for a money market fund; it was equity heavy
2 AugWeekend profit shareParticipation accounts pay nothing at weekends, engine fixed
3 AugMoney in and outMeasuring return without stripping cash flow is meaningless
4 AugInside the fundsThe real assets inside a fund became data too
5 AugReading pricesClaude was barred from reading numbers out of search results
6 AugBank screenSix corrections in one day, the base of the measurement was wrong
10 AugSecond ledgerA separate portfolio moved to its own root, double counting ended
12 AugHarder baselinesDrift and momentum added, the headline collapsed
13 AugDeep reviewThe scoring engine was rewritten
20 AugPublicationDataset and methodology opened anonymously

The most useful file: the error log

I gave every correction a number. K1, K2, K3 and onwards. Today I am at 53.

Each record holds: when the error happened, when it was noticed, who found it, how many days it stayed hidden, how it was fixed, and whether the same thing had happened before.

Who found the error Claude · 43 me · 10 Time until noticed median 1 day mean 2.5 days longest 15 days
Errors found by the user are not credited to the agent's self detection record. Without that split the number is useless.

This file taught me more than the forecasts did. Most of the errors were not in the model’s reasoning but in the base of the measurement: a wrong price, money counted twice, profit share booked to a weekend, a move counted a second time.

Why I wrote the analysis plan first

One detail makes everything else possible: I wrote down which test I would run at which threshold before seeing the data.

This is not ordinary rigour. Here the same agent produces the forecast, scores it and changes the method. In a setup like that, looking at the result and then asking “which subset did I do well in” is not merely possible, it is the default behaviour. Preregistration is the only barrier I have against it.

For the same reason there is a test for whether the corrections systematically favour the agent’s own report card. There, a significant result is bad news rather than good.

The part that has nothing to do with finance

The class of error here is not specific to finance. Ask these three questions about your own work:

  • Your classifier is 95% accurate. Is 94% of the data already one label?
  • Your A/B test won. Was the control arm the best simple thing you could have done, or something easy to beat?
  • Your recommender beats a popularity ranking. Does it beat the last thing the user clicked?

Putting three baselines in place costs almost nothing next to putting one in place. The only difference is that one tells you the truth and the other makes you feel good.

At the end of twenty days

Every recorded finding is negative: the point forecast adds no information, all three baselines are not beaten together, the probabilities lose to a simple count, the bands are too wide.

But learning that was what I wanted at the start, not getting rich. When I look at my portfolio now I know what pushes what: how much of the return is explained by the steady slide of the lira, how the two forces on gold cancel each other, and that today’s fund price is really yesterday’s close.

The system improves not by forecasting more cleverly but by learning what it cannot forecast. That is what twenty days taught me.

The dataset, the methodology and the preregistration document were published anonymously, and every number here can be reproduced with an independent script.

Notes. The sample is small: 20 days, roughly three independent observations per day, a single volatility regime. None of the results here is statistically settled. The assets are referred to by the aliases A1 through A6, and no amount, balance, quantity or institution appears anywhere. This text is not investment advice, and the forecasts were never used in a trading decision.