From 62de5fd689a871d1b1c2be2b6c0862c35881affe Mon Sep 17 00:00:00 2001 From: skynetcap <100323448+skynetcap@users.noreply.github.com> Date: Wed, 20 Dec 2023 15:11:14 -0800 Subject: [PATCH] OBv2: Normalize prices/sizes into doubles, instead of longs --- .../com/mmorrell/openbook/OpenBookUtil.java | 16 ++++++++++++ .../openbook/manager/OpenBookManager.java | 25 ++++++++----------- .../com/mmorrell/openbook/model/BookSide.java | 18 +++++++++++++ openbook/src/test/java/OpenBookTest.java | 11 ++++++-- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/openbook/src/main/java/com/mmorrell/openbook/OpenBookUtil.java b/openbook/src/main/java/com/mmorrell/openbook/OpenBookUtil.java index c7ec3f7..875b9ba 100644 --- a/openbook/src/main/java/com/mmorrell/openbook/OpenBookUtil.java +++ b/openbook/src/main/java/com/mmorrell/openbook/OpenBookUtil.java @@ -71,4 +71,20 @@ public static int readInt32(byte[] data, int offset) { return bb.getInt(0); } + public static double priceLotsToNumber(long price, byte baseDecimals, byte quoteDecimals, long baseLotSize, + long quoteLotSize) { + double top = (price * quoteLotSize * getBaseSplTokenMultiplier(baseDecimals)); + double bottom = (baseLotSize * getQuoteSplTokenMultiplier(quoteDecimals)); + + return (top / bottom); + } + + public static double getBaseSplTokenMultiplier(byte baseDecimals) { + return Math.pow(10, baseDecimals); + } + + public static double getQuoteSplTokenMultiplier(byte quoteDecimals) { + return Math.pow(10, quoteDecimals); + } + } diff --git a/openbook/src/main/java/com/mmorrell/openbook/manager/OpenBookManager.java b/openbook/src/main/java/com/mmorrell/openbook/manager/OpenBookManager.java index fd6826f..5a244f8 100644 --- a/openbook/src/main/java/com/mmorrell/openbook/manager/OpenBookManager.java +++ b/openbook/src/main/java/com/mmorrell/openbook/manager/OpenBookManager.java @@ -80,28 +80,23 @@ public Optional getMarket(PublicKey marketId, boolean useCache, .getAccountInfo(openBookMarket.getBids(), Map.of("commitment", Commitment.PROCESSED)) .getDecodedData() ); + bids.setBaseDecimals(openBookMarket.getBaseDecimals()); + bids.setQuoteDecimals(openBookMarket.getQuoteDecimals()); + bids.setBaseLotSize(openBookMarket.getBaseLotSize()); + bids.setQuoteLotSize(openBookMarket.getQuoteLotSize()); BookSide asks = BookSide.readBookSide( client.getApi() .getAccountInfo(openBookMarket.getAsks(), Map.of("commitment", Commitment.PROCESSED)) .getDecodedData() ); + asks.setBaseDecimals(openBookMarket.getBaseDecimals()); + asks.setQuoteDecimals(openBookMarket.getQuoteDecimals()); + asks.setBaseLotSize(openBookMarket.getBaseLotSize()); + asks.setQuoteLotSize(openBookMarket.getQuoteLotSize()); - openBookMarket.setBidOrders( - bids.getLeafNodes().stream() - .sorted(Comparator.comparingDouble(LeafNode::getPrice).reversed()) - .map(leafNode -> new OpenBookOrder(leafNode.getPrice(), leafNode.getQuantity(), - leafNode.getOwner())) - .collect(Collectors.toList()) - ); - - openBookMarket.setAskOrders( - asks.getLeafNodes().stream() - .sorted(Comparator.comparingDouble(LeafNode::getPrice).reversed()) - .map(leafNode -> new OpenBookOrder(leafNode.getPrice(), leafNode.getQuantity(), - leafNode.getOwner())) - .collect(Collectors.toList()) - ); + openBookMarket.setBidOrders(bids.getOrders()); + openBookMarket.setAskOrders(asks.getOrders()); } return Optional.of(openBookMarket); diff --git a/openbook/src/main/java/com/mmorrell/openbook/model/BookSide.java b/openbook/src/main/java/com/mmorrell/openbook/model/BookSide.java index a410574..5974c8f 100644 --- a/openbook/src/main/java/com/mmorrell/openbook/model/BookSide.java +++ b/openbook/src/main/java/com/mmorrell/openbook/model/BookSide.java @@ -1,5 +1,6 @@ package com.mmorrell.openbook.model; +import com.mmorrell.openbook.OpenBookUtil; import lombok.Builder; import lombok.Data; @@ -26,6 +27,12 @@ public class BookSide { private List reservedRoots; private OrderTreeNodes orderTreeNodes; + // From the parent Market + private byte baseDecimals; + private byte quoteDecimals; + private long baseLotSize; + private long quoteLotSize; + public static BookSide readBookSide(byte[] data) { return BookSide.builder() .roots( @@ -62,4 +69,15 @@ public List getLeafNodes() { .map(LeafNode::readLeafNode) .collect(Collectors.toList()); } + + public List getOrders() { + return getLeafNodes().stream() + .map(leafNode -> OpenBookOrder.builder() + .price(OpenBookUtil.priceLotsToNumber(leafNode.getPrice(), baseDecimals, quoteDecimals, + baseLotSize, quoteLotSize)) + .size((leafNode.getQuantity() * baseLotSize) / OpenBookUtil.getBaseSplTokenMultiplier(baseDecimals)) + .trader(leafNode.getOwner()) + .build()) + .toList(); + } } diff --git a/openbook/src/test/java/OpenBookTest.java b/openbook/src/test/java/OpenBookTest.java index 9adf521..68f0cb3 100644 --- a/openbook/src/test/java/OpenBookTest.java +++ b/openbook/src/test/java/OpenBookTest.java @@ -17,6 +17,9 @@ import java.util.Comparator; import java.util.List; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + @Slf4j public class OpenBookTest { @@ -77,10 +80,14 @@ public void orderBookTest() throws RpcException, IOException { @Test public void getOBv2MarketWithBooksTest() { // SOL/USDC - log.info("Manager: {}", openBookManager.getMarket( + OpenBookMarket solUsdc = openBookManager.getMarket( PublicKey.valueOf("C3YPL3kYCSYKsmHcHrPWx1632GUXGqi2yMXJbfeCc57q"), false, true - )); + ).get(); + + log.info("Manager: {}", solUsdc); + + assertFalse(solUsdc.getBidOrders().isEmpty()); } }