Skip to main content

Autonomous trading: news does not predict stock direction

· 22 min read
Vadim Nicolai
Senior Software Engineer

Twelve combinations of event feed and window, measured: a catalyst does not separate the up tail from the down tail on this equities screen. The one arm that crossed t = 2 was logged as a lead and refused promotion.

Does a catalyst separate winners from losers? The measurement cannot say. No separation was detected across the twelve feed-and-window combinations, but the test can only rule out an effect larger than about 2.5pp — see the correction below. Measured: catalyst and no-catalyst names posted nearly identical spreads. The one signal that looked like it did — insider purchases within five days — was logged as a lead, priced against its own sixteen-test background, and refused promotion.

Self-evolving agents: survivorship bias wrong way in stocks

· 19 min read
Vadim Nicolai
Senior Software Engineer

Survivorship bias is supposed to flatter a backtest. A survivor-only universe deletes the names that died along the way. Every number computed on it should therefore come out looking better than the truth. That is the textbook direction — and for this board, the textbooks had it backwards.

The measurement that broke the assumption came from a 10-minute autonomous research loop. It ran the previous evening and logged the result as a measurement only: no lane, constant, module, or gate default was changed.

The loop re-screened its own universe. The survivor-only reference — a single active=true snapshot of Polygon's ticker list — had been used to type every name on all 236 point-in-time dates. That reference produced a benchmark that was too low.

Readmitting every name the gate had silently excluded moved the equal-weighted screened universe from +5.64 to +6.54 bps at k=1, and from +27.34 to +29.07 bps at k=5.

Read that table twice.

equal-weighted screened universesurvivor-onlyall names readmitted
k=1+5.64 bps+6.54 bps
k=5+27.34 bps+29.07 bps

The bias did not flatter the backtest. It censored the names that made the backtest look worse. The reason is structural, not mystical: this panel never observes a delisting as a return. There is no −100% row to be spared.

Removing names did not remove disasters. It removed a type of name — and that type was exactly what the extreme-return lanes were looking for.

An AI That Audits Trading Alpha

· 18 min read
Vadim Nicolai
Senior Software Engineer

Take a statistic that cannot exist and give it a p-value that means something else. That is what one paper in the queue did: it reported Spearman rho = 0.94, p = 0.017 over five assets. On five untied ranks, rho lives on a finite grid spaced exactly 0.1 apart. The smallest two-sided p the test can produce is 0.0167, and 0.017 is the exact p-value of a perfect ranking. The nearest attainable rho, 0.90, carries p = 0.0833 — not significant at 5%. The claim is not subtly wrong; it is printed arithmetic that could not have come from the test the paper claims to have run.

The system that caught it is not another return-predicting model. It is an auditor: a loop over a local corpus of 21,305 quant-finance paper abstracts, with 21,119 still queued, 29 papers read end to end by a human, and 82 machine screens completed. Each tick claims one paper, asks a language model two questions about it, runs deterministic nulls against real market data, and records a verdict under a schema that refuses records which certify themselves. The most important thing I can tell you about this loop is not that it found fake alpha. It is that its ceiling is the corpus, not the model — and that honesty about that ceiling is the actual product.

NautilusTrader + candle: A Rust AI Trading Stack

· 19 min read
Vadim Nicolai
Senior Software Engineer

Your model says buy. Your risk engine says no. Who wins?

In most trading stacks the honest answer is "whoever is louder." A Python notebook model outshouts a config-file risk limit by default. But there is a sharper question hiding behind that one, and it changes the outcome: what happens when the model is wrong, and the architecture is built so it cannot hide?

This is the story of a two-plane algorithmic trading stack in Rust — four crates, 388 tests, zero failures — where an ML model fitted with Hugging Face's candle was given every chance to earn its place, and then lost to a momentum factor on out-of-sample data. The model did not fail because someone judged it unworthy. It failed because it could not show a number, and the thing that checked the number lived in a different process and a different dependency graph.

That is the design. Everything else in this build follows from it.

AI-First Crypto Trading Principles

· 169 min read
Vadim Nicolai
Senior Software Engineer

An optimistic backtest can show Sharpe 5 where live reality is negative, and an AI-first crypto trading system graded by it will optimise into the gap with total conviction — because inside that simulator the strategy genuinely works.

The simulator is not a test. It is the model's reward function. That is the sharpest trap I know, and the rest of this post is what I found while walking into it.

Here is the shape of what I found. Give a router a third action — quote, cross, or abstain — and it takes the third. Doing nothing scores zero; every alternative scores less; and zero wins 11 of 11 panels without the signal being consulted at all. The fitted policies that do trade pick about 1.6% of rows and still end below zero. A model that has learned to almost-not-play is not broken. It is reporting the absence of an edge — the one output no trade-count metric will ever reward.

Everything that decides whether such a system makes money on a perp lives in the coupling between model and market: fees, funding, regime, and the evidence you are willing to accept. A round trip costs 4–14 bps before the model says a word.

I went looking for that edge at sub-minute horizons and did not find it. What the search produced instead was thirty-nine principles about how to run a model against a market — each ending with the condition that breaks it, each carrying the measured number behind it, and several carrying the number that killed an earlier version of the same claim. They are worth more than the strategy would have been.

Concurrency and parallelism in LlamaIndex

· 11 min read
Vadim Nicolai
Senior Software Engineer

Most write-ups about concurrency in LlamaIndex tell you half the story. They show you how to decorate a step with num_workers=5 and call it a day. What they don't tell you is that the storage layer under those parallel steps fails in opposite ways. The default 4 workers guarantee you'll hit both failure modes eventually. I’ve timed the workflow side on llama-index-workflows 2.22.2 (PyPI release) and I’ve lived through the silent corpus inflation and lock-contention meltdowns that happen when those workers hammer the vector store. Here’s the full picture.

The Four-Component Feedback Loop That Turns a Static Agent Into a Search Problem

· 18 min read
Vadim Nicolai
Senior Software Engineer

Most AI agents you deploy today are frozen the moment they go live. You handcraft the prompts, select the tools, wire up the memory, and hope the configuration survives contact with real users. It doesn't. Tasks drift, APIs change, user intents shift – and your agent silently degrades. The conventional fix is another round of manual reconfiguration. But there's a more principled path: treat agent design not as a one-time assembly but as a continuous search problem.

Evolving the Reasoner: How Agents Learn to Optimise Their Own Behaviour and Prompts

· 19 min read
Vadim Nicolai
Senior Software Engineer

Most self-evolving agent demonstrations—those that appear to learn by picking better tools or adjusting dialogue style—avoid modifying the core reasoning engine. Evolving the reasoner itself—the chain-of-thought architecture, the internal planning logic, the very way an agent thinks—is the hard, brittle, data-starved problem that separates parlor tricks from genuine lifelong adaptation.

Evolving the Substrate: Optimising What an Agent Remembers and Which Tools It Can Wield

· 13 min read
Vadim Nicolai
Senior Software Engineer

Most teams building self-evolving agents obsess over prompt engineering or fine-tuning the LLM. They miss the bigger lever: the substrate—what the agent remembers and which tools it wields. A prompt is ephemeral; memory and tools are structural. Evolving the substrate yields compounding returns that no amount of prompt tweaking can match. Fang et al. (2025) survey of self-evolving agents confirms this: the components that persist across sessions—memory and tools—define the agent's operational range far more than any instruction string. In this third part of the series, I'll lay out why memory and tool optimisation are the neglected backbone of lifelong agent systems, back every claim with data from the literature, and give you a decision framework you can implement today.