-
Notifications
You must be signed in to change notification settings - Fork 12
Business Logic Portfolio and Risk Management
This document details position accounting, weighted average cost basis calculations, Realized & Unrealized Profit & Loss (P&L) formulas, and pre-trade risk management controls in Emporia Trading Platform's portfolio-service.
portfolio-service maintains real-time position state records for each user account and instrument symbol.
-
Long Position: Position quantity
$> 0$ . Benefits when market price increases. -
Short Position: Position quantity
$< 0$ . Benefits when market price decreases. -
Flat Position: Position quantity
$= 0$ . No open market exposure.
flowchart TD
FillEvent["Execution Fill Event Received"] --> CheckDir{"Existing Position Side?"}
CheckDir -->|Same Side| AddPos["Increase Position Size & Update Average Cost"]
CheckDir -->|Opposite Side| ReducePos["Reduce Position Size & Calculate Realized P&L"]
ReducePos --> CheckZero{"New Quantity == 0?"}
CheckZero -- Yes --> Flat["Position Closed (FLAT)"]
CheckZero -- No --> Partial["Position Partially Closed / Flipped"]
When adding to an existing position (e.g., buying more shares for an existing long position):
Realized PnL is locked in when a position is reduced or closed out:
-
Closing a Long Position (Selling shares at price
$P_{\text{exit}}$ ):$$\text{Realized PnL} = Q_{\text{closed}} \times (P_{\text{exit}} - \text{CostBasis})$$ -
Closing a Short Position (Buying back shares at price
$P_{\text{exit}}$ ):$$\text{Realized PnL} = Q_{\text{closed}} \times (\text{CostBasis} - P_{\text{exit}})$$
Unrealized PnL reflects the paper profit or loss of open positions marked against current market quotes (
-
For Long Positions:
$$\text{Unrealized PnL} = Q_{\text{position}} \times (P_{\text{mark}} - \text{CostBasis})$$ -
For Short Positions:
$$\text{Unrealized PnL} = |Q_{\text{position}}| \times (\text{CostBasis} - P_{\text{mark}})$$
Mark Price Selection:
- Long positions mark against current Best Bid (
$P_{\text{bid}}$ ). - Short positions mark against current Best Ask (
$P_{\text{ask}}$ ).
Before an order is submitted to execution venues, portfolio-service and authorisation-service enforce pre-trade risk constraints:
flowchart TD
Order["Inbound Order Command"] --> Risk1{"Order Value <= Max Order Limit?"}
Risk1 -- No --> Block1["Reject: Exceeds Max Single Order Value ($100k)"]
Risk1 -- Yes --> Risk2{"Position + Order <= Max Symbol Position Limit?"}
Risk2 -- No --> Block2["Reject: Exceeds Symbol Position Exposure Cap"]
Risk2 -- Yes --> Risk3{"Required Margin <= Available Buying Power?"}
Risk3 -- No --> Block3["Reject: Insufficient Account Buying Power"]
Risk3 -- Yes --> Pass["Pass Pre-Trade Risk Checks"]
- Max Order Value Limit: Restricts single order size (e.g. max $100,000 per order) to prevent catastrophic fat-finger entries.
- Symbol Concentration Limit: Restricts max net position per symbol (e.g. max 10,000 shares of any single ticker).
- Buying Power & Margin Verification: Verifies that cash balance plus available margin covers initial margin requirements before order routing.
- Trading Terminology Glossary
- Order Lifecycle & Validation
- Order Routing & SOR
- Market Data & Pricing
- Portfolio & Risk Management
- Architecture & Order Flow
- Static Data Service
- Market Data Service
- Order Command Service
- Order Management Service (OMS)
- Execution Service
- Portfolio Service
- Design Patterns
- Microservices Overview
- Exchange-Core Integration
- Testing & Verification
- Deployment & Operations
- Repository: emporia
- Tech Stack: Java 21 | Spring Boot 4.0.7 | React 19 | Kafka | gRPC
- Coverage: 91.95% JaCoCo