Chapter 32: Key Takeaways — Building a Platform from Scratch
Architecture and Design
Use a layered architecture separating routers (HTTP), services (business logic), engines (market mechanisms), and models (data). This makes each layer independently testable and replaceable.
Start with FastAPI for prediction market backends. Its native Pydantic validation, automatic OpenAPI documentation, and async support accelerate development significantly.
Version your API from day one (/api/v1/). Breaking changes happen; versioning lets you evolve without disrupting existing clients.
Use SQLite for prototyping, PostgreSQL for production. SQLAlchemy makes the switch a one-line configuration change.
Order Book Engine
Price-time priority is the standard matching rule: best price first, then earliest order among ties.
Limit orders rest in the book and provide liquidity; market orders consume liquidity and execute immediately.
Lazy cancellation (setting remaining quantity to zero) is cheaper than heap removal and works well when cancellations are infrequent relative to new orders.
The trade executes at the maker's (resting order's) price, rewarding liquidity providers.
LMSR Automated Market Maker
Cost function: $C(\mathbf{q}) = b \cdot \ln\!\left(\sum_{i=1}^{n} e^{q_i / b}\right)$ determines the running total spent by all traders.
Price function: $p_i = e^{q_i / b} / \sum_j e^{q_j / b}$ (softmax) produces probabilities that always sum to 1.
Trade cost: $C(\mathbf{q'}) - C(\mathbf{q})$ is the cost difference before and after the share vector changes.
Maximum loss: $b \cdot \ln(n)$ bounds the market maker's worst-case subsidy. For binary markets: $\approx 0.693 \cdot b$.
The liquidity parameter $b$ controls the trade-off between price stability (high $b$) and subsidy cost (also high $b$). For binary markets with 40-100 traders, $b = 100$ is a reasonable starting point.
Always use the log-sum-exp trick to prevent numerical overflow in the exponential calculations.
REST API Design
Keep routers thin: They should validate input, call the service, and format the response. Business logic belongs in services.
Use Pydantic models for all request and response schemas. This provides automatic validation, documentation, and serialization.
Design endpoints around resources (markets, orders, positions) with standard HTTP methods (GET, POST, DELETE).
Return appropriate HTTP status codes: 201 for creation, 400 for bad requests, 401 for authentication failures, 404 for not found.
Authentication
JWT tokens are stateless: no database lookup needed per request, which scales well.
Hash passwords with bcrypt (via passlib). Never store plaintext passwords.
Use dependency injection (Depends(get_current_user)) to protect endpoints cleanly.
Store secrets in environment variables, never in source code.
Set token expiration appropriately (1 hour is common for access tokens).
Market Resolution
Markets follow a lifecycle: Open (trading active) -> Closed (trading stopped) -> Resolved (payouts distributed).
**Winning positions pay $1 per share**; losing positions pay $0.
Voiding refunds participants at cost basis when a market cannot be properly resolved.
Pre-specify resolution criteria in the market description to avoid disputes.
Record closing prices for calibration analysis—this proves the platform's forecasting value.
Order Book vs. LMSR Decision Framework
Use LMSR when: few traders, niche topics, need guaranteed liquidity, want simple UX.
Use order book when: many traders, high volume, want best price discovery, cost-sensitive.
Consider a hybrid that defaults to LMSR and adds an order book overlay when volume justifies it.
Frontend Considerations
API-first development: Use FastAPI's /docs to explore endpoints before building the frontend.
Use WebSockets for real-time price updates instead of polling.
Optimistic updates make the UI feel responsive: update immediately, roll back on error.
Token management: Store JWTs in httpOnly cookies for production security.
Common Pitfalls to Avoid
Do not use floating-point for money in production. Use Decimal or integer-cent representation.
Do not store engine state only in memory. Server restarts will lose all order books and AMM states. Persist to database or Redis.
Do not allow allow_origins=["*"] in production CORS configuration.
Do not set $b$ too low for LMSR. This creates excessive price volatility that discourages participation.
Do not skip input validation. Always validate that prices are in [0, 1], quantities are positive, and markets are open before executing trades.