Skip to content

Commit 03ec1b0

Browse files
committed
feat: add orderdbook example using websocket
1 parent bdbab8c commit 03ec1b0

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
import { Network } from '../src/clients/constants';
2+
import { SocketClient } from '../src/clients/socket-client';
3+
4+
function test(): void {
5+
let orderBookBidList: [number, number, number][] = [];
6+
let orderBookAskList: [number, number, number][] = [];
7+
8+
const mySocket = new SocketClient(
9+
Network.mainnet().indexerConfig,
10+
() => {
11+
console.log('socket opened');
12+
13+
mySocket.subscribeToOrderbook('ETH-USD');
14+
},
15+
() => {
16+
console.log('socket closed');
17+
},
18+
(message) => {
19+
try {
20+
if (typeof message.data === "string") {
21+
const jsonString = message.data as string;
22+
const parsingData = JSON.parse(jsonString);
23+
const messageId = parsingData.message_id;
24+
const orderBookDataList = parsingData.contents;
25+
26+
if (orderBookDataList instanceof Array) {
27+
// common orderBook data;
28+
[orderBookBidList, orderBookAskList] = updateOrderBook(
29+
orderBookDataList,
30+
orderBookBidList,
31+
orderBookAskList,
32+
messageId,
33+
);
34+
35+
// sort
36+
orderBookBidList = sortByNthElementDesc(
37+
orderBookBidList,
38+
0,
39+
);
40+
orderBookAskList = sortByNthElementAsc(
41+
orderBookAskList,
42+
0,
43+
);
44+
45+
// resolving crossed orderBook
46+
if (orderBookBidList[0][0] >= orderBookAskList[0][0]) {
47+
[orderBookBidList, orderBookAskList] =
48+
resolveCrossedOrderBook(
49+
orderBookBidList,
50+
orderBookAskList,
51+
);
52+
}
53+
54+
printOrderBook(orderBookBidList, orderBookAskList);
55+
56+
if (orderBookBidList.length > 300) {
57+
orderBookBidList.splice(50);
58+
}
59+
60+
if (orderBookAskList.length > 300) {
61+
orderBookAskList.splice(50);
62+
}
63+
} else if (
64+
orderBookDataList !== null &&
65+
orderBookDataList !== undefined
66+
) {
67+
// initial OrderBook data
68+
setInitialOrderBook(
69+
orderBookDataList,
70+
orderBookBidList,
71+
orderBookAskList,
72+
messageId,
73+
);
74+
}
75+
}
76+
} catch (e) {
77+
console.error('Error parsing JSON message:', e);
78+
}
79+
},
80+
(event) => {
81+
console.error('Encountered error:', event.message);
82+
},
83+
);
84+
85+
mySocket.connect();
86+
}
87+
88+
const sortByNthElementAsc = (arr: [number, number, number][], n: number): [number, number, number][] => {
89+
return arr.sort((a, b) => {
90+
if (a[n] < b[n]) return -1;
91+
if (a[n] > b[n]) return 1;
92+
return 0;
93+
});
94+
};
95+
const sortByNthElementDesc = (arr: [number, number, number][], n: number): [number, number, number][] => {
96+
return arr.sort((a, b) => {
97+
if (a[n] > b[n]) return -1;
98+
if (a[n] < b[n]) return 1;
99+
return 0;
100+
});
101+
};
102+
103+
const printOrderBook = (
104+
orderBookBidList: [number, number, number][],
105+
orderBookAskList: [number, number, number][],
106+
): void => {
107+
// print
108+
console.log(`OrderBook for ETH-USD:`);
109+
console.log(`Price Qty`);
110+
for (let i = 4; i > -1; i--) {
111+
const priceStr = String(orderBookAskList[i][0]);
112+
const spaces = createSpaces(10 - priceStr.length);
113+
console.log(`${priceStr}${spaces}${orderBookAskList[i][1]}`);
114+
}
115+
console.log('---------------------');
116+
for (let i = 0; i < 5; i++) {
117+
const priceStr = String(orderBookAskList[i][0]);
118+
const spaces = createSpaces(10 - priceStr.length);
119+
console.log(`${priceStr}${spaces}${orderBookBidList[i][1]}`);
120+
}
121+
console.log('');
122+
};
123+
124+
function createSpaces(count: number): string {
125+
if(count <= 0 ){
126+
return "";
127+
}
128+
129+
let spaces = "";
130+
for (let i = 0; i < count; i++) {
131+
spaces += " ";
132+
}
133+
return spaces;
134+
}
135+
136+
const resolveCrossedOrderBook = (
137+
orderBookBidList: [number, number, number][],
138+
orderBookAskList: [number, number, number][],
139+
): [[number, number, number][], [number, number, number][]] => {
140+
while (orderBookBidList[0][0] >= orderBookAskList[0][0]) {
141+
if (orderBookBidList[0][2] < orderBookAskList[0][2]) {
142+
orderBookBidList.shift();
143+
} else if (orderBookBidList[0][2] > orderBookAskList[0][2]) {
144+
orderBookAskList.shift();
145+
} else {
146+
if (orderBookBidList[0][1] > orderBookAskList[0][1]) {
147+
orderBookBidList[0][1] -= orderBookAskList[0][1];
148+
orderBookAskList.shift();
149+
} else if (orderBookBidList[0][1] < orderBookAskList[0][1]) {
150+
orderBookAskList[0][1] -= orderBookBidList[0][1];
151+
orderBookBidList.shift();
152+
} else {
153+
orderBookAskList.shift();
154+
orderBookBidList.shift();
155+
}
156+
}
157+
}
158+
159+
return [orderBookBidList, orderBookAskList];
160+
};
161+
const setInitialOrderBook = (
162+
orderBookDataList: { bids: []; asks: [] },
163+
orderBookBidList: [number, number, number][],
164+
orderBookAskList: [number, number, number][],
165+
messageId: number,
166+
): void => {
167+
orderBookDataList.bids.forEach((item: { price: string; size: string }) => {
168+
orderBookBidList.push([Number(item.price), Number(item.size), messageId]);
169+
});
170+
171+
orderBookDataList.asks.forEach((item: { price: string; size: string }) => {
172+
orderBookAskList.push([Number(item.price), Number(item.size), messageId]);
173+
});
174+
};
175+
176+
const updateOrderBook = (
177+
orderBookDataList: { bids: [[]]; asks: [[]] }[],
178+
orderBookBidList: [number, number, number][],
179+
orderBookAskList: [number, number, number][],
180+
messageId: number,
181+
): [[number, number, number][], [number, number, number][]] => {
182+
orderBookDataList.forEach((entry: { bids: [[]]; asks: [[]] }) => {
183+
if (entry.bids !== null && entry.bids !== undefined) {
184+
const flattened = entry.bids.reduce((acc: any[], val: any[]) => acc.concat(val), []);
185+
const entryBidPrice = Number(flattened[0]);
186+
const entryBidSize = Number(flattened[1]);
187+
188+
// remove prices with zero Qty
189+
if (entryBidSize === 0) {
190+
for (let i = orderBookBidList.length - 1; i >= 0; i--) {
191+
if (orderBookBidList[i][0] === entryBidPrice) {
192+
orderBookBidList.splice(i, 1);
193+
}
194+
}
195+
} else {
196+
// The price that already exists in the order book is modified only Qty
197+
if (
198+
orderBookBidList.some((innerArray) => innerArray[0] === entryBidPrice)
199+
) {
200+
orderBookBidList.forEach((item, index) => {
201+
if (item[0] === entryBidPrice) {
202+
orderBookBidList[index][1] = entryBidSize;
203+
orderBookBidList[index][2] = messageId;
204+
}
205+
});
206+
} else {
207+
// Add new data to order book
208+
orderBookBidList.push([entryBidPrice, entryBidSize, messageId]);
209+
}
210+
}
211+
}
212+
if (entry.asks !== null && entry.asks !== undefined) {
213+
const flattened = entry.asks.reduce((acc: any[], val: any[]) => acc.concat(val), []);
214+
const entryAskPrice = Number(flattened[0]);
215+
const entryAskSize = Number(flattened[1]);
216+
217+
if (entryAskSize === 0) {
218+
// remove prices with zero Qty
219+
for (let i = orderBookAskList.length - 1; i >= 0; i--) {
220+
if (orderBookAskList[i][0] === entryAskPrice) {
221+
orderBookAskList.splice(i, 1);
222+
}
223+
}
224+
} else {
225+
// The price that already exists in the order book is modified only Qty
226+
if (
227+
orderBookAskList.some((innerArray) => innerArray[0] === entryAskPrice)
228+
) {
229+
orderBookAskList.forEach((item, index) => {
230+
if (item[0] === entryAskPrice) {
231+
orderBookAskList[index][1] = entryAskSize;
232+
orderBookAskList[index][2] = messageId;
233+
}
234+
});
235+
} else {
236+
// Add new data to order book
237+
orderBookAskList.push([entryAskPrice, entryAskSize, messageId]);
238+
}
239+
}
240+
}
241+
});
242+
243+
return [orderBookBidList, orderBookAskList];
244+
};
245+
246+
test();

0 commit comments

Comments
 (0)