Skip to content

Commit

Permalink
feat: add orderdbook example using websocket
Browse files Browse the repository at this point in the history
  • Loading branch information
2hyunbin committed Dec 26, 2024
1 parent ddb5237 commit e0505a0
Showing 1 changed file with 246 additions and 0 deletions.
246 changes: 246 additions & 0 deletions v4-client-js/examples/websocket_orderbook_example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
import { Network } from '../src/clients/constants';
import { SocketClient } from '../src/clients/socket-client';

function test(): void {
let orderBookBidList: [number, number, number][] = [];
let orderBookAskList: [number, number, number][] = [];

const mySocket = new SocketClient(
Network.mainnet().indexerConfig,
() => {
console.log('socket opened');

mySocket.subscribeToOrderbook('ETH-USD');
},
() => {
console.log('socket closed');
},
(message) => {
try {
if (typeof message.data === "string") {
const jsonString = message.data as string;
const parsingData = JSON.parse(jsonString);
const messageId = parsingData.message_id;
const orderBookDataList = parsingData.contents;

if (orderBookDataList instanceof Array) {
// common orderBook data;
[orderBookBidList, orderBookAskList] = updateOrderBook(
orderBookDataList,
orderBookBidList,
orderBookAskList,
messageId,
);

// sort
orderBookBidList = sortByNthElementDesc(
orderBookBidList,
0,
);
orderBookAskList = sortByNthElementAsc(
orderBookAskList,
0,
);

// resolving crossed orderBook
if (orderBookBidList[0][0] >= orderBookAskList[0][0]) {
[orderBookBidList, orderBookAskList] =
resolveCrossedOrderBook(
orderBookBidList,
orderBookAskList,
);
}

printOrderBook(orderBookBidList, orderBookAskList);

if (orderBookBidList.length > 300) {
orderBookBidList.splice(50);
}

if (orderBookAskList.length > 300) {
orderBookAskList.splice(50);
}
} else if (
orderBookDataList !== null &&
orderBookDataList !== undefined
) {
// initial OrderBook data
setInitialOrderBook(
orderBookDataList,
orderBookBidList,
orderBookAskList,
messageId,
);
}
}
} catch (e) {
console.error('Error parsing JSON message:', e);
}
},
(event) => {
console.error('Encountered error:', event.message);
},
);

mySocket.connect();
}

const sortByNthElementAsc = (arr: [number, number, number][], n: number): [number, number, number][] => {
return arr.sort((a, b) => {
if (a[n] < b[n]) return -1;
if (a[n] > b[n]) return 1;
return 0;
});
};
const sortByNthElementDesc = (arr: [number, number, number][], n: number): [number, number, number][] => {
return arr.sort((a, b) => {
if (a[n] > b[n]) return -1;
if (a[n] < b[n]) return 1;
return 0;
});
};

const printOrderBook = (
orderBookBidList: [number, number, number][],
orderBookAskList: [number, number, number][],
): void => {
// print
console.log(`OrderBook for ETH-USD:`);
console.log(`Price Qty`);
for (let i = 4; i > -1; i--) {
const priceStr = String(orderBookAskList[i][0]);
const spaces = createSpaces(10 - priceStr.length);
console.log(`${priceStr}${spaces}${orderBookAskList[i][1]}`);
}
console.log('---------------------');
for (let i = 0; i < 5; i++) {
const priceStr = String(orderBookAskList[i][0]);
const spaces = createSpaces(10 - priceStr.length);
console.log(`${priceStr}${spaces}${orderBookBidList[i][1]}`);
}
console.log('');
};

function createSpaces(count: number): string {
if(count <= 0 ){
return "";
}

let spaces = "";
for (let i = 0; i < count; i++) {
spaces += " ";
}
return spaces;
}

const resolveCrossedOrderBook = (
orderBookBidList: [number, number, number][],
orderBookAskList: [number, number, number][],
): [[number, number, number][], [number, number, number][]] => {
while (orderBookBidList[0][0] >= orderBookAskList[0][0]) {
if (orderBookBidList[0][2] < orderBookAskList[0][2]) {
orderBookBidList.shift();
} else if (orderBookBidList[0][2] > orderBookAskList[0][2]) {
orderBookAskList.shift();
} else {
if (orderBookBidList[0][1] > orderBookAskList[0][1]) {
orderBookBidList[0][1] -= orderBookAskList[0][1];
orderBookAskList.shift();
} else if (orderBookBidList[0][1] < orderBookAskList[0][1]) {
orderBookAskList[0][1] -= orderBookBidList[0][1];
orderBookBidList.shift();
} else {
orderBookAskList.shift();
orderBookBidList.shift();
}
}
}

return [orderBookBidList, orderBookAskList];
};
const setInitialOrderBook = (
orderBookDataList: { bids: []; asks: [] },
orderBookBidList: [number, number, number][],
orderBookAskList: [number, number, number][],
messageId: number,
): void => {
orderBookDataList.bids.forEach((item: { price: string; size: string }) => {
orderBookBidList.push([Number(item.price), Number(item.size), messageId]);
});

orderBookDataList.asks.forEach((item: { price: string; size: string }) => {
orderBookAskList.push([Number(item.price), Number(item.size), messageId]);
});
};

const updateOrderBook = (
orderBookDataList: { bids: [[]]; asks: [[]] }[],
orderBookBidList: [number, number, number][],
orderBookAskList: [number, number, number][],
messageId: number,
): [[number, number, number][], [number, number, number][]] => {
orderBookDataList.forEach((entry: { bids: [[]]; asks: [[]] }) => {
if (entry.bids !== null && entry.bids !== undefined) {
const flattened = entry.bids.reduce((acc: any[], val: any[]) => acc.concat(val), []);
const entryBidPrice = Number(flattened[0]);
const entryBidSize = Number(flattened[1]);

// remove prices with zero Qty
if (entryBidSize === 0) {
for (let i = orderBookBidList.length - 1; i >= 0; i--) {
if (orderBookBidList[i][0] === entryBidPrice) {
orderBookBidList.splice(i, 1);
}
}
} else {
// The price that already exists in the order book is modified only Qty
if (
orderBookBidList.some((innerArray) => innerArray[0] === entryBidPrice)
) {
orderBookBidList.forEach((item, index) => {
if (item[0] === entryBidPrice) {
orderBookBidList[index][1] = entryBidSize;
orderBookBidList[index][2] = messageId;
}
});
} else {
// Add new data to order book
orderBookBidList.push([entryBidPrice, entryBidSize, messageId]);
}
}
}
if (entry.asks !== null && entry.asks !== undefined) {
const flattened = entry.asks.reduce((acc: any[], val: any[]) => acc.concat(val), []);
const entryAskPrice = Number(flattened[0]);
const entryAskSize = Number(flattened[1]);

if (entryAskSize === 0) {
// remove prices with zero Qty
for (let i = orderBookAskList.length - 1; i >= 0; i--) {
if (orderBookAskList[i][0] === entryAskPrice) {
orderBookAskList.splice(i, 1);
}
}
} else {
// The price that already exists in the order book is modified only Qty
if (
orderBookAskList.some((innerArray) => innerArray[0] === entryAskPrice)
) {
orderBookAskList.forEach((item, index) => {
if (item[0] === entryAskPrice) {
orderBookAskList[index][1] = entryAskSize;
orderBookAskList[index][2] = messageId;
}
});
} else {
// Add new data to order book
orderBookAskList.push([entryAskPrice, entryAskSize, messageId]);
}
}
}
});

return [orderBookBidList, orderBookAskList];
};

test();

0 comments on commit e0505a0

Please sign in to comment.