-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMatchingAlgorithm.java
More file actions
238 lines (215 loc) · 8.73 KB
/
Copy pathMatchingAlgorithm.java
File metadata and controls
238 lines (215 loc) · 8.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
import java.util.*;
import java.time.LocalTime;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MatchingAlgorithm {
public String type; //Auction or Continuous
public ArrayList<Order> orders = new ArrayList<>();
public HashMap<Instrument, PriorityQueue<Order>> buyPQMap = new HashMap<>();
public HashMap<Instrument, PriorityQueue<Order>> sellPQMap = new HashMap<>();
public int startContinuousIndex = 0;
public HashMap<Instrument, Double> instrumentPriceTimesVolume = new HashMap<>();
public HashMap<Instrument, Double> instrumentVolume = new HashMap<>();
public MatchingAlgorithm() {
}
public MatchingAlgorithm(String instrumentsCSV, String clientsCSV, String ordersCSV) {
Instrument.readcsv(instrumentsCSV);
new Client(clientsCSV);
Order.readcsv(ordersCSV);
for (Instrument x : Instrument.instrumentHashMap.values()) {
PriorityQueue<Order> buyTemp = new PriorityQueue<>(new BuyOrderComparator());
PriorityQueue<Order> sellTemp = new PriorityQueue<>(new SellOrderComparator());
buyPQMap.put(x, buyTemp);
sellPQMap.put(x, sellTemp);
}
}
public void continuous() {
for (int i=startContinuousIndex; i < orders.size(); i++) {
Order order = orders.get(i);
if (order == null) {
break;
}
//add into PQ of either buy or sell
//get the instrument id and run the match on instrument ID
if (order.side) {
buyPQMap.get(order.instrument).add(order);
} else {
sellPQMap.get(order.instrument).add(order);
}
Instrument instrument = order.instrument;
this.match(instrument);
}
}
public double findOpenPrice(Instrument instrument) {
Object[] array = Order.orderHashSet.toArray();
Order[] xs = (Order[]) array;
Arrays.sort(xs, Comparator.comparing(x -> x.time));
List<Order> ys = Stream.of(xs)
.filter(x -> x.instrument.equals(instrument))
.filter(x -> x.time.compareTo(LocalTime.of(9,30,0)) < 0)
.collect(Collectors.toList());
// key: price | val: quantity
HashMap<Double, Integer> map = new HashMap<>();
for (Order order : ys) {
double currPrice = order.price;
if (currPrice == Double.MAX_VALUE || currPrice == Double.MIN_VALUE) {
continue;
}
ArrayList<Order> buy = new ArrayList<>();
ArrayList<Order> sell = new ArrayList<>();
for (Order t : ys) {
if (t.side) {
buy.add(t);
} else {
sell.add(t);
}
}
buy.sort((x, y) -> (int) (y.price - x.price));
sell.sort((x, y) -> (int) (x.price - y.price));
// Calculate Max Orders Fulfilled
// Find Buy Floor
int buyFloorIndex = Integer.MIN_VALUE;
for (int i = 0; i < buy.size(); i++) {
if (currPrice > buy.get(i).price) {
buyFloorIndex = i;
break;
}
}
// Find Sell Floor
// Find Buy Floor
int sellFloorIndex = Integer.MIN_VALUE;
for (int i = 0; i < sell.size(); i++) {
if (currPrice > sell.get(i).price) {
sellFloorIndex = i;
break;
}
}
if (sellFloorIndex == Integer.MIN_VALUE || buyFloorIndex == Integer.MIN_VALUE) {
map.put(currPrice, 0);
continue;
}
int buyQty = 0;
for (int i = 0; i < buyFloorIndex; i++ ) {
buyQty += buy.get(i).quantity;
}
int sellQty = 0;
for (int i = 0; i < sellFloorIndex; i++ ) {
sellQty += sell.get(i).quantity;
}
map.put(currPrice, Math.min(buyQty, sellQty));
}
double openPrice = 0;
int maxQty = Integer.MIN_VALUE;
for (double price : map.keySet()) {
if (map.get(price) > maxQty) {
maxQty = map.get(price);
openPrice = price;
}
}
return openPrice;
}
public void match(Instrument instrument) {
if (!buyPQMap.containsKey(instrument) || !sellPQMap.containsKey(instrument) || buyPQMap.get(instrument).isEmpty() || sellPQMap.get(instrument).isEmpty()) {
return;
}
Order buyOrder = buyPQMap.get(instrument).poll();
Order sellOrder = sellPQMap.get(instrument).poll();
ArrayList<Order> tempPoppedOrders = new ArrayList<>();
while (!buyPQMap.get(instrument).isEmpty() && !sellPQMap.get(instrument).isEmpty()) {
if (buyOrder.price != Double.MAX_VALUE && sellOrder.price != Double.MIN_VALUE && buyOrder.price < sellOrder.price) {
break;
}
while (buyOrder.price == Double.MAX_VALUE && sellOrder.price == Double.MIN_VALUE) {
//compare time values
if (buyOrder.time.compareTo(sellOrder.time) > 0) {
while (!sellPQMap.get(instrument).isEmpty() && sellOrder.price == Double.MIN_VALUE) {
tempPoppedOrders.add(sellOrder);
sellOrder = sellPQMap.get(instrument).poll();
}
} else {
while (!buyPQMap.get(instrument).isEmpty() && buyOrder.price == Double.MAX_VALUE) {
tempPoppedOrders.add(buyOrder);
buyOrder = buyPQMap.get(instrument).poll();
}
}
}
double dealingPrice = 0.0;
double dealingQuantity = 0.0;
if (buyOrder.price >= sellOrder.price) {
//compare time
if (buyOrder.time.compareTo(sellOrder.time) > 0) {
dealingPrice = sellOrder.price;
} else {
dealingPrice = buyOrder.price;
}
dealingQuantity = Math.min(buyOrder.quantity, sellOrder.quantity);
buyOrder.quantity -= dealingQuantity;
sellOrder.quantity -= dealingQuantity;
}
if (buyOrder.quantity == 0) {
buyOrder = !buyPQMap.get(instrument).isEmpty() ? buyPQMap.get(instrument).poll() : null;
}
if (sellOrder.quantity == 0) {
sellOrder = !sellPQMap.get(instrument).isEmpty() ? sellPQMap.get(instrument).poll() : null;
}
this.instrumentVolume.put(instrument, this.instrumentVolume.getOrDefault(instrument, 0.0) + dealingQuantity);
this.instrumentPriceTimesVolume.put(instrument, this.instrumentPriceTimesVolume.getOrDefault(instrument, 0.0) + dealingQuantity * dealingPrice);
}
if (buyOrder != null && buyOrder.quantity != 0.0) {
buyPQMap.get(instrument).add(buyOrder);
}
if (sellOrder != null && sellOrder.quantity != 0.0) {
sellPQMap.get(instrument).add(sellOrder);
}
for (int i = 0; i < tempPoppedOrders.size(); i++) {
Order order = tempPoppedOrders.get(i);
if (order.side) {
buyPQMap.get(instrument).add(order);
} else {
sellPQMap.get(instrument).add(order);
}
}
}
public boolean checkInstrumentExists(Order order) {
return Instrument.instrumentHashMap.containsKey(order.instrument.id);
}
public boolean checkCurrency(Order order) {
return order.client.currencies.contains(order.instrument.currency);
}
public boolean checkLotSize(Order order) {
return order.quantity % order.instrument.lotSize == 0 ? true : false;
}
public boolean checkPosition(Order order) {
//no position check is needed for client, so pass this check
if (!order.client.positionCheck) {
return true;
}
//if the client doesn't own the instrument at all or if the quantity they own is less than the required quantity of the order
if (!order.client.position.containsKey(order.instrument) || (order.client.position.get(order.instrument) < order.quantity)) {
return false;
}
return true;
}
public void openAuctionMatch(Instrument instrument) {
double openPrice = findOpenPrice(instrument);
List<Order> auction = Stream.of((Order[]) Order.orderHashSet.toArray())
.filter(x -> x.instrument.equals(instrument))
.filter(x -> x.time.compareTo(LocalTime.of(9,30,0)) < 0)
.collect(Collectors.toList());
}
public static void main(String[] args) {
MatchingAlgorithm x = new MatchingAlgorithm("C:\\Users\\USER\\Documents\\BOFA\\CodeToConnect2024\\test-set\\input_instruments.csv", "C:\\Users\\USER\\Documents\\BOFA\\CodeToConnect2024\\test-set\\input_clients.csv", "C:\\Users\\USER\\Documents\\BOFA\\CodeToConnect2024\\test-set\\input_orders.csv");
for (Order order : Order.orderHashSet) {
if (!x.checkInstrumentExists(order)) {
ExchangeReportGenerator.addFailedPolicy(order.id, "REJECTED - INSTRUMENT NOT FOUND");
} else if (!x.checkCurrency(order)) {
ExchangeReportGenerator.addFailedPolicy(order.id, "REJECTED - MISMATCH CURRENCY");
} else if (!x.checkLotSize(order)) {
ExchangeReportGenerator.addFailedPolicy(order.id, "REJECTED - INVALID LOT SIZE");
} else if (!x.checkPosition(order)) {
ExchangeReportGenerator.addFailedPolicy(order.id, "REJECTED - POSITION CHECK FAILED");
}
}
ExchangeReportGenerator.generateCSVFile();
}
}