Platform’s core system splits into two independent business domains, decoupled by strict interface contracts and unidirectional dependencies:
Both domains strictly forbid circular dependencies and communicate via async message queue and command dispatch.
| Module | Function | Key Output |
|---|---|---|
| L1 Account & Assets | User registration, multi-chain deposit/withdrawal, balance management | Account ID, wallet address, balance snapshot |
| L2 Order Routing | Order classification, three-mode routing, threshold decision | Routing instruction (INTERNAL/HL), Order ID |
| L3 Platform B-book Execution | INTERNAL fill, position accounting, fee settlement | Fill confirmation, Position ID, fill price |
| L4 HL Proxy Execution | HL order submission, receipt mapping, price correction | HL Order ID, fill price, error receipt |
| L7 Market Data | Market subscription, caching, sync | Mark price, funding rate, depth data |
| L8 Settlement & Reconciliation | PnL calculation, funding fee settlement, reconciliation | Settlement record, profit/loss voucher, reconciliation report |
❌ Direct balance modification (except fills/liquidation/withdrawal) ❌ Self-triggered liquidation (must be commanded by Risk domain) ❌ Hedge decision-making (entirely L6 responsibility) ❌ Risk rule checking (outside order format validation scope)
| Module | Function | Key Output |
|---|---|---|
| Pre-Trade Risk Check | Pre-order approval | Approved/Rejected, reason, warnings |
| Exposure Monitor | Real-time exposure calculation, aggregation | Net exposure, direction, real-time update |
| Margin & Liquidation Engine | Margin ratio calculation, liquidation trigger | Margin ratio, liquidation signal, execution ID |
| Hedge Engine (L6) | Hedge threshold, ratio, instruction generation | Hedge instruction, priority, target account |
| Risk Reserve Management | Reserve net value, liquidity management | Reserve balance, available limit, inflow record |
| Circuit Breaker | Multi-dimensional breaker monitoring | Breaker status, trigger reason, recovery condition |
Risk Domain → Ledger Domain: Read-only + Send commands
Ledger Domain → Risk Domain: Send events only
Forbidden Reverse Calls
Purpose: Verify risk control conditions are met before order submission
Request Parameters
{
"request_id": "order_req_20260409_001",
"user_id": "user_12345",
"symbol": "BTC",
"side": "LONG",
"size": 0.5,
"notional": 20000,
"leverage": 10,
"margin_mode": "ISOLATED",
"order_type": "MARKET",
"timestamp": 1712688000000
}
Response Parameters
{
"approved": true,
"order_id": "order_20260409_001",
"reject_reason": null,
"risk_warnings": [
"account_equity_low: Used margin is 92% of total equity, consider funding account"
],
"metadata": {
"margin_ratio": 0.92,
"max_leverage_allowed": 15,
"user_risk_level": "MEDIUM"
}
}
Error Codes
| Error Code | Meaning | HTTP Code |
|---|---|---|
| INSUFFICIENT_MARGIN | Insufficient margin | 400 |
| SYMBOL_SUSPENDED | Symbol trading suspended | 400 |
| EXPOSURE_LIMIT_EXCEEDED | Exposure limit exceeded | 400 |
| USER_RESTRICTED | User restricted | 403 |
| RESERVE_INSUFFICIENT | Risk reserve insufficient, cannot open INTERNAL order | 400 |
| LEVERAGE_EXCEED | Leverage exceeds user limit | 400 |
Idempotency Strategy
request_idTimeout Handling
Caller: L2 Order Routing module Frequency: Per order
Purpose: Ledger domain notifies Risk domain of INTERNAL exposure change (async, non-blocking)
Message Format
{
"event_id": "exposure_evt_20260409_001",
"event_type": "OPEN",
"user_id": "user_12345",
"symbol": "BTC",
"direction": "LONG",
"position_size": 0.5,
"entry_price": 40000,
"delta_notional": 20000,
"current_exposure": {
"net_exposure": 45000,
"long_notional": 65000,
"short_notional": 20000
},
"timestamp": 1712688000000,
"source": "L3_EXECUTION"
}
Producer: L3 (internalization execution), L4 (HL receipt) Consumer: L6 (hedge engine, exposure monitoring) Transport: Redis Streams, at-least-once Ensure Monotonicity: Consumer uses message ID sorting, idempotent dedup
Timeout Handling
Purpose: Risk domain commands Ledger domain to execute user position liquidation
Request Parameters
{
"trigger_id": "liq_trg_20260409_001",
"position_id": "pos_20260408_123",
"user_id": "user_12345",
"symbol": "BTC",
"direction": "LONG",
"position_size": 0.5,
"trigger_price": 38000,
"margin_ratio": 0.095,
"liquidation_type": "ISOLATED",
"execution_target": "INTERNAL",
"urgency": "HIGH",
"timestamp": 1712688000000
}
Response Parameters
{
"execution_id": "liq_exe_20260409_001",
"status": "EXECUTING",
"position_id": "pos_20260408_123",
"close_price": null,
"filled_size": 0,
"remaining_size": 0.5,
"estimated_loss": -2000,
"liquidation_fee": 2000,
"timestamp": 1712688000000
}
Final Response (After Fill)
{
"execution_id": "liq_exe_20260409_001",
"status": "COMPLETED",
"close_price": 38500,
"filled_size": 0.5,
"actual_loss": -2250,
"liquidation_fee": 2000,
"platform_profit": 1600,
"reserve_fund_contribution": 400,
"settlement_time_ms": 2500
}
Error Codes
| Error Code | Meaning |
|---|---|
| POSITION_ALREADY_CLOSED | Position already closed |
| POSITION_NOT_FOUND | Position not found |
| HL_UNAVAILABLE | HL liquidation failed (HL-side position liquidated) |
| EXECUTION_TIMEOUT | Liquidation execution timeout (>5s) |
| INSUFFICIENT_LIQUIDITY | Insufficient liquidation liquidity |
| UNAUTHORIZED | Unauthorized command source |
Idempotency Strategy
trigger_idTimeout Handling
Caller: L6 Risk domain Frequency: Event-driven (margin ratio trigger)
Purpose: Risk domain L6 commands Ledger domain L4 to hedge platform net exposure on HL
Request Parameters
{
"instruction_id": "hedge_instr_20260409_001",
"symbol": "BTC",
"direction": "SHORT",
"size": 0.4,
"leverage": 10,
"max_slippage_bps": 100,
"urgency": "NORMAL",
"reason": "net_exposure_500k_exceeded",
"timestamp": 1712688000000
}
Response Parameters
{
"execution_id": "hedge_exe_20260409_001",
"status": "EXECUTING",
"symbol": "BTC",
"direction": "SHORT",
"order_size": 0.4,
"hl_order_id": "hl_order_99999",
"timestamp": 1712688000000
}
Final Response (After Fill)
{
"execution_id": "hedge_exe_20260409_001",
"status": "COMPLETED",
"symbol": "BTC",
"fill_price": 40100,
"filled_size": 0.4,
"notional_filled": 16040,
"taker_fee": 5.61,
"net_cost": 5.61,
"remaining_exposure": 100000,
"settlement_time_ms": 3200
}
Error Codes
| Error Code | Meaning |
|---|---|
| HEDGE_ACCOUNT_INSUFFICIENT | Hedge account margin insufficient |
| SLIPPAGE_EXCEEDED | Slippage exceeds limit |
| HL_UNAVAILABLE | HL connection interrupted |
| EXECUTION_TIMEOUT | Hedge instruction timeout |
| INVALID_SIZE | Hedge size exceeds limit |
Idempotency Strategy
instruction_idTimeout Handling
Caller: L6 Hedge engine Frequency: Threshold-triggered (on exposure change)
Purpose: Switch L2’s three routing modes (NORMAL_MODE / HL_MODE / BETTING_MODE)
Request Parameters
{
"change_id": "mode_chg_20260409_001",
"new_mode": "HL_MODE",
"trigger_type": "AUTO",
"operator_id": null,
"reason": "net_exposure_exceeded_1m_threshold",
"enforced": false,
"timestamp": 1712688000000
}
Response Parameters
{
"applied": true,
"change_id": "mode_chg_20260409_001",
"previous_mode": "NORMAL_MODE",
"new_mode": "HL_MODE",
"effective_at": 1712688000100,
"effective_for_ms": 0,
"auto_fallback_threshold": {
"trigger": "net_exposure_below_500k",
"fallback_mode": "NORMAL_MODE"
}
}
Error Codes
| Error Code | Meaning |
|---|---|
| ALREADY_IN_MODE | Already in target mode |
| UNAUTHORIZED | Operator unauthorized |
| INVALID_MODE | Invalid mode |
Idempotency Strategy
change_idTimeout Handling
Caller: L6 Risk domain (auto), L9 Admin (manual) Frequency: Low (minute-level)
Purpose: Risk domain queries user account state for decision-making
Request Parameters
{
"user_id": "user_12345",
"include_details": false
}
Response Parameters
{
"user_id": "user_12345",
"total_equity": 100000,
"available_balance": 5000,
"frozen_margin": 60000,
"cross_margin_used": 35000,
"unrealized_pnl": 2500,
"positions": {
"internal": [
{
"position_id": "pos_001",
"symbol": "BTC",
"direction": "LONG",
"size": 0.5,
"entry_price": 40000,
"current_price": 41000,
"margin_used": 20000,
"margin_mode": "ISOLATED",
"unrealized_pnl": 500
}
],
"hyperliquid": [
{
"symbol": "ETH",
"direction": "SHORT",
"size": 10,
"entry_price": 2000,
"current_price": 1950,
"unrealized_pnl": 500
}
]
},
"margin_ratios": {
"account_level": 0.92,
"isolated_positions": [0.85, 0.78]
}
}
Error Codes
| Error Code | Meaning |
|---|---|
| USER_NOT_FOUND | User not found |
| ACCOUNT_LOCKED | Account locked |
Timeout Handling
Caller: L6 Hedge engine, liquidation engine, pre-trade risk check Frequency: High (multiple times per second)
| Category | Communication | Consistency | Path |
|---|---|---|---|
| Core path: order → fill → accounting | Synchronous transaction | ACID | Database transaction + distributed lock |
| Cross-domain notify: exposure/position change | Async message | At-least-once | Redis Streams + consumer idempotent |
| Command dispatch: liquidation/hedge/mode | Async message | At-least-once | Command queue + retry + idempotency key |
| Read operation: query balance/position | Sync query | Eventual | Cache + TTL + version number |
Periodic Full Reconciliation (every hour)
1. Ledger domain export: user total equity, total positions, total exposure, total risk value
2. Risk domain export: latest risk monitoring snapshot, liquidation blacklist, freeze list
3. Reconcile dimensions:
- Is user total equity consistent?
- Is net exposure value consistent?
- Are liquidated positions synchronized?
4. Discover discrepancy → Generate audit report → Alert → Manual review → Compensating transaction
Compensating Transaction Examples
| Discrepancy | Root Cause | Compensation |
|---|---|---|
| Liquidation failed, position not closed | HL connection lost or timeout | Retry 3 times (1s interval) → Alert → Manual confirm → Force HL_MODE |
| Exposure value mismatch | Fill event lost | Scan fill records → Resend exposure event → Recalculate hedge |
| Risk reserve balance incorrect | Inflow record lost | Check user loss vouchers → Supplement entry → Alert |
| User balance tampered | Abnormal operation log | Rollback to last correct version + manual audit |
Synchronous (Strong Consistency)
Asynchronous (Eventual Consistency)
Code Example
# Sync path: order processing
with db.transaction():
order = Order.create(user_id, symbol, side, size)
if route == 'INTERNAL':
position = Position.create(order)
balance.update(fee=-fee_amount)
else:
hl_order = hl_api.create_order(...)
db.commit()
# Async notify: exposure change
message_queue.publish('exposure_changes', {
'event_id': uuid4(),
'user_id': order.user_id,
'delta_notional': order.notional,
...
})
Each cross-domain interface has an idempotency key:
request_id (client-generated + timestamp)trigger_id (risk system-generated)instruction_id (L6-generated)change_id (control system-generated)Storage Schema
CREATE TABLE idempotency_keys (
key_type VARCHAR(50),
key_value VARCHAR(256),
result JSON,
created_at TIMESTAMP,
PRIMARY KEY (key_type, key_value),
INDEX (created_at)
);
Check: SELECT result FROM idempotency_keys WHERE key_value = ?
Partition by User: Ensure same-user exposure events ordered
partition_key = f"user_{event.user_id}"
message_queue.publish('exposure_changes', event, partition=partition_key)
Consumer Dedup: Idempotent consumer
def consume_exposure_event(event):
last_event_id = redis.get(f"last_event_{event.user_id}")
if event.event_id <= last_event_id:
return # Already processed, skip
# Process event
update_exposure(event)
redis.set(f"last_event_{event.user_id}", event.event_id)
PreTradeCheck must be <10ms, else impacts trading UX
Caching Strategy
def pre_trade_check(order):
cache_key = f"ptc_{order.user_id}_{order.symbol}"
cached = cache.get(cache_key)
if cached and cached['timestamp'] > now - 100ms:
return cached['result']
try:
result = risk_service.check(order, timeout=10ms)
cache.set(cache_key, result, ttl=100ms)
return result
except TimeoutError:
# Use last result or default reject
return cached or {'approved': False}
Liquidation is high-priority, must have retry mechanism
def execute_liquidation(trigger):
for retry in range(3):
try:
result = liquidation_service.execute(trigger, timeout=5000ms)
if result.status == 'COMPLETED':
return result
except Exception as e:
if retry < 2:
sleep(1)
continue
else:
alert(f"Liquidation {trigger.trigger_id} failed after 3 retries", severity=CRITICAL)
# Force HL_MODE, manual handling
routing_mode.set('HL_MODE')
raise
Auto-Correct Small Discrepancies
Manual Review Large Discrepancies
def reconcile():
discrepancies = ledger_domain.export() ^ risk_domain.export()
for disc in discrepancies:
if abs(disc.amount) < 100:
auto_correct(disc)
else:
create_audit_ticket(disc, status='PENDING_REVIEW')
alert(f"Large discrepancy detected: {disc.amount}")
Via clear domain boundaries, unidirectional dependencies, and sync+async hybrid communication, we achieve:
✅ Decoupling: Both domains evolve independently, stable interfaces ✅ Observability: Async messages fully traceable across chain ✅ Fault Tolerance: Liquidation/hedge has retry + manual backstop ✅ Consistency: Sync transactions + async reconciliation double guarantee ✅ Efficiency: Core path sync <10ms, non-critical async non-blocking