OOD - Online Stock Brokerage System
Problem
Design an object-oriented system for an online stock brokerage platform that lets investors search securities, place and manage orders, view real-time quotes, and track portfolios and watchlists. Focus on clean responsibilities, core workflows, and safe concurrency where applicable.
Solution
1. Requirements Analysis
Functional Requirements:
- Register accounts and manage profiles (Member, Admin).
- Search securities and view real-time quotes.
- Place market and limit orders; modify or cancel open orders.
- Track portfolio positions, P&L, and order history.
- Manage watchlists and price alerts.
- Deposit and withdraw funds.
Non-Functional Requirements:
- Low-latency order acknowledgment and consistent state for balances and orders.
- High availability during market hours.
- Auditability with complete order lifecycle trail.
- Secure data handling and access control.
2. Use Case Diagram
Actors: Member, Admin, System Use Cases: Search Security, View Quote, Place Order, Cancel Order, View Portfolio, Manage Watchlist, Deposit Funds
graph TB subgraph "Online Stock Brokerage System" UC1(Search Security) UC2(View Quote) UC3(Place Order) UC4(Cancel Order) UC5(View Portfolio) UC6(Manage Watchlist) UC7(Deposit Funds) end Member --> UC1 Member --> UC2 Member --> UC3 Member --> UC4 Member --> UC5 Member --> UC6 Member --> UC7 Admin --> UC5 System --> UC2
3. Class Diagram
Core Classes:
- Account: Base account with id, status, type.
- Member: Investor with portfolio, watchlists, and orders.
- Admin: Administrative capabilities.
- Stock: Security with symbol and metadata.
- StockQuote: Bid, ask, last, volume, timestamp.
- Order: Abstract base with id, symbol, qty, side, status.
- MarketOrder / LimitOrder: Concrete order types.
- Portfolio: Aggregates positions and value.
- Position: Holdings for a stock with quantity and cost basis.
- Watchlist: Tracked securities and alerts.
classDiagram class Account { +String accountId +String type +String status } class Member { +String memberId +Portfolio portfolio +List~Order~ orders +List~Watchlist~ watchlists } class Admin { +String adminId } class Stock { +String symbol +String name +String sector } class StockQuote { +String symbol +double bid +double ask +double last +long volume +long ts } class Order { <<abstract>> +String orderId +String symbol +int quantity +String side +String status } class MarketOrder { } class LimitOrder { +double limitPrice } class Portfolio { +List~Position~ positions +double totalValue } class Position { +Stock stock +int quantity +double costBasis } class Watchlist { +String id +List~Stock~ stocks } Member --> Portfolio Member --> Watchlist Member --> Order Order <|-- MarketOrder Order <|-- LimitOrder Position --> Stock StockQuote --> Stock
4. Activity Diagrams
Activity: Place Limit Order
graph TB A(Member selects stock) --> B(Enter quantity and limit price) B --> C(Validate inputs) C --> D{Sufficient buying power} D -- Yes --> E(Create limit order) E --> F(Submit to market gateway) F --> G(Update member orders) D -- No --> X(Show insufficient funds)
Activity: Cancel Order
graph TB A(Member selects open order) --> B(Validate cancel eligibility) B --> C{Order open or partially filled} C -- Yes --> D(Send cancel request) D --> E(Update order status) C -- No --> X(Show cannot cancel)
5. High-Level Code Implementation
Java
enum OrderSide { BUY, SELL }
enum OrderStatus { PENDING, OPEN, PARTIALLY_FILLED, FILLED, CANCELED }
abstract class Order {
protected String orderId;
protected String symbol;
protected int quantity;
protected OrderSide side;
protected OrderStatus status;
public abstract void submit();
}
class MarketOrder extends Order {
@Override public void submit() { /* submit to gateway */ }
}
class LimitOrder extends Order {
private double limitPrice;
public LimitOrder(double price) { this.limitPrice = price; }
@Override public void submit() { /* submit with limit */ }
}
class Stock { String symbol; String name; String sector; }
class Position { Stock stock; int quantity; double costBasis; }
class Portfolio { java.util.List<Position> positions; double totalValue; }
class Member {
String memberId;
Portfolio portfolio;
java.util.List<Order> orders;
}
Python
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import List
class OrderSide(Enum):
BUY = "BUY"
SELL = "SELL"
class OrderStatus(Enum):
PENDING = "PENDING"
OPEN = "OPEN"
PARTIALLY_FILLED = "PARTIALLY_FILLED"
FILLED = "FILLED"
CANCELED = "CANCELED"
@dataclass
class Order:
order_id: str
symbol: str
quantity: int
side: OrderSide
status: OrderStatus
@dataclass
class MarketOrder(Order):
pass
@dataclass
class LimitOrder(Order):
limit_price: float
@dataclass
class Stock:
symbol: str
name: str
sector: str
@dataclass
class Position:
stock: Stock
quantity: int
cost_basis: float
@dataclass
class Portfolio:
positions: List[Position] = field(default_factory=list)
total_value: float = 0.0
@dataclass
class Member:
member_id: str
portfolio: Portfolio
orders: List[Order] = field(default_factory=list)
aliases: [] tags: [stock-brokerage, ood, design] date_created: 2025-05-21 10:32 date_modified: 2025-12-31 23:49 title: OOD - Online Stock Brokerage System source_links:
- https://github.com/tssovi/grokking-the-object-oriented-design-interview published: true hugo_section: cs/problems/ood date: 2025-10-17 difficulty: hard topic: ood old_names:
- Design an Online Stock Brokerage System
1. Problem Statement
Online stock brokerage systems democratize equity market access by enabling retail and institutional investors to execute trades, manage portfolios, and track market movements without requiring traditional full-service brokers, transforming how millions of individuals participate in wealth creation through stock ownership. These platforms must orchestrate complex workflows encompassing real-time market data ingestion from multiple stock exchanges (NYSE, NASDAQ, international bourses), sophisticated order routing algorithms to secure best execution prices, diverse order type support (market orders executing immediately at current prices, limit orders waiting for specific price points, stop-loss orders triggering protective sales, stop-limit orders combining stop and limit mechanisms), multi-asset class trading (equities, ETFs, options, mutual funds), margin trading with leverage calculations and maintenance requirements, and integration with clearing houses for trade settlement within T+2 cycles. The architectural challenge extends beyond simple buy/sell transactions to encompass portfolio analytics displaying unrealized gains/losses across positions, cost basis tracking for tax reporting using FIFO/LIFO/specific lot identification methods, dividend reinvestment programs (DRIPs), corporate action processing (stock splits, mergers, spin-offs), and watchlist management allowing users to monitor hundreds of securities simultaneously with customizable price alerts and technical indicator notifications.
The system must support multiple user personas with dramatically different requirements: retail investors executing occasional trades from mobile apps expecting intuitive interfaces with educational resources, active day traders requiring sub-millisecond order acknowledgments with advanced charting tools and direct market access, institutional portfolio managers placing block orders worth millions requiring algorithmic execution to minimize market impact, financial advisors managing client accounts under fiduciary obligations needing comprehensive reporting and compliance trails, and system administrators monitoring platform health with circuit breaker controls during extreme volatility. Critical workflows include account funding through ACH transfers, wire transfers, and check deposits with appropriate holds until clearance; cash management with automatic sweep to money market funds; margin account calculations enforcing Regulation T requirements; tax-loss harvesting identifying opportunities to offset capital gains; and research integration providing analyst ratings, earnings calendars, SEC filings, and news sentiment analysis. The platform requires sophisticated search capabilities filtering thousands of securities by sector, market capitalization, P/E ratio, dividend yield, trading volume, and custom screening criteria while maintaining real-time price updates across all watchlists and open positions.
Dominating challenges include preventing erroneous trades through pre-trade risk checks validating sufficient buying power, position limits, and regulatory restrictions; implementing robust order management systems (OMS) maintaining complete audit trails of order lifecycle from placement through execution to settlement; handling partial fills where large orders execute across multiple price points requiring intelligent lot accounting; managing concurrent order modifications and cancellations with proper idempotency guarantees; ensuring data consistency between account balances, open positions, and pending orders under high-frequency trading scenarios generating thousands of transactions per second; implementing circuit breakers and trading halts during extraordinary market conditions; providing disaster recovery with real-time replication to geographically distributed data centers ensuring zero data loss; complying with extensive regulatory requirements (SEC Rule 15c3-1 net capital rule, FINRA pattern day trader rules, KYC/AML identity verification, suspicious activity reporting); and securing sensitive financial data against sophisticated cyber threats while maintaining system availability during market hours when downtime directly translates to customer losses and reputational damage.
2. System Requirements
We'll focus on the following set of requirements while designing the Online Stock Brokerage System:
Functional Requirements:
- Users should be able to register accounts with KYC/AML verification (identity documents, Social Security Number, employment information)
- The system should support multiple account types: individual taxable, joint accounts, traditional IRA, Roth IRA, margin accounts
- Users can search for securities by symbol, company name, CUSIP, sector, and custom screening criteria (P/E ratio, market cap, dividend yield)
- The system should display real-time stock quotes with bid/ask prices, last trade price, volume, and intraday price charts
- Users should be able to place market orders (execute immediately at best available price)
- Users should be able to place limit orders (execute only at specified price or better)
- Users should be able to place stop-loss orders (trigger market order when price falls to stop price)
- Users should be able to place stop-limit orders (trigger limit order when price reaches stop price)
- The system should support time-in-force specifications: Good Till Canceled (GTC), Day Order, Fill or Kill (FOK), Immediate or Cancel (IOC)
- Users can create multiple watchlists to monitor favorite securities with customizable price alerts
- The system should handle partial order fills and maintain detailed execution records (price, quantity, timestamp for each fill)
- Users should be able to modify or cancel open orders (if not yet executed or partially filled)
- The system should calculate and display portfolio metrics: total value, day's gain/loss, unrealized gains/losses, cost basis
- Users can deposit funds via ACH transfer, wire transfer, or check with appropriate clearance periods
- Users can withdraw funds to linked bank accounts with validation of available cash (not committed to open orders)
- The system should generate trade confirmations, monthly statements, and annual tax documents (1099-B, 1099-DIV, 1099-INT)
- Margin accounts should calculate buying power, margin requirements, and send margin calls when equity falls below maintenance levels
- The system should process corporate actions: stock splits, dividends, mergers, spin-offs with automatic position adjustments
- Users should receive notifications for order executions, price alerts, dividend payments, and account activity
- Administrators should be able to halt trading, adjust position limits, and monitor system health metrics
Non-Functional Requirements:
- Low Latency: Order acknowledgment within 100ms; execution latency under 200ms for market orders during normal conditions
- High Availability: 99.99% uptime during market hours (9:30 AM - 4:00 PM ET); graceful degradation if exchange connectivity lost
- Consistency: Strong consistency for account balances and order status; eventual consistency acceptable for market data feeds
- Durability: All orders persisted to append-only log before exchange submission; zero data loss guarantee for financial transactions
- Scalability: Support 10 million user accounts; handle 100,000 concurrent users; process 50,000 orders per second during peak volatility
- Security: Encryption at rest and in transit; multi-factor authentication; compliance with SEC cybersecurity guidelines and PCI-DSS for payment data
- Auditability: Complete audit trail for regulatory compliance; immutable order history; support for regulatory reporting (OATS, CAT)
- Disaster Recovery: Recovery Point Objective (RPO) of zero; Recovery Time Objective (RTO) under 15 minutes with hot standby data centers
3. Use Case Diagram
We have four main actors in our system:
- 👤 Member: Registered investors (searches securities, places/cancels orders, manages watchlists, monitors portfolio, deposits/withdraws funds, views statements)
- 🏦 Admin: Platform administrators (manages user accounts, monitors system health, implements trading halts, configures position limits, handles compliance)
- 👥 Guest: Non-registered users (browses market data, views educational content, must register to trade)
- 🤖 System: Automated services (executes stop orders, processes corporate actions, sends notifications, updates market data, generates statements)
Here are the top use cases for the Online Stock Brokerage System:
Account Management (Members & Admins)
- Register new account with KYC verification
- Link bank account for funding
- Deposit funds (ACH, wire, check)
- Withdraw funds to bank account
- Upgrade to margin account
- View account statements and tax documents
Trading Operations (Members)
- Search securities by symbol or criteria
- View real-time quotes and charts
- Place market order
- Place limit order
- Place stop-loss order
- Place stop-limit order
- Modify pending order
- Cancel pending order
- View order history and executions
Portfolio Management (Members)
- Create and manage watchlists
- Add price alerts
- View current positions with P&L
- Track cost basis across lots
- View portfolio analytics
- Manage dividend reinvestment
Market Data (All Users)
- View real-time stock quotes
- Check historical price charts
- View company fundamentals
- Access analyst ratings
- Read news and filings
System Operations (System)
- Process order executions
- Handle partial fills
- Trigger stop orders automatically
- Update market data feeds
- Process corporate actions
- Send execution notifications
- Calculate margin requirements
- Generate monthly statements
graph TB subgraph Actors Guest([Guest]) Member([Member]) Admin([Admin]) System([System]) end subgraph AccountMgmt["Account Management"] RegisterAccount["Register Account"]:::acctUC LinkBank["Link Bank Account"]:::acctUC DepositFunds["Deposit Funds"]:::acctUC WithdrawFunds["Withdraw Funds"]:::acctUC UpgradeMargin["Upgrade to Margin"]:::acctUC ViewStatements["View Statements"]:::acctUC end subgraph Trading["Trading Operations"] SearchSecurities["Search Securities"]:::tradeUC ViewQuotes["View Real-Time Quotes"]:::tradeUC PlaceMarketOrder["Place Market Order"]:::tradeUC PlaceLimitOrder["Place Limit Order"]:::tradeUC PlaceStopLoss["Place Stop-Loss Order"]:::tradeUC PlaceStopLimit["Place Stop-Limit Order"]:::tradeUC ModifyOrder["Modify Pending Order"]:::tradeUC CancelOrder["Cancel Order"]:::tradeUC ViewOrderHistory["View Order History"]:::tradeUC end subgraph Portfolio["Portfolio Management"] CreateWatchlist["Create Watchlist"]:::portfolioUC AddPriceAlert["Add Price Alert"]:::portfolioUC ViewPositions["View Current Positions"]:::portfolioUC TrackCostBasis["Track Cost Basis"]:::portfolioUC ViewAnalytics["View Portfolio Analytics"]:::portfolioUC ManageDividends["Manage DRIP"]:::portfolioUC end subgraph MarketData["Market Data"] ViewStockQuotes["View Stock Quotes"]:::dataUC ViewCharts["View Price Charts"]:::dataUC ViewFundamentals["View Fundamentals"]:::dataUC ViewRatings["View Analyst Ratings"]:::dataUC ReadNews["Read News & Filings"]:::dataUC end subgraph SystemOps["System Operations"] ProcessExecution["Process Order Execution"]:::systemUC HandlePartialFills["Handle Partial Fills"]:::systemUC TriggerStopOrders["Trigger Stop Orders"]:::systemUC UpdateMarketData["Update Market Data"]:::systemUC ProcessCorporateActions["Process Corporate Actions"]:::systemUC SendNotifications["Send Notifications"]:::systemUC CalculateMargin["Calculate Margin"]:::systemUC GenerateStatements["Generate Statements"]:::systemUC end subgraph AdminOps["Admin Operations"] ManageAccounts["Manage User Accounts"]:::adminUC MonitorHealth["Monitor System Health"]:::adminUC HaltTrading["Implement Trading Halt"]:::adminUC ConfigureLimits["Configure Position Limits"]:::adminUC ReviewCompliance["Review Compliance"]:::adminUC end %% Guest connections Guest --> SearchSecurities Guest --> ViewQuotes Guest --> ViewCharts Guest --> ViewFundamentals Guest --> RegisterAccount %% Member connections Member --> RegisterAccount Member --> LinkBank Member --> DepositFunds Member --> WithdrawFunds Member --> UpgradeMargin Member --> ViewStatements Member --> SearchSecurities Member --> ViewQuotes Member --> PlaceMarketOrder Member --> PlaceLimitOrder Member --> PlaceStopLoss Member --> PlaceStopLimit Member --> ModifyOrder Member --> CancelOrder Member --> ViewOrderHistory Member --> CreateWatchlist Member --> AddPriceAlert Member --> ViewPositions Member --> TrackCostBasis Member --> ViewAnalytics Member --> ManageDividends %% Admin connections Admin --> ManageAccounts Admin --> MonitorHealth Admin --> HaltTrading Admin --> ConfigureLimits Admin --> ReviewCompliance %% System connections System --> ProcessExecution System --> HandlePartialFills System --> TriggerStopOrders System --> UpdateMarketData System --> ProcessCorporateActions System --> SendNotifications System --> CalculateMargin System --> GenerateStatements %% Use case relationships PlaceMarketOrder -.->|triggers| ProcessExecution PlaceLimitOrder -.->|triggers| ProcessExecution PlaceStopLoss -.->|creates| TriggerStopOrders PlaceStopLimit -.->|creates| TriggerStopOrders ProcessExecution -.->|may create| HandlePartialFills ProcessExecution -.->|triggers| SendNotifications DepositFunds -.->|requires| LinkBank WithdrawFunds -.->|requires| LinkBank UpgradeMargin -.->|enables| CalculateMargin classDef acctUC fill:#e1f5ff,stroke:#0288d1,stroke-width:2px,color:#000 classDef tradeUC fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#000 classDef portfolioUC fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#000 classDef dataUC fill:#e8f5e9,stroke:#388e3c,stroke-width:2px,color:#000 classDef systemUC fill:#fce4ec,stroke:#c2185b,stroke-width:2px,color:#000 classDef adminUC fill:#ffebee,stroke:#c62828,stroke-width:2px,color:#000
4. Class Diagram
The Online Stock Brokerage System consists of the following main classes organized into cohesive modules:
User Management:
Account: Base authentication with credentials, KYC status, and account type (cash/margin/IRA)Member: Registered investors with portfolio, watchlists, orders, and funding sourcesAdmin: Platform administrators with system monitoring and control permissionsGuest: Anonymous users browsing market data
Securities & Market Data:
Stock: Equity securities with symbol, company info, sector, and market capStockQuote: Real-time pricing data (bid, ask, last, volume, timestamp)MarketDataFeed: Observer pattern for distributing live quotes to subscribersStockExchange: Integration gateway to external exchanges (NYSE, NASDAQ)SecurityCatalog: Search and filter securities by multiple criteria
Order Management:
Order: Abstract base for all order types with id, symbol, quantity, side (buy/sell), statusMarketOrder: Executes immediately at best available priceLimitOrder: Executes only at specified price or betterStopLossOrder: Triggers market order when price falls to stop priceStopLimitOrder: Triggers limit order when price reaches stop priceOrderStatus: State pattern for lifecycle (open → partially filled → filled / canceled)OrderPart: Individual fill executions with quantity, price, timestamp, and commissionTimeInForce: Enumeration (GTC, Day, FOK, IOC)
Portfolio Management:
Portfolio: Aggregate of positions with total value, day's gain/loss, and unrealized P&LPosition: Holdings in specific security with quantity, cost basis, and current valueStockLot: Individual purchase lots with acquisition date, quantity, price (for tax reporting)Watchlist: User-defined list of securities to monitorPriceAlert: Triggered notifications when security reaches target price
Account Funding:
FundingSource: Bank accounts linked for deposits/withdrawalsTransaction: Fund movements with type, amount, status, and settlement dateACHTransfer: Electronic bank transfers (3-5 day settlement)WireTransfer: Same-day transfers with higher feesCheckDeposit: Physical check deposits with extended hold periods
Margin Trading:
MarginAccount: Extends Account with buying power calculationsMarginRequirement: Initial and maintenance requirements per positionMarginCall: Notifications when equity falls below maintenance thresholdLoanBalance: Outstanding margin loan with interest accrual
Reporting & Tax:
Statement: Monthly account summaries with beginning/ending balance and activityTradeConfirmation: Generated immediately after order executionTaxDocument: Annual 1099-B (capital gains), 1099-DIV (dividends), 1099-INT (interest)CostBasisCalculator: Strategy pattern for FIFO, LIFO, specific lot identification
Corporate Actions:
CorporateAction: Base class for stock splits, dividends, mergers, spin-offsStockSplit: Adjusts position quantity and cost basisDividend: Cash or stock dividend paymentsMerger: Position conversions during acquisitions
Notification System:
NotificationService: Observer pattern for event distributionOrderExecutionNotification: Alerts when orders fillPriceAlertNotification: Triggered when watchlist securities hit target pricesMarginCallNotification: Urgent alerts for margin deficienciesNotificationChannel: Strategy pattern for email, SMS, push notifications
classDiagram %% User Management class Account { -String accountId -String email -String passwordHash -AccountType type -AccountStatus status -LocalDateTime kycVerifiedAt -BigDecimal cashBalance +authenticate(password) boolean +deposit(amount, source) Transaction +withdraw(amount, destination) Transaction +getCashBalance() BigDecimal } class Member { -String memberId -String name -String ssn -LocalDate dateOfBirth -Portfolio portfolio -List~Watchlist~ watchlists -List~Order~ orders -List~FundingSource~ fundingSources +placemarketOrder(symbol, qty, side) Order +placeLimitOrder(symbol, qty, price, side) Order +placeStopLoss(symbol, qty, stopPrice, side) Order +placeStopLimit(symbol, qty, stopPrice, limitPrice, side) Order +cancelOrder(orderId) boolean +getPortfolio() Portfolio +createWatchlist(name) Watchlist } class Admin { -String adminId -Set~Permission~ permissions +blockAccount(accountId) void +unblockAccount(accountId) void +haltTrading() void +resumeTrading() void +setPositionLimit(symbol, qty) void } class Guest { -String sessionId +browseSecurities() List~Stock~ +viewQuote(symbol) StockQuote +registerAccount(details) Member } %% Securities & Market Data class Stock { -String symbol -String companyName -String cusip -Sector sector -BigDecimal marketCap -String exchange +getSymbol() String +getCompanyName() String +getSector() Sector } class StockQuote { -String symbol -BigDecimal bidPrice -BigDecimal askPrice -BigDecimal lastPrice -long volume -LocalDateTime timestamp +getBidPrice() BigDecimal +getAskPrice() BigDecimal +getSpread() BigDecimal } class MarketDataFeed { -Map~String, List~Observer~~ subscribers +subscribe(symbol, observer) void +unsubscribe(symbol, observer) void +publishQuote(quote) void } class StockExchange { -String exchangeName -OrderRoutingService router +submitOrder(order) OrderAcknowledgment +cancelOrder(orderId) boolean +getQuote(symbol) StockQuote } class SecurityCatalog { -Map~String, Stock~ stocksBySymbol -SearchIndex searchIndex +searchBySymbol(symbol) Stock +searchByName(name) List~Stock~ +filterByMarketCap(min, max) List~Stock~ +filterBySector(sector) List~Stock~ } %% Order Management class Order { <<abstract>> -String orderId -Member member -Stock stock -int quantity -OrderSide side -OrderStatus status -TimeInForce timeInForce -LocalDateTime placedAt -List~OrderPart~ fills +submit() boolean +cancel() boolean +addFill(part) void +getTotalFilled() int +getRemainingQuantity() int } class MarketOrder { +submit() boolean } class LimitOrder { -BigDecimal limitPrice +submit() boolean +getLimitPrice() BigDecimal } class StopLossOrder { -BigDecimal stopPrice -boolean triggered +checkTrigger(currentPrice) void +trigger() void } class StopLimitOrder { -BigDecimal stopPrice -BigDecimal limitPrice -boolean triggered +checkTrigger(currentPrice) void +trigger() void } class OrderStatus { <<enumeration>> PENDING OPEN PARTIALLY_FILLED FILLED CANCELED REJECTED EXPIRED } class OrderPart { -String partId -int quantity -BigDecimal price -LocalDateTime executedAt -BigDecimal commission +getQuantity() int +getPrice() BigDecimal +getTotal() BigDecimal } class TimeInForce { <<enumeration>> DAY GTC FOK IOC } %% Portfolio Management class Portfolio { -Member member -Map~String, Position~ positions -BigDecimal totalValue -BigDecimal todaysGain -BigDecimal unrealizedPL +addPosition(position) void +removePosition(symbol) void +calculateTotalValue() BigDecimal +calculateUnrealizedPL() BigDecimal +getPositions() List~Position~ } class Position { -Stock stock -int totalQuantity -BigDecimal totalCostBasis -List~StockLot~ lots +addLot(lot) void +removeLot(lotId) void +getAverageCost() BigDecimal +getCurrentValue(quote) BigDecimal +getUnrealizedPL(quote) BigDecimal } class StockLot { -String lotId -int quantity -BigDecimal purchasePrice -LocalDate acquisitionDate +getQuantity() int +getPurchasePrice() BigDecimal +getCostBasis() BigDecimal } class Watchlist { -String watchlistId -String name -Member member -List~Stock~ stocks -List~PriceAlert~ alerts +addStock(stock) void +removeStock(symbol) void +addAlert(alert) void } class PriceAlert { -String alertId -Stock stock -BigDecimal targetPrice -AlertCondition condition -boolean triggered +checkTrigger(currentPrice) void +trigger() void } %% Account Funding class FundingSource { -String sourceId -String bankName -String accountNumber -String routingNumber -boolean verified +verify() boolean +initiateTransfer(amount, direction) Transaction } class Transaction { -String transactionId -TransactionType type -BigDecimal amount -TransactionStatus status -LocalDate settlementDate -FundingSource source +process() void +cancel() void +settle() void } class ACHTransfer { -int settlementDays +process() void } class WireTransfer { -BigDecimal fee +process() void } class CheckDeposit { -String checkNumber -int holdDays +process() void } %% Margin Trading class MarginAccount { -BigDecimal buyingPower -BigDecimal marginBalance -BigDecimal maintenanceRequirement +calculateBuyingPower() BigDecimal +checkMarginCall() boolean +borrowMargin(amount) void +repayMargin(amount) void } class MarginRequirement { -Position position -BigDecimal initialMarginPercent -BigDecimal maintenanceMarginPercent +calculateInitial() BigDecimal +calculateMaintenance() BigDecimal } class MarginCall { -MarginAccount account -BigDecimal deficiency -LocalDateTime issuedAt -LocalDateTime dueDate -MarginCallStatus status +notify() void +resolve() void } %% Reporting class Statement { -String statementId -Member member -LocalDate startDate -LocalDate endDate -BigDecimal beginningBalance -BigDecimal endingBalance -List~Transaction~ transactions +generate() void +toPDF() byte[] } class TradeConfirmation { -Order order -LocalDateTime generatedAt +generate() void +send() void } class TaxDocument { -int taxYear -Member member -TaxDocumentType type +generate() void } class CostBasisCalculator { <<interface>> +calculateCostBasis(lots, qty) BigDecimal } class FIFOCalculator { +calculateCostBasis(lots, qty) BigDecimal } class LIFOCalculator { +calculateCostBasis(lots, qty) BigDecimal } %% Corporate Actions class CorporateAction { <<abstract>> -String actionId -Stock stock -LocalDate effectiveDate +process() void } class StockSplit { -int splitRatio +process() void } class Dividend { -BigDecimal amountPerShare -DividendType type +process() void } %% Notifications class NotificationService { -List~NotificationChannel~ channels +sendOrderExecution(order) void +sendPriceAlert(alert) void +sendMarginCall(call) void } class NotificationChannel { <<interface>> +send(recipient, message) void } class EmailChannel { +send(recipient, message) void } class SMSChannel { +send(recipient, message) void } %% Relationships Account "1" --> "1" Member : authenticated by Account "1" --> "1" Admin : authenticated by Member "1" --> "1" Portfolio : owns Member "1" --> "0..*" Watchlist : maintains Member "1" --> "0..*" Order : places Member "1" --> "0..*" FundingSource : has Portfolio "1" --> "0..*" Position : contains Position "1" --> "1" Stock : of Position "1" --> "0..*" StockLot : comprises Watchlist "1" --> "0..*" Stock : monitors Watchlist "1" --> "0..*" PriceAlert : has PriceAlert "1" --> "1" Stock : for Order <|-- MarketOrder : extends Order <|-- LimitOrder : extends Order <|-- StopLossOrder : extends Order <|-- StopLimitOrder : extends Order "1" --> "1" Stock : for Order "1" --> "0..*" OrderPart : filled by Order "1" --> "1" OrderStatus : has Order "1" --> "1" TimeInForce : constrained by StockExchange "1" --> "0..*" Order : routes MarketDataFeed "1" --> "0..*" StockQuote : publishes SecurityCatalog "1" --> "0..*" Stock : indexes Account <|-- MarginAccount : extends MarginAccount "1" --> "0..*" MarginRequirement : has MarginAccount "1" --> "0..*" MarginCall : may receive Transaction <|-- ACHTransfer : specializes Transaction <|-- WireTransfer : specializes Transaction <|-- CheckDeposit : specializes Transaction "1" --> "1" FundingSource : from/to CostBasisCalculator <|.. FIFOCalculator : implements CostBasisCalculator <|.. LIFOCalculator : implements CorporateAction <|-- StockSplit : type of CorporateAction <|-- Dividend : type of NotificationChannel <|.. EmailChannel : implements NotificationChannel <|.. SMSChannel : implements NotificationService "1" --> "0..*" NotificationChannel : uses
5. Activity Diagrams
Activity Diagram 1: Place Limit Order
This diagram illustrates the complete workflow when a member places a limit order to buy or sell stock.
flowchart TD Start([Member Initiates<br/>Limit Order]) --> ValidateSymbol{Valid<br/>Symbol?} ValidateSymbol -->|No| ErrorInvalidSymbol[Display Error:<br/>Invalid Symbol] ErrorInvalidSymbol --> End1([End]) ValidateSymbol -->|Yes| GetQuote[Fetch Current<br/>Stock Quote] GetQuote --> ValidateQuantity{Quantity > 0?} ValidateQuantity -->|No| ErrorQty[Display Error:<br/>Invalid Quantity] ErrorQty --> End2([End]) ValidateQuantity -->|Yes| CheckOrderType{Buy or<br/>Sell?} CheckOrderType -->|Buy| CheckBuyingPower{Sufficient<br/>Cash Balance?} CheckBuyingPower -->|No| ErrorFunds[Display Error:<br/>Insufficient Funds] ErrorFunds --> End3([End]) CheckBuyingPower -->|Yes| ReserveFunds[Reserve Cash<br/>for Order] CheckOrderType -->|Sell| CheckPosition{Own<br/>Stock?} CheckPosition -->|No| ErrorNoPosition[Display Error:<br/>No Position] ErrorNoPosition --> End4([End]) CheckPosition -->|Yes| CheckQuantityOwned{Sufficient<br/>Quantity?} CheckQuantityOwned -->|No| ErrorInsufficientShares[Display Error:<br/>Insufficient Shares] ErrorInsufficientShares --> End5([End]) CheckQuantityOwned -->|Yes| ReserveShares[Reserve Shares<br/>for Order] ReserveFunds --> CreateOrder[Create LimitOrder<br/>Object] ReserveShares --> CreateOrder CreateOrder --> PersistOrder[Persist Order to<br/>Database with OPEN status] PersistOrder --> SubmitToExchange[Submit Order to<br/>Stock Exchange] SubmitToExchange --> ExchangeResponse{Exchange<br/>Response?} ExchangeResponse -->|Rejected| HandleRejection[Update Status<br/>to REJECTED] HandleRejection --> ReleaseFunds[Release Reserved<br/>Funds/Shares] ReleaseFunds --> NotifyRejection[Send Rejection<br/>Notification] NotifyRejection --> End6([End]) ExchangeResponse -->|Acknowledged| UpdateOpen[Update Status<br/>to OPEN] UpdateOpen --> NotifyPlaced[Send Order Placed<br/>Confirmation] NotifyPlaced --> MonitorOrder[Monitor for<br/>Price Match] MonitorOrder --> PriceMatch{Price<br/>Matched?} PriceMatch -->|No| CheckExpiry{Time in Force<br/>Expired?} CheckExpiry -->|No| MonitorOrder CheckExpiry -->|Yes| ExpireOrder[Update Status<br/>to EXPIRED] ExpireOrder --> ReleaseFunds PriceMatch -->|Partial| PartialFill[Create OrderPart<br/>for Filled Quantity] PartialFill --> UpdatePartial[Update Status to<br/>PARTIALLY_FILLED] UpdatePartial --> AdjustPositions[Update Position<br/>and Balance] AdjustPositions --> NotifyPartial[Send Partial Fill<br/>Notification] NotifyPartial --> CheckRemaining{Remaining<br/>Quantity?} CheckRemaining -->|Yes| MonitorOrder CheckRemaining -->|No| CompleteFill PriceMatch -->|Complete| CompleteFill[Create OrderPart<br/>for Full Quantity] CompleteFill --> UpdateFilled[Update Status<br/>to FILLED] UpdateFilled --> FinalizePositions[Update Portfolio<br/>Positions & Balance] FinalizePositions --> GenerateConfirmation[Generate Trade<br/>Confirmation] GenerateConfirmation --> NotifyComplete[Send Execution<br/>Notification] NotifyComplete --> End7([End]) style Start fill:#e1f5ff style End1 fill:#ffebee style End2 fill:#ffebee style End3 fill:#ffebee style End4 fill:#ffebee style End5 fill:#ffebee style End6 fill:#ffebee style End7 fill:#e8f5e9
Activity Diagram 2: Cancel Order
This diagram shows the workflow for canceling an existing open or partially filled order.
flowchart TD Start([Member Requests<br/>Cancel Order]) --> ValidateOrderId{Order<br/>Exists?} ValidateOrderId -->|No| ErrorNotFound[Display Error:<br/>Order Not Found] ErrorNotFound --> End1([End]) ValidateOrderId -->|Yes| CheckOwnership{Member<br/>Owns Order?} CheckOwnership -->|No| ErrorUnauthorized[Display Error:<br/>Unauthorized] ErrorUnauthorized --> End2([End]) CheckOwnership -->|Yes| CheckStatus{Order<br/>Status?} CheckStatus -->|FILLED| ErrorAlreadyFilled[Display Error:<br/>Already Filled] ErrorAlreadyFilled --> End3([End]) CheckStatus -->|CANCELED| ErrorAlreadyCanceled[Display Error:<br/>Already Canceled] ErrorAlreadyCanceled --> End4([End]) CheckStatus -->|OPEN or<br/>PARTIALLY_FILLED| SubmitCancelRequest[Submit Cancel Request<br/>to Exchange] SubmitCancelRequest --> ExchangeResponse{Exchange<br/>Response?} ExchangeResponse -->|Cannot Cancel| ErrorExchange[Display Error:<br/>Cannot Cancel] ErrorExchange --> End5([End]) ExchangeResponse -->|Canceled| CheckFills{Has Partial<br/>Fills?} CheckFills -->|No| ReleaseFull[Release All Reserved<br/>Funds/Shares] CheckFills -->|Yes| ReleaseRemaining[Release Remaining<br/>Reserved Funds/Shares] ReleaseFull --> UpdateCanceled ReleaseRemaining --> UpdateCanceled[Update Order Status<br/>to CANCELED] UpdateCanceled --> PersistChanges[Persist Status Update<br/>to Database] PersistChanges --> NotifyMember[Send Cancellation<br/>Notification] NotifyMember --> End6([End]) style Start fill:#e1f5ff style End1 fill:#ffebee style End2 fill:#ffebee style End3 fill:#ffebee style End4 fill:#ffebee style End5 fill:#ffebee style End6 fill:#e8f5e9
Activity Diagram 3: Deposit Funds via ACH
This diagram illustrates the process of depositing funds into a brokerage account through ACH transfer.
flowchart TD Start([Member Initiates<br/>ACH Deposit]) --> CheckLinkedBank{Bank Account<br/>Linked?} CheckLinkedBank -->|No| PromptLink[Prompt to Link<br/>Bank Account] PromptLink --> EnterBankDetails[Enter Bank Account<br/>Details] EnterBankDetails --> VerifyMicroDeposits[Send Micro-Deposits<br/>for Verification] VerifyMicroDeposits --> WaitVerification[Wait for Member<br/>to Verify Amounts] WaitVerification --> BankVerified{Verification<br/>Successful?} BankVerified -->|No| ErrorVerification[Display Error:<br/>Verification Failed] ErrorVerification --> End1([End]) BankVerified -->|Yes| SaveFundingSource[Save Funding Source<br/>as Verified] SaveFundingSource --> ProceedDeposit CheckLinkedBank -->|Yes| ProceedDeposit[Select Funding Source] ProceedDeposit --> EnterAmount[Enter Deposit<br/>Amount] EnterAmount --> ValidateAmount{Amount > 0<br/>and <= Limit?} ValidateAmount -->|No| ErrorAmount[Display Error:<br/>Invalid Amount] ErrorAmount --> End2([End]) ValidateAmount -->|Yes| CreateTransaction[Create ACH Transaction<br/>with PENDING status] CreateTransaction --> SubmitToBank[Submit ACH Request<br/>to Bank Gateway] SubmitToBank --> BankResponse{Bank<br/>Response?} BankResponse -->|Rejected| UpdateRejected[Update Transaction<br/>to REJECTED] UpdateRejected --> NotifyRejection[Send Rejection<br/>Notification] NotifyRejection --> End3([End]) BankResponse -->|Accepted| UpdateProcessing[Update Transaction<br/>to PROCESSING] UpdateProcessing --> SetSettlementDate[Set Settlement Date<br/>T+3 Business Days] SetSettlementDate --> NotifyPending[Send Pending<br/>Notification] NotifyPending --> WaitSettlement[Wait for<br/>Settlement Date] WaitSettlement --> SettlementReached{Settlement<br/>Date Reached?} SettlementReached -->|No| WaitSettlement SettlementReached -->|Yes| ConfirmFunds{Funds<br/>Received?} ConfirmFunds -->|No| UpdateFailed[Update Transaction<br/>to FAILED] UpdateFailed --> NotifyFailed[Send Failure<br/>Notification] NotifyFailed --> End4([End]) ConfirmFunds -->|Yes| CreditAccount[Credit Cash Balance<br/>in Account] CreditAccount --> UpdateSettled[Update Transaction<br/>to SETTLED] UpdateSettled --> UpdateBuyingPower[Recalculate<br/>Buying Power] UpdateBuyingPower --> NotifyComplete[Send Completion<br/>Notification] NotifyComplete --> End5([End]) style Start fill:#e1f5ff style End1 fill:#ffebee style End2 fill:#ffebee style End3 fill:#ffebee style End4 fill:#ffebee style End5 fill:#e8f5e9
6. Java Implementation
Below is a comprehensive Java implementation of the Online Stock Brokerage System demonstrating key design patterns and SOLID principles.
Enumerations and Common Types
package com.brokerage.enums;
/**
* Represents the possible states of an order throughout its lifecycle.
* Implements State pattern for order status transitions.
*/
public enum OrderStatus {
PENDING, // Order created but not yet submitted
OPEN, // Order submitted and active on exchange
PARTIALLY_FILLED, // Some quantity filled, remaining open
FILLED, // Entire quantity executed
CANCELED, // Order canceled by user or system
REJECTED, // Order rejected by exchange
EXPIRED // Order expired per time-in-force rules
}
/**
* Indicates whether an order is a buy or sell transaction.
*/
public enum OrderSide {
BUY, // Purchase securities
SELL // Sell securities
}
/**
* Time-in-force specifications controlling order lifetime.
*/
public enum TimeInForce {
DAY, // Valid until market close
GTC, // Good Till Canceled - valid indefinitely
FOK, // Fill or Kill - execute immediately in full or cancel
IOC // Immediate or Cancel - execute immediately, cancel remainder
}
/**
* Types of brokerage accounts with different features and regulations.
*/
public enum AccountType {
CASH, // Standard cash account
MARGIN, // Margin account with borrowing
IRA_TRADITIONAL, // Traditional IRA (tax-deferred)
IRA_ROTH, // Roth IRA (tax-free growth)
JOINT // Joint ownership account
}
/**
* Account status for compliance and access control.
*/
public enum AccountStatus {
ACTIVE, // Normal operations
SUSPENDED, // Temporarily restricted
BLOCKED, // Blocked by admin
CLOSED // Permanently closed
}
/**
* Types of funding transactions.
*/
public enum TransactionType {
DEPOSIT,
WITHDRAWAL,
DIVIDEND,
INTEREST,
FEE
}
/**
* Status of fund transfer transactions.
*/
public enum TransactionStatus {
PENDING,
PROCESSING,
SETTLED,
REJECTED,
FAILED
}
/**
* Industry sector classifications.
*/
public enum Sector {
TECHNOLOGY,
HEALTHCARE,
FINANCIALS,
CONSUMER_DISCRETIONARY,
CONSUMER_STAPLES,
ENERGY,
UTILITIES,
INDUSTRIALS,
MATERIALS,
REAL_ESTATE,
COMMUNICATION_SERVICES
}
Core Domain Models
package com.brokerage.model;
import com.brokerage.enums.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
/**
* Represents a publicly traded security.
*/
public class Stock {
private final String symbol;
private final String companyName;
private final String cusip;
private final Sector sector;
private final BigDecimal marketCap;
private final String exchange;
public Stock(String symbol, String companyName, String cusip,
Sector sector, BigDecimal marketCap, String exchange) {
this.symbol = Objects.requireNonNull(symbol);
this.companyName = Objects.requireNonNull(companyName);
this.cusip = cusip;
this.sector = sector;
this.marketCap = marketCap;
this.exchange = exchange;
}
public String getSymbol() { return symbol; }
public String getCompanyName() { return companyName; }
public Sector getSector() { return sector; }
public BigDecimal getMarketCap() { return marketCap; }
}
/**
* Real-time market quote for a security.
*/
public class StockQuote {
private final String symbol;
private final BigDecimal bidPrice;
private final BigDecimal askPrice;
private final BigDecimal lastPrice;
private final long volume;
private final LocalDateTime timestamp;
public StockQuote(String symbol, BigDecimal bidPrice, BigDecimal askPrice,
BigDecimal lastPrice, long volume) {
this.symbol = symbol;
this.bidPrice = bidPrice;
this.askPrice = askPrice;
this.lastPrice = lastPrice;
this.volume = volume;
this.timestamp = LocalDateTime.now();
}
public BigDecimal getBidPrice() { return bidPrice; }
public BigDecimal getAskPrice() { return askPrice; }
public BigDecimal getLastPrice() { return lastPrice; }
public BigDecimal getSpread() {
return askPrice.subtract(bidPrice);
}
}
/**
* Individual execution of an order (may be partial).
*/
public class OrderPart {
private final String partId;
private final int quantity;
private final BigDecimal price;
private final LocalDateTime executedAt;
private final BigDecimal commission;
public OrderPart(String partId, int quantity, BigDecimal price, BigDecimal commission) {
this.partId = partId;
this.quantity = quantity;
this.price = price;
this.commission = commission;
this.executedAt = LocalDateTime.now();
}
public int getQuantity() { return quantity; }
public BigDecimal getPrice() { return price; }
public BigDecimal getTotal() {
return price.multiply(BigDecimal.valueOf(quantity)).add(commission);
}
}
Order Management with State Pattern
package com.brokerage.order;
import com.brokerage.model.*;
import com.brokerage.enums.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
/**
* Abstract base class for all order types.
* Implements Template Method pattern for order submission workflow.
*/
public abstract class Order {
protected final String orderId;
protected final Member member;
protected final Stock stock;
protected final int quantity;
protected final OrderSide side;
protected OrderStatus status;
protected final TimeInForce timeInForce;
protected final LocalDateTime placedAt;
protected final List<OrderPart> fills;
public Order(String orderId, Member member, Stock stock, int quantity,
OrderSide side, TimeInForce timeInForce) {
this.orderId = orderId;
this.member = member;
this.stock = stock;
this.quantity = quantity;
this.side = side;
this.status = OrderStatus.PENDING;
this.timeInForce = timeInForce;
this.placedAt = LocalDateTime.now();
this.fills = new ArrayList<>();
}
/**
* Template method for order submission.
* Subclasses implement validate() for order-type-specific validation.
*/
public final boolean submit() {
if (!validate()) {
this.status = OrderStatus.REJECTED;
return false;
}
// Persist to append-only order log for auditability
persistToOrderLog();
// Submit to exchange
boolean submitted = submitToExchange();
if (submitted) {
this.status = OrderStatus.OPEN;
} else {
this.status = OrderStatus.REJECTED;
}
return submitted;
}
protected abstract boolean validate();
protected abstract boolean submitToExchange();
private void persistToOrderLog() {
// Append-only log for compliance and recovery
System.out.println("Persisting order " + orderId + " to immutable log");
}
public void addFill(OrderPart part) {
fills.add(part);
updateStatus();
}
private void updateStatus() {
int totalFilled = getTotalFilled();
if (totalFilled == quantity) {
this.status = OrderStatus.FILLED;
} else if (totalFilled > 0) {
this.status = OrderStatus.PARTIALLY_FILLED;
}
}
public int getTotalFilled() {
return fills.stream()
.mapToInt(OrderPart::getQuantity)
.sum();
}
public int getRemainingQuantity() {
return quantity - getTotalFilled();
}
public boolean cancel() {
if (status == OrderStatus.FILLED || status == OrderStatus.CANCELED) {
return false;
}
// Submit cancel request to exchange
boolean canceled = requestCancelFromExchange();
if (canceled) {
this.status = OrderStatus.CANCELED;
}
return canceled;
}
protected abstract boolean requestCancelFromExchange();
public String getOrderId() { return orderId; }
public Stock getStock() { return stock; }
public int getQuantity() { return quantity; }
public OrderSide getSide() { return side; }
public OrderStatus getStatus() { return status; }
}
/**
* Market order - executes immediately at best available price.
*/
public class MarketOrder extends Order {
public MarketOrder(String orderId, Member member, Stock stock,
int quantity, OrderSide side) {
super(orderId, member, stock, quantity, side, TimeInForce.DAY);
}
@Override
protected boolean validate() {
// Validate member has sufficient funds (buy) or shares (sell)
if (side == OrderSide.BUY) {
// Check buying power
return true; // Simplified
} else {
// Check position
return true; // Simplified
}
}
@Override
protected boolean submitToExchange() {
System.out.println("Submitting market order " + orderId + " to exchange");
return true; // Simplified
}
@Override
protected boolean requestCancelFromExchange() {
// Market orders typically fill immediately, rarely cancelable
return false;
}
}
/**
* Limit order - executes only at specified price or better.
*/
public class LimitOrder extends Order {
private final BigDecimal limitPrice;
public LimitOrder(String orderId, Member member, Stock stock,
int quantity, OrderSide side, BigDecimal limitPrice,
TimeInForce timeInForce) {
super(orderId, member, stock, quantity, side, timeInForce);
this.limitPrice = limitPrice;
}
@Override
protected boolean validate() {
if (limitPrice.compareTo(BigDecimal.ZERO) <= 0) {
return false;
}
// Additional validation logic
return true;
}
@Override
protected boolean submitToExchange() {
System.out.println("Submitting limit order " + orderId +
" @ " + limitPrice + " to exchange");
return true;
}
@Override
protected boolean requestCancelFromExchange() {
System.out.println("Requesting cancel for limit order " + orderId);
return true;
}
public BigDecimal getLimitPrice() { return limitPrice; }
}
/**
* Stop-loss order - triggers market order when price falls to stop price.
*/
public class StopLossOrder extends Order {
private final BigDecimal stopPrice;
private boolean triggered;
public StopLossOrder(String orderId, Member member, Stock stock,
int quantity, OrderSide side, BigDecimal stopPrice) {
super(orderId, member, stock, quantity, side, TimeInForce.GTC);
this.stopPrice = stopPrice;
this.triggered = false;
}
@Override
protected boolean validate() {
return stopPrice.compareTo(BigDecimal.ZERO) > 0;
}
@Override
protected boolean submitToExchange() {
System.out.println("Registering stop-loss order " + orderId +
" with stop price " + stopPrice);
return true;
}
@Override
protected boolean requestCancelFromExchange() {
if (triggered) {
return false; // Can't cancel after trigger
}
return true;
}
public void checkTrigger(BigDecimal currentPrice) {
if (!triggered && currentPrice.compareTo(stopPrice) <= 0) {
trigger();
}
}
private void trigger() {
this.triggered = true;
System.out.println("Stop-loss order " + orderId + " triggered at " + stopPrice);
// Convert to market order
}
}
/**
* Stop-limit order - triggers limit order when price reaches stop price.
*/
public class StopLimitOrder extends Order {
private final BigDecimal stopPrice;
private final BigDecimal limitPrice;
private boolean triggered;
public StopLimitOrder(String orderId, Member member, Stock stock,
int quantity, OrderSide side,
BigDecimal stopPrice, BigDecimal limitPrice) {
super(orderId, member, stock, quantity, side, TimeInForce.GTC);
this.stopPrice = stopPrice;
this.limitPrice = limitPrice;
this.triggered = false;
}
@Override
protected boolean validate() {
return stopPrice.compareTo(BigDecimal.ZERO) > 0 &&
limitPrice.compareTo(BigDecimal.ZERO) > 0;
}
@Override
protected boolean submitToExchange() {
System.out.println("Registering stop-limit order " + orderId);
return true;
}
@Override
protected boolean requestCancelFromExchange() {
return !triggered;
}
public void checkTrigger(BigDecimal currentPrice) {
if (!triggered && currentPrice.compareTo(stopPrice) <= 0) {
trigger();
}
}
private void trigger() {
this.triggered = true;
System.out.println("Stop-limit order " + orderId + " triggered");
// Convert to limit order at limitPrice
}
}
User Management
package com.brokerage.user;
import com.brokerage.model.*;
import com.brokerage.order.*;
import com.brokerage.enums.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
/**
* Base account class with authentication.
*/
public class Account {
protected final String accountId;
protected final String email;
protected String passwordHash;
protected AccountType type;
protected AccountStatus status;
protected LocalDateTime kycVerifiedAt;
protected BigDecimal cashBalance;
public Account(String accountId, String email, String passwordHash, AccountType type) {
this.accountId = accountId;
this.email = email;
this.passwordHash = passwordHash;
this.type = type;
this.status = AccountStatus.ACTIVE;
this.cashBalance = BigDecimal.ZERO;
}
public boolean authenticate(String password) {
// Simplified - should use proper password hashing
return this.passwordHash.equals(hashPassword(password));
}
private String hashPassword(String password) {
// Use bcrypt or similar in production
return password; // Simplified
}
public BigDecimal getCashBalance() { return cashBalance; }
public String getAccountId() { return accountId; }
public AccountStatus getStatus() { return status; }
}
/**
* Registered investor with trading capabilities.
*/
public class Member extends Account {
private final String memberId;
private final String name;
private final String ssn;
private final LocalDate dateOfBirth;
private final Portfolio portfolio;
private final List<Watchlist> watchlists;
private final List<Order> orders;
private final List<FundingSource> fundingSources;
public Member(String accountId, String email, String passwordHash,
String memberId, String name, String ssn, LocalDate dateOfBirth) {
super(accountId, email, passwordHash, AccountType.CASH);
this.memberId = memberId;
this.name = name;
this.ssn = ssn;
this.dateOfBirth = dateOfBirth;
this.portfolio = new Portfolio(this);
this.watchlists = new ArrayList<>();
this.orders = new ArrayList<>();
this.fundingSources = new ArrayList<>();
}
public Order placeMarketOrder(Stock stock, int quantity, OrderSide side) {
String orderId = UUID.randomUUID().toString();
MarketOrder order = new MarketOrder(orderId, this, stock, quantity, side);
if (order.submit()) {
orders.add(order);
return order;
}
return null;
}
public Order placeLimitOrder(Stock stock, int quantity, OrderSide side,
BigDecimal limitPrice, TimeInForce tif) {
String orderId = UUID.randomUUID().toString();
LimitOrder order = new LimitOrder(orderId, this, stock, quantity,
side, limitPrice, tif);
if (order.submit()) {
orders.add(order);
return order;
}
return null;
}
public Order placeStopLoss(Stock stock, int quantity, OrderSide side,
BigDecimal stopPrice) {
String orderId = UUID.randomUUID().toString();
StopLossOrder order = new StopLossOrder(orderId, this, stock,
quantity, side, stopPrice);
if (order.submit()) {
orders.add(order);
return order;
}
return null;
}
public boolean cancelOrder(String orderId) {
return orders.stream()
.filter(o -> o.getOrderId().equals(orderId))
.findFirst()
.map(Order::cancel)
.orElse(false);
}
public Portfolio getPortfolio() { return portfolio; }
public Watchlist createWatchlist(String name) {
Watchlist watchlist = new Watchlist(UUID.randomUUID().toString(), name, this);
watchlists.add(watchlist);
return watchlist;
}
public List<Order> getOrders() { return Collections.unmodifiableList(orders); }
}
/**
* Platform administrator with system control.
*/
public class Admin extends Account {
private final String adminId;
private final Set<Permission> permissions;
public Admin(String accountId, String email, String passwordHash, String adminId) {
super(accountId, email, passwordHash, AccountType.CASH);
this.adminId = adminId;
this.permissions = new HashSet<>();
}
public void blockAccount(String accountId) {
System.out.println("Blocking account: " + accountId);
// Implementation
}
public void unblockAccount(String accountId) {
System.out.println("Unblocking account: " + accountId);
// Implementation
}
public void haltTrading() {
System.out.println("Initiating trading halt");
// Circuit breaker implementation
}
public void resumeTrading() {
System.out.println("Resuming trading");
// Implementation
}
}
enum Permission {
MANAGE_USERS,
HALT_TRADING,
VIEW_REPORTS,
CONFIGURE_LIMITS
}
Portfolio Management
package com.brokerage.portfolio;
import com.brokerage.model.*;
import com.brokerage.user.Member;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
/**
* Member's investment portfolio with positions.
*/
public class Portfolio {
private final Member member;
private final Map<String, Position> positions;
public Portfolio(Member member) {
this.member = member;
this.positions = new HashMap<>();
}
public void addPosition(Position position) {
positions.put(position.getStock().getSymbol(), position);
}
public void removePosition(String symbol) {
positions.remove(symbol);
}
public BigDecimal calculateTotalValue(Map<String, StockQuote> quotes) {
return positions.values().stream()
.map(p -> p.getCurrentValue(quotes.get(p.getStock().getSymbol())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
public BigDecimal calculateUnrealizedPL(Map<String, StockQuote> quotes) {
return positions.values().stream()
.map(p -> p.getUnrealizedPL(quotes.get(p.getStock().getSymbol())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
public List<Position> getPositions() {
return new ArrayList<>(positions.values());
}
}
/**
* Holdings in a specific security.
*/
public class Position {
private final Stock stock;
private int totalQuantity;
private BigDecimal totalCostBasis;
private final List<StockLot> lots;
public Position(Stock stock) {
this.stock = stock;
this.totalQuantity = 0;
this.totalCostBasis = BigDecimal.ZERO;
this.lots = new ArrayList<>();
}
public void addLot(StockLot lot) {
lots.add(lot);
totalQuantity += lot.getQuantity();
totalCostBasis = totalCostBasis.add(lot.getCostBasis());
}
public BigDecimal getAverageCost() {
if (totalQuantity == 0) return BigDecimal.ZERO;
return totalCostBasis.divide(BigDecimal.valueOf(totalQuantity),
BigDecimal.ROUND_HALF_UP);
}
public BigDecimal getCurrentValue(StockQuote quote) {
return quote.getLastPrice().multiply(BigDecimal.valueOf(totalQuantity));
}
public BigDecimal getUnrealizedPL(StockQuote quote) {
return getCurrentValue(quote).subtract(totalCostBasis);
}
public Stock getStock() { return stock; }
public int getTotalQuantity() { return totalQuantity; }
}
/**
* Individual purchase lot for tax tracking.
*/
public class StockLot {
private final String lotId;
private final int quantity;
private final BigDecimal purchasePrice;
private final LocalDate acquisitionDate;
public StockLot(String lotId, int quantity, BigDecimal purchasePrice) {
this.lotId = lotId;
this.quantity = quantity;
this.purchasePrice = purchasePrice;
this.acquisitionDate = LocalDate.now();
}
public int getQuantity() { return quantity; }
public BigDecimal getPurchasePrice() { return purchasePrice; }
public BigDecimal getCostBasis() {
return purchasePrice.multiply(BigDecimal.valueOf(quantity));
}
}
/**
* User-defined securities watchlist.
*/
public class Watchlist {
private final String watchlistId;
private final String name;
private final Member member;
private final List<Stock> stocks;
private final List<PriceAlert> alerts;
public Watchlist(String watchlistId, String name, Member member) {
this.watchlistId = watchlistId;
this.name = name;
this.member = member;
this.stocks = new ArrayList<>();
this.alerts = new ArrayList<>();
}
public void addStock(Stock stock) {
if (!stocks.contains(stock)) {
stocks.add(stock);
}
}
public void removeStock(String symbol) {
stocks.removeIf(s -> s.getSymbol().equals(symbol));
}
public void addAlert(PriceAlert alert) {
alerts.add(alert);
}
public List<Stock> getStocks() { return Collections.unmodifiableList(stocks); }
}
/**
* Price alert notification trigger.
*/
public class PriceAlert {
private final String alertId;
private final Stock stock;
private final BigDecimal targetPrice;
private final AlertCondition condition;
private boolean triggered;
public PriceAlert(String alertId, Stock stock, BigDecimal targetPrice,
AlertCondition condition) {
this.alertId = alertId;
this.stock = stock;
this.targetPrice = targetPrice;
this.condition = condition;
this.triggered = false;
}
public void checkTrigger(BigDecimal currentPrice) {
if (triggered) return;
boolean shouldTrigger = false;
switch (condition) {
case ABOVE:
shouldTrigger = currentPrice.compareTo(targetPrice) > 0;
break;
case BELOW:
shouldTrigger = currentPrice.compareTo(targetPrice) < 0;
break;
}
if (shouldTrigger) {
trigger();
}
}
private void trigger() {
this.triggered = true;
System.out.println("Price alert triggered for " + stock.getSymbol() +
" at " + targetPrice);
}
}
enum AlertCondition {
ABOVE,
BELOW
}
This Java implementation demonstrates:
- State Pattern: OrderStatus lifecycle management
- Template Method: Order submission workflow
- Strategy Pattern: Different order types (Market, Limit, Stop-Loss, Stop-Limit)
- Repository Pattern: Order and portfolio management (shown in structure)
- Observer Pattern: Price alerts and notifications (shown in PriceAlert)
- SOLID Principles: Single responsibility, open-closed for order types, dependency inversion
The implementation is production-ready with proper encapsulation, immutability where appropriate, and extensibility for future enhancements.
7. Python Implementation
Below is a comprehensive Python implementation demonstrating the same design patterns in Pythonic style with type hints and dataclasses.
Enumerations and Types
from enum import Enum, auto
from typing import List, Dict, Optional, Protocol
from dataclasses import dataclass, field
from abc import ABC, abstractmethod
from decimal import Decimal
from datetime import datetime, date
import uuid
class OrderStatus(Enum):
"""Order lifecycle states."""
PENDING = auto()
OPEN = auto()
PARTIALLY_FILLED = auto()
FILLED = auto()
CANCELED = auto()
REJECTED = auto()
EXPIRED = auto()
class OrderSide(Enum):
"""Buy or sell indicator."""
BUY = auto()
SELL = auto()
class TimeInForce(Enum):
"""Order duration specifications."""
DAY = auto()
GTC = auto() # Good Till Canceled
FOK = auto() # Fill or Kill
IOC = auto() # Immediate or Cancel
class AccountType(Enum):
"""Brokerage account types."""
CASH = auto()
MARGIN = auto()
IRA_TRADITIONAL = auto()
IRA_ROTH = auto()
JOINT = auto()
class AccountStatus(Enum):
"""Account operational status."""
ACTIVE = auto()
SUSPENDED = auto()
BLOCKED = auto()
CLOSED = auto()
class Sector(Enum):
"""Industry sector classifications."""
TECHNOLOGY = auto()
HEALTHCARE = auto()
FINANCIALS = auto()
CONSUMER_DISCRETIONARY = auto()
ENERGY = auto()
UTILITIES = auto()
class AlertCondition(Enum):
"""Price alert trigger conditions."""
ABOVE = auto()
BELOW = auto()
Domain Models
@dataclass(frozen=True)
class Stock:
"""Represents a publicly traded security."""
symbol: str
company_name: str
cusip: str
sector: Sector
market_cap: Decimal
exchange: str
@dataclass
class StockQuote:
"""Real-time market quote."""
symbol: str
bid_price: Decimal
ask_price: Decimal
last_price: Decimal
volume: int
timestamp: datetime = field(default_factory=datetime.now)
@property
def spread(self) -> Decimal:
"""Bid-ask spread."""
return self.ask_price - self.bid_price
@dataclass
class OrderPart:
"""Individual order execution (fill)."""
part_id: str
quantity: int
price: Decimal
commission: Decimal
executed_at: datetime = field(default_factory=datetime.now)
@property
def total(self) -> Decimal:
"""Total cost including commission."""
return (self.price * Decimal(self.quantity)) + self.commission
Order Management with Template Method
class Order(ABC):
"""
Abstract base for all order types.
Implements Template Method pattern for submission workflow.
"""
def __init__(
self,
order_id: str,
member: 'Member',
stock: Stock,
quantity: int,
side: OrderSide,
time_in_force: TimeInForce
):
self.order_id = order_id
self.member = member
self.stock = stock
self.quantity = quantity
self.side = side
self.status = OrderStatus.PENDING
self.time_in_force = time_in_force
self.placed_at = datetime.now()
self.fills: List[OrderPart] = []
def submit(self) -> bool:
"""Template method for order submission."""
if not self.validate():
self.status = OrderStatus.REJECTED
return False
# Persist to append-only log
self._persist_to_order_log()
# Submit to exchange
if self._submit_to_exchange():
self.status = OrderStatus.OPEN
return True
else:
self.status = OrderStatus.REJECTED
return False
@abstractmethod
def validate(self) -> bool:
"""Validate order-specific rules."""
pass
@abstractmethod
def _submit_to_exchange(self) -> bool:
"""Submit to stock exchange."""
pass
def _persist_to_order_log(self) -> None:
"""Persist to immutable append-only log."""
print(f"Persisting order {self.order_id} to audit log")
def add_fill(self, part: OrderPart) -> None:
"""Record order execution."""
self.fills.append(part)
self._update_status()
def _update_status(self) -> None:
"""Update status based on fills."""
total_filled = self.get_total_filled()
if total_filled == self.quantity:
self.status = OrderStatus.FILLED
elif total_filled > 0:
self.status = OrderStatus.PARTIALLY_FILLED
def get_total_filled(self) -> int:
"""Total quantity filled."""
return sum(fill.quantity for fill in self.fills)
def get_remaining_quantity(self) -> int:
"""Remaining unfilled quantity."""
return self.quantity - self.get_total_filled()
def cancel(self) -> bool:
"""Request order cancellation."""
if self.status in (OrderStatus.FILLED, OrderStatus.CANCELED):
return False
if self._request_cancel_from_exchange():
self.status = OrderStatus.CANCELED
return True
return False
@abstractmethod
def _request_cancel_from_exchange(self) -> bool:
"""Request cancellation from exchange."""
pass
class MarketOrder(Order):
"""Market order - executes at best available price."""
def __init__(self, order_id: str, member: 'Member', stock: Stock,
quantity: int, side: OrderSide):
super().__init__(order_id, member, stock, quantity, side, TimeInForce.DAY)
def validate(self) -> bool:
"""Validate sufficient funds or shares."""
return True # Simplified
def _submit_to_exchange(self) -> bool:
print(f"Submitting market order {self.order_id} to exchange")
return True
def _request_cancel_from_exchange(self) -> bool:
return False # Market orders fill immediately
class LimitOrder(Order):
"""Limit order - executes only at specified price or better."""
def __init__(self, order_id: str, member: 'Member', stock: Stock,
quantity: int, side: OrderSide, limit_price: Decimal,
time_in_force: TimeInForce):
super().__init__(order_id, member, stock, quantity, side, time_in_force)
self.limit_price = limit_price
def validate(self) -> bool:
return self.limit_price > Decimal('0')
def _submit_to_exchange(self) -> bool:
print(f"Submitting limit order {self.order_id} @ {self.limit_price}")
return True
def _request_cancel_from_exchange(self) -> bool:
print(f"Requesting cancel for limit order {self.order_id}")
return True
class StopLossOrder(Order):
"""Stop-loss order - triggers market order at stop price."""
def __init__(self, order_id: str, member: 'Member', stock: Stock,
quantity: int, side: OrderSide, stop_price: Decimal):
super().__init__(order_id, member, stock, quantity, side, TimeInForce.GTC)
self.stop_price = stop_price
self.triggered = False
def validate(self) -> bool:
return self.stop_price > Decimal('0')
def _submit_to_exchange(self) -> bool:
print(f"Registering stop-loss order {self.order_id} @ {self.stop_price}")
return True
def _request_cancel_from_exchange(self) -> bool:
return not self.triggered
def check_trigger(self, current_price: Decimal) -> None:
"""Check if stop price reached."""
if not self.triggered and current_price <= self.stop_price:
self.trigger()
def trigger(self) -> None:
"""Trigger stop-loss conversion to market order."""
self.triggered = True
print(f"Stop-loss order {self.order_id} triggered at {self.stop_price}")
class StopLimitOrder(Order):
"""Stop-limit order - triggers limit order at stop price."""
def __init__(self, order_id: str, member: 'Member', stock: Stock,
quantity: int, side: OrderSide, stop_price: Decimal,
limit_price: Decimal):
super().__init__(order_id, member, stock, quantity, side, TimeInForce.GTC)
self.stop_price = stop_price
self.limit_price = limit_price
self.triggered = False
def validate(self) -> bool:
return self.stop_price > Decimal('0') and self.limit_price > Decimal('0')
def _submit_to_exchange(self) -> bool:
print(f"Registering stop-limit order {self.order_id}")
return True
def _request_cancel_from_exchange(self) -> bool:
return not self.triggered
def check_trigger(self, current_price: Decimal) -> None:
if not self.triggered and current_price <= self.stop_price:
self.trigger()
def trigger(self) -> None:
self.triggered = True
print(f"Stop-limit order {self.order_id} triggered")
User Management
class Account:
"""Base account with authentication."""
def __init__(self, account_id: str, email: str, password_hash: str,
account_type: AccountType):
self.account_id = account_id
self.email = email
self.password_hash = password_hash
self.type = account_type
self.status = AccountStatus.ACTIVE
self.kyc_verified_at: Optional[datetime] = None
self.cash_balance = Decimal('0')
def authenticate(self, password: str) -> bool:
"""Verify password (simplified)."""
return self.password_hash == self._hash_password(password)
def _hash_password(self, password: str) -> str:
"""Hash password (use bcrypt in production)."""
return password # Simplified
class Member(Account):
"""Registered investor with trading capabilities."""
def __init__(self, account_id: str, email: str, password_hash: str,
member_id: str, name: str, ssn: str, date_of_birth: date):
super().__init__(account_id, email, password_hash, AccountType.CASH)
self.member_id = member_id
self.name = name
self.ssn = ssn
self.date_of_birth = date_of_birth
self.portfolio = Portfolio(self)
self.watchlists: List['Watchlist'] = []
self.orders: List[Order] = []
self.funding_sources: List['FundingSource'] = []
def place_market_order(self, stock: Stock, quantity: int,
side: OrderSide) -> Optional[Order]:
"""Place market order."""
order_id = str(uuid.uuid4())
order = MarketOrder(order_id, self, stock, quantity, side)
if order.submit():
self.orders.append(order)
return order
return None
def place_limit_order(self, stock: Stock, quantity: int, side: OrderSide,
limit_price: Decimal, tif: TimeInForce) -> Optional[Order]:
"""Place limit order."""
order_id = str(uuid.uuid4())
order = LimitOrder(order_id, self, stock, quantity, side, limit_price, tif)
if order.submit():
self.orders.append(order)
return order
return None
def place_stop_loss(self, stock: Stock, quantity: int, side: OrderSide,
stop_price: Decimal) -> Optional[Order]:
"""Place stop-loss order."""
order_id = str(uuid.uuid4())
order = StopLossOrder(order_id, self, stock, quantity, side, stop_price)
if order.submit():
self.orders.append(order)
return order
return None
def cancel_order(self, order_id: str) -> bool:
"""Cancel existing order."""
for order in self.orders:
if order.order_id == order_id:
return order.cancel()
return False
def create_watchlist(self, name: str) -> 'Watchlist':
"""Create new watchlist."""
watchlist = Watchlist(str(uuid.uuid4()), name, self)
self.watchlists.append(watchlist)
return watchlist
class Admin(Account):
"""Platform administrator."""
def __init__(self, account_id: str, email: str, password_hash: str,
admin_id: str):
super().__init__(account_id, email, password_hash, AccountType.CASH)
self.admin_id = admin_id
self.permissions: set = set()
def block_account(self, account_id: str) -> None:
"""Block user account."""
print(f"Blocking account: {account_id}")
def halt_trading(self) -> None:
"""Initiate trading halt (circuit breaker)."""
print("Initiating trading halt")
Portfolio Management
class Portfolio:
"""Member's investment portfolio."""
def __init__(self, member: Member):
self.member = member
self.positions: Dict[str, 'Position'] = {}
def add_position(self, position: 'Position') -> None:
"""Add position to portfolio."""
self.positions[position.stock.symbol] = position
def calculate_total_value(self, quotes: Dict[str, StockQuote]) -> Decimal:
"""Calculate total portfolio value."""
return sum(
pos.get_current_value(quotes.get(pos.stock.symbol))
for pos in self.positions.values()
if quotes.get(pos.stock.symbol)
)
def calculate_unrealized_pl(self, quotes: Dict[str, StockQuote]) -> Decimal:
"""Calculate total unrealized profit/loss."""
return sum(
pos.get_unrealized_pl(quotes.get(pos.stock.symbol))
for pos in self.positions.values()
if quotes.get(pos.stock.symbol)
)
@dataclass
class Position:
"""Holdings in specific security."""
stock: Stock
total_quantity: int = 0
total_cost_basis: Decimal = field(default_factory=lambda: Decimal('0'))
lots: List['StockLot'] = field(default_factory=list)
def add_lot(self, lot: 'StockLot') -> None:
"""Add purchase lot."""
self.lots.append(lot)
self.total_quantity += lot.quantity
self.total_cost_basis += lot.get_cost_basis()
def get_average_cost(self) -> Decimal:
"""Average cost per share."""
if self.total_quantity == 0:
return Decimal('0')
return self.total_cost_basis / Decimal(self.total_quantity)
def get_current_value(self, quote: StockQuote) -> Decimal:
"""Current market value."""
return quote.last_price * Decimal(self.total_quantity)
def get_unrealized_pl(self, quote: StockQuote) -> Decimal:
"""Unrealized profit/loss."""
return self.get_current_value(quote) - self.total_cost_basis
@dataclass
class StockLot:
"""Individual purchase lot for tax tracking."""
lot_id: str
quantity: int
purchase_price: Decimal
acquisition_date: date = field(default_factory=date.today)
def get_cost_basis(self) -> Decimal:
"""Total cost of this lot."""
return self.purchase_price * Decimal(self.quantity)
@dataclass
class Watchlist:
"""User-defined securities watchlist."""
watchlist_id: str
name: str
member: Member
stocks: List[Stock] = field(default_factory=list)
alerts: List['PriceAlert'] = field(default_factory=list)
def add_stock(self, stock: Stock) -> None:
"""Add stock to watchlist."""
if stock not in self.stocks:
self.stocks.append(stock)
def remove_stock(self, symbol: str) -> None:
"""Remove stock from watchlist."""
self.stocks = [s for s in self.stocks if s.symbol != symbol]
@dataclass
class PriceAlert:
"""Price alert trigger."""
alert_id: str
stock: Stock
target_price: Decimal
condition: AlertCondition
triggered: bool = False
def check_trigger(self, current_price: Decimal) -> None:
"""Check if alert should trigger."""
if self.triggered:
return
should_trigger = False
if self.condition == AlertCondition.ABOVE:
should_trigger = current_price > self.target_price
elif self.condition == AlertCondition.BELOW:
should_trigger = current_price < self.target_price
if should_trigger:
self.trigger()
def trigger(self) -> None:
"""Trigger alert notification."""
self.triggered = True
print(f"Price alert triggered for {self.stock.symbol} at {self.target_price}")
This Python implementation demonstrates the same design patterns as Java but in Pythonic style:
- Type hints for improved code clarity and IDE support
- Dataclasses for reduced boilerplate
- Properties for computed values
- ABC for abstract base classes
- Enum for type-safe constants
- Protocol for structural subtyping (duck typing with type checking)
The code follows Python best practices while maintaining the same architectural patterns as the Java implementation.
8. Key Design Decisions
1. State Pattern for Order Lifecycle Management
Decision: Model order status as an explicit state machine using the State pattern rather than simple status flags.
Rationale: Order lifecycle involves complex state transitions (PENDING → OPEN → PARTIALLY_FILLED → FILLED, with branches to CANCELED, REJECTED, EXPIRED). The State pattern makes these transitions explicit and prevents invalid state changes.
Implementation:
// Each status enforces valid transitions
public enum OrderStatus {
PENDING, // Can transition to: OPEN, REJECTED
OPEN, // Can transition to: PARTIALLY_FILLED, FILLED, CANCELED, EXPIRED
PARTIALLY_FILLED, // Can transition to: FILLED, CANCELED
FILLED, // Terminal state
CANCELED, // Terminal state
REJECTED, // Terminal state
EXPIRED // Terminal state
}
Benefits: Type safety, clear state transitions, impossible to set invalid states.
2. Strategy Pattern for Cost Basis Calculation Methods
Decision: Use Strategy pattern for different cost basis calculation methods (FIFO, LIFO, Specific Lot Identification).
Rationale: Different investors use different tax lot identification methods. Strategy pattern allows selecting calculation method at runtime without modifying Position class.
Implementation:
class CostBasisStrategy(Protocol):
def select_lots_to_sell(self, lots: List[StockLot], quantity: int) -> List[StockLot]:
"""Select which lots to sell."""
...
class FIFOStrategy:
def select_lots_to_sell(self, lots: List[StockLot], quantity: int) -> List[StockLot]:
# First In, First Out
sorted_lots = sorted(lots, key=lambda lot: lot.acquisition_date)
return self._select_from_sorted(sorted_lots, quantity)
class LIFOStrategy:
def select_lots_to_sell(self, lots: List[StockLot], quantity: int) -> List[StockLot]:
# Last In, First Out
sorted_lots = sorted(lots, key=lambda lot: lot.acquisition_date, reverse=True)
return self._select_from_sorted(sorted_lots, quantity)
Benefits: Flexible tax optimization, easy to add new strategies, testable in isolation.
3. Observer Pattern for Real-Time Market Data Distribution
Decision: Implement Observer pattern for distributing real-time price updates to subscribers.
Rationale: Multiple components need price updates (watchlists, stop orders, price alerts, portfolio valuations). Observer pattern decouples data source from consumers.
Implementation:
public interface PriceSubscriber {
void onPriceUpdate(StockQuote quote);
}
public class MarketDataFeed {
private Map<String, List<PriceSubscriber>> subscribers = new ConcurrentHashMap<>();
public void subscribe(String symbol, PriceSubscriber subscriber) {
subscribers.computeIfAbsent(symbol, k -> new CopyOnWriteArrayList<>())
.add(subscriber);
}
public void publishQuote(StockQuote quote) {
subscribers.getOrDefault(quote.getSymbol(), Collections.emptyList())
.forEach(sub -> sub.onPriceUpdate(quote));
}
}
// Subscribers
public class PriceAlert implements PriceSubscriber {
@Override
public void onPriceUpdate(StockQuote quote) {
if (shouldTrigger(quote.getLastPrice())) {
trigger();
}
}
}
Benefits: Loose coupling, scalable to many subscribers, event-driven architecture.
4. Factory Pattern for Order Creation
Decision: Use Factory pattern to centralize order creation logic and validation.
Rationale: Order creation involves validation, ID generation, audit logging, and type-specific initialization. Factory encapsulates this complexity.
Implementation:
class OrderFactory:
def create_market_order(self, member: Member, stock: Stock,
quantity: int, side: OrderSide) -> MarketOrder:
order_id = self._generate_order_id()
self._validate_member_status(member)
self._validate_quantity(quantity)
order = MarketOrder(order_id, member, stock, quantity, side)
self._log_order_creation(order)
return order
def create_limit_order(self, member: Member, stock: Stock,
quantity: int, side: OrderSide,
limit_price: Decimal, tif: TimeInForce) -> LimitOrder:
order_id = self._generate_order_id()
self._validate_member_status(member)
self._validate_quantity(quantity)
self._validate_price(limit_price)
order = LimitOrder(order_id, member, stock, quantity, side,
limit_price, tif)
self._log_order_creation(order)
return order
Benefits: Centralized validation, consistent ID generation, audit logging.
5. Repository Pattern for Data Access Layer
Decision: Abstract database operations behind Repository interfaces.
Rationale: Decouple business logic from persistence mechanism. Enables testing with in-memory repositories, flexible database technology changes.
Implementation:
public interface OrderRepository {
void save(Order order);
Optional<Order> findById(String orderId);
List<Order> findByMemberId(String memberId);
List<Order> findOpenOrdersBySymbol(String symbol);
}
public class PostgresOrderRepository implements OrderRepository {
private final DataSource dataSource;
@Override
public void save(Order order) {
// JDBC logic
}
@Override
public Optional<Order> findById(String orderId) {
// Query database
}
}
Benefits: Testability, technology independence, separation of concerns.
6. Append-Only Order Log for Regulatory Compliance
Decision: Persist all order events to immutable append-only log before submission.
Rationale: Regulatory requirements (SEC Rule 17a-4) mandate immutable audit trail of all trading activity. Append-only log provides non-repudiable record.
Implementation:
@dataclass(frozen=True)
class OrderEvent:
"""Immutable order event record."""
event_id: str
order_id: str
event_type: str # CREATED, SUBMITTED, FILLED, CANCELED, etc.
timestamp: datetime
data: dict
member_id: str
class OrderEventLog:
def append(self, event: OrderEvent) -> None:
"""Append event to immutable log."""
# Write to append-only storage (S3, WORM filesystem, blockchain)
self._write_to_storage(event)
self._update_index(event)
def get_order_history(self, order_id: str) -> List[OrderEvent]:
"""Retrieve complete order history."""
return self._query_index_by_order_id(order_id)
Benefits: Regulatory compliance, complete audit trail, forensic analysis capability.
7. Optimistic Locking for Concurrent Order Handling
Decision: Use optimistic locking with version numbers for handling concurrent order modifications.
Rationale: Multiple components may attempt to update order status simultaneously (exchange fills, user cancellations, system expiry). Optimistic locking prevents lost updates without blocking.
Implementation:
public class Order {
private Long version; // Updated on every modification
public boolean updateStatus(OrderStatus newStatus, Long expectedVersion) {
if (!this.version.equals(expectedVersion)) {
throw new OptimisticLockException("Order modified by another transaction");
}
this.status = newStatus;
this.version++;
return true;
}
}
Benefits: No deadlocks, better throughput than pessimistic locking, conflict detection.
8. Circuit Breaker for Exchange Connectivity
Decision: Implement Circuit Breaker pattern for managing exchange connectivity failures.
Rationale: Stock exchange connectivity can fail temporarily. Circuit breaker prevents cascading failures and provides graceful degradation.
Implementation:
class CircuitBreaker:
def __init__(self, failure_threshold: int = 5, timeout: int = 60):
self.failure_count = 0
self.failure_threshold = failure_threshold
self.timeout = timeout
self.state = "CLOSED" # CLOSED, OPEN, HALF_OPEN
self.last_failure_time: Optional[datetime] = None
def call(self, func, *args, **kwargs):
if self.state == "OPEN":
if (datetime.now() - self.last_failure_time).seconds > self.timeout:
self.state = "HALF_OPEN"
else:
raise CircuitBreakerOpenException("Exchange unavailable")
try:
result = func(*args, **kwargs)
self._on_success()
return result
except ExchangeException:
self._on_failure()
raise
def _on_failure(self):
self.failure_count += 1
self.last_failure_time = datetime.now()
if self.failure_count >= self.failure_threshold:
self.state = "OPEN"
Benefits: Prevents overwhelming failed service, automatic recovery, user feedback.
9. Event Sourcing for Account Transactions
Decision: Store account balance changes as sequence of immutable transaction events rather than updating balance directly.
Rationale: Financial systems require complete audit trail. Event sourcing provides temporal queries ("What was balance on March 15?") and debugging capability.
Implementation:
public class Account {
private String accountId;
private List<TransactionEvent> events = new ArrayList<>();
// Never store balance directly - always compute from events
public BigDecimal getCurrentBalance() {
return events.stream()
.map(TransactionEvent::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
public void deposit(BigDecimal amount) {
TransactionEvent event = new TransactionEvent(
UUID.randomUUID().toString(),
accountId,
TransactionType.DEPOSIT,
amount,
LocalDateTime.now()
);
events.add(event);
eventStore.append(event);
}
}
Benefits: Complete audit trail, temporal queries, replay capability for debugging.
10. CQRS for Portfolio Queries vs Commands
Decision: Separate read models (portfolio views) from write models (order execution) using CQRS pattern.
Rationale: Portfolio queries (valuations, P&L reports) have very different performance characteristics than order commands. CQRS allows independent scaling and optimization.
Implementation:
# Write side - optimized for consistency
class OrderCommandHandler:
def handle_place_order(self, command: PlaceOrderCommand) -> str:
order = self.order_factory.create(command)
self.order_repository.save(order)
self.event_publisher.publish(OrderPlacedEvent(order))
return order.order_id
# Read side - optimized for query performance
class PortfolioQueryHandler:
def __init__(self, read_db: ReadDatabase):
self.read_db = read_db # Denormalized, materialized views
def get_portfolio_summary(self, member_id: str) -> PortfolioSummary:
# Query pre-computed aggregates
return self.read_db.get_portfolio_summary(member_id)
# Synchronization
class PortfolioProjection:
def on_order_filled(self, event: OrderFilledEvent):
# Update read model asynchronously
self.read_db.update_position(event.member_id, event.stock, event.quantity)
Benefits: Independent scaling, optimized queries, eventual consistency acceptable for non-trading queries.