Published July 2026 • By @qrak

I Built a Trading Bot That Doesn't Just Calculate — It Sees, Remembers, and Learns from Its Failures

The complete 7-month engineering journey of an open-source, vision-capable crypto bot.


1. The Wrocław Warehouse Spark

In December 2025, I was living in Wrocław, Poland. By day, I worked 8-hour shifts in a physical warehouse. My back was sore, my energy depleted, but my mind was occupied with a single question: Why are all the "AI trading bots" on the market so incredibly dumb?

I spent my evenings testing open-source strategy templates. I did what every YouTube tutorial recommended: pulled RSI, MACD, and Bollinger Bands values via Python, wrote a basic prompt template, and dumped the floats into the ChatGPT API.

The bot's decisions were confident, articulate, and completely wrong. It would say: "RSI is at 28, oversold. BUY." The next morning, the market would slide another 4.5%, dragging my paper portfolio down with it.

The problem wasn't the AI model. The problem was the architecture. I was building a stateless calculator, not a reasoning engine.

2. Chronological Timeline (Dec 2025 – Jul 2026)

Phase 1: Float Prompts (Dec 2025 – Jan 2026)

Calculated indicators in Python and dumped them as YAML text into Claude/Gemini. The bot was stateless, forgot past trades, and bled capital (-4.2%).

Phase 2: Multimodal Chart Vision (Feb – Mar 2026)

Scrapped 900 lines of hardcoded pattern-matching heuristics. Plotly now renders a 1080p chart image (SMA, RSI, Volume, CMF, OBV) fed directly to Gemini Flash. The visual model spots pattern geometry far better than programmatic rules.

Phase 3: Stateful Vector Memory (Apr – May 2026)

Integrated local SQLite and ChromaDB (768D BAAI/bge-base-en-v1.5 embeddings). Every closed trade is embedded. The bot queries top-5 similar past setups. Introduced the Surprise Ratio metric to filter out market noise.

Phase 4: EV & Falsification Gates (Jun 2026)

Added deterministic Expected Value math (Kelly sizing, min 1.5 R:R threshold) and the Falsification Gate (forcing the LLM to write a strict price invalidation trigger before any trade is executed).

Phase 5: 8-Agent Dev System (Mid-Jul 2026)

Built a local multi-agent system (.ai/ directory). A Supervisor orchestrates 7 specialized developer agents (Bolt, Palette, Sentinel, Refactor, Concise, Bugfixer, Smoke Tests) to maintain the codebase.

Phase 6: Hardened Executor Separation (Late-Jul 2026)

Decoupled the engine into Semantic Signal (reasoning) and llm_trader_executor (CCXT order placement, leverage, OCO stop-losses, and dead-letter queue).

3. The Mathematics & Engineering

Numba JIT Indicator Engine

50+ custom technical indicators written in NumPy and Numba. Every calculation compiles to machine code on first call and caches the result, running in microseconds on a standard CPU:

@njit(cache=True)
def _ema_numba(prices: np.ndarray, period: int) -> np.ndarray:
    alpha = 2.0 / (period + 1)
    result = np.empty_like(prices)
    result[0] = prices[0]
    for i in range(1, len(prices)):
        result[i] = alpha * prices[i] + (1 - alpha) * result[i - 1]
    return result

The Surprise Ratio Metric

To prevent the bot from learning bad habits from lucky trades (e.g. buying a support breach that won due to random news spikes):

Surprise Ratio = |Realized P&L - Expected P&L| / |Expected P&L|

Trades with a surprise ratio > 1.5 carry a ⚠️ high surprise tag in vector memory so the LLM discounts them in future cycles.

Deterministic Expected Value Gate

EV = (Win Rate × Average Win) - ((1 - Win Rate) × Average Loss) - Fees

If EV is negative or Risk-to-Reward ratio is under 1.5, the signal is rejected outright, overriding the LLM.

4. Quick Start

git clone https://github.com/qrak/LLM_trader.git && cd LLM_trader
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp keys.env.example keys.env  # Add GOOGLE_STUDIO_API_KEY (free tier works)
python start.py               # Dashboard launches at http://localhost:8000