Fly-Brain Trader v3: a mushroom-body reward learner, at five checkpoints

A small, biologically inspired reward learner modelled on the fruit fly's mushroom body. There's no backprop and no gradient descent. The network learns online through a three-factor, dopamine-gated plasticity rule: presynaptic activity × postsynaptic target × a reward-prediction-error signal. The reward signal is loss-averse ("pain" for losses weighted 2×, "happiness" for gains). It also gets counterfactual ("fictive") updates for actions it didn't take, and a performance bonus ("love") while it beats a benchmark.

The repository releases the same network at five points in its training run: random init → synthetic curriculum → real-data pre-training → validation → blind test. You can inspect what each stage did to the weights.

Research artefact, not a trading model. In the blind test (Jan 2024 – Oct 2026) it returned +3.0% a year in US dollars, against +22.5% for the S&P 500. Its stock picks beat random picks made on the same schedule (raw p = 0.041), but that isn't significant after correcting for the 10 tests in the study (Holm p = 0.41). Don't use it to trade. "Pain", "happiness" and "love" are scalar reward terms in an update rule. The model doesn't experience anything.

Paper: paper.pdf, Pain, Happiness and Love in a Fly-Brain Trader: Blind Tests of a Connectome-Inspired Reward Learner in Equity Markets (working paper, Oct 2026) Code, training and evaluation scripts: github.com/MikhailPeganov/fly-brain-trader


Model summary

Stock brain Market brain
Task Rank stocks each week (score → top-20 long book) Decide long vs short each week
Inputs 22 features 10 features
Input encoding 110 projection neurons (5 Gaussian tuning curves per feature, σ = 1.2) 50 projection neurons
Hidden layer 2,000 Kenyon cells, k-WTA (top 100 = 5% active) 500 Kenyon cells, top 25 active
Input → hidden Fixed sparse random projection, 7 inputs per cell, log-normal weights (14,000 non-zeros) Fixed, 3,500 non-zeros
Hidden → output Plastic: 2 output neurons × (2,000 KC + 110 direct) = 4,220 trainable synapses 2 × 550 = 1,100 trainable synapses
Output balance d = (L − S)/(L + S), divided by its running RMS Same, compared with its own running mean/std

This is a random-features model with a learned linear readout. The expansion layer is never trained. Only the readout synapses change, and they change through a local reward-modulated rule, not a loss gradient. The direct projection-neuron → output pathway (lateral-horn-like) lets simple monotone rules be learned without relying on sparse conjunctions.

Training objective: the plasticity rule

Every week, each position's outcome u (next-week return in volatility units, c = trading cost) is turned into a loss-averse valence. Losses are weighted λ = 2× as heavily as gains, as in prospect theory:

r = pos · u − c
v = max(r, 0) − λ · max(−r, 0)                      λ = 2

The output neuron for the side that was traded receives v. The side that wasn't traded receives a weaker fictive signal (φ = 0.3), computed from what it would have earned. Each signal is taken relative to a running baseline b, which gives a reward-prediction error as in the Schultz–Dayan–Montague account of dopamine. That error then updates only the synapses of the Kenyon cells that were active:

b ← b + 0.01 (mean(g) − b)                          running baseline (RPE reference)
w ← w + η (g − b)ᵀ a / n                            three-factor update, η = 0.01
w ← w + ρ (w₀ − w)                                  homeostasis, ρ = 2×10⁻⁴, w₀ = 1
w ← clip(w, 0, 3)                                   synapses stay excitatory and bounded

Love (performance shaping): once a week the trader compares its trailing 52-week USD return with the S&P 500's. When it leads by Λ > 0, the synapses behind its current holdings and its current long/short call get extra reinforcement:

Δw_side = η · min(Λ / 0.10, 1) · aᵀ 1[held] / n

Falling behind triggers no extra update. A slow "tonic pain" trace (pain_fast, pain_slow in the config) raises the trading threshold after runs of losses.

Training procedure

One continuous run (seed 0), weekly steps, with no resets between stages. Each checkpoint is a snapshot of the same weights.

Stage Checkpoint Data Steps Learning rate Exploration
0 0_untrained none: random wiring, all readout synapses at w₀ = 1 0 — —
1 1_after_school Synthetic curriculum: 5 simulated markets × up to 6 interleaved rounds. Each lesson is a fresh 100-stock, 1,300-day episode (~208 weekly updates) up to 30 lessons 0.03 Gaussian score noise σ = 0.5
2 2_after_pretrain Tokyo small caps, Mar 2017 – Dec 2021 ~250 weeks 0.01 σ = 0.5
3 3_after_validation Tokyo small caps, 2022 – 23 (the only period used to choose settings) 97 weeks 0.01 none
4 4_after_blind_test Tokyo small caps, Jan 2024 – Oct 2026, never seen during design 136 weeks 0.01 none

Evaluation is prequential. In stages 3 and 4 the model keeps learning online, but each week's decision is made before it learns from that week's outcome. Every reported return is therefore out-of-sample at the time of the decision. The test period was simulated once, after all settings were locked in code.

Curriculum ("maths school"). Before it sees real prices, the brain is trained on synthetic markets that each follow one textbook mechanism: random walk, momentum (AR(1) drift), mean reversion (Ornstein–Uhlenbeck), low-volatility premium with clustered volatility, and news shocks that move prices the next week. Worlds are interleaved and shuffled each round so later lessons don't overwrite earlier ones. After each lesson, the brain sits an exam on a fresh episode. The score is the rank IC against next-week returns, and the pass mark is half the IC of the hidden true signal (the "oracle").

Hyperparameter selection. Only one setting was tuned: the market brain's shorting threshold θ ∈ {0.75, 1.5}, chosen on 2022–23 validation. θ = 1.5 was locked before any test data was read. Everything else was fixed in advance.

Hyperparameters

Name Value Meaning
n_kc, k 2,000, 100 Kenyon cells, active cells (5% sparsity)
fan-in 7 random projection neurons per Kenyon cell
T, sigma 5, 1.2 tuning curves per feature, tuning width
lr (η) 0.01 (0.03 in school) readout learning rate
lam (λ) 2.0 loss aversion (pain weight)
fictive (φ) 0.3 counterfactual update strength
homeo (ρ) 2 × 10⁻⁴ pull towards w₀
w0, wmax 1.0, 3.0 baseline and max synaptic weight
direct 1.0 direct-pathway gain
θ (market brain) 1.5 σ short when this much more bearish than usual
love cap 10 pts lead over the S&P 500 that gives full-strength love

Training dynamics

How the synapses changed per stage

Mean absolute change per readout synapse, computed from the released checkpoints:

Stage Stock brain Market brain
School 0.0220 0.153
Pre-train 2017–21 0.0031 0.032
Validation 2022–23 0.0012 0.013
Blind test 2024–26 0.0012 0.019
  • Most of the learning happens in the curriculum. School moves the stock brain about 7× more than five years of real Tokyo data. Real markets are low-signal, and the loss-averse RPE update mostly cancels out.
  • Weights stay close to the homeostatic set point. The stock brain's readout ends at mean 0.998 and std 0.034 around w₀ = 1. What it learns lives in small, consistent offsets, not large weights.
  • The random projection never changes. pn_to_kc is identical across all five checkpoints, which you can check by diffing the safetensors.

What it learned

Learned preferences

Preference per feature is measured as the slope of the long-vs-short balance as that one feature sweeps from −2 to +2, with all others held at zero. The curriculum installs strong news preferences: positive on tone and bullish keywords, negative on bearish keywords. It also installs a strong preference for the least-squares forecast. Real Tokyo data then gradually shifts the brain towards lower volatility, lower beta and away from lottery-like jumps (MAX), the same tilts the paper finds in the holdings.

Curriculum exams (final, this seed)

Synthetic world Rank IC Oracle IC Result
Random walk −0.000 0 pass (no false signal)
Momentum 0.042 0.115 fail (37% of oracle)
Mean reversion 0.014 0.231 fail (6%)
Low-volatility premium 0.038 0.029 pass
News predicts next week 0.041 0.054 pass

A real capacity limit. Across three seeds the learner never acquired momentum and mean reversion together. That held even with the direct pathway, regime features, longer schooling and different learning rates. The two rules map the same inputs to opposite actions ("buy recent winners" vs "buy recent losers"). A single-layer, loss-averse readout averages them away instead of gating on regime. News, which conflicts with nothing, was learned by all three seeds.

Evaluation (blind test, Tokyo small caps, USD, after costs)

Metric Value
Annual return +3.0% (S&P 500 +22.5%)
Sharpe 0.26
Max drawdown −19%
Weeks short 12%
Picks vs 2,000 random pickers on the same schedule p = 0.041 raw · 0.41 Holm
Long/short timing vs random weeks p = 0.26
2022–23 validation −15.2% a year (S&P 500 +1.2%)

Costs are half the live quoted spread, plus the price impact of a $10k order (Amihud) and a 0.10% commission. Only stocks with at least $100k of daily turnover are eligible. The testing framework was itself validated: on 40 placebo markets, 2 came out significant at 5%, and planted signals were detected (IC 0.06 → p = 0.003). Retraining with the training script reproduces the blind-test return exactly (reproduces_published_result: true in training_log.json).

Quick start

import numpy as np
from flybrain_v3_minimal import FlyBrain, FEATURES

brain = FlyBrain.load("checkpoints/4_after_blind_test", "stock_brain")
X = np.clip(np.random.default_rng(0).normal(size=(100, len(FEATURES))), -2.5, 2.5)   # 100 made-up stocks
balance, score = brain.decide(X)            # rank by score; balance > 0 leans "long"
top20 = np.argsort(-score)[:20]

# one online learning step: pain/happiness from what happened next (returns in volatility units)
brain.feel(X, position=np.isin(np.arange(100), top20).astype(float), outcome=np.random.normal(size=100))

flybrain_v3_minimal.py needs only numpy and safetensors. Its forward pass and plasticity rule match the training code's decisions exactly. Run python flybrain_v3_minimal.py to load every checkpoint and print its top picks on the same random input. That shows the ranking emerge between 0_untrained (no preference) and 1_after_school.

Files

checkpoints/<stage>/stock_brain.safetensors    pn_to_kc (110×2000, fixed) · w_long, w_short (2110, plastic) · tuning_centers
checkpoints/<stage>/market_brain.safetensors   pn_to_kc (50×500) · w_long, w_short (550) · tuning_centers
checkpoints/<stage>/config.json                sizes, learning settings and running state (baselines, gain control, tonic pain)
training_log.json                              exam scores, validation and blind-test metrics, learned preferences per stage

Inputs (22 features, cross-sectional normal scores clipped to ±2.5)

  • Quant factors: 12-1 momentum, 1-month and 1-week return, distance to 52-week high, 60-day volatility, biggest daily jump (MAX), Amihud illiquidity, volume trend, 3-month return vs market, share of no-trade days
  • Simple-model features: 50/200-day trend, time-series momentum, Bollinger z-score, rolling least-squares forecast, EWMA volatility, market beta
  • News: company-level volume, tone, bullish and bearish keyword share. These were zero in real Tokyo data, because no company news history was available, so they were only trained in school.
  • Regime: whether trend or mean-reversion rules have been paying recently

Limitations

  • One market, one seed, and one 2.8-year test window. Treat the Tokyo picking signal as a hypothesis for forward testing.
  • Survivorship bias: the universe is today's listings. Spreads are a single 2026 snapshot.
  • Historical news is market-level only. The curriculum's synthetic markets are stylised.
  • This model is inspired by the mushroom body. It isn't a simulation of the measured FlyWire connectome.
  • Retraining on freshly downloaded data won't reproduce these exact numbers if the vendor's history changes.

Data

No market or news data is included, only the model's weights, configs and results. Training used Yahoo Finance prices, live Yahoo quotes for spreads, and the GDELT 2.0 news archive, each under its own terms. The GitHub repository's scripts download them.

Citation

@misc{peganov2026flybrain,
  title  = {Pain, Happiness and Love in a Fly-Brain Trader: Blind Tests of a Connectome-Inspired Reward Learner in Equity Markets},
  author = {Peganov, Mikhail},
  year   = {2026},
  note   = {Working paper}
}

License

MIT

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading