A production-ready, low-latency orderbook matching engine built with Rust, featuring price-time priority matching, real-time trade settlement, and a modern HTTP API.
- Overview
- Key Features
- Architecture
- Technology Stack
- Getting Started
- API Documentation
- Core Concepts
- Project Structure
- Design Decisions
- Testing
- Performance Characteristics
- Known Limitations
- Future Enhancements
- Contributing
- License
This project implements a limit order book (LOB) with a matching engine designed for high throughput and low latency. It uses a single-threaded actor model for the core matching engine, eliminating lock contention while maintaining strict sequential consistency.
What is an OrderBook?
An orderbook is a real-time list of buy and sell orders for a specific asset (in this case, BTC/USD). It matches buyers with sellers based on price-time priority:
- Best price first - Orders with better prices match first
- FIFO at same price - Orders at the same price level match in chronological order (first-in, first-out)
Use Cases:
- Cryptocurrency exchanges
- Stock trading platforms
- Automated market makers (AMMs)
- Educational/research projects
- High-frequency trading (HFT) simulations
- ✅ Limit Orders - Place orders at specific prices
- ✅ Market Orders - Execute immediately at best available prices
- ✅ Order Cancellation - Cancel open orders with automatic fund refunds
- ✅ Real-time Matching - Price-time priority matching algorithm
- ✅ Balance Management - Fund reservation and settlement system
- ✅ OrderBook Depth Queries - View current market depth
- ✅ Single-Threaded Engine - No lock contention, guaranteed consistency
- ✅ Message Passing Architecture - Clean separation via async channels
- ✅ Fixed-Point Arithmetic - No floating-point precision errors
- ✅ JWT Authentication - Secure user authentication with bcrypt
- ✅ Async/Await - Built on Tokio runtime for scalability
- ✅ Type Safety - Leverages Rust's ownership system
- O(log n) order insertion/removal (BTreeMap)
- O(1) best bid/ask lookup
- O(1) FIFO matching at price levels (VecDeque)
- O(1) order lookup by ID (HashMap)
┌─────────────────┐
│ HTTP Client │
└────────┬────────┘
│ REST API (JSON)
▼
┌─────────────────────────────────────────────┐
│ Actix-Web HTTP Server │
│ ┌───────────────────────────────────────┐ │
│ │ Routes: │ │
│ │ • POST /api/auth/signup │ │
│ │ • POST /api/auth/signin │ │
│ │ • POST /api/orders/limit (auth) │ │
│ │ • POST /api/orders/market (auth) │ │
│ │ • DELETE /api/orders/:id (auth) │ │
│ │ • GET /api/depth │ │
│ │ • GET /api/user/balance (auth) │ │
│ │ • POST /api/user/onramp (auth) │ │
│ └───────────────────────────────────────┘ │
└────────┬────────────────────────────────────┘
│
│ OrderBookCommand
│ (via mpsc channel)
▼
┌─────────────────────────────────────────────┐
│ OrderBook Engine (Single Thread) │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ OrderBook State │ │
│ │ • bids: BTreeMap<Price, Orders> │ │
│ │ • asks: BTreeMap<Price, Orders> │ │
│ │ • orders: HashMap<Uuid, Order> │ │
│ │ • balances: HashMap<Uuid, Balance> │ │
│ └─────────────────────────────────────┘ │
│ │
│ Processing: │
│ 1. Validate balance │
│ 2. Reserve funds │
│ 3. Match order │
│ 4. Settle trades │
│ 5. Update balances │
└────────┬────────────────────────────────────┘
│
│ OrderBookResponse
│ (via oneshot channel)
▼
┌─────────────────┐
│ HTTP Response │
└─────────────────┘
The orderbook engine runs in a single async task, processing commands sequentially:
pub async fn run_orderbook_engine(mut rx: mpsc::Receiver<OrderBookCommand>) {
let mut orderbook = OrderBook::new();
while let Some(command) = rx.recv().await {
// Process ONE command at a time
match command {
PlaceLimitOrder { .. } => { /* ... */ }
CancelOrder { .. } => { /* ... */ }
// ... other commands
}
}
}Benefits:
- No mutex/rwlock overhead
- Guaranteed sequential consistency
- No race conditions
- Simpler reasoning about state
How concurrency works:
- Multiple HTTP handlers can send commands concurrently (multi-producer)
- Commands queue in the mpsc channel
- Engine processes them one-by-one (single-consumer)
- Each command gets a response via its own oneshot channel
| Component | Technology | Purpose |
|---|---|---|
| Language | Rust 1.75+ | Memory safety, zero-cost abstractions |
| Async Runtime | Tokio | Async I/O, task scheduling |
| Web Framework | Actix-Web | HTTP server, routing |
| Authentication | jsonwebtoken + bcrypt | JWT tokens, password hashing |
| Data Structures | BTreeMap, VecDeque, HashMap | Orderbook storage |
| Channels | tokio::sync::mpsc, oneshot | Message passing |
| Serialization | Serde + serde_json | JSON API |
| Logging | env_logger | Request/response logging |
| Testing | Rust built-in | Unit tests |
-
Rust 1.75 or higher
# Install Rust via rustup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Verify installation rustc --version cargo --version
-
Optional: httpie or curl for testing API endpoints
# macOS brew install httpie # Linux sudo apt install httpie
-
Clone the repository
git clone https://github.com/yourusername/orderbook.git cd orderbook -
Build the project
# Debug build (faster compilation) cargo build # Release build (optimized for performance) cargo build --release
-
Run tests
cargo test
# Run in development mode (with logs)
RUST_LOG=info cargo run
# Or run the compiled binary
./target/debug/Orderbook
# For production (release mode)
./target/release/OrderbookExpected output:
🚀 Starting Orderbook System...
📊 Orderbook engine started
🌐 Starting HTTP server on http://127.0.0.1:8080
OrderBook engine started and listening for commands...
The server is now running on http://127.0.0.1:8080
All endpoints return JSON. Protected endpoints require a JWT token in the Authorization: Bearer <token> header.
Create a new user account.
Endpoint: POST /api/auth/signup
Request Body:
{
"username": "trader1",
"email": "[email protected]",
"password": "secure_password"
}Response (200 OK):
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "trader1",
"email": "[email protected]"
}Example using httpie:
http POST :8080/api/auth/signup \
username=trader1 \
[email protected] \
password=secure_passwordExample using curl:
curl -X POST http://127.0.0.1:8080/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"username":"trader1","email":"[email protected]","password":"secure_password"}'Authenticate and receive a JWT token.
Endpoint: POST /api/auth/signin
Request Body:
{
"email": "[email protected]",
"password": "secure_password"
}Response (200 OK):
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"user_id": "550e8400-e29b-41d4-a716-446655440000"
}Token expires in 24 hours.
Example:
http POST :8080/api/auth/signin \
[email protected] \
password=secure_passwordSave the token for authenticated requests:
export TOKEN="eyJ0eXAiOiJKV1QiLCJhbGc..."All order endpoints require authentication (Authorization: Bearer <token>).
Place a limit order at a specific price.
Endpoint: POST /api/orders/limit
Request Body:
{
"side": "Buy", // "Buy" or "Sell"
"price": 50000.0, // Price per BTC in USD
"quantity": 0.5 // Amount of BTC
}Response (200 OK):
{
"order_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "Matched", // or "Added to book"
"trades": [
{
"trade_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"maker_id": "buyer-uuid",
"taker_id": "seller-uuid",
"price": 50000.0,
"quantity": 0.3,
"timestamp": "2025-01-15T10:30:00Z"
}
]
}Example:
http POST :8080/api/orders/limit \
"Authorization: Bearer $TOKEN" \
side=Buy \
price:=50000.0 \
quantity:=0.5Notes:
- Buy orders require sufficient USD balance (price × quantity)
- Sell orders require sufficient BTC balance
- Funds are reserved when order is placed
- If the order matches, trades are executed immediately
- Unmatched portion remains in the orderbook
Execute immediately at the best available price(s).
Endpoint: POST /api/orders/market
Request Body:
{
"side": "Buy", // "Buy" or "Sell"
"quantity": 1.0 // Amount of BTC (no price specified)
}Response (200 OK):
{
"order_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"status": "Filled", // or "No liquidity"
"trades": [
{
"trade_id": "...",
"price": 49800.0, // Executed at best ask
"quantity": 0.7,
"timestamp": "2025-01-15T10:31:00Z"
},
{
"trade_id": "...",
"price": 49850.0, // Slippage to next level
"quantity": 0.3,
"timestamp": "2025-01-15T10:31:00Z"
}
]
}Example:
http POST :8080/api/orders/market \
"Authorization: Bearer $TOKEN" \
side=Sell \
quantity:=1.0Market Order Behavior:
- Executes immediately or fails
- Never added to orderbook
- May experience price slippage across multiple levels
- Returns error if insufficient liquidity
Cancel an open order and refund reserved funds.
Endpoint: DELETE /api/orders/:order_id
Path Parameter:
order_id- UUID of the order to cancel
Response (200 OK):
{
"order_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"success": true
}Response (400 Bad Request):
{
"error": "Not authorized to cancel this order"
}Example:
http DELETE :8080/api/orders/3fa85f64-5717-4562-b3fc-2c963f66afa6 \
"Authorization: Bearer $TOKEN"Notes:
- Only the user who placed the order can cancel it
- Reserved funds are automatically refunded
- Partially filled orders refund the remaining quantity
View current market depth (top 10 price levels on each side).
Endpoint: GET /api/depth
No authentication required.
Response (200 OK):
{
"bids": [
[49900.0, 2.5], // [price, total_quantity]
[49850.0, 1.8],
[49800.0, 3.2]
],
"asks": [
[50100.0, 1.5],
[50150.0, 2.0],
[50200.0, 0.8]
]
}Example:
http GET :8080/api/depthNotes:
- Returns top 10 levels by default
- Bids sorted descending (highest first)
- Asks sorted ascending (lowest first)
- Each level shows aggregated quantity at that price
Check your current USD and BTC balances.
Endpoint: GET /api/user/balance
Requires authentication.
Response (200 OK):
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"balances": {
"USD": 25000.0,
"BTC": 0.5
}
}Example:
http GET :8080/api/user/balance \
"Authorization: Bearer $TOKEN"Add funds to your account.
Endpoint: POST /api/user/onramp
Requires authentication.
Request Body:
{
"currency": "USD", // "USD" or "BTC"
"amount": 10000.0
}Response (200 OK):
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"currency": "USD",
"new_balance": 35000.0
}Example:
http POST :8080/api/user/onramp \
"Authorization: Bearer $TOKEN" \
currency=USD \
amount:=10000.0Notes:
- This simulates depositing funds (no real payment processing)
- Use to fund your account for testing
- Supports both USD and BTC deposits
# 1. Sign up
http POST :8080/api/auth/signup \
username=alice [email protected] password=test123
# 2. Sign in and save token
export TOKEN=$(http POST :8080/api/auth/signin \
[email protected] password=test123 | jq -r '.token')
# 3. Deposit funds
http POST :8080/api/user/onramp \
"Authorization: Bearer $TOKEN" \
currency=USD amount:=100000.0
# 4. Check balance
http GET :8080/api/user/balance \
"Authorization: Bearer $TOKEN"
# 5. Place a limit buy order
http POST :8080/api/orders/limit \
"Authorization: Bearer $TOKEN" \
side=Buy price:=50000.0 quantity:=1.0
# 6. View orderbook
http GET :8080/api/depth
# 7. Cancel order (if needed)
http DELETE :8080/api/orders/<order_id> \
"Authorization: Bearer $TOKEN"The orderbook maintains two sorted maps of price levels:
OrderBook
├─ bids: BTreeMap<Reverse<Price>, PriceLevel> (descending - best bid first)
│ └─ 50000 → [Order1, Order2, Order3] (FIFO queue)
│ └─ 49900 → [Order4]
│ └─ 49800 → [Order5, Order6]
│
├─ asks: BTreeMap<Price, PriceLevel> (ascending - best ask first)
│ └─ 50100 → [Order7, Order8]
│ └─ 50200 → [Order9]
│ └─ 50300 → [Order10]
│
├─ orders: HashMap<Uuid, Order> (fast lookup by ID)
└─ user_balances: HashMap<Uuid, UserBalance> (user funds)
Key Properties:
- BTreeMap provides O(log n) insertion and sorted iteration
- Reverse wrapper on bid prices ensures highest bid is first
- VecDeque at each price level maintains FIFO order
- HashMap allows O(1) order lookup for cancellations
1. Create order with price limit
2. Check if price crosses spread:
- Buy: if order_price >= best_ask → can match
- Sell: if order_price <= best_bid → can match
3. Match against opposite side while price favorable:
- Execute trades at maker's price
- Update order quantities
- Settle balances
4. If remaining quantity > 0:
- Add to orderbook at order's price levelExample:
OrderBook:
Asks: [($50,100, 2 BTC), ($50,200, 1 BTC)]
Incoming: Buy 3 BTC @ $50,150
Matching:
- Match 2 BTC @ $50,100 (fully fills ask)
- Remaining: 1 BTC
- Check next ask: $50,200 > $50,150 (limit exceeded)
- Stop matching
Result:
- 2 BTC executed @ $50,100
- 1 BTC added to bids @ $50,150
1. Create order with no price limit
2. Match against best available prices:
- Keep matching until fully filled
- No price limit check
- May cross multiple price levels (slippage)
3. If insufficient liquidity:
- Return error (order not placed)Example:
OrderBook:
Asks: [($50,000, 1 BTC), ($50,100, 2 BTC), ($50,200, 1 BTC)]
Incoming: Market Buy 3.5 BTC
Matching:
- Match 1 BTC @ $50,000
- Match 2 BTC @ $50,100
- Match 0.5 BTC @ $50,200
Result:
- Total: 3.5 BTC
- Average price: $50,085.71
- Price slippage experienced
The system uses async channels to decouple the HTTP layer from the orderbook engine.
// HTTP Handler (Many threads)
let (response_tx, response_rx) = oneshot::channel();
orderbook_tx.send(OrderBookCommand::PlaceLimitOrder {
user_id, side, price, quantity,
response_tx, // ← Oneshot sender for response
}).await?;
let response = response_rx.await?; // ← Wait for engine to respond
// OrderBook Engine (Single thread)
while let Some(command) = mpsc_rx.recv().await {
match command {
PlaceLimitOrder { response_tx, .. } => {
// Process order
let result = orderbook.match_order(order);
// Send response back
response_tx.send(result);
}
}
}Channel Types:
- mpsc (multi-producer, single-consumer) - For commands from HTTP handlers
- oneshot (one-time response) - For engine responses back to handlers
When a limit order is placed, funds are reserved (locked):
Buy Order:
Required: price × quantity (in USD)
Reserve: Deduct USD from available balance
Sell Order:
Required: quantity (in BTC)
Reserve: Deduct BTC from available balanceExample:
User balance: { USD: 100,000, BTC: 2.0 }
Place Buy 1 BTC @ $50,000:
- Reserve: $50,000 USD
- New balance: { USD: 50,000 (available), BTC: 2.0 }
- Reserved: $50,000 (locked in order)
Place Sell 0.5 BTC @ $51,000:
- Reserve: 0.5 BTC
- New balance: { USD: 50,000, BTC: 1.5 (available) }
- Reserved: $50,000 USD + 0.5 BTC
When orders match, funds are settled (exchanged):
Buyer (taker): Buy 1 BTC @ $50,000
Seller (maker): Sell 1 BTC @ $50,000
Settlement:
1. Debit buyer: -$50,000 USD (from reserved)
2. Credit buyer: +1 BTC
3. Debit seller: -1 BTC (from reserved)
4. Credit seller: +$50,000 USDWhen an order is cancelled, reserved funds are refunded:
Cancelled Buy Order:
- Refund: price × remaining_quantity (in USD)
Cancelled Sell Order:
- Refund: remaining_quantity (in BTC)Example:
Order: Buy 10 BTC @ $50,000 (reserved $500,000)
Matched: 3 BTC (used $150,000)
Cancelled with 7 BTC remaining
Refund: $350,000 USD (7 × $50,000)
orderbook/
├── Cargo.toml # Dependencies and project metadata
├── README.md # This file
├── ARCHITECTURE.md # Detailed architecture documentation
├── engine.md # Engine implementation details
├── src/
│ ├── main.rs # HTTP server setup and entry point
│ ├── lib.rs # Library exports
│ │
│ ├── engine/
│ │ ├── mod.rs
│ │ └── engine.rs # OrderBook engine event loop
│ │
│ ├── handlers/ # HTTP request handlers
│ │ ├── mod.rs
│ │ ├── auth.rs # Signup/signin endpoints
│ │ ├── orders.rs # Order placement/cancellation
│ │ ├── market.rs # OrderBook depth queries
│ │ └── user.rs # Balance and onramp endpoints
│ │
│ ├── messages/ # Inter-task communication
│ │ ├── mod.rs
│ │ └── commands.rs # Command/Response enums
│ │
│ ├── orderbook/ # Core orderbook logic
│ │ ├── mod.rs
│ │ ├── orderbook.rs # OrderBook struct and data structure
│ │ ├── price_level.rs # FIFO queue for orders at a price
│ │ ├── matching.rs # Limit order matching algorithm
│ │ ├── market_matching.rs # Market order matching algorithm
│ │ └── settlement.rs # Trade settlement and balance updates
│ │
│ ├── types/ # Domain types
│ │ ├── mod.rs
│ │ ├── price.rs # Fixed-point price (6 decimals)
│ │ ├── quantity.rs # Fixed-point quantity (8 decimals)
│ │ ├── order.rs # Order struct and enums
│ │ ├── trade.rs # Trade execution record
│ │ └── user.rs # User and UserBalance structs
│ │
│ ├── state/
│ │ ├── mod.rs
│ │ └── app_state.rs # Shared application state
│ │
│ └── utils/ # Utilities
│ ├── mod.rs
│ ├── auth.rs # JWT and password utilities
│ ├── error.rs # Error types and conversions
│ └── middleware.rs # JWT validation middleware
| Module | Responsibility |
|---|---|
| engine | Single-threaded event loop processing orderbook commands |
| handlers | HTTP request/response handling and routing |
| messages | Command and response types for message passing |
| orderbook | Core matching engine and orderbook data structure |
| types | Domain types (Price, Quantity, Order, Trade, User) |
| state | Shared application state (mpsc sender) |
| utils | Authentication, error handling, middleware |
Decision: Run the orderbook in a single async task, processing commands sequentially.
Rationale:
- Eliminates need for locks/mutexes
- Guarantees sequential consistency
- Simpler to reason about state transitions
- No race conditions possible
Trade-offs:
- Single point of processing (but high throughput due to no locking)
- Cannot leverage multi-core for orderbook operations
- Good for single trading pair; multiple pairs need separate engines
Decision: Use BTreeMap<Price, PriceLevel> for bids and asks.
Rationale:
- Auto-sorts by price (O(log n) insertion)
- Easy to iterate in price order
- Fast best bid/ask lookup (first/last entry)
Alternatives considered:
- HashMap - O(1) insertion but not sorted
- SkipList - Similar performance but not in standard library
Decision: Use VecDeque<Order> at each price level.
Rationale:
- Implements price-time priority (FIFO)
- O(1) front/back operations
- Efficient for queue operations
Alternatives considered:
- Vec - Less efficient for removing front elements
- LinkedList - More allocations, cache-unfriendly
Decision: Store prices and quantities as u64 with fixed decimal places.
Rationale:
- Avoids floating-point precision errors
- Deterministic comparisons
- Critical for financial calculations
Implementation:
- Price: 6 decimals (e.g., 50000.123456)
- Quantity: 8 decimals (e.g., 1.23456789 BTC)
Decision: Use async channels for communication between HTTP and engine.
Rationale:
- Clean separation of concerns
- Decouples HTTP layer from orderbook
- Each request gets individual response
- Follows actor model pattern
Trade-offs:
- Additional serialization/deserialization overhead
- Slightly higher latency than direct function calls
- More complex than shared-memory approach
Decision: Reserve funds when limit orders are placed.
Rationale:
- Prevents double-spending
- Ensures atomic operations
- Clear accounting of available vs reserved funds
Implementation:
- Deduct on order placement
- Credit on trade execution or cancellation
cargo test24 unit tests covering:
| Module | Tests | Coverage |
|---|---|---|
| types/order.rs | 16 | Order creation, filling, cancellation, status updates |
| types/price.rs | 2 | Ordering, arithmetic operations |
| types/quantity.rs | 2 | Addition, subtraction |
| types/trade.rs | 2 | Trade creation, ID uniqueness |
| types/user.rs | 3 | User creation, balance operations |
| utils/auth.rs | 2 | Password hashing, JWT generation |
running 24 tests
test types::order::tests::test_cancel_order ... ok
test types::order::tests::test_fill_order ... ok
test types::order::tests::test_order_creation ... ok
test types::order::tests::test_partial_fill ... ok
test types::price::tests::test_price_ordering ... ok
test types::quantity::tests::test_quantity_add ... ok
test utils::auth::tests::test_hash_password ... ok
test utils::auth::tests::test_create_jwt ... ok
...
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Use the API examples to test the full system end-to-end.
| Operation | Complexity | Data Structure |
|---|---|---|
| Insert order | O(log n) | BTreeMap insertion |
| Cancel order | O(log n) | BTreeMap removal |
| Match order | O(m × log n) | m = matches, n = price levels |
| Get best bid/ask | O(1) | BTreeMap first/last |
| Get order by ID | O(1) | HashMap lookup |
| FIFO at price level | O(1) | VecDeque front/back |
Per order: ~200 bytes
- Order struct: ~120 bytes
- HashMap entry: ~40 bytes
- BTreeMap entry: ~40 bytes
Example capacity:
- 1 GB RAM → ~5 million orders
- 10 GB RAM → ~50 million orders
Single-threaded engine:
- Simple limit order: ~100,000 ops/sec
- Complex matching: ~50,000 ops/sec
- OrderBook queries: ~200,000 ops/sec
Bottlenecks:
- BTreeMap operations (logarithmic)
- Trade settlement (balance updates)
- Serialization/deserialization (JSON)
Note: These are rough estimates; actual performance depends on hardware and workload.
Issue: All data stored in RAM, lost on shutdown.
Impact:
- No persistence across restarts
- Limited by available memory
- No audit trail
Future: Add PostgreSQL or Redis persistence layer.
Issue: Market orders don't pre-validate balance (see src/engine/engine.rs:86).
Impact:
- May fail mid-execution if user lacks funds
- Could lead to partial fills being rejected
Future: Estimate required balance from orderbook depth.
Issue: Hardcoded BTC/USD only.
Impact:
- Cannot trade other pairs (ETH/USD, etc.)
- Need to run multiple engines for multiple pairs
Future: Add pair parameter to orderbook, support multiple pairs.
Issue: Secret key hardcoded in src/utils/auth.rs:11.
Impact:
- Security risk if code exposed
- Cannot rotate keys
Future: Use environment variable (JWT_SECRET).
Issue: Only HTTP polling for orderbook updates.
Impact:
- Higher latency for real-time data
- More network overhead
Future: Add WebSocket endpoint for subscriptions.
Issue: Cannot query past trades or cancelled orders.
Impact:
- Limited analytics
- No audit trail
Future: Add trade history storage and query endpoint.
Issue: Depth query always returns 10 levels.
Impact:
- Cannot customize depth
- May be insufficient for analysis
Future: Add depth query parameter.
- Database persistence (PostgreSQL)
- Order history and trade log
- WebSocket real-time updates
- Environment-based configuration
- Market order balance estimation
- Request rate limiting
- Multiple trading pairs
- Stop-loss / take-profit orders
- Order book snapshots
- Admin dashboard
- Performance metrics (Prometheus)
- Comprehensive integration tests
- OCO (One-Cancels-Other) orders
- Iceberg orders
- Fee structure
- Maker/taker rebates
- Trading API keys (separate from user auth)
- Deposit/withdrawal workflow
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for new functionality
- Ensure all tests pass (
cargo test) - Format code (
cargo fmt) - Run linter (
cargo clippy) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Rust naming conventions (snake_case for functions/variables)
- Add documentation comments for public APIs
- Keep functions focused and small
- Prefer explicit error handling over panics
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Actix-Web - Fast, pragmatic web framework
- Powered by Tokio - Asynchronous runtime for Rust
- Inspired by real-world cryptocurrency exchange architectures
For questions or support:
- Open an issue on GitHub
- Email: [email protected]
- Discord: Your#1234
- ARCHITECTURE.md - Detailed system architecture
- engine.md - OrderBook engine implementation details
Built with ❤️ and Rust