Case study
Institutional bond trading platform
An institutional bond trading platform with an anonymous order book, request for quote, and live sockets. The notes record the settlement and yield checks.

Summary
An institutional bond alternative trading system for the Mexican market: an anonymous central order book, request for quote, live WebSockets, and yield analytics. Django with a domain layout, plus a Next.js PWA. Two protocols can run on the same security.
Role. The engineering history records a bank-to-bank bond-trading product, named MTrade and Cicada in the notes, from work at Citrusbug Technolabs between February 2022 and September 2024. Django REST, PostgreSQL, and a real-time React frontend were structured so T+0 and request-for-quote trading could settle together.
Outcome. The project notes record zero settlement discrepancies on that product, and say T+0 and request-for-quote settlement races were closed with the domain layout, PostgreSQL serializable isolation, and isolated React state machines. The notes state the audit result as full compliance. Yield calculators are checked at nine decimal places against Bloomberg tests. FX comes from Banxico UDI and APILayer.
The business gap
The gap
Two trading protocols on the same security can race at settlement. A desk also needs an anonymous book, request for quote, and yield figures it can check.
Why it was built
The notes describe a bank-to-bank product where T+0 and request-for-quote trading had to settle together, with live sockets for traders and a separate path for historic data.
How the build closed it
The Next.js PWA enters Daphne for HTTP and WebSockets. Django REST serves /api/v0. Channels fans the book out to user, streamer, and analyst groups. The matcher is in-process recursive SQL on price, priority, and id, inside one Postgres transaction, with pgviews for the blotter. Celery expires orders. The Kafka historic-data consumer is a second process with a dead-letter queue. The project notes record zero settlement discrepancies, and say those settlement races were closed with the domain layout, PostgreSQL serializable isolation, and isolated React state machines, with the audit result stated as full compliance. Yield calculators are checked at nine decimal places against Bloomberg tests. FX comes from Banxico UDI and APILayer. T+n settlement crosses two holiday calendars. The UI is a role, license, and feature-flag matrix. The domain layout uses UUID foreign keys, a leftover app_zero package, and circular imports.
Architecture
The source notes describe this system as a graph, not as a picture file. The diagram below is that graph: every box and every link is a node or an edge from the notes.
- Client
- API
- Queue
- Data
- External
Parts
- Next PWA: Trader, admin, scanners, and market-watch workspaces.
- Daphne ASGI: Producer image: HTTP and WebSockets.
- DRF /api/v0: Token and two-factor auth. Access follows the picked role.
- Channels WS: Redis groups for users, streamers, and analysts.
- Order-book matcher: Recursive SQL volume matcher, plus request for quote.
- Postgres + pgviews: UUID entities and blotter views.
- Celery + RabbitMQ: Order expiry, FX beat, and limit restore.
- Kafka HD consumer: Historic data reporter and a dead-letter queue.
- Banxico / Duo / FCM: UDI and FX, two-factor auth, push, object storage, and SendGrid.
Connections
- Next PWA to Daphne ASGI: token and sockets.
- Daphne ASGI to DRF /api/v0: REST.
- Daphne ASGI to Channels WS: live book.
- DRF /api/v0 to Order-book matcher: order.
- Order-book matcher to Postgres + pgviews: atomic match.
- DRF /api/v0 to Celery + RabbitMQ: expiry.
- Kafka HD consumer to Postgres + pgviews: historic ticks.
- Channels WS to Next PWA: depth.
- DRF /api/v0 to Banxico / Duo / FCM: two-factor and FX.
High-level design
- The Next.js PWA enters Daphne for HTTP and WebSockets. Django REST serves /api/v0. Channels fans out the book.
- The central-order-book matcher is in-process recursive SQL on Postgres and pgviews. Celery expires orders.
- The Kafka historic-data consumer is a second process. Banxico, Duo, and FCM sit at the edge.
Low-level design
- The matcher is recursive SQL on price, priority, and id, inside one database transaction.
- Yield calculators run at nine decimal places against Bloomberg tests. FX comes from Banxico UDI and APILayer.
- WebSocket groups are users, streamers, and data analysts. The Kafka historic-data consumer is a second process with a dead-letter queue.
Infrastructure and services
- Postgres + pgviews. UUID entities and blotter views.
- Celery + RabbitMQ. Order expiry, FX beat, and limit restore.
- Kafka HD consumer. Historic data reporter and a dead-letter queue.
- Banxico / Duo / FCM. UDI and FX, two-factor auth, push, object storage, and SendGrid.
Tech stack
Python
Django
PostgreSQL
Next.js
React
Celery
RabbitMQ
Kafka
Redis
SendGrid
Amazon S3
Firebase
- Duo
- Banxico
Logos are Simple Icons shipped with this site. Where a brand mark is unavailable, the name is shown on its own.
Client review
Order book, request-for-quote and live sockets behave like a real desk. Traders can rehearse the flow before we wire production venues.
Client testimonial
The architecture diagram and the live desk view matched. Compliance finally had something concrete to review.
Constraints in the source
- The domain layout inside Django uses UUID foreign keys, a leftover app_zero package, and circular imports.
- T+n settlement crosses two holiday calendars. The UI is a role, license, and feature-flag matrix.
