Rockwell Investor Software
An operator dashboard for a one-person trading system, designed to make a wrong number impossible to miss rather than easy to ignore.
- Engagement
- Personal project
- Role
- Product Design & Engineering
- Platform
- Web dashboard, dark-first
- Sector
- Retail algorithmic trading
- Scope
- 20 pages, 3 asset classes
- Build
- Next.js + Python API, v0.8.1

Interactive prototype — best viewed on desktopInteractive prototype — click to try it
In a trading system, a bug usually shows up as a withdrawal, not a stack trace. The same goes for a dashboard. The dangerous failure is a figure that looks fine and isn't, not one that looks wrong. Most finance UI is designed to reassure. This one is designed to make you doubt the numbers in the right order. First, does the system's record agree with the broker's? Then, what does the record say? Only then, is the approach working? The same idea sets the controls. Every ceiling on the page says where it comes from. Anything the interface cannot do (place an order, raise a limit, turn off defined-risk, go live) is stated in the interface itself. Nothing is quietly left out.
Reconciliation first, then the numbers it vouches for.
Every figure on the overview is computed from the system's own model of the account. If that model disagrees with the broker, every figure below it is wrong in a way that looks right. So the check comes first, before any of the numbers it vouches for.
- Key jobs
- Verify, Scan, Decide
- Session
- Minutes, before 09:30
- Differentiator
- Unhideable reconciliation
The Banner Cannot Be Hidden
The overview's panels can be reordered and switched off in settings, except reconciliation. It shows a locked "cannot be hidden" tag, and the API rejects any panel list that leaves it out. A dashboard that lets you hide it will get it hidden on exactly the morning it matters.
Two Books, Never Merged
Positions puts the local book next to the broker's and gives each symbol an agree or disagree status. A merged table would be tidier, but merging is exactly where a discrepancy disappears.
Small Samples Carry Their Own Caveat
A win rate over six round trips is a description, not evidence. Charts built on small samples show the n next to the figure and say in plain text what the number cannot tell you.
The Status Bar Admits What It Is Showing
Every page says whether it is reading the live local API or a generated fixture, and which plane and profile are active. The public deployment reads "generated fixture — local API not running" on every screen instead of passing a demo off as a live account.
A ticket that sends nothing.
The system is not allowed to be autonomous at launch. Autonomy is earned per strategy and a human confirms each order. So the trade ticket is a record first and an instruction second.
- Key jobs
- Enter, Check, Confirm
- Session
- Market hours
- Differentiator
- Reason is required
Limits Apply As You Type
The pre-trade check runs the same limits the confirmation will, next to the form, so a refusal shows up before the ticket is recorded rather than after.
A Reason Is Required
The reason field can't be skipped. Three weeks later, looking at a position you don't remember opening, that row is the answer. Automations must carry one too, and it is stamped on every ticket they propose.
Refusals Stay In The Book
A ticket a limit refused stays in the ticket book with the rule that refused it. The page says why: a limit that stopped an order is the most useful row in the journal.
Prices Travel As Strings
The limit price field says under it that the value is sent as a string. JSON numbers are binary floating point, and a price that has passed through one can't be reconciled. The API rejects a numeric price outright.
Drafts Arrive With Their Reasoning
An idea written down the night before carries its limit, signal and reason onto the ticket. A draft is scored on how completely it is written, not on how good it is, and the biggest part of that score is what would prove the idea wrong, because nothing else in the system asks for it.
Every mark says how old it is.
Paper trading meant holding real positions through a real session, and that needed a page the first cut didn't have. Live answers one question: what has today done to what I hold? It has to answer without making a price look fresher than it is.
- Key jobs
- Watch, Adjust, Protect
- Session
- Market hours
- Differentiator
- Stale prices refused
Age Is A Column
Every mark shows how many seconds old it is. A mark goes stale at 60 seconds, and Confirm refuses any quote older than that, so outside market hours every order is refused. The page says this under the table instead of leaving it to a failed click.
The Day's Shape, With Your Levels On It
The cards view gives each position the shape of its day, with the previous close, the cost basis and any resting target or stop drawn on it. A shared-scale mode lets a $60 name and a $90 name be compared by how far they moved, not by how tall the chart is.
Unprotected Is Counted
The page header counts positions that have no exit behind them. Protect rests a take-profit and a stop behind an open lot as a single ticket. It is written to the journal first and still waits for a person to confirm it.
Missing Is Never Zero
If a day change can't be computed, it is shown as missing, never as zero. A held name with no quote is valued at its last trade, so one unquoted symbol no longer drops the whole page back to demo data.
Dials a profile can move, ceilings nothing can.
A profile, passive or aggressive, sets sizing, concentration and turnover. It never sets a ceiling. The limits page is built to make that difference obvious at a glance.
- Key jobs
- Tune, Halt, Audit
- Session
- Occasional
- Differentiator
- Sourced ceilings
Every Ceiling Names Its Source
Each limit row shows this profile's value, the ceiling, and the chapter the ceiling comes from: the fat-finger fraction, cash account with no margin, the kill switch. A number with its reason next to it is hard to argue down at the wrong moment.
Fixed Is Marked, Not Just Enforced
Defined-risk-only carries a "fixed — not editable anywhere" tag. In settings it's shown as an explanation, not a checkbox, because the API refuses a profile that turns it off.
A Sticky Kill Switch
Halting takes a written reason and only a person can clear it. The note under the button explains why: a kill switch that something other than a person can reset has stopped being one.
The Cost Of A Stance Is Shown Beside It
Each profile shows what its turnover costs per year before any edge: 10.7% for passive, 37.7% for aggressive, at the fitted 18.9 bps round trip. The main cost of the budget is turnover, not infrastructure, so it gets the same weight as the limits.
The first real orders, and what they found.
A simulator fills when it is asked to, so a whole class of bug can never show up in one. Connecting Confirm to Alpaca's paper account was the step between a working design and a working system. The first orders tested the design as much as the code.
- Key jobs
- Connect, Confirm, Recover
- Session
- Since September 2026
- Differentiator
- A person confirms every order
Paper Cannot Point At Live
Paper runs as its own instance, alongside the demo and the local simulator. It has its own data root, cannot be pointed at a live account, and caps every strategy at Propose however far it has climbed.
Three Defects In The First Orders
A draft opened on the ticket as the wrong symbol. A fill that landed after Confirm went unrecorded and halted the plane. The log redactor mistook timestamps for credentials and blanked them, so the plane couldn't read its own journal back. All three surfaced in the first orders on paper. Each one is fixed, and each is written into the changelog.
A Draft's Symbol Is Never Swapped
The fix for the first defect is a rule rather than a patch. A draft for a name the book doesn't carry stays blocked until you pick a symbol yourself, and that pick clears the reason written for the other one. A reason attached to the wrong instrument is worse than no reason.
Slates Written At Night
The goal is drafts written in the evening becoming checked tickets at the open. The first piece is built: an automation whose content is the drafts rather than one named instrument. It is refused until it can actually fire, so it can never show as enabled while doing nothing.
Autonomy earned one rung at a time.
Strategies move up a ladder: backtest, paper, shadow, propose, execute. The gates between rungs are mechanical. The page is built so that whatever stands in the way can be read at a glance.
- Key jobs
- Review, Promote, Hold
- Session
- Post-close
- Differentiator
- Every blocker at once
All Unmet Gates, Listed Together
A strategy lists everything between it and the next rung at once. Reporting one blocker, fixing it, then finding the next is how a one-day gate turns into a week.
The Top Rung Is Drawn, And Refused
SIZE, the system choosing its own position size, appears on every ladder with a dashed outline and is never granted. It is shown as a decision rather than left out, so nobody takes its absence for an unfinished feature.
Assumed Numbers Say So
Cost models carry a measured or assumed tag. The crypto rate has never been fitted to a real fill, so it is marked assumed and caps crypto strategies at paper, whatever their backtest says.
Registered Before They Ran
The first two strategies, momentum and reversion, were written down before they were walk-forwarded on real daily history, and both results are kept. Neither cleared its gate. Momentum scored 0.90 against a 0.95 deflated-Sharpe bar and drew down 30%, twice the ceiling. The ladder shows that as plainly as it would show a pass.
Demotion Is Automatic, Promotion Is Not
A daily review can move a strategy down a rung without asking. Moving one up takes a person. The asymmetry is deliberate: a system that can only make itself more cautious needs no supervision to do it.
Dark by default, glass that never costs contrast.
The operator reads this before the open and after the close, often in a dim room, often on a second monitor. Dark is the design target rather than a theme toggle. The glass look had to be reconciled with that, not traded against it.
- Key jobs
- Glance, Read, Compare
- Session
- 06:00 and after close
- Differentiator
- Tested contrast
The Lift Comes From The Edge
Near-white wash more than doubles a dark panel's luminance and pushes loss-red text under 4.5:1. So the glass highlight is a 1px rim and a hairline border, never a fill. Every glass panel sits at or below the luminance of the flat surface it replaced.
The Brightness Lives In The Field
The ambient background carries the colour, in a place where nothing is printed. The panel fill is raised to absorb it, and the result is the background every readable token is tested against.
Direction Is Never Hue Alone
Gains and losses carry a glyph and a sign as well as colour. A red/green pair on near-black is muddy, and invisible to anyone with red/green colour-vision deficiency. The loss colour was moved in hue as well as lightness to hold its contrast.
Tabular Figures Everywhere They Line Up
Prices, sizes, basis points and timestamps are set in tabular numerals so columns align without a grid. Nothing that reports a number moves; the ambient field stops entirely under reduced motion.
Light Is Derived, Never Drawn
A light theme exists now, derived from the dark palette rather than designed on its own, so gain, loss and warning mean the same thing in both. Dark stays the default and nothing reads the OS setting. The theme is applied before first paint, so the page never flashes from one to the other.
Process
The system started as a manuscript: two volumes, one on equities and one on options, with every threshold taken from a measurement in the text rather than an estimate. The dashboard came out of that. Each page answers a question from a chapter, and each ceiling points back to the chapter that set it. I wrote the design standard before building the pages: dark-first, glass without a contrast cost, direction never carried by hue alone. That way, layout questions had answers that weren't a matter of taste. The front end is Next.js. It talks to a small Python API that owns all the state, and the deployed page is a read-only fixture generated from real payloads, so the public site can't drift from the contract it stands in for. Since then, each batch of work has been driven by using the thing: the live view came out of holding paper positions through a session, and most of the latest release came from one morning at the ticket. Every batch ships as a numbered release with its own changelog entry.
Research methods
- A two-volume manuscript written alongside the build, which serves as the system's specification
- Measured transaction costs across equities, options and crypto, and the annual drag at each turnover
- Two strategies registered before a walk-forward on real daily history, with both results recorded and neither promoted
- Alert fatigue: how often an operator can be paged before paging stops working
- Colour audit of the glass surface: luminance of the field and fill, contrast per token, red/green vision deficiency
- Broker, bank and wallet credential models, and where each can safely be held
Deliverables
- Twenty-page operator dashboard: before the open, during, after the close, personal record, configuration and reference
- Paper trading against Alpaca, with a person confirming every order and fills polled back into the book
- Live session view with per-position day charts, resting exits and stale-price refusal
- Trade ticket, drafts, walkthrough, automation builder and exit-policy calculator with limits applied live
- Strategy promotion ladder with mechanical gates for equities, options and crypto
- Written design standard for a dark glass surface and its derived light theme, enforced by tests
- Read-only public deployment backed by a generated fixture, with an in-product changelog
The operator surface
23Responsive: 390px
8Next project
Newport Social Society