Autonomous Trading Agent
Excel is the cockpit. PowerShell is the engine. The model never touches an order.
- 0Model influence on any order placed
- 0Deterministic signals scored per stock
- 0Stocks scored every cycle
The problem
Retail trading tools give you two options. A black box that trades and will not tell you why, or a chart you stare at and act on by feel. Neither leaves a record you can audit afterward, which means neither can be improved — only argued about.
Why it mattered
I wanted to build an agentic system where being wrong has an unambiguous scoreboard. Markets provide that. The discipline it forces — explicit limits, a full audit trail, a defined failure state, and a hard line around what the model is allowed to decide — is the same discipline the accounting automation needs, tested somewhere the consequences are immediate and the account is mine.
The old process
- Read market data manually
- Form a view
- Size the position by feel
- Place the order
- Keep no rigorous record of why
The idea
Put the model where judgement helps and keep it out of where money moves. Then put the entire control surface inside the one application every finance person already knows how to operate.
The system
An Alpaca paper-trading system operated entirely from an Excel workbook. VBA buttons on a Control Panel tab write a config cache and launch PowerShell. The scanner scores every active watchlist stock on four deterministic signals — RSI(14), dip from the 10-day high, volume against its 10-day average, and price against the 20-day SMA — ranks them, and buys the top scorers inside a daily spend cap and a maximum position count. A second script manages trailing stops and laddered profit-taking across every open position. Orders above a dollar threshold do not execute: they go to a pending queue, fire an email and an SMS, and expire in fifteen minutes unless approved from the workbook. A Claude layer sits beside all of it as an analyst — it reads the log, the pending queue and the day's spending state and answers questions in plain English. It has no authority to place, size, or approve anything.
How it works
- Task Scheduler runs a cycle every few minutes during market hours
- Excel writes a config cache; PowerShell reads settings and the watchlist from it
- Daily bars pulled from the Alpaca data API; RSI, dip, volume ratio and SMA gap computed in PowerShell
- Each stock scored, ranked, and checked against live quotes — a stale or missing quote forces the score to −999 so no order goes out on an old price
- Top scorers bought within the remaining daily budget and open position slots
- Orders over the approval threshold divert to a pending queue with email and SMS alerts and a fifteen-minute expiry
- The trailing-stop script raises stops as positions run and sells ladders at the configured profit steps
- Every fill writes to the workbook with the score, each signal value, the stop it set, and a plain-English sentence explaining the buy
Architecture
Execution cycle
- 01Schedule
Unattended trigger
- 02Market data
Alpaca API
- 03Signal
Model layer + deterministic rules
- 04Risk gate
Explicit limits, hard-coded
- 05Order
Placed via API — paper by default
- 06Log + dashboard
Full decision audit trail
EXCEPTION PATH
Halt and log — Defined failure state, not an unhandled exception at 3am
Design decisions
- The model has no order authority
- Signals are arithmetic — RSI, dip, volume, SMA — and the buy is a sorted list against a budget. Claude is never called anywhere in the order path. It reads the log and answers questions. A model that cannot place an order cannot talk itself into one.
- Excel is the interface on purpose
- The watchlist, the thresholds, the per-symbol stops, the trade history and the approvals are all cells. Anyone in finance can operate it on the first try and change a limit without touching code. The workbook is not a report on the system. It is the system's front end.
- Every buy explains itself in English
- A translation layer turns the raw signal values into a sentence — why the RSI mattered, how far off the high it was, what the volume meant — and writes it beside the trade. If you cannot reconstruct the reasoning six weeks later, you do not have an audit trail, you have a receipt.
- Approval is a threshold, not a mode
- Small orders execute. Anything over the dollar limit stops and waits for a person, alerts by email and text, and dies on its own in fifteen minutes if nobody answers. Doing nothing is the safe default, so the timeout expires toward safety.
- Config cache instead of live spreadsheet reads
- Excel writes its settings to JSON before launching a script, so the engine never blocks on a workbook that is open, frozen, or waiting on the very script trying to read it. The deadlock is obvious in hindsight and expensive to find at market open.
- Secrets are excluded from model context by allowlist
- The analyst layer is handed an explicit list of safe settings — limits, thresholds, notification flags. Keys and passwords are never in the payload, because a denylist eventually misses one and an allowlist cannot.
- Portable by design
- A setup script re-patches every hard-coded path across all scripts and inside the VBA itself. The requirement on a new machine is Windows and Excel. No Python, no runtime, no install.
- A bad quote sold a position, so bad quotes are now disqualifying
- A price feed returned zero for an open position. Zero is below every stop ever set, so the stop triggered and the shares went. Nothing was broken — every line of code did exactly what it was told. Now any stock without a fresh live quote has its score forced to −999 and drops out of consideration entirely, because the failure mode of a missing price is not a small error, it is a confident wrong answer. That guard exists because the system ran unattended long enough to find the case, which is the argument for running things unattended.
- The spreadsheet is allowed to fail; the order is not
- Writing the trade to Excel happens after the order is placed and inside its own error handler. When a type-cast bug broke the workbook write, the log says 'Excel log write failed (order still placed)' — the record degraded, the trade did not. Order of operations is a control decision, not a coding style.
Controls
- Daily spend cap enforced against a persisted per-day state file
- Maximum concurrent positions, checked before any scan
- Minimum score threshold — a ranked list is not a mandate to buy
- Per-symbol stop-loss percentages set in the watchlist
- Approval threshold with email and SMS alerting and a fifteen-minute expiry
- Live-quote validation that disqualifies any stock without a fresh price
- Warning when a held position is missing from the watchlist and therefore has no stop protection
- Paper account throughout; the model is never given order authority
- API keys and passwords excluded from model context by allowlist
- Notifications on every fill and every pending approval, by email and SMS
Testing
Continuous scheduled operation is the test, and it earned its keep. The log runs from April 2026 to the present and contains the things local testing never produces: a data subscription refusing recent quotes, an Excel instance held open by another process, a type-cast failure on the spreadsheet write that had to not take the order down with it, a position held outside the watchlist and therefore unprotected, and one bad quote that arrived as a zero.
Result
Running since April, on schedule, through market hours. The approval path has fired for real: an order over the dollar threshold stopped, sent an email and a text, waited, and executed only after a click in the workbook. The Claude layer gets used the way it was meant to — 'how am I looking for the month', 'what should I do first thing Monday' — answered from the log rather than from imagination. Every order is arithmetic against a limit. Every limit is a cell someone can change. Every trade carries its own explanation in plain English. The model is genuinely useful and structurally incapable of costing money.
Impact
- An agentic system running unattended on a schedule since April 2026
- Human approval path proven end to end: threshold, alert, wait, expire or execute
- Demonstrated pattern: deterministic math where money moves, model where judgement helps
- An Excel front end a finance team could operate without a developer present
- Failure modes found by running it, and guards written in response
What I took from it
Unattended is a completely different engineering problem from interactive. Nobody is there to notice that something looks off, so every assumption has to be checked by the system itself. That lesson is the whole reason the accounting agent has a deterministic gate.
What I would build next
Broader instrument coverage and a more rigorous evaluation harness. The live switch stays where it is.