Skip to content

003Interactive

Building a neuroevolution trading squad: from gambler to market wizard

Let a crowd of random trading bots compete, breed and mutate on Apple's 2024 share price. After thirty generations they return +43%, against +34% for buy-and-hold. Train one yourself, then see why that number doesn't count.

Published
Updated
Reading time
5 min

The conclusion first: the instrument below trains a trading bot in a few seconds. Given the full thirty generations, that bot makes about +43% on Apple's 2024 share price. Buying at the start of the same year and doing nothing makes +34%.

The number is real, but it doesn't mean the bot can trade. Half of this article is about how it was trained; the other half is about why you shouldn't believe it. Train one yourself first.

fig 01/neuroevolution / trading

AAPL

2 January – 31 December 2024, daily close

change over the year
+34.90%
1601802002202402602024-012024-042024-072024-10

buy sell

Set the parameters and press Train. In every generation the whole population trades this year once.

Every bot starts with $10,000 and may do one thing a day: buy one share, sell the share it has held longest, or nothing. Return on investment values any shares still held at year end at the final close. On the chart, cyan triangles are buys and pink triangles are sells; the dashed line on the evolution curve is buy-and-hold.

Training runs entirely in your browser, and the result is stored there, so it is still here the next time you visit.

How it is trained

There are no gradients here and no backpropagation. The reason is practical: "how much did this year make" is not a target you can differentiate, and the market has no "correct trades" to use as labels. So evolution does the work instead:

  1. Generate 50 random bots.
  2. Let each one trade through the year's prices, and score it by its return at year end.
  3. Keep the few with the best scores and let them mix their weights in pairs, with a little random mutation, to produce the next generation. Add a few brand-new random individuals so the population can't get stuck on one habit.
  4. Repeat.

Each bot's brain is a small 30 → 24 → 3 network. The input is the daily percentage change over the past 30 days. The output is three scores, for "hold", "buy" and "sell", and the highest one wins:

content/posts/trading-agent/components/trading.ts
export function observe(closes: number[], day: number): Float32Array {
  const out = new Float32Array(WINDOW); // WINDOW = 30
  for (let i = 0; i < WINDOW; i++) {
    const t = day - (WINDOW - 1) + i;
    if (t >= 1) out[i] = ((closes[t] - closes[t - 1]) / closes[t - 1]) * 100;
  }
  return out;
}

The three parameters on the instrument map onto the steps above: generations is how many times to repeat, population is how many bots each generation has, and mutation rate is the chance that each weight is randomly changed. Press Train and the evolution curve climbs generation by generation, ending about nine percentage points above the dashed buy-and-hold line.

It looks as if they understand this market better and better.

What it actually learned

I trained six different random seeds for thirty generations each (population 50 and mutation rate 15%, all of them the instrument's defaults; stopping at 20 generations gives +41.5% to +43.8%). Every return landed between +42.9% and +43.9%, and the winners all did nearly the same thing: most of the buying happens in the first half of the year, while the price is still low (the year's lowest close is $165 on 19 April), and by year end the bot is almost fully invested. In between it makes a few dozen small sell-high, buy-low round trips, eight or nine in ten of them profitable.

Apple rose 35% over 2024. In a year like that, any strategy that fills up while the price is low and holds to the end beats filling up at $185 on 2 January.

Now look again at where the evolution curve starts. In all six seeds the best bot of the first generation, the best of 50 random bots that have not evolved at all, already makes +39% to +41%, above the dashed line every time. I also generated 2,000 random bots: 13% beat buy-and-hold, and the best made +41%. Thirty generations of evolution squeeze out only about three more percentage points. A baseline that guessing can beat says something about this year's prices and these rules, not about the bot.

Six seeds converging on the same behaviour looks at first like "it found a pattern". The more plausible explanation is the opposite: this year has one obvious low, and every road to a high score passes through it.

Three faces of the same mistake

  • Overfitting. Evolution finds any pattern in historical data that raises the score, whether or not the pattern means anything. The +43% above is a live example.
  • It has seen one kind of market. There is one stock here and one bull year, so the habit the bots pick up is "fill up and hold". In a falling year the same habit loses badly.
  • What it never saw, it cannot have learned. Sudden news, policy changes, liquidity drying up: if it didn't happen in the training data, the bot has no response to it.

Making this experiment honest would take at least three things: split the data into a training period and a test period and report results only on the test period; add trading costs; score across several stocks and several kinds of market. This page does none of them, so its numbers can illustrate the problem but not place an order.

What the bots on this page do best is find the best script for a stretch of history whose ending is already known.


This article first appeared on my previous site in April 2025. The interactive parts were rewritten from scratch in TypeScript when it moved into this notebook; in September 2026 the text was rewritten and the conclusion moved from the end to the beginning.