Beyond Market Data
Building a production Excel trading dashboard on the IBKR TWS API — and why the part that looks easy isn't.
The contraption you've probably already built
If you trade through Interactive Brokers and you keep Excel open next to TWS, you've probably assembled some contraption to bridge the two — a copy-paste routine, an xlwings script, a websocket feed. For years mine was the old DDE + Java SocketBridge, streaming positions into one Excel instance, with VBA pumping them into the primary workbook I use to monitor portfolios and trading.
That bridge held together with habit and good intentions until a Windows update changed how Excel and OneDrive cooperate, preventing workbooks on a cloud-backed drive from finding each other. The pipeline was dead. Patching it would have been one kludge too many, so I decided to rebuild it the right way. That decision is where this whole project starts.
Why the spreadsheet
I've spent more than twenty years building trading systems — low-latency order transmission in C++, research pipelines in C# over enterprise SQL, and more recently the Python stack that now drives most quantitative R&D. For the dashboard a trader works from — the screen where every input converges and every order goes out — I keep coming back to Excel.
That choice still raises eyebrows. Can Excel really support production workflows — real-time operations with money on the line? It's a fair question, and plenty of capable engineers answer it with a flat no. I won't relitigate the whole thing here; the full case is its own essay (Why Excel). But a few key points: most of what a working trader actually wants to do is easier in a spreadsheet — that's the whole appeal, and it isn't an illusion. The data and the logic are fully exposed; the user can rearrange the dashboard while operating, without filing a dev ticket and waiting for a new build. That simplicity is real, and it covers most of what a trader needs. Excel stays easy for a long stretch, then turns hard all at once — a cliff you don't see coming until you're over it, where real-time, money-on-the-line use requires software-engineering depth not typically associated with spreadsheet work. This series is about going over that cliff.
A good trading dashboard shows quotes, current positions, target positions, account values, and open orders all at once — everything relevant to a working trade, visible and current to the second. The best put the order ticket one click from the data that drives it.
The sample RTD server, and the empty stubs
Rebuilding on DDE wasn't an option. I'd built the original system on it before 2020, and I only learned how bad that foundation was after I had it working well enough to move on to the next problem. IBKR's DDE implementation does have the full functional breadth — orders, accounts, positions — but DDE is a protocol from 1987: it blocks Excel's UI, conflicts with other software, and jams up when pushed too hard. Building production trading infrastructure on it today would be engineering malpractice.
The modern answer is RTD (Real-Time Data) — Microsoft's latest protocol for streaming into Excel without breaking it. IBKR ships a sample RTD server with the TWS API, so I started there.
IBKR's documentation is explicit that the RTD sample is a demonstration, "not intended to be used as production level trading tools," covering top-of-book market data only. But the callbacks for everything beyond market data are stubbed out: EWrapper's .updateAccountValue, .updatePortfolio, .position, and the rest are empty, but present. I read that as an invitation: fill in what's missing and turn RTD into the DDE replacement it should be — one that handles production workloads in modern Excel without flinching. My initial guess was that implementing those callbacks would take a few hundred lines of C# and a week or two.
Six methods and a firehose
That guess was off by about half a year and seventeen thousand lines of code — and the reason is the part that looks easiest. Microsoft's IRTDServer interface consists of just six methods:
ServerStartServerTerminateConnectDataDisconnectDataRefreshDataHeartbeat
Implement those and Excel does the rest. It looks like an afternoon's work — and that's the problem: you can't see how hard this gets until you're over the cliff. Two things keep the drop hidden.
On the Excel side: those six methods are called through Windows COM on Excel's main thread. The interface practically invites you to break every rule of multithreading, and for lightweight uses you can get away with it. On the other side, the one the interface never makes you think about, is the data feed. Here that's the TWS API: a firehose that will gladly pump data faster than Excel can take it, and keep spraying while the receiver is drowning. Until you reckon with that, you don't see how hard the piece in the middle — the RTD server itself — is going to be. Wire in a serious data feed and you don't get exceptions, you get confusion: Excel might silently stop updating, freeze intermittently, or lock up for good.
Get it right and the payoff is a single, simple, reliable interface. Every real-time value the dashboard needs is a native formula against one component, ProgID Tws.Rtd:
=RTD("Tws.Rtd", , "AAPL", "BID")— a streaming quote=RTD("Tws.Rtd", , "account", "U1234567", "NetLiquidation")— an account value=RTD("Tws.Rtd", , "position", "U1234567", "AAPL", "Size")— a live position=RTD("Tws.Rtd", , "orders", "U1234567", "ListCsv")— the order book
The things the API sample leaves out — account values, positions, P&L, orders — all use the same grammar, streaming into cells without blocking the user.
The finished RTD server runs over 17,000 lines of C#. Behind it, a test suite of another 30,000 lines exercises more than 1,300 tests.
What the desk actually trades
You don't need hedge-fund volume to want a robust Excel dashboard, but it's fair to ask what this one supports. Over the first five months of 2026, my desk traded roughly $87 million a month through TWS. A typical day runs about 150 orders across 50 names; on my busiest single day I sent 293 orders. Flow isn't uniform across the session, either: it bunches toward the close — the half-hour when the dashboard has to keep up or get out of the way, because a slow or stale screen there costs real money. The day it has to work hardest is also the day it's most likely to break, which is why the engine was engineered and load-tested well beyond my own desk's peak volume.
The distinguishing problem isn't the order entry — that piece has its own demands, and its own article. It's the inbound traffic: a dashboard like this holds a far larger body of live, fast-moving state than any analyst's workbook — quotes, positions, account values, all updating at once — and it has to stay correct while the firehose sprays. That volume-and-freshness demand is what a careful engineer answers with one rule above all others, the rule the rest of this series turns on: Fail Loud.
When the trader looks at a cell, they have to be able to trust it. A blank cell is honest — it says the system doesn't know. A cell that shows data that has quietly gone stale is a trade error waiting to happen. So the engine is built to fail loud: a principle I repeated throughout the code is that stale data is worse than no data. Following that principle — across broken connections and undocumented quirks on both sides of the bridge — is part of production engineering that real money makes non-negotiable, and it's a big reason "fill in the stubs" took more than half a year.
What's coming
This piece is the setup; the war stories are the substance. Three hard problems took most of those months, and each gets its own article:
- Keeping the dashboard current when the TWS connection breaks — and it does, for a dull catalog of reasons — without the trader having to fix it.
- The host fighting back: the undocumented ways Excel's own RTD contract quietly stops cooperating at production scale, and how to notice before the trader does.
- Sending orders from a spreadsheet — an apparent anti-pattern, given that RTD is built for streaming data into Excel — and the one discipline that keeps it safe.
I trade through this system with my own money, every session. The principles in the next three pieces aren't ones I read in a book; they're the ones that fell out of running the dashboard live, watching what broke, and noticing — over months, then years — which fixes were Excel-specific and which were universal to anyone consuming the TWS API.
Next: the connection drops, four nested races, and the bug that fixed itself four times before it was actually fixed.