← VIJAY MICHAEL
Program & Technical Delivery · Case Record

TOS-BOT: a production trading system, run like a regulated release process

Ten months of solo build and operation of an automated intraday equities platform, plus the research rig that decides what is allowed anywhere near live capital. This page is about the engineering and the process. The strategy is not here, on purpose.

Vijay Michael, M.S. Role Program lead / technical product owner Period Jan 2026 – present Status Live, real capital
825
files in the live tree
381
Python modules
405
files under hash manifest
35
dated change packages
2,217
trades reconstructed for study
SYSTEM

What the system does

The platform watches a rotating pool of US equities through the pre-market and opening session, evaluates entry and exit conditions once per second against live and reconstructed bars, and routes the resulting orders to a broker. It runs unattended from before 04:00 ET, supervises itself, records everything it saw, and reconciles against the broker's own record at the end of the day.

Several strategy variants run side by side. Some trade real capital. Others run in shadow mode on the same live feed, taking no positions, so a candidate can be measured against production conditions for weeks before anyone argues for promoting it.

Market data
Consolidated US equities feed for bars and trades, a separate broker feed for reference data, and a desktop terminal bridge for the scanner's ranked universe. Three sources, three failure modes, each with its own liveness check.
Scanner service
Maintains the candidate universe and hands the engine host a ranked, freshness-stamped watchlist. A stale watchlist is treated as an outage, not as data.
Engine host
133 Python modules. Evaluates every active strategy variant on the same tick stream so variants are comparable by construction rather than by later normalisation.
Supervision
A watchdog in its own process, independent of the engines: position ground truth, a daily loss limit, a flatten net, and a heartbeat every component has to answer.
Operator surface
45 self-contained HTML dashboards and a control panel: live position and P&L state, per-variant attribution, health banners, and manual override. No terminal required to run the day.
Record keeping
Every evaluated second is written to a per-day SQLite store, separate from the trade log, so the question "did the system see this?" can be answered independently of "did it trade this?".

The operator console

One screen decides whether the day proceeds. Per-engine attribution across each session window sits at the top, the ranked candidate universe on the left, and one card per active slot showing what every engine currently thinks about that symbol. A single entry and exit is running through it below; the trade lands in the blotter underneath as it closes.

LIVE TRADING ENGINES 09:51:12 ET PRIVACY: ON
ENGINE P/L SUMMARY · AUTO-REFRESHING
WINDOW 1WINDOW 2SESSION
Engine 15 19 24
Engine B2 7 9
Engine 24 13 17
Engine C1 5 6
RANKED UNIVERSE

1SUNE$3.82121.06M

2FTFT$2.6178.03M

3YMAT$2.3036.03M

4ODD$16.5711.91M

5TNON$2.6911.48M

6BIAF$10.6810.41M

7TENX$2.139.15M

8FJET$2.057.30M

9BNC$4.565.98M

10LABT$2.285.08M

V1SUNE$3.83
BUY SIGNAL
WAITING
ENGINE 1
WAITING
ENGINE B
WAITING
ENGINE 2
WAITING
ENGINE C
WAITING
▸ BUY GATES
▸ TRADE HISTORY
▸ L2 · BUCKETS · DATA FLOW
V2FTFT$2.59
BUY SIGNAL
WAITING
ENGINE 1
WAITING
ENGINE B
WAITING
ENGINE 2
WAITING
ENGINE C
WAITING
▸ BUY GATES
▸ TRADE HISTORY
▸ L2 · BUCKETS · DATA FLOW
V3YMAT$2.29
BUY SIGNAL
WAITING
ENGINE 1
WAITING
ENGINE B
WAITING
ENGINE 2
WAITING
ENGINE C
WAITING
▸ BUY GATES
▸ TRADE HISTORY
▸ L2 · BUCKETS · DATA FLOW
V4ODD$16.55
BUY SIGNAL
WAITING
ENGINE 1
WAITING
ENGINE B
WAITING
ENGINE 2
WAITING
ENGINE C
WAITING
▸ BUY GATES
▸ TRADE HISTORY
▸ L2 · BUCKETS · DATA FLOW
 
ENGINE 2 — TODAY'S TRADES · ALL SYMBOLS
INSYMENTRYQTYP/L
10:44:50BIAF$11.28443
10:29:36SUNE$3.391474
10:26:06BIAF$11.32441
10:10:36SUNE$3.181572
10:03:46SUNE$3.131594
10:01:21BIAF$11.37439
09:57:56SUNE$3.131597
09:47:41BIAF$11.25444
09:41:41BIAF$11.59431
ALL 17 trades
The console as it runs, with privacy mode engaged — a real feature of the panel. Currency is masked — the profit and loss figures are the one thing this page withholds, because a 46-day sample cannot support a performance claim. Everything else is real: symbols, quotes, entries, quantities, timestamps and every engine state. Every engine evaluates every slot independently, so a disagreement between them is visible at a glance instead of reconstructed afterwards, and every fill is auditable to the second.
ARCHITECTURE

One channel can place an order. The other physically cannot.

The single design decision I would defend hardest is the split below. Orders leave on a send-only webhook. Everything that reads account state — the watchdog's ground truth, the operator panel, the end-of-day reconciliation — comes back over a separate, credential-scoped read-only API that has no order endpoint at all.

The result is that the component most likely to have a bug under stress, the supervisor deciding whether to intervene, is reading from a path that cannot itself cause a trade.

Animated sequence: an order leaves the engine host, passes a risk gate, a send-only router and reaches the execution venue, where it fills and the position goes long. A separate read-only account API returns position state to the watchdog. The exit is sent reduce-only, fills, the position returns to flat, and the day is reconciled against the broker record. Animated sequence: an order leaves the engine host, passes a risk gate, a send-only router and reaches the execution venue, where it fills and the position goes long. A separate read-only account API returns position state to the watchdog. The exit is sent reduce-only, fills, the position returns to flat, and the day is reconciled against the broker record.
One round trip, start to finish. The upper track is the only path that can change a position; the lower one can only observe it. Exits are sent reduce-only, so an exit can never open a position in the opposite direction — that rule exists because the absence of it once did exactly that.
SAFETY

Safety controls, and the failure each one answers

None of these were designed up front. Each is the permanent residue of something that went wrong once, in production, with money on it.

ControlThe failure it preventsOrigin
Reduce-only exits An entry that never filled left the exit free to open a fresh short instead of closing nothing.Exits are now structurally incapable of increasing exposure. Incident
Confirm-before-arm A variant could be armed for live routing without anyone stating the account and mode out loud. Incident
Boot-order preflight A convenience launcher changed how the process was invoked, which silently disabled a bridge that keyed off the launch path.Preflight now asserts the launch contract before the market opens and fails loudly. Incident
Recorder boot check The evidence recorder only started from certain launchers. Three sessions of bar data were lost with no error anywhere.Absence of data is now itself an alarm. Incident
Credential validity check A mistyped path pointed at a token file that did not exist, so the check on token age passed while the credential was dead.Freshness is not validity — the check now proves the token works. Incident
Supervised stop path A network-level kill switch blocked the exit path along with the entry path, leaving open positions with no way out.Replaced with a stop that flattens first, then stops. Incident
Watchlist freshness gate A frozen upstream terminal served yesterday's candidates as if they were today's. Incident
Duplicate-process detection Two copies of the same engine means two orders per signal; two copies of the feed means a rate-limit storm. Pre-emptive
The operating rule

A production incident is not closed by a runbook note. It is closed by an automated check that would have caught it, running before the next session. A runbook entry depends on a human remembering at 4am. A check does not.

PROCESS

Change control: additive only, proven by hash

The live code tree is immutable while running. Every change ships as a dated package that states exactly which files it touches, installs itself, and can revert itself. Thirty-five such packages exist, each one a permanent record of what changed and why.

Before a package is accepted, the entire tree is hashed and compared file by file against the running baseline. The deploy note has to show the expected modification count and nothing else. Then the revert is run and the tree is hashed again, and it has to come back byte-identical. A change that cannot prove it undoes itself does not ship.

Doctrine
New behaviour lives in add-on modules that wrap existing chokepoints rather than editing them. Removing the add-on folder returns the system to the prior version with nothing to undo.
Verification
Full-tree hash before and after install, and again after revert. Runtime output is excluded from the comparison so real changes are never buried in daily churn.
Rollout
Behaviour-changing features ship observe first. The feature runs, logs every decision it would have made, and blocks nothing. It is promoted only after its observed decisions are reviewed against real sessions.
Interaction proof
Where two add-ons wrap the same function, the audit exercises both install orders and proves that an allowed action still reaches the original untouched and a blocked one never reaches it at all.
Pre-session QC
A single harness re-runs the checks offline before the open: manifest drift, duplicate processes, watchdog liveness, feed heartbeat, credential validity, watchlist freshness, kill-limit state. Any failure raises a banner on the operator panel.
Worked example · 2026-09-04

A new entry filter. Scope: one 14-line insertion into the launcher, one operator-panel card, two new files. Install proof: 2 modified, 4 added, 0 missing against the running baseline. Revert proof: 0 modified, 0 added, 0 missing — byte-identical. Shipped in observe mode, blocking nothing, on an audit of 26 of 26 cases.

RESEARCH

The research rig, and why it distrusts itself

Nothing reaches the live system on the strength of a backtest alone. The research platform reconstructs each candidate trade from one-second bars and then asks two independent questions about it, from two sources that do not share a failure mode:

Did it trade this?
The live trade log. Proves the production system actually took the position.
Did it see this?
The independent evidence recorder. Proves the live engine evaluated that exact second and what its conditions read at the time.
Verdict classes
Agreement, structural disagreement (a trade the backtest can take but the live system cannot, because it was already holding), genuine contradiction, and no evidence either way — kept as a separate class rather than quietly scored as a pass or a fail.
Calibration
The recorder confirms 220 of the 233 seconds it demonstrably evaluated, a 94.4% agreement rate. Every disagreement rate produced by the rig is discounted by that 5.6% floor before it is read as evidence against anything.

Two data traps that cost real time

Recorder files are named for the session they were opened in, not the session they contain, and several open the evening before. Indexing by filename produced a fake 62% "the system never saw it" rate that was entirely an artefact. Files are now indexed by the real time span of their contents.

Separately, the reconstruction's exits resolve against bar wicks, which is the optimistic end of the range. That is stated on every result the rig produces rather than discovered later by whoever reads it.

EVIDENCE

Evidence discipline: the part most backtests skip

The research backlog ran to roughly twenty candidate changes. The majority were killed. Two examples are worth stating plainly, because they are the reason I trust the remaining ones at all.

CandidateWhat the first result saidWhat the audit foundCall
Variant with the strongest backtest A large positive return across the sample. The entire result traced to a single overnight data gap the walk-forward treated as a continuous session. Corrected, the same variant lost heavily.The bug was systemic and invalidated a whole class of earlier results, which were re-run. Killed
A gate-window filter A clean improvement across the book. The windows were counting bars rather than seconds, admitting roughly 8% phantom trades that could not have existed live. Killed
Shadow variants on the live feed Promising on paper. Run in shadow against production conditions instead of promoted on the backtest. Observing
The honest caveat, stated on the record

The live sample is roughly 46 to 47 trading days. A power analysis on that sample says it is far short of what would be needed to separate a real effect from noise for changes of the size being tested. Every in-sample filter result the rig produces is therefore reported as suggestive, never as a win. Reporting an underpowered result as a win is the single most expensive mistake available in this domain, and the discipline not to do it is the deliverable.

METHOD

How it was built: AI-assisted, human-owned

Effectively all of the implementation was produced with an AI coding agent. I did not write most of these 381 modules by hand, and I would not claim otherwise. What I did own is the part that makes the output usable: the specification, the acceptance criteria, the verification, and the decision to ship or not.

That division is the whole reason the change-control machinery above exists. An agent that can produce a working feature in an hour can also produce a plausible-looking one that quietly breaks a dependency three files away. Hash-proofed additive packages, observe-mode rollout, install-order audits and a pre-session QC harness are not bureaucracy — they are the control surface that makes fast AI-generated change safe to put in front of real capital.

What I specify
The behaviour, the chokepoint it may touch, the files it may not touch, the rollback, and the evidence the change has to produce before I will look at it.
What I verify
The hash proof, the revert proof, the interaction audit, and the observed decisions from the first live sessions. I assume the agent is wrong until the tree says otherwise.
What this generalises to
Any team shipping AI-generated code into a system where a silent regression is expensive. The bottleneck stops being authorship and becomes verification, and verification has to be designed.
TRANSFER

What this maps to on a team

Requirements & acceptance

Ambiguous strategy intent turned into testable specifications with per-variant acceptance criteria, so "is this better?" became a question with a defined answer.

Release & change management

An additive-only process with verifiable rollback, adopted because the system could not be taken offline to fix a bad deploy.

Risk identification

Failure modes enumerated at the channel level, not the feature level. Read and write paths separated so the supervisor cannot cause the event it supervises.

Incident management

Root-cause analysis on live incidents, each closed by permanent automated coverage rather than documentation.

Prioritisation under uncertainty

A ~20-item backlog ranked against statistical power, with candidates cancelled on evidence including the one with the best headline result.

Stakeholder reporting

Self-contained analytics dashboards built so a decision-maker can reach the go/no-go call themselves, including when the honest answer is "inconclusive".

Vendor & integration management

Three market-data providers and a broker routing layer, each with its own liveness contract, credential lifecycle and documented failure behaviour.

Operating discipline

A system that starts before 04:00 ET unattended, supervises itself, and reconciles against the broker's record daily.