Compute sale value of shares with binary search to keep k constant.
This commit is contained in:
parent
a0ed63070f
commit
43b404e7ed
|
@ -114,19 +114,47 @@ export function calculateCpmmPurchase(
|
||||||
return { shares, newPool, newP, fees }
|
return { shares, newPool, newP, fees }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCpmmShareValue(
|
function computeK(y: number, n: number, p: number) {
|
||||||
|
return y ** p * n ** (1 - p)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sellSharesK(
|
||||||
|
y: number,
|
||||||
|
n: number,
|
||||||
|
p: number,
|
||||||
|
s: number,
|
||||||
|
outcome: 'YES' | 'NO',
|
||||||
|
b: number
|
||||||
|
) {
|
||||||
|
return outcome === 'YES'
|
||||||
|
? computeK(y - b + s, n - b, p)
|
||||||
|
: computeK(y - b, n - b + s, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateCpmmShareValue(
|
||||||
contract: FullContract<CPMM, Binary>,
|
contract: FullContract<CPMM, Binary>,
|
||||||
shares: number,
|
shares: number,
|
||||||
outcome: string
|
outcome: 'YES' | 'NO'
|
||||||
) {
|
) {
|
||||||
const { pool } = contract
|
const { pool, p } = contract
|
||||||
const { YES: y, NO: n } = pool
|
|
||||||
|
|
||||||
// TODO: calculate using new function
|
const k = computeK(pool.YES, pool.NO, p)
|
||||||
const poolChange = outcome === 'YES' ? shares + y - n : shares + n - y
|
|
||||||
const k = y * n
|
// Find bet amount that preserves k after selling shares.
|
||||||
const shareValue = 0.5 * (shares + y + n - Math.sqrt(4 * k + poolChange ** 2))
|
let lowAmount = 0
|
||||||
return shareValue
|
let highAmount = shares
|
||||||
|
let mid = 0
|
||||||
|
let kGuess = 0
|
||||||
|
while (Math.abs(k - kGuess) > 0.00000000001) {
|
||||||
|
mid = lowAmount + (highAmount - lowAmount) / 2
|
||||||
|
kGuess = sellSharesK(pool.YES, pool.NO, p, shares, outcome, mid)
|
||||||
|
if (kGuess < k) {
|
||||||
|
highAmount = mid
|
||||||
|
} else {
|
||||||
|
lowAmount = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mid
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCpmmSale(
|
export function calculateCpmmSale(
|
||||||
|
@ -135,7 +163,11 @@ export function calculateCpmmSale(
|
||||||
) {
|
) {
|
||||||
const { shares, outcome } = bet
|
const { shares, outcome } = bet
|
||||||
|
|
||||||
const rawSaleValue = calculateCpmmShareValue(contract, shares, outcome)
|
const rawSaleValue = calculateCpmmShareValue(
|
||||||
|
contract,
|
||||||
|
Math.abs(shares),
|
||||||
|
outcome as 'YES' | 'NO'
|
||||||
|
)
|
||||||
|
|
||||||
const { fees, remainingBet: saleValue } = getCpmmLiquidityFee(
|
const { fees, remainingBet: saleValue } = getCpmmLiquidityFee(
|
||||||
contract,
|
contract,
|
||||||
|
@ -153,9 +185,11 @@ export function calculateCpmmSale(
|
||||||
? [y + shares - saleValue + fee, n - saleValue + fee]
|
? [y + shares - saleValue + fee, n - saleValue + fee]
|
||||||
: [y - saleValue + fee, n + shares - saleValue + fee]
|
: [y - saleValue + fee, n + shares - saleValue + fee]
|
||||||
|
|
||||||
const newPool = { YES: newY, NO: newN }
|
const postBetPool = { YES: newY, NO: newN }
|
||||||
|
|
||||||
return { saleValue, newPool, fees }
|
const { newPool, newP } = addCpmmLiquidity(postBetPool, contract.p, fee)
|
||||||
|
|
||||||
|
return { saleValue, newPool, newP, fees }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCpmmProbabilityAfterSale(
|
export function getCpmmProbabilityAfterSale(
|
||||||
|
|
|
@ -92,7 +92,7 @@ export const getCpmmSellBetInfo = (
|
||||||
) => {
|
) => {
|
||||||
const { pool, p } = contract
|
const { pool, p } = contract
|
||||||
|
|
||||||
const { saleValue, newPool, fees } = calculateCpmmSale(contract, {
|
const { saleValue, newPool, newP, fees } = calculateCpmmSale(contract, {
|
||||||
shares,
|
shares,
|
||||||
outcome,
|
outcome,
|
||||||
})
|
})
|
||||||
|
@ -128,6 +128,7 @@ export const getCpmmSellBetInfo = (
|
||||||
return {
|
return {
|
||||||
newBet,
|
newBet,
|
||||||
newPool,
|
newPool,
|
||||||
|
newP,
|
||||||
newBalance,
|
newBalance,
|
||||||
fees,
|
fees,
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ export const sellShares = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
.collection(`contracts/${contractId}/bets`)
|
.collection(`contracts/${contractId}/bets`)
|
||||||
.doc()
|
.doc()
|
||||||
|
|
||||||
const { newBet, newPool, newBalance, fees } = getCpmmSellBetInfo(
|
const { newBet, newPool, newP, newBalance, fees } = getCpmmSellBetInfo(
|
||||||
user,
|
user,
|
||||||
shares,
|
shares,
|
||||||
outcome,
|
outcome,
|
||||||
|
@ -56,15 +56,24 @@ export const sellShares = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
newBetDoc.id
|
newBetDoc.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!isFinite(newP)) {
|
||||||
|
return {
|
||||||
|
status: 'error',
|
||||||
|
message: 'Trade rejected due to overflow error.',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFinite(newBalance)) {
|
if (!isFinite(newBalance)) {
|
||||||
throw new Error('Invalid user balance for ' + user.username)
|
throw new Error('Invalid user balance for ' + user.username)
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.update(userDoc, { balance: newBalance })
|
transaction.update(userDoc, { balance: newBalance })
|
||||||
transaction.create(newBetDoc, newBet)
|
transaction.create(newBetDoc, newBet)
|
||||||
transaction.update(
|
transaction.update(
|
||||||
contractDoc,
|
contractDoc,
|
||||||
removeUndefinedProps({
|
removeUndefinedProps({
|
||||||
pool: newPool,
|
pool: newPool,
|
||||||
|
p: newP,
|
||||||
collectedFees: addObjects(fees ?? {}, collectedFees ?? {}),
|
collectedFees: addObjects(fees ?? {}, collectedFees ?? {}),
|
||||||
volume: volume + Math.abs(newBet.amount),
|
volume: volume + Math.abs(newBet.amount),
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user