guest@make-directory:~$ cat ./blogs/tradeflow-two-clocks-that-never-touch/index.mdx

Andrew Schwartz / 2026-07-18 / 4 min read

TradeFlow: Two Clocks That Never Touch

Why we built an algorithmic trading engine whose main job is telling you your strategy is noise, and why no language model is allowed anywhere near the order path.

We do not publish our clients' systems, so the software we can show you is our own. TradeFlow is one of those: a layered, broker-agnostic algorithmic trading research engine, MIT licensed, with an Alpaca adapter and nothing above the broker layer that knows or cares which venue it is talking to.

It is educational software and paper-trading by default. Trading is genuinely risky, and this project does not change that. What it does is stop you fooling yourself quite so quickly, which turns out to be most of the battle.

The interesting part is not the trading. It is a structural decision we keep reaching for in client systems too.

Two clocks

The one idea that explains everything else in the codebase is that TradeFlow runs on two clocks that never touch.

The research clock is offline, slow, and exploratory: backtest, optimize, walk-forward validate, and optionally let an AI agent poke at the results. Non-determinism is welcome here. Language models are welcome here. This clock only ever proposes — it writes provenance-stamped configuration to disk and stops.

The trade clock is live, deterministic, and model-free: bar arrives, signal computes, order goes out. No model sits in the order path. There is nothing to prompt-inject, and nothing non-deterministic to debug at the moment real money is moving.

Promotion between the two is a manual human step. Nothing in the automation flips PAPER_TRADE or places an order.

Why that boundary is structural, not a rule

Anyone can write "the AI must not place orders" in a README. The problem with rules is that they hold right up until someone is in a hurry.

So the MCP server that exposes the research surface to agents builds only a data client. Not a trading client with an unused method — a client that has no order-execution capability in it at all. An agent connected to TradeFlow cannot place an order for the same reason a calculator cannot send email: the capability was never constructed.

This is the difference between a policy and an architecture, and it is worth internalising well before AI is in the picture. If the safe behavior depends on everyone remembering the rule, the safe behavior is not safe. If the unsafe action is unrepresentable, you can stop worrying about it.

We apply the same test to client systems. Can this service reach the production database? Not should it — can it. The answers are frequently uncomfortable.

The refusal is the product

make demo runs the whole pipeline on synthetic data with no keys and no network, and renders two panels side by side: an equity curve that looks convincingly tradeable in-sample, and the walk-forward verdict that refuses to promote it.

That refusal is the feature. It is very easy to build a backtester that makes every strategy look good — you simply fit parameters to history and report the result. The useful engine is the one that holds a strategy out of sample and tells you the pattern does not survive contact with data it has not seen.

The parallel to ordinary software work is not subtle. A demo environment will confirm almost any belief you bring to it. The valuable step is the one that tries to falsify the thing before it reaches production, which is also why software is easy in isolation.

What we learned building it

No native build step was worth the constraint. Indicators are pure pandas and numpy rather than TA-Lib, so installation is one command and the Docker image carries no compiler toolchain. We gave up some convenience and got back an install that works on the first try, which for a tool people are evaluating is a better trade than it sounds.

Broker-agnostic paid for itself immediately. Everything is written against a Broker and MarketDataProvider interface. Alpaca is simply the first implementation. Adding a venue means writing one adapter and touching nothing else — the same discipline that lets a client swap a payment provider without a rewrite.

State needs a home you can point at. The research journal, trial store, bar cache, and promoted configs live in ~/.tradeflow, and tradeflow --version prints which copy is running and where its state lives. Boring, and it eliminates an entire class of "why is it doing that" conversations.

Trying it

No clone needed:

uv tool install tradeflow-engine
tradeflow demo      # the full pipeline on synthetic data — no keys, no network
tradeflow init      # add free Alpaca paper keys when you are ready

The distribution is tradeflow-engine; the command and the importable package are both tradeflow. Full documentation, the engineering wiki, and the changelog are at tradeflow.mk-dir.com.

Start with tradeflow demo. It is the fastest way to see an engine argue with its own results.

Why this is on a consultancy's website

Because it is the part of our work you can actually inspect. Client systems are theirs to talk about, not ours — so if you want to know how we reason about determinism, blast radius, interface boundaries, and keeping AI usefully outside the path where mistakes are expensive, the code is public and the commit history is honest.

If your systems have a place where a mistake gets costly and nobody is certain what can reach it, that is a good conversation to start.

Andrew Schwartz

Andrew is the founder and principal engineer at Make Directory Developers. He works where business operations meet software engineering, and spends most of his time inside systems other people built.

guest@make-directory:~$ ls ./related