Skip to content

Business Logic Order Lifecycle

tien.nguyen edited this page Jul 30, 2026 · 1 revision

Business Logic: Order Lifecycle & State Machine

This document details the financial domain rules governing order types, order validation constraints, mathematical invariants, state machine transitions, and fill accounting in the Emporia Trading Platform.


๐Ÿ“ˆ Order Types & Supported Parameters

Emporia supports equity order submission with parameters aligned to institutional execution standards:

Parameter Type / Values Description & Constraints
side BUY / SELL Order side. BUY increases long position or covers short; SELL decreases long or initiates short.
orderType MARKET / LIMIT / STOP_LOSS / TAKE_PROFIT Execution instruction type. MARKET executes immediately at best available price; LIMIT requires limitPrice.
quantity BigDecimal ($> 0$) Total requested order quantity in shares. Must be a positive multiple of the instrument's sizeIncrement.
limitPrice BigDecimal ($> 0$) Maximum price for a BUY limit order or minimum price for a SELL limit order. Must align with tickSize.
timeInForce DAY / IOC / FOK / GTC Order validity duration. IOC (Immediate-or-Cancel), FOK (Fill-or-Kill), GTC (Good-Till-Cancelled).

๐Ÿ›ก๏ธ Pre-Trade Order Validation Rules

Before an order command is accepted by order-command-service, it undergoes quantitative validation against static exchange listings:

flowchart TD
    Command["Order Command Received"] --> CheckQty{"Quantity > 0 & Aligned to Size Increment?"}
    CheckQty -- No --> RejectQty["Reject: Invalid Quantity / Lot Size"]
    CheckQty -- Yes --> CheckPrice{"Is LIMIT order & Price > 0?"}
    CheckPrice -- No --> RejectPrice["Reject: Missing / Non-positive Limit Price"]
    CheckPrice -- Yes --> CheckTick{"Price Aligned to Tick Size?"}
    CheckTick -- No --> RejectTick["Reject: Price violates Tick Increment"]
    CheckTick -- Yes --> CheckBand{"Price within Price Collar Band?"}
    CheckBand -- No --> RejectCollar["Reject: Price outside Permitted Collar"]
    CheckBand -- Yes --> Accept["Publish CREATE to Kafka (order.commands.v1)"]
Loading

Validation Formulas

  1. Size Increment Alignment: $$\text{quantity} \pmod{\text{sizeIncrement}} = 0$$ Example: If sizeIncrement = 1.0, an order for 100 shares is valid; 100.5 shares is rejected.

  2. Tick Size Alignment: $$\text{limitPrice} \pmod{\text{tickSize}} = 0$$ Example: If tickSize = 0.01, $25.10 is valid; $25.105 is rejected.

  3. Price Collar Band Guard: $$\text{lowerBand} \le \text{limitPrice} \le \text{upperBand}$$ Protects against fat-finger errors and rogue algorithmic prices.


๐Ÿ”„ State Machine & Transition Rules

Trading orders move through deterministic state transitions enforced by synchronized methods on the TradingOrder domain entity.

stateDiagram-v2
    [*] --> PENDING_NEW: Order Received
    PENDING_NEW --> LIVE: Validated & Acked by OMS
    PENDING_NEW --> REJECTED: Validation Failure / Risk Breach
    LIVE --> PARTIALLY_FILLED: Partial Venue Fill
    LIVE --> FILLED: Full Venue Fill
    LIVE --> CANCELLED: Order Cancel Confirmed
    PARTIALLY_FILLED --> PARTIALLY_FILLED: Additional Partial Fill
    PARTIALLY_FILLED --> FILLED: Final Fill (Remaining Qty = 0)
    PARTIALLY_FILLED --> CANCELLED: Cancel Unfilled Balance
    CANCELLED --> FILLED: Late Full Fill Accepted
    CANCELLED --> CANCELLED: Late Partial Fill Accepted
    FILLED --> [*]
    CANCELLED --> [*]
    REJECTED --> [*]
Loading

๐Ÿงฎ Numerical Invariants & Fill Accounting

For every execution fill applied to a TradingOrder, the following mathematical invariants are strictly enforced:

1. Conservation of Quantity

$$\text{quantity} = \text{tradedQuantity} + \text{remainingQuantity}$$

At order creation: $\text{tradedQuantity} = 0$, $\text{remainingQuantity} = \text{quantity}$. Upon full fill: $\text{tradedQuantity} = \text{quantity}$, $\text{remainingQuantity} = 0$.

2. Volume-Weighted Average Price (VWAP) Calculation

When a fill of size $\Delta q$ arrives at fill price $p_{\text{fill}}$, the cumulative average trade price $\bar{P}_{\text{new}}$ is updated:

$$\bar{P}_{\text{new}} = \frac{(\bar{P}_{\text{prev}} \times q_{\text{prev}}) + (p_{\text{fill}} \times \Delta q)}{q_{\text{prev}} + \Delta q}$$

Decimal Precision: Calculated using BigDecimal with 6 decimal places of precision (RoundingMode.HALF_UP).


โšก Late Fill Domain Business Logic

In real-world electronic trading, execution venue fills and cancellation messages race over networks.

  • Rule: If an order has been CANCELLED, any execution fill that occurred at the exchange prior to or concurrently with the cancellation must still be accepted and accounted for.
  • Handling: applyFill() accepts fills on orders in LIVE, PARTIALLY_FILLED, or CANCELLED status. If a fill consumes the remaining quantity, the order status advances to FILLED, ensuring position and trade accounting accuracy.

Clone this wiki locally