Skip to content

Paper Trading

The UserPaperTradePortfolio Durable Object implements the full paper trading engine.

Balance & Margin

  • Starting balance: $10,000
  • Account failure: Disabled by default (ChallengeManager enables via setBalanceForChallenge)
  • Margin modes: CROSS (default) and ISOLATED. CROSS includes unrealized PnL in available margin. Mode cannot be changed with open positions or limit orders.
  • Available margin: balance + unrealizedPnL - marginUsed - reservedMargin

Position Management

3-case netting algorithm:

  1. Same direction — adds to existing position
  2. Partial close — reduces position size
  3. Full reversal — closes and opens opposite

Explicit partial close: closePosition() accepts optional sizeUsd to close a specific amount. Remaining position keeps original entry price.

Validation Rules

  • Integer leverage only, 1 to token-dependent max (see apps/backend/src/constants/symbols/leverage.ts)
  • Minimum order size: $10 USD (configurable via min_order_size account setting)
  • Required margin ≤ available balance
  • Leverage can only increase (≥ existing position leverage), never decrease
  • System auto-adjusts leverage before adding to position if higher leverage requested
  • Adding to position must not cause immediate liquidation

Leverage Management

  • changeLeverage() RPC: Increase leverage for existing position (strictly increasing only)
  • Auto-adjustment: When opening with higher leverage, system increases existing position's leverage first
  • Effects: Releases margin, updates liquidation price, re-registers liquidation alert

Fee System

7-tier volume-based fees tracked over a 14-day rolling window.

Pending Order State Machine

CREATED → PENDING → EXECUTED / FAILED

Survives DO eviction. Margin is reserved at creation time for "eventually correct" execution.

BigNumber Serialization

Generic Serialized<T> type with serialize() and parseMonetary() helpers for safe monetary arithmetic.

Idempotency

24-hour TTL deduplication keys for: OPEN/CLOSE_POSITION, CLOSE_ALL_POSITIONS, LIMIT_ORDER, CANCEL_ALL_LIMIT_ORDERS, RESET, START_CHALLENGE. PROCESSING status prevents race conditions.