Skip to content

Commit ae28757

Browse files
committed
matching algorithm
1 parent 60fc8e1 commit ae28757

16 files changed

+208
-150
lines changed

OrderBook/bin/Order.class

827 Bytes
Binary file not shown.

OrderBook/bin/OrderBook.class

4.26 KB
Binary file not shown.

OrderBook/bin/OrderBookApp.class

1.96 KB
Binary file not shown.
1.46 KB
Binary file not shown.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import java.io.*;
2+
import java.nio.file.*;
3+
4+
public class Helpers {
5+
6+
public static void printFileContents(String filePath) {
7+
try {
8+
String content = Files.readString(Paths.get(filePath));
9+
System.out.println(content);
10+
} catch (IOException e) {
11+
System.err.println("Unable to open " + filePath);
12+
}
13+
}
14+
15+
public static void printFill(OrderFill fill, int quantity, long startTime, long endTime) {
16+
double averagePrice = fill.unitsTransacted > 0 ? fill.totalValue / fill.unitsTransacted : 0.0;
17+
long timeTaken = endTime - startTime;
18+
System.out.println("Filled "+fill.unitsTransacted+"/"+quantity+" units @ $"+averagePrice+" avg. price in "+timeTaken+" ns");
19+
}
20+
}
355 Bytes
Binary file not shown.

OrderBook/src/main/orderbook/Order.java

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 129 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,144 @@
1-
package orderbook;
1+
import java.util.*;
22

3-
import java.util.ArrayList;
4-
import java.util.Collections;
5-
import java.util.HashMap;
6-
import java.util.List;
7-
import java.util.Map;
8-
import java.util.TreeMap;
3+
class Order {
4+
int quantity;
5+
double price;
6+
String side;
97

10-
public class OrderBook {
11-
12-
TreeMap<Double, List<Order>> buyOrders = new TreeMap<>(Collections.reverseOrder());
13-
TreeMap<Double, List<Order>> sellOrders = new TreeMap<>();
14-
HashMap<String, Order> orderMap = new HashMap<>();
8+
Order(int quantity, double price, String side) {
9+
this.quantity = quantity;
10+
this.price = price;
11+
this.side = side;
12+
}
13+
}
1514

16-
public void addOrder(Order order) {
17-
TreeMap<Double, List<Order>> refTreeMap = order.getIsBuyOrder() ? buyOrders : sellOrders;
18-
refTreeMap.putIfAbsent(order.getPrice(), new ArrayList<>());
19-
refTreeMap.get(order.getPrice()).add(order);
20-
orderMap.put(order.getId(), order);
15+
final class Orderbook {
16+
private final TreeMap<Double, List<Order>> bids = new TreeMap<>(Collections.reverseOrder());
17+
private final TreeMap<Double, List<Order>> asks = new TreeMap<>();
18+
19+
public Orderbook(boolean generateDummies) {
20+
if (generateDummies) {
21+
Random random = new Random(12);
22+
23+
for (int i = 0; i < 10; i++) {
24+
double randomPrice = 90.0 + random.nextInt(1001) / 100.0;
25+
addOrder(random.nextInt(100) + 1, randomPrice, "BUY");
26+
addOrder(random.nextInt(100) + 1, randomPrice, "BUY");
27+
}
28+
29+
for (int i = 0; i < 10; i++) {
30+
double randomPrice = 100.0 + random.nextInt(1001) / 100.0;
31+
addOrder(random.nextInt(100) + 1, randomPrice, "SELL");
32+
addOrder(random.nextInt(100) + 1, randomPrice, "SELL");
33+
}
34+
35+
}
2136
}
22-
23-
public boolean removeOrders(String orderId) {
24-
Order order = orderMap.remove(orderId);
25-
if(order==null) {
26-
return false;
37+
38+
public void addOrder(int qty, double price, String side) {
39+
Order order = new Order(qty, price, side.equals("BUY") ? "BUY" : "SELL");
40+
TreeMap<Double, List<Order>> book = side.equals("BUY") ? bids : asks;
41+
42+
book.computeIfAbsent(price, k -> new ArrayList<>()).add(order);
43+
}
44+
45+
public void print() {
46+
System.out.println("========== Orderbook =========");
47+
printLeg(asks, "ASK");
48+
49+
double bestAsk = bestQuote("SELL");
50+
double bestBid = bestQuote("BUY");
51+
System.out.println("====== " + String.format("%.2f", (bestAsk - bestBid) / bestBid * 10000) + "bps ======");
52+
53+
printLeg(bids, "BUY");
54+
System.out.println("==============================\n\n");
55+
}
56+
57+
private void printLeg(TreeMap<Double, List<Order>> book, String side) {
58+
if (side.equals("ASK")) {
59+
for (Map.Entry<Double, List<Order>> entry : book.entrySet()) {
60+
printPriceLevel(entry.getKey(), entry.getValue(), "31");
61+
}
62+
} else {
63+
NavigableSet<Double> descendingKeys = book.navigableKeySet().descendingSet();
64+
for (Double key : descendingKeys) {
65+
printPriceLevel(key, book.get(key), "32");
66+
}
67+
}
68+
}
69+
70+
private void printPriceLevel(double price, List<Order> orders, String color) {
71+
int totalQuantity = 0;
72+
for (Order order : orders) {
73+
totalQuantity += order.quantity;
2774
}
28-
TreeMap<Double, List<Order>> refTreeMap = order.getIsBuyOrder() ? buyOrders : sellOrders;
29-
List<Order> ordersAtPrice = refTreeMap.get(order.getPrice());
30-
ordersAtPrice.remove(order);
31-
if(ordersAtPrice.isEmpty()) {
32-
refTreeMap.remove(order.getPrice());
75+
System.out.printf("\t\033[1;%sm\u20B9%6.2f%5d\033[0m ", color, price, totalQuantity);
76+
for (int i = 0; i < totalQuantity / 10; i++) {
77+
System.out.print("█");
3378
}
34-
return true;
79+
System.out.println();
80+
}
81+
82+
private double bestQuote(String side) {
83+
TreeMap<Double, List<Order>> book = side.equals("BUY") ? bids : asks;
84+
return book.isEmpty() ? 0.0 : book.firstKey();
3585
}
86+
3687

37-
public void viewOrders() {
38-
System.out.println("Buy Orders are: ");
39-
if(!buyOrders.isEmpty()) {
40-
for(Map.Entry<Double, List<Order>> entry : buyOrders.entrySet()) {
41-
System.out.println("Price: "+entry.getKey()+" -> "+entry.getValue());
88+
89+
public OrderFill handleOrder(String type, int orderQuantity, String side, double price) {
90+
int unitsTransacted = 0;
91+
double totalValue = 0.0;
92+
93+
TreeMap<Double, List<Order>> book = side.equals("BUY") ? asks : bids;
94+
95+
Iterator<Map.Entry<Double, List<Order>>> iterator = book.entrySet().iterator();
96+
while (iterator.hasNext() && orderQuantity > 0) {
97+
Map.Entry<Double, List<Order>> entry = iterator.next();
98+
double priceLevel = entry.getKey();
99+
100+
if (type.equals("LIMIT") && ((side.equals("BUY") && priceLevel > price)
101+
|| (side.equals("SELL") && priceLevel < price))) {
102+
break;
42103
}
43-
} else {
44-
System.out.println("No buy orders.");
45-
}
46104

47-
System.out.println("Sell Orders are: ");
48-
if(!sellOrders.isEmpty()) {
49-
for(Map.Entry<Double, List<Order>> entry : sellOrders.entrySet()) {
50-
System.out.println("Price: "+entry.getKey()+" -> "+entry.getValue());
105+
List<Order> orders = entry.getValue();
106+
Iterator<Order> orderIterator = orders.iterator();
107+
while (orderIterator.hasNext() && orderQuantity > 0) {
108+
Order order = orderIterator.next();
109+
110+
if (order.quantity > orderQuantity) {
111+
unitsTransacted += orderQuantity;
112+
totalValue += orderQuantity * priceLevel;
113+
order.quantity -= orderQuantity;
114+
orderQuantity = 0;
115+
} else {
116+
unitsTransacted += order.quantity;
117+
totalValue += order.quantity * priceLevel;
118+
orderQuantity -= order.quantity;
119+
orderIterator.remove();
120+
}
51121
}
52-
} else {
53-
System.out.println("No sell orders.");
122+
123+
if (orders.isEmpty()) {
124+
iterator.remove();
125+
}
126+
}
127+
128+
if (type.equals("LIMIT") && orderQuantity > 0) {
129+
addOrder(orderQuantity, price, side.equals("BUY") ? "BUY" : "SELL");
54130
}
131+
132+
return new OrderFill(unitsTransacted, totalValue);
55133
}
134+
}
56135

136+
class OrderFill {
137+
int unitsTransacted;
138+
double totalValue;
139+
140+
OrderFill(int unitsTransacted, double totalValue) {
141+
this.unitsTransacted = unitsTransacted;
142+
this.totalValue = totalValue;
143+
}
57144
}
3.02 KB
Binary file not shown.
Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,68 @@
1-
package orderbook;
2-
31
import java.util.Scanner;
42

53
public class OrderBookApp {
6-
4+
75
public static void main(String[] args) {
6+
Orderbook ob = new Orderbook(true);
7+
Scanner scanner = new Scanner(System.in);
8+
System.out.println("""
9+
___ _ ____ _ __ _ \r
10+
/ _ \\ _ __ __| | ___ _ __| __ ) ___ ___ | | __ / / (_) __ ___ ____ _ \r
11+
| | | | '__/ _` |/ _ \\ '__| _ \\ / _ \\ / _ \\| |/ / / / | |/ _` \\ \\ / / _` |\r
12+
| |_| | | | (_| | __/ | | |_) | (_) | (_) | < / / | | (_| |\\ V / (_| |\r
13+
\\___/|_| \\__,_|\\___|_| |____/ \\___/ \\___/|_|\\_\\ /_/ _/ |\\__,_| \\_/ \\__,_|\r
14+
|__/ """ //
15+
//
16+
//
17+
//
18+
//
19+
);
20+
while (true) {
21+
System.out.println("Options\n-----------------------------------\n|1. Print Orderbook |\n|2. Submit order |\n|3. Exit |\n-----------------------------------\nChoice: ");
22+
int action = scanner.nextInt();
23+
24+
if (action == 1) {
25+
ob.print();
26+
} else if (action == 2) {
27+
System.out.println("Enter order type:\n1. Market order\n2. Limit order\nSelection: ");
28+
int orderTypeInput = scanner.nextInt();
29+
String orderType = (orderTypeInput == 1) ? "MARKET" : "LIMIT";
30+
31+
System.out.println("\nEnter side:\n1. Buy\n2. Sell\nSelection: ");
32+
int sideInput = scanner.nextInt();
33+
String side = (sideInput == 1) ? "BUY" : "SELL";
34+
35+
System.out.println("\nEnter order quantity: ");
36+
int quantity = scanner.nextInt();
37+
38+
if (orderType.equals("MARKET")) {
39+
System.out.println("\nSubmitting market " + (side.equals("BUY") ? "buy" : "sell")
40+
+ " order for " + quantity + " units..\n");
41+
42+
long startTime = System.nanoTime();
43+
OrderFill fill = ob.handleOrder(orderType, quantity, side, 0.0);
44+
long endTime = System.nanoTime();
45+
46+
Helpers.printFill(fill, quantity, startTime, endTime);
47+
} else if (orderType.equals("LIMIT")) {
48+
System.out.println("\nEnter limit price: ");
49+
double price = scanner.nextDouble();
50+
51+
System.out.println("\nSubmitting limit " + (side.equals("BUY") ? "buy" : "sell")
52+
+ " order for " + quantity + " units @ \u20B9" + price + "..\n");
53+
54+
long startTime = System.nanoTime();
55+
OrderFill fill = ob.handleOrder(orderType, quantity, side, price);
56+
long endTime = System.nanoTime();
857

9-
OrderBook orderBook = new OrderBook();
10-
Scanner sc = new Scanner(System.in);
11-
12-
while(true) {
13-
14-
System.out.println("---ORDER BOOK MENU---");
15-
System.out.println("1) Add Order");
16-
System.out.println("2) View Orders");
17-
System.out.println("3) Delete Order");
18-
System.out.println("4) Exit");
19-
20-
int choice = sc.nextInt();
21-
String id;
22-
23-
switch (choice) {
24-
case 1:
25-
System.out.print("Enter OrderId: ");
26-
id = sc.next();
27-
System.out.print("Enter Price: ");
28-
double price = sc.nextDouble();
29-
System.out.print("Enter quantity: ");
30-
int quantity = sc.nextInt();
31-
System.out.print("Is it a Buy Order(true/false): ");
32-
boolean isBuyOrder = sc.nextBoolean();
33-
orderBook.addOrder(new Order(id, price, quantity, isBuyOrder));
34-
System.out.println("Order added successfully!");
35-
break;
36-
case 2:
37-
orderBook.viewOrders();
38-
break;
39-
case 3:
40-
if(orderBook.buyOrders.isEmpty() && orderBook.sellOrders.isEmpty()) {
41-
System.out.println("There are no orders to be removed.");
42-
break;
43-
}
44-
System.out.print("Enter the OrderId to be removed: ");
45-
id = sc.next();
46-
boolean isRemoved = orderBook.removeOrders(id);
47-
if(isRemoved) {
48-
System.out.println("Order Removed Successfully!");
49-
} else {
50-
System.out.println("No such order.");
51-
}
52-
break;
53-
case 4:
54-
System.out.println("exited.");
55-
sc.close();
56-
return;
57-
58-
default:
59-
System.out.println("Invalid choice, please try again.");
58+
Helpers.printFill(fill, quantity, startTime, endTime);
59+
}
60+
System.out.println();
61+
} else if(action == 3) {
62+
break;
6063
}
6164
}
65+
scanner.close();
66+
System.out.println("Program terminated.");
6267
}
6368
}
297 Bytes
Binary file not shown.

OrderBook/src/main/orderbook/OrderMatcher.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

OrderBook/src/main/orderbook/OrderUtils.java

Lines changed: 0 additions & 5 deletions
This file was deleted.
5.17 KB
Binary file not shown.

OrderBook/src/test/OrderBookTest.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

OrderBook/src/test/OrderMatcherTest.java

Whitespace-only changes.

0 commit comments

Comments
 (0)