Implement buy YES calculation

This commit is contained in:
Austin Chen 2022-06-08 19:56:59 -07:00
parent 17ae9d953d
commit 06c49be05b
2 changed files with 79 additions and 2 deletions

View File

@ -89,6 +89,7 @@ export function calculateLPCost(
deltaL: number deltaL: number
) { ) {
// TODO: this is subtly wrong, because of rounding between curTick and sqrtPrice // TODO: this is subtly wrong, because of rounding between curTick and sqrtPrice
// Also below in buyYES
const upperTick = Math.min(maxTick, Math.max(minTick, curTick)) const upperTick = Math.min(maxTick, Math.max(minTick, curTick))
const costN = toRatio(upperTick) ** 0.5 - toRatio(minTick) ** 0.5 const costN = toRatio(upperTick) ** 0.5 - toRatio(minTick) ** 0.5
@ -101,6 +102,62 @@ export function calculateLPCost(
} }
} }
// Returns a preview of the new pool + number of YES shares purchased.
// Does NOT modify the pool
// Hm, logic is pretty complicated. Let's see if we can simplify this.
export function buyYes(
pool: Swap3Pool,
amount: number // In M$
) {
const tickStates = sortedTickStates(pool)
let tick = pool.tick
let stateIndex = 0
let amountLeft = amount
let yesPurchased = 0
while (amountLeft > 0) {
// Find the current tick state
while (tick >= tickStates[stateIndex + 1].tick) {
stateIndex++
if (stateIndex > tickStates.length - 2) {
// We've reached the end of the tick states...
throw new Error('Ran out of tick states')
}
}
const state = tickStates[stateIndex]
const nextState = tickStates[stateIndex + 1]
// Copied from above; TODO extract to common function
const noCost = toRatio(nextState.tick) ** 0.5 - toRatio(tick) ** 0.5
const yesCost =
1 / toRatio(tick) ** 0.5 - 1 / toRatio(nextState.tick) ** 0.5
if (noCost * state.liquidityGross <= amountLeft) {
// We can fully purchase up until the next tick state
amountLeft -= noCost * state.liquidityGross
yesPurchased += yesCost * state.liquidityGross
tick = nextState.tick
} else {
// Buy as much as we can at the current tick state. Derivation:
// noCostLeft = toRatio(upTick) ** 0.5 - toRatio(tick) ** 0.5
// (noCostLeft + toRatio(tick) ** 0.5) ** 2 = toRatio(upTick)
// TODO check flooring done here
const noCostLeft = amountLeft / state.liquidityGross
const finalTick = fromRatio((noCostLeft + toRatio(tick) ** 0.5) ** 2)
const yesCostLeft =
1 / toRatio(tick) ** 0.5 - 1 / toRatio(finalTick) ** 0.5
amountLeft = 0
yesPurchased += yesCostLeft * state.liquidityGross
tick = finalTick
}
}
return {
newPoolTick: tick,
yesPurchased,
}
}
// Currently, this mutates the pool. Should it return a new object instead? // Currently, this mutates the pool. Should it return a new object instead?
export function addPosition( export function addPosition(
pool: Swap3Pool, pool: Swap3Pool,
@ -165,5 +222,9 @@ export function toProb(tick: number) {
// Returns the tick for a given probability from 0 to 1 // Returns the tick for a given probability from 0 to 1
export function fromProb(prob: number) { export function fromProb(prob: number) {
const ratio = prob / (1 - prob) const ratio = prob / (1 - prob)
return fromRatio(ratio)
}
function fromRatio(ratio: number) {
return Math.floor(Math.log(ratio) / Math.log(1.0001)) return Math.floor(Math.log(ratio) / Math.log(1.0001))
} }

View File

@ -1,5 +1,6 @@
import { import {
addPosition, addPosition,
buyYes,
calculateLPCost, calculateLPCost,
fromProb, fromProb,
getSwap3Probability, getSwap3Probability,
@ -136,11 +137,14 @@ export default function Swap() {
tickStates: [], tickStates: [],
} }
INIT_POOL = addPosition(INIT_POOL, -(2 ** 23), 2 ** 20, 100) INIT_POOL = addPosition(INIT_POOL, -(2 ** 23), 2 ** 20, 100)
INIT_POOL = addPosition(INIT_POOL, fromProb(0.32), fromProb(0.35), 100)
INIT_POOL = grossLiquidity(INIT_POOL) INIT_POOL = grossLiquidity(INIT_POOL)
const [pool, setPool] = useState(INIT_POOL) const [pool, setPool] = useState(INIT_POOL)
const [minTick, setMinTick] = useState(0) const [minTick, setMinTick] = useState(0)
const [maxTick, setMaxTick] = useState(0) const [maxTick, setMaxTick] = useState(0)
const [buyAmount, setBuyAmount] = useState(0)
const { requiredN, requiredY } = calculateLPCost( const { requiredN, requiredY } = calculateLPCost(
pool.tick, pool.tick,
@ -149,6 +153,8 @@ export default function Swap() {
100 // deltaL 100 // deltaL
) )
const { newPoolTick, yesPurchased } = buyYes(pool, buyAmount)
return ( return (
<Col className="mx-auto max-w-2xl gap-10 p-4"> <Col className="mx-auto max-w-2xl gap-10 p-4">
{/* <BalanceTable /> */} {/* <BalanceTable /> */}
@ -200,10 +206,20 @@ export default function Swap() {
<Col> <Col>
Bob: Buy Tokens Bob: Buy Tokens
{/* <input className="input" placeholder="User" type="text" /> */} {/* <input className="input" placeholder="User" type="text" /> */}
<input className="input" placeholder="Amount" type="number" /> <input
className="input"
placeholder="Amount"
type="number"
onChange={(e) => setBuyAmount(parseFloat(e.target.value))}
/>
<Row className="gap-2 py-2">
<div>Y shares purchaseable: {yesPurchased.toFixed(2)}</div>
<div>New Tick: {newPoolTick}</div>
<div>New prob: {formatPercent(toProb(newPoolTick))}</div>
</Row>
<Row className="gap-2"> <Row className="gap-2">
<button className="btn">Buy YES</button> <button className="btn">Buy YES</button>
<button className="btn">Buy NO</button> {/* <button className="btn">Buy NO</button> */}
</Row> </Row>
</Col> </Col>
</Col> </Col>