Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Introduce and use TickPriceHelper.TickFromVolumes #1606

Merged
merged 2 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions src/liquidityProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would delete some code here... normalizeofferparams is never used to get the price, so remove the price calculation completely.

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 {
Expand Down
23 changes: 23 additions & 0 deletions src/util/tickPriceHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
59 changes: 57 additions & 2 deletions test/unit/tickPriceHelper.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) `, () => {
Expand Down Expand Up @@ -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);
Expand Down