Order Book Mechanics and Optimized Data Structures in Java
An Order Book is a record of all buy and sell orders in a market for a specific financial instrument, such as stocks, bonds, or commodities. It helps traders determine market depth, liquidity, and current prices.
The order book consists of two parts:
Buy Orders (Bids): Orders placed by traders to buy at specific prices.
Sell Orders (Asks/Offers): Orders placed by traders to sell at specific prices.
The orders in the book are generally sorted by price. For buy orders, the highest price is at the top, and for sell orders, the lowest price is at the top. The order book is updated in real time as orders are added, canceled, or filled.
Order Book Levels
Level 1: Refers to the best bid (highest buy order) and best ask (lowest sell order). This provides the current market price.
Level 2: Includes the full market depth, listing multiple levels of bid and ask prices. It provides more granular information, showing how many orders exist at each price level.
Level 3: Represents the most detailed level, showing individual orders with their full details, including time, size, and exact order placement.
Key Terms:
Bid Price: The price a buyer is willing to pay.
Ask Price: The price a seller is asking for.
Spread: The difference between the best bid and best ask prices.
Market Depth: The number of buy and sell orders at different price levels.
Efficient Data Structure for an Order Book in Java
To design an efficient order book, we need to represent both the buy (bid) and sell (ask) orders efficiently. An efficient data structure allows us to:
Quickly access the best bid and best ask.
Add, modify, or cancel orders quickly.
Keep track of the order book levels.
Design Considerations:
Fast Insertion and Deletion: Orders need to be added, modified, or removed in constant or logarithmic time.
Efficient Price Matching: To find the best bid and ask prices efficiently.
Market Depth: Store multiple levels of bids and asks.
Data Structure Design:
Bid Side: A
TreeMapcan be used to store the bids in descending order (highest bid first).Ask Side: A
TreeMapcan be used to store the asks in ascending order (lowest ask first).Order Book: Use a class that holds these two maps (
TreeMap<Double, PriorityQueue<Order>>for example) for the bids and asks. APriorityQueuehelps manage orders at the same price level.
Here's how we can implement an order book in Java:
Java Code Implementation:
import java.util.*;
class Order {
private final String orderId;
private final int quantity;
private final double price;
public Order(String orderId, int quantity, double price) {
this.orderId = orderId;
this.quantity = quantity;
this.price = price;
}
public String getOrderId() {
return orderId;
}
public int getQuantity() {
return quantity;
}
public double getPrice() {
return price;
}
@Override
public String toString() {
return "Order[ID=" + orderId + ", qty=" + quantity + ", price=" + price + "]";
}
}
class OrderBook {
// TreeMap for Buy orders (Bid side) - prices sorted in descending order
private final TreeMap<Double, PriorityQueue<Order>> bids = new TreeMap<>(Collections.reverseOrder());
// TreeMap for Sell orders (Ask side) - prices sorted in ascending order
private final TreeMap<Double, PriorityQueue<Order>> asks = new TreeMap<>();
// Method to add an order to the order book
public void addOrder(Order order, boolean isBuy) {
if (isBuy) {
bids.putIfAbsent(order.getPrice(), new PriorityQueue<>(Comparator.comparingInt(Order::getQuantity).reversed()));
bids.get(order.getPrice()).add(order);
} else {
asks.putIfAbsent(order.getPrice(), new PriorityQueue<>(Comparator.comparingInt(Order::getQuantity)));
asks.get(order.getPrice()).add(order);
}
}
// Method to remove an order from the order book
public void removeOrder(String orderId, boolean isBuy) {
if (isBuy) {
bids.values().forEach(queue -> queue.removeIf(order -> order.getOrderId().equals(orderId)));
} else {
asks.values().forEach(queue -> queue.removeIf(order -> order.getOrderId().equals(orderId)));
}
}
// Method to match orders (simple version)
public void matchOrders() {
while (!bids.isEmpty() && !asks.isEmpty()) {
double bestBid = bids.firstKey();
double bestAsk = asks.firstKey();
if (bestBid >= bestAsk) {
// Match the orders at the best price level
PriorityQueue<Order> bidQueue = bids.get(bestBid);
PriorityQueue<Order> askQueue = asks.get(bestAsk);
Order bidOrder = bidQueue.peek();
Order askOrder = askQueue.peek();
int tradeQuantity = Math.min(bidOrder.getQuantity(), askOrder.getQuantity());
System.out.println("Trade: " + tradeQuantity + " units at price: " + bestAsk);
// Update quantities or remove the order if fully matched
if (bidOrder.getQuantity() == tradeQuantity) {
bidQueue.poll();
}
if (askOrder.getQuantity() == tradeQuantity) {
askQueue.poll();
}
// Remove empty price levels
if (bidQueue.isEmpty()) bids.pollFirstEntry();
if (askQueue.isEmpty()) asks.pollFirstEntry();
} else {
break; // No match possible
}
}
}
// Method to print the current state of the order book
public void printOrderBook() {
System.out.println("Bids (Buy Orders):");
bids.forEach((price, queue) -> queue.forEach(order -> System.out.println(order)));
System.out.println("Asks (Sell Orders):");
asks.forEach((price, queue) -> queue.forEach(order -> System.out.println(order)));
}
}
public class Main {
public static void main(String[] args) {
OrderBook orderBook = new OrderBook();
// Adding some buy and sell orders
orderBook.addOrder(new Order("B1", 100, 101.5), true); // Buy order at 101.5
orderBook.addOrder(new Order("B2", 150, 102.0), true); // Buy order at 102.0
orderBook.addOrder(new Order("S1", 100, 100.5), false); // Sell order at 100.5
orderBook.addOrder(new Order("S2", 50, 101.0), false); // Sell order at 101.0
orderBook.addOrder(new Order("S3", 200, 102.0), false); // Sell order at 102.0
// Print the order book
orderBook.printOrderBook();
// Match orders
orderBook.matchOrders();
// Print the updated order book
orderBook.printOrderBook();
}
}
Key Features of the Code:
Order Class: Represents an individual order with an ID, quantity, and price.
OrderBook Class:
Bids and Asks: The buy orders are stored in a
TreeMapwith descending order (Collections.reverseOrder()) and the sell orders in aTreeMapwith ascending order.Add Orders: The
addOrdermethod inserts an order into the appropriatePriorityQueuein the map based on whether it's a buy or sell order.Remove Orders: The
removeOrdermethod allows removing an order by its ID.Match Orders: The
matchOrdersmethod matches buy orders with sell orders when the best bid is greater than or equal to the best ask price. It performs a simple matching logic by executing trades.Print Order Book: The
printOrderBookmethod prints the current state of the order book, showing all bids and asks.
Efficiency:
TreeMap: Provides log(n) time complexity for insertion, removal, and access operations due to its balanced nature.
PriorityQueue: Helps manage orders at the same price level efficiently by maintaining the order of execution (FIFO or reversed FIFO depending on buy or sell).
Order Matching: The matching process uses a simple approach of comparing the best bid and best ask prices. Once a match is found, it executes the trade and updates the order book.
Extending the Design:
Order Matching Algorithms: This simple matching algorithm can be expanded to handle more advanced features such as partial matching, market orders, limit orders, and so on.
Market Data Integration: Real-time market data could be incorporated using WebSocket or FIX protocols to keep the order book up-to-date.
📈 Order Types in Trading
In financial markets, order types define how a trade should be executed. They give instructions to brokers or exchanges about price, quantity, and timing. Different order types help traders manage risk, control execution, and implement trading strategies.
1. Market Order
Definition: Buy or sell immediately at the best available price.
Use case: When execution is more important than price.
Example: "Buy 100 shares of Apple immediately, regardless of price."
2. Limit Order
Definition: Buy or sell only at a specific price or better.
Use case: When price matters more than speed.
Example: "Sell 50 shares of Tesla at $700 or higher."
3. Stop Order (Stop-Loss Order)
Definition: Converts into a market order once a certain trigger price (stop price) is reached.
Use case: To limit losses or protect profits.
Example: "If Amazon falls to $3000, sell all my shares."
4. Stop-Limit Order
Definition: Becomes a limit order once the stop price is triggered.
Use case: Control execution price after a stop is hit.
Example: "If Bitcoin drops to $30,000, sell but only at $29,800 or better."
5. Fill or Kill (FOK)
Definition: Must be filled completely immediately or canceled.
Use case: For large trades where partial fills are not acceptable.
Example: "Buy 10,000 shares right now, or don’t buy at all."
6. Immediate or Cancel (IOC)
Definition: Fill what you can immediately, cancel the rest.
Use case: Partial execution is acceptable.
Example: "Buy as many shares as possible now, but don't wait."
7. Good Till Cancelled (GTC)
Definition: An order that stays active until the trader cancels it or it’s filled.
Use case: Persistent order placement.
Example: "Keep selling my shares at $500 until it happens."
8. Day Order
Definition: Valid only for the trading day it’s placed.
Use case: Avoid holding unexecuted orders overnight.
Example: "Try to buy shares today, cancel if not filled by market close."
9. Iceberg Order
Definition: Only a small portion of the order is visible to the market; the rest is hidden.
Use case: To minimize market impact when trading large volumes.
Example: "Show only 100 shares at a time out of my 10,000-share sell order."
