This year I wanted to level up in AI assisted coding as a senior engineer. Also I have interests on Trading. So I built a paper derivatives exchange: order book, limit and market orders, matching engine, positions. Python, FastAPI, PostgreSQL. I used Cursor the whole time, but not the way you might think. I didn't type "build me an exchange" and hit enter. I wrote the architecture first. Then I drove Cursor one module at a time. That made all the difference.
If you're thinking of building something like this with an AI pair programmer, here's what actually worked for me.
Write the plan before you write (or generate) any code
The first thing I did was open a doc, not the IDE. I wrote a single architecture and projects file. In it I spelled out:
- How repos are split (frontend and backend always separate, one deployable per backend).
- Which repo does what (exchange API, demo UI, where gamification would plug in later).
- Tech choices: FastAPI, PostgreSQL, Binance public API for prices. Why no Kafka yet.
- Module boundaries: core, market_data, orders, matching, positions, integration. Each with a clear job and a public interface.
That doc became the plan Cursor and I worked from. When Cursor suggested putting the UI in the same repo as the API, I pointed back at the doc and said no. That's basically what Cursor calls Plan Mode: get the design and the file-level plan right before you let the agent write code.
One deployable, but with real boundaries (modular monolith)
I went with a modular monolith. One service, one database, but strict module boundaries. Each module has a public interface (like OrderService.place, OrderBook.add). Nothing crosses the boundary by importing another module's internals.
Why? Two reasons. First, ops stay simple. Second, I could give Cursor very focused tasks. "Implement OrderService.place in the orders module and wire it to the matching engine." Not "build the whole trading flow." I pasted or pointed at the architecture doc so it didn't invent a different structure.
The matching engine: break it into steps you can verify
The matching engine is the heart of the thing. I wanted price-time priority, limit and market orders, and on fill we'd update positions and optionally ping a gamification API.
I didn't ask for "a matching engine" in one go. I broke it down.
- Data structures. Define Order, Fill, and an OrderBook (bids and asks by price level). I described the behavior I wanted and had Cursor implement add, insert, cancel, best bid, best ask.
- Matching logic. When we place an order, load the book from the DB (all open limit orders), run book.add(order), get back a list of Fills. Cursor implemented that. I reviewed how fills were applied to orders and positions.
- Persistence. Orders and positions live in PostgreSQL. The book is rebuilt from the DB on every place and cancel. So we don't rely on long-lived in-memory state. That was a deliberate trade: simplicity and correctness over ultra-low latency for this project.
Each step was one focused prompt with clear success criteria. When something was wrong (for example the maker order not updating on fill), I didn't keep patching in chat. I reverted, tightened the plan, and ran the agent again. Cursor's own docs say to do that. It works.
Let the agent find context. You own the boundaries.
I didn't paste the whole codebase into the prompt. I kept an architecture doc and a README as the "rules." I pointed at existing code: "Add the integration call where we apply fills, same pattern as in positions/service.py." I let Cursor use grep and semantic search to find where orders are saved and where positions are updated.
That kept prompts short and kept the agent inside the boundaries I'd set.
What I shipped and what I'd do next
I ended up with: order book, limit and market orders, positions, real market data from Binance (no API key), optional POST to a gamification API on fill, and a README with an architecture diagram, system design notes, and an API table. Docker Compose for local run.
What I'd do before calling it production-ready: add rate limiting (e.g. Redis) and proper unit tests for the matching engine (OrderBook.add, insert, cancel) plus integration tests for place, cancel, and book. Then the agent can iterate against a test suite too.
The takeaway
A mini derivatives exchange is a real project. Using Cursor like a senior meant: (1) writing the architecture and module map first, (2) breaking implementation into small steps I could review, (3) giving the agent clear boundaries and examples instead of "build everything," and (4) reverting and refining the plan when it went off spec. The result is a codebase I can explain in an interview and a story about how I used AI without letting it own the design.
If you're building something similar, try starting with a one-pager: repos, modules, and why this way. Then drive Cursor one module at a time. You'll get better code and a better story.
Repo links: mini-derivatives-exchange (backend), mini-exchange-ui (frontend). Both READMEs have architecture diagrams, API docs, and system design notes.
Top comments (0)