diff --git a/.changeset/healthy-ads-shake.md b/.changeset/healthy-ads-shake.md new file mode 100644 index 0000000..613e1b9 --- /dev/null +++ b/.changeset/healthy-ads-shake.md @@ -0,0 +1,5 @@ +--- +"@mangrovedao/mgv": patch +--- + +Add adjust params for kandel diff --git a/src/lib/kandel/params.ts b/src/lib/kandel/params.ts index 123f8a0..b8cd2d4 100644 --- a/src/lib/kandel/params.ts +++ b/src/lib/kandel/params.ts @@ -22,6 +22,7 @@ export type RawKandelPositionParams = { midPrice: number pricePoints: bigint market: MarketParams + adjust?: boolean | undefined } export type PositionKandelParams = { @@ -31,22 +32,46 @@ export type PositionKandelParams = { pricePoints: bigint } +function getTick(price: number, tickSpacing: bigint, adjust: boolean) { + const lowerTick = tickFromPrice(price, tickSpacing, false) + if (!adjust) return lowerTick + const upperTick = tickFromPrice(price, tickSpacing, true) + + if (upperTick === lowerTick) return lowerTick + + const lowerPrice = priceFromTick(lowerTick) + const upperPrice = priceFromTick(upperTick) + + const lowerDiff = Math.abs(price - lowerPrice) + const upperDiff = Math.abs(price - upperPrice) + + return lowerDiff < upperDiff ? lowerTick : upperTick +} + export function getKandelPositionRawParams( params: RawKandelPositionParams, ): PositionKandelParams { const { market, pricePoints } = params - const baseQuoteTickIndex0 = tickFromPrice( - humanPriceToRawPrice(params.minPrice, market), + const minPriceRaw = humanPriceToRawPrice(params.minPrice, market) + const midPriceRaw = humanPriceToRawPrice(params.midPrice, market) + const maxPriceRaw = humanPriceToRawPrice(params.maxPrice, market) + + const baseQuoteTickIndex0 = getTick( + minPriceRaw, market.tickSpacing, + params.adjust ?? false, ) - const midTick = tickFromPrice( - humanPriceToRawPrice(params.midPrice, market), + const midTick = getTick( + midPriceRaw, market.tickSpacing, + params.adjust ?? false, ) - const maxTick = tickFromPrice( - humanPriceToRawPrice(params.maxPrice, market), + const maxTick = getTick( + maxPriceRaw, market.tickSpacing, + params.adjust ?? false, ) + let baseQuoteTickOffset = ((maxTick - baseQuoteTickIndex0) / (pricePoints - 1n) / diff --git a/src/lib/tick.test.ts b/src/lib/tick.test.ts index 673297b..acf09b7 100644 --- a/src/lib/tick.test.ts +++ b/src/lib/tick.test.ts @@ -3,6 +3,7 @@ import { MAX_SAFE_VOLUME, inboundFromOutbound, outboundFromInbound, + tickFromPrice, tickFromVolumes, } from './tick.js' @@ -44,6 +45,12 @@ describe('ticks', () => { assertEq(tickFromVolumes(1000000n * 10n ** 18n, 999999n * 10n ** 18n), 0n) }) + test('tickFromPrice', () => { + assertEq(tickFromPrice(1), 0n) + assertEq(tickFromPrice(1.0001), 1n) + assertEq(tickFromPrice(0.9998, 1n, true), -2n) + }) + test('outboundFromInbound and inboundFromOutbound', () => { testPrice(1n, 1n) testPrice(2n, 1n) diff --git a/src/lib/tick.ts b/src/lib/tick.ts index ff26484..fff2f58 100644 --- a/src/lib/tick.ts +++ b/src/lib/tick.ts @@ -31,10 +31,16 @@ export function tickInRange(tick: bigint): boolean { * Computes the tick value corresponding to the price of the asset. * @param price the price of the asset * @param tickSpacing the tick spacing of the market @default 1n + * @param roundUp round up the result @default false * @returns A Tick instance corresponding to the price of the asset. */ -export function tickFromPrice(price: number, tickSpacing = 1n): bigint { - const rawTick = BigInt(Math.floor(Math.log(price) / Math.log(1.0001))) +export function tickFromPrice( + price: number, + tickSpacing = 1n, + roundUp = false, +): bigint { + const roundMethod = roundUp ? Math.ceil : Math.floor + const rawTick = BigInt(roundMethod(Math.log(price) / Math.log(1.0001))) const bin = rawTick / tickSpacing + (rawTick % tickSpacing > 0n ? 1n : 0n) return bin * tickSpacing }