Vector memory: how an LLM trader remembers its mistakes
This project stores closed-trade experiences in semantic memory and retrieves the most relevant history before acting.
The problem with stateless bots
An LLM without memory treats every decision as if it were the first one ever made. It does not know that it bought the same breakdown pattern twice before — and lost both times. The first version of this project (December 2025) was exactly that: a stateless prompt pipeline producing confident, articulate, consistently wrong decisions.
The fix was not a better model. It was architecture: give the system a brain that actually remembers.
Every closed trade becomes a vector
When a trade closes, its full context and outcome are embedded with BAAI/bge-base-en-v1.5 — 768 dimensions — and stored in ChromaDB. Three collections carry the memory:
trading_experiences— closed-trade experiences with their context, outcome and P&L;semantic_rules— rules the reflection engine has written from results, in plain language;system_constraints_rejections— signals that were refused, and the reason.
Confidence statistics are not a fourth collection: they are computed on demand from the same embeddings (compute_confidence_stats), which keeps one source of truth for "how am I actually doing?".
Retrieval: "have I seen this before?"
Before each decision the brain assembles a context it can reason from:
- 3 most similar past trades — retrieved by vector similarity (over-fetched, then re-scored 70% similarity / 30% recency), each labelled with a match breakdown;
- win-rate statistics computed over the 20 nearest trades in the current market context;
- 5 most recent rejected signals — so the bot remembers what it refused and why;
- 3 learned rules that match the current regime (trend + ADX + volatility label).
If the sample is too thin the prompt says so, in capitals: "⚠️ LIMITED DATA: treat these as ANECDOTES, not as an established pattern". A bot that pretends two trades are a track record is worse than one with no memory at all.
The Surprise Ratio: separating luck from skill
Not all outcomes are equally informative. A support breach that won because of a random news spike teaches the wrong lesson. Every trade therefore gets a surprise score:
Anything above 1.5 is tagged ⚠️ high surprise in vector memory, so the model discounts it in later cycles. The bot learns from what it understood, not from what it got lucky on.
The reflection engine
Periodically a reflection pass reviews recent outcomes and synthesises new rules from what worked and what did not. The rules are semantic — natural language, embedded, retrieved when conditions match — and they are typed: anti_pattern (things to avoid), corrective (adjustments) and best practice. A matched anti-pattern forces the model to state the conflict and lower its confidence instead of quietly ignoring it.
A missed +EV opportunity is treated as mathematically identical to a realized loss (it is written into the prompt that way), so the loop stays honest about omissions too: act → embed the outcome → retrieve the lesson → act differently.
The dashboard shows the memory bank in action — retrievals, rules and rejections behind every decision.
Live dashboard ↗Next: the executor →