Every quantitative research team rebuilds the same scaffolding. Somebody writes the loader that returns prices as they stood on the day of the decision rather than as they were later restated. Somebody writes the split that keeps a label’s future window out of the training data. Somebody writes the fill logic that decides whether an order executes at today’s close or tomorrow’s open, and the accounting that charges commission and slippage against it. None of this is the interesting part of anyone’s research. All of it is where the errors that invalidate a result actually live.
We turned that scaffolding into libraries while writing the third edition of Machine Learning for Trading because nine end-to-end case studies need a single implementation of these decisions rather than nine. This week the last of them reached a stable release. Six packages now cover the workflow from raw market data through live trading.
The six ML4T libraries across the research workflow
That is the release. The rest of this piece is about why the timing turned out to matter more than we expected.
Deciding how to organize your strategy research is the part that no library automates. It is also what I am teaching in a free 30-minute session on Wednesday, August 26, Managing Your Strategy Research Process.
Coding agents changed the argument for domain libraries
For most of the time we were building these, the case was ordinary. Shared, tested infrastructure beats six private copies of the same fragile code, the same way it does in any other field.
Coding agents made the case sharper, and in a direction that surprised us. The obvious prediction was that agents reduce the value of libraries: if a model can write a backtest in thirty seconds, why maintain one? What actually happens is the reverse.
An agent will write you that backtest. It will be clean, it will run, and it will produce a Sharpe ratio. What it will not tell you is that it filled orders at a price nobody could have traded at, that it scored the model on data containing the answer, or that the number it reported is the best of forty variants it tried and discarded. The code being correct Python says nothing about whether the experiment was sound.
The deeper problem is continuity. When a person writes that code, the assumptions live in their head, and they carry them from one experiment to the next. When an agent generates it, nothing carries them. The next run regenerates the file from scratch and may resolve a dozen small questions differently: how missing assets are handled, how ties are broken, which lag count goes into a standard error. Two results you intended to compare are then answering slightly different questions, and nothing in either output says so.
So the division of labor we settled on is this. The agent decides which experiment is worth running. The library decides what a fill is. Speed of generation is exactly why the second half has to be fixed: an agent can produce forty variants in an afternoon, and forty variants are only informative if they differ in the way you intended and in no other way.
What each library decides for you
The point of each package is not that it has functions for a topic. It is that it settles a specific question the same way every time, so that two experiments remain comparable.
ml4t-data settles what the data looked like at the moment of the decision. It covers more than 20 market, macro, factor, and prediction-market sources, stores them locally as Parquet with metadata, and handles incremental updates, gap detection, and validation. Getting this wrong is the single most common way a backtest ends up trading on information that did not exist yet.
ml4t-engineer settles how a feature or a label is constructed, and where the boundary sits between what a model may see and what it is predicting. Its registry holds 120 features, 60 of them validated against TA-Lib to a tolerance of
1e-6.ml4t-models settles what the model is actually fitted to. Financial data arrives as a panel of many assets over time, and whether you are predicting the cross-section on a given day or a single asset’s path changes the model contract. The library makes that explicit rather than leaving it to a reshape.
ml4t-diagnostic settles how a result is scored: the lag count in a standard error when returns overlap, the purge and embargo that stop a validation split from leaking, the trial count that goes into a multiple-testing correction. These are the adjustments that separate a real edge from a well-dressed one.
ml4t-backtest settles when an order fills, at what price, and what it costs, along with account rules, risk limits, and an exported record of the run.
ml4t-live settles what happens between a validated strategy and a funded account: shadow and paper modes, risk limits, reconciliation against the broker, and execution journals. Its adapters for Alpaca, Interactive Brokers, DataBento, and CCXT sit outside the stable contract and require an explicit experimental opt-in.
All six are MIT-licensed and on PyPI, with documentation at ml4trading.io/docs.
Putting it to work: an agent that runs experiments
Chapter 24 of the third edition builds a research operator on top of these libraries. It is worth describing plainly, because the architecture is the point rather than the code.
The operator is a single Python module. It gives a language model ten general-purpose tools, none of them financial: run a shell command, read and write files, read Parquet, query a database, search for a methodology document, and declare the task finished. It contains no sequence of financial calculations at all.
Three things sit outside it.
The first is a corpus of about sixty short methodology notes, each describing one method such as walk-forward validation or a deflated Sharpe ratio, and naming the library function that implements it. The model retrieves these at run time. The methodology can be improved without touching the operator.
The second is the libraries, which the model calls through the shell like any other user.
The third is a research registry, which is simply a database of previous experiments: what configuration was trained, what predictions it produced, what backtest was run on them, and what the metrics were. This is what makes a new experiment comparable to an old one, because the agent can look up exactly how the earlier run was configured instead of guessing.
The agent decides which experiment to run; the libraries decide how it is computed
That last piece turns out to matter more than it sounds. When I asked the operator whether an ensemble could improve one of the book’s ETF case studies, the specification it recovered from the registry was four fields: score_weighted_top_k, top_k=20, monthly rebalancing, long-only. Those four fields are the entire reason its result could be compared with the baseline at all.
Two runs
The ensemble run combined the strongest predictions from three model families and reran the cost-aware backtest under the baseline’s recovered configuration. Mean information coefficient, the rank correlation between predictions and subsequent returns, rose from 0.052 to 0.065. Portfolio Sharpe fell from 0.92 to 0.56, with three of eight validation folds showing negative IC.
The agent recommended against adopting the ensemble, and identified why. Its fold-level instability, amplified by an allocator that concentrates on the highest-scoring names, is what costs portfolio performance even as rank correlation improves. That is one of the case study’s own teaching points, reached in 39 turns without being pointed at it. The comparison runs on the validation window, since the registry holds holdout predictions for the baseline alone, and the chapter notebook records that scope against the original run artifact.
A second run tested how much of a US firm-characteristics strategy depended on its smallest names. Filtering the existing validation predictions to the top three market-cap quartiles cut Sharpe from 4.27 to 2.24, lowered IC from 0.074 to 0.048, and deepened maximum drawdown from 15% to 52%. Turnover was nearly unchanged, 1.77 against 1.80, because the filter screens signals without retraining. That makes it a sensitivity screen rather than a capacity estimate: it shows the result leans heavily on small caps, and it does not separate that from reduced breadth, nor say what a capacity-constrained implementation would earn.
Neither run produced a stronger strategy. Both produced a specified experiment, a recorded configuration, and a result that the next iteration can build against, which is most of what research actually consists of.
Where the tools stop
The libraries constrain what gets computed. They do not constrain what gets concluded from it. Which evaluation window supports which claim, whether a specification answers the question that was actually asked, and whether a result justifies a decision are review judgments, and no package boundary reaches them. That is why the operator records the evaluation window, the fold-level statistics, and every generated script rather than only the final recommendation.
There is also a security boundary worth stating plainly, because it is easy to get wrong. The operator restricts file edits to a designated output directory, but that is a guardrail for a cooperative model rather than a sandbox. Its shell tool runs commands with the host user’s privileges, so a confused or jailbroken model can write outside that directory or reach the network. The published notebook replays a recorded trace by default and executes nothing the model supplies. Running it live against an external model needs real isolation: a container, dropped privileges, read-only mounts, and no network egress unless you mean to allow it.
An unattended system needs more still: deterministic seeds, contamination tracking, explicit approval points, and limits on what may act downstream of a research note.
What this adds up to
A research agent is only as trustworthy as the tools it calls. Give it a shell and a prompt and it will reimplement finance from memory, differently each time. Give it versioned libraries that have already settled how a fill works, where a validation boundary sits, and how a trial count enters a correction, and its output becomes something a reviewer can check and a second run can reproduce.
That is what these six libraries are for, and it is why finishing them mattered more in 2026 than it would have in 2023.
All six are on PyPI now, and the Chapter 24 operator is public.




