A production-style A-share market broker engine built with FastAPI, SQLAlchemy, and Pydantic V2. Implements the complete order lifecycle: capture, risk checks, matching, fee calculation, T+1 settlement, and reconciliation.
Meridian — 精准定位,如同子午线划分时区,每一笔交易都在正确的时刻发生。
graph TB
Client[Client] -->|REST API| FastAPI[FastAPI Server]
FastAPI --> Auth[JWT Auth]
FastAPI --> RateLimit[Rate Limiter]
FastAPI --> TradeAPI[Trade API]
FastAPI --> AccountAPI[Account API]
FastAPI --> RiskAPI[Risk API]
FastAPI --> OpsAPI[Health/Metrics]
TradeAPI --> RiskService[Risk Service]
TradeAPI --> TradingService[Trading Service]
TradingService --> FeeService[Fee Service]
TradingService --> MatchingEngine[Matching Engine]
TradingService --> DB[(Database)]
MatchingEngine --> OrderBook[Order Book]
OrderBook --> Bids[Bids - SortedList]
OrderBook --> Asks[Asks - SortedList]
RiskService --> RiskRules[(Risk Rules)]
subgraph Observability
Structlog[Structured Logging]
Prometheus[Prometheus Metrics]
TraceID[Trace ID Middleware]
end
- FIFO Price-Time Priority Matching with O(log n) price level insertion via
sortedcontainers - Order Types: Limit, Market
- Time in Force: Day, GTC, IOC (Immediate or Cancel), FOK (Fill or Kill)
- ClOrdID / Idempotency: Safe retries with client order IDs
- Thread-safe with
threading.Lock(single-process constraint documented) - OrderBookStore ABC for Redis-backed horizontal scaling
- Fee Model: Commission 0.025% (min 5 CNY), Stamp Tax 0.05% (sell-only), Transfer Fee 0.001%
- Price Limits (涨跌停板): Main board ±10%, ChiNext/STAR ±20%, ST ±5%
- Call Auction (集合竞价): Opening/closing price determination with volume maximization
- T+1 Settlement: Bought shares unavailable until next trading day
- Per-symbol position limits, total position limits, daily trade count limits
- Price deviation checks, trading window enforcement
- Risk Rule DSL: Compile expressions like
order.quantity > 1000into runtime checks
- FIX 4.4 Gateway: NewOrderSingle (D), ExecutionReport (8), OrderCancelRequest (F)
- Algorithmic Orders: TWAP (time-weighted) and VWAP (volume-weighted) order splitting
- Event Sourcing: Append-only order lifecycle audit trail
- Backtest Framework: Replay orders from CSV, calculate P&L and max drawdown
- Mock Market Data Feed: Random walk price generator with L1 quote cache
- Structured Logging: structlog with JSON/console renderers + trace_id middleware
- Prometheus Metrics: Order counters, execution histograms, fee collection
- Health Endpoints:
/healthz,/readyz,/metrics
| Component | Technology |
|---|---|
| Framework | FastAPI + Uvicorn |
| ORM | SQLAlchemy 2.0 |
| Validation | Pydantic V2 |
| Matching | Custom FIFO engine with SortedList |
| Auth | JWT (python-jose) |
| Rate Limiting | slowapi |
| Logging | structlog (JSON/console) + trace_id |
| Metrics | prometheus-client |
| FIX Protocol | Custom FIX 4.4 gateway |
| Event Bus | Kafka (pluggable) |
| Order Book Store | In-memory / Redis (pluggable) |
| Testing | pytest + Hypothesis + pytest-benchmark |
| Linting | ruff |
| CI | GitHub Actions |
| Deployment | Docker + docker-compose |
python -m venv .venv
source .venv/bin/activate # Linux/Mac
pip install -r requirements.txt
uvicorn main:app --reload- API docs: http://127.0.0.1:8000/docs
- Health: http://127.0.0.1:8000/healthz
- Metrics: http://127.0.0.1:8000/metrics
# All tests
pytest minibroker/tests/ -v
# With benchmarks
pytest minibroker/tests/ -v --benchmark-enable
# Property tests only
pytest minibroker/tests/test_services/test_properties.py -v# Single container
docker build -t meridian .
docker run -p 8000:8000 meridian
# Full stack (app + Redis + Kafka)
docker-compose up -dImportant: The matching engine is an in-memory singleton. Use --workers 1 (already set in Dockerfile).
| Env Var | Description | Default |
|---|---|---|
DATABASE_URL |
SQLAlchemy database URL | sqlite:///./minibroker.db |
ENVIRONMENT |
Environment name | development |
SECRET_KEY |
JWT signing key | dev-secret-change-in-production |
# Get auth token
curl -X POST http://localhost:8000/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"username": "trader", "password": "trader123"}'
# Submit order
curl -X POST http://localhost:8000/api/v1/trade/order \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"account_id": "buyer-1",
"symbol": "AAPL",
"side": "buy",
"order_type": "limit",
"quantity": "100",
"price": "150.00",
"time_in_force": "day",
"cl_ord_id": "my-order-001"
}'{
"account_id": "buyer-1",
"symbol": "AAPL",
"side": "buy",
"order_type": "limit",
"quantity": "100",
"price": "150.00",
"time_in_force": "ioc"
}Benchmarked on Linux (WSL2):
| Operation | Latency | Throughput |
|---|---|---|
| Submit + Match | ~8μs | 114K OPS |
| 1000 resting orders | ~4.3ms | - |
| Match against deep book (100 levels) | ~600μs | - |
alembic upgrade headpython scripts/seed_demo_data.pyCreates buyer-1 (100K balance), seller-1 (1000 shares each in AAPL/MSFT/GOOG), and risk rules.