From be870cc8ff53f305900bd2a4687cd19c064e19dc Mon Sep 17 00:00:00 2001 From: Troels Damgaard Date: Fri, 17 Nov 2023 15:04:00 +0100 Subject: [PATCH 1/2] feat: Introduce and use TickPriceHelper.TickFromVolumes --- src/liquidityProvider.ts | 27 +++++++-------------------- src/util/tickPriceHelper.ts | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/liquidityProvider.ts b/src/liquidityProvider.ts index d53d2e6d3..2fffe95d7 100644 --- a/src/liquidityProvider.ts +++ b/src/liquidityProvider.ts @@ -14,8 +14,6 @@ import { OfferLogic } from "."; import PrettyPrint, { prettyPrintFilter } from "./util/prettyPrint"; import Trade from "./util/trade"; import TickPriceHelper from "./util/tickPriceHelper"; -import { TickLib } from "./util/coreCalculations/TickLib"; -import { BigNumber } from "ethers/lib/ethers"; // eslint-disable-next-line @typescript-eslint/no-namespace namespace LiquidityProvider { @@ -219,36 +217,25 @@ class LiquidityProvider { } { const tickPriceHelper = new TickPriceHelper(p.ba, market); let tick: ethers.BigNumber, gives: Big, price: Big; - // deduce price from tick & gives, or deduce tick & gives from volume & price if ("tick" in p) { + // deduce price from tick & gives tick = ethers.BigNumber.from(p.tick); price = tickPriceHelper.priceFromTick(tick); gives = Big(p.gives); } else if ("price" in p) { + // deduce tick & gives from volume & price price = Big(p.price); tick = tickPriceHelper.tickFromPrice(price); - if (p.ba === "asks") { - gives = Big(p.volume); - } else { + if (p.ba === "bids") { gives = Big(p.volume).mul(price); + } else { + gives = Big(p.volume); } } else { + // deduce tick and price from wants & gives gives = Big(p.gives); const wants = Big(p.wants); - - tick = TickLib.tickFromVolumes( - BigNumber.from( - p.ba === "asks" - ? wants.mul(Big(10).pow(market.quote.decimals)).toFixed() - : wants.mul(Big(10).pow(market.base.decimals)).toFixed(), - ), - BigNumber.from( - p.ba === "asks" - ? gives.mul(Big(10).pow(market.base.decimals)).toFixed() - : gives.mul(Big(10).pow(market.quote.decimals)).toFixed(), - ), - ); - + tick = tickPriceHelper.tickFromVolumes(wants, gives); if (p.ba === "bids") { price = Big(gives).div(wants); } else { diff --git a/src/util/tickPriceHelper.ts b/src/util/tickPriceHelper.ts index 5698a616a..9429708c2 100644 --- a/src/util/tickPriceHelper.ts +++ b/src/util/tickPriceHelper.ts @@ -137,6 +137,29 @@ class TickPriceHelper { : this.market.base.decimals, ); } + + /** + * Calculates the tick from inbound and outbound volumes. + * @param inboundVolume inbound amount to calculate the tick for + * @param outboundVolume outbound amount to calculate the tick for + * @returns raw offer list tick for volumes + */ + tickFromVolumes(inboundVolume: Bigish, outboundVolume: Bigish): BigNumber { + const rawInbound = UnitCalculations.toUnits( + inboundVolume, + this.ba === "bids" + ? this.market.base.decimals + : this.market.quote.decimals, + ); + const rawOutbound = UnitCalculations.toUnits( + outboundVolume, + this.ba === "bids" + ? this.market.quote.decimals + : this.market.base.decimals, + ); + const tick = TickLib.tickFromVolumes(rawInbound, rawOutbound); + return tick; + } } export default TickPriceHelper; From b7275f6d3659c6e2af11d63ff25bec32ed37dc25 Mon Sep 17 00:00:00 2001 From: Troels Damgaard Date: Wed, 22 Nov 2023 14:31:44 +0100 Subject: [PATCH 2/2] TickFromVolumes tests --- test/unit/tickPriceHelper.unit.test.ts | 59 +++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/test/unit/tickPriceHelper.unit.test.ts b/test/unit/tickPriceHelper.unit.test.ts index cc8c33a93..2762849fd 100644 --- a/test/unit/tickPriceHelper.unit.test.ts +++ b/test/unit/tickPriceHelper.unit.test.ts @@ -150,6 +150,34 @@ describe(`${TickPriceHelper.prototype.constructor.name} unit tests suite`, () => }); }); + describe(TickPriceHelper.prototype.tickFromVolumes.name, () => { + it("returns tick=0 for inboundVolume=1, outboundVolume=1 with base decimals: 6, quote decimals: 6 (bids semibook)", () => { + // Arrange + const tickPriceHelper = new TickPriceHelper("bids", { + base: { decimals: 6 }, + quote: { decimals: 6 }, + }); + + // Act + const result = tickPriceHelper.tickFromVolumes(1, 1); + // Assert + assert.equal(0, result.toNumber()); + }); + + it("returns tick=0 for inboundVolume=1, outboundVolume=1 with base decimals: 6, quote decimals: 6 (asks semibook)", () => { + // Arrange + const tickPriceHelper = new TickPriceHelper("asks", { + base: { decimals: 6 }, + quote: { decimals: 6 }, + }); + + // Act + const result = tickPriceHelper.tickFromVolumes(1, 1); + // Assert + assert.equal(0, result.toNumber()); + }); + }); + describe(TickPriceHelper.prototype.tickFromPrice.name, () => { priceAndTickPairs.forEach(({ args, tick, price }) => { it(`returns tick=${tick} for price ${price} with base decimals: ${args.market.base.decimals}, quote decimals: ${args.market.quote.decimals} (${args.ba} semibook)) `, () => { @@ -235,8 +263,35 @@ describe(`${TickPriceHelper.prototype.constructor.name} unit tests suite`, () => .tickFromPrice(displayPrice) .toNumber(); - assert.equal(rawAskTick, calcAskTick); - assert.equal(rawBidTick, calcBidTick); + // relate tickFromPrice to tickFromVolumes + const calcAskTickFromVolumes = askTickPriceHelper + .tickFromVolumes(displayAskInbound, displayAskOutbound) + .toNumber(); + const calcBidTickFromVolumes = bidTickPriceHelper + .tickFromVolumes(displayBidInbound, displayBidOutbound) + .toNumber(); + + assert.equal( + rawAskTick, + calcAskTickFromVolumes, + "rawAskTick not equal to ask tick calculated from volumes", + ); + assert.equal( + rawBidTick, + calcBidTickFromVolumes, + "rawBidTick not equal to bid tick calculated from volumes", + ); + + assert.equal( + rawAskTick, + calcAskTick, + "rawAskTick not equal to ask tick calculated from price", + ); + assert.equal( + rawBidTick, + calcBidTick, + "rawBidTick not equal to bid tick calculated from price", + ); const calcAskPrice = askTickPriceHelper.priceFromTick(rawAskTick); const calcBidPrice = bidTickPriceHelper.priceFromTick(rawBidTick);