new cfmm: k = y^(1-p) * n^p

This commit is contained in:
mantikoros 2022-03-11 16:04:08 -06:00
parent bb8f7cc966
commit 062d4f88fd
11 changed files with 87 additions and 132 deletions

View File

@ -1,6 +1,6 @@
import { Bet } from './bet'
import { getDpmProbability } from './calculate-dpm'
import { getCpmmLiquidity, getCpmmProbability } from './calculate-cpmm'
import { getCpmmProbability } from './calculate-cpmm'
import { Binary, CPMM, DPM, FreeResponse, FullContract } from './contract'
import { User } from './user'
import { LiquidityProvision } from './liquidity-provision'
@ -9,42 +9,13 @@ import { noFees } from './fees'
export const PHANTOM_ANTE = 0.001
export const MINIMUM_ANTE = 10
export function getCpmmAnteBet(
creator: User,
contract: FullContract<CPMM, Binary>,
anteId: string,
amount: number,
outcome: 'YES' | 'NO'
) {
const p = getCpmmProbability(contract.pool)
const { createdTime } = contract
const bet: Bet = {
id: anteId,
userId: creator.id,
contractId: contract.id,
amount: amount,
shares: amount,
outcome,
probBefore: p,
probAfter: p,
createdTime,
isAnte: true,
fees: noFees,
}
return bet
}
export function getCpmmInitialLiquidity(
creator: User,
contract: FullContract<CPMM, Binary>,
anteId: string,
amount: number
) {
const { createdTime, pool } = contract
const liquidity = getCpmmLiquidity(pool)
const { createdTime, pool, p } = contract
const lp: LiquidityProvision = {
id: anteId,
@ -54,7 +25,8 @@ export function getCpmmInitialLiquidity(
isAnte: true,
amount: amount,
liquidity,
liquidity: amount,
probability: getCpmmProbability(pool, p),
}
return lp

View File

@ -2,12 +2,14 @@ import * as _ from 'lodash'
import { Bet } from './bet'
import { Binary, CPMM, FullContract } from './contract'
import { CREATOR_FEE, Fees, LIQUIDITY_FEE, PLATFORM_FEE } from './fees'
import { CREATOR_FEE, Fees, LIQUIDITY_FEE, noFees, PLATFORM_FEE } from './fees'
export function getCpmmProbability(pool: { [outcome: string]: number }) {
// For binary contracts only.
export function getCpmmProbability(
pool: { [outcome: string]: number },
p: number
) {
const { YES, NO } = pool
return NO / (YES + NO)
return (p * NO) / ((1 - p) * YES + p * NO)
}
export function getCpmmOutcomeProbabilityAfterBet(
@ -16,7 +18,7 @@ export function getCpmmOutcomeProbabilityAfterBet(
bet: number
) {
const { newPool } = calculateCpmmPurchase(contract, bet, outcome)
const p = getCpmmProbability(newPool)
const p = getCpmmProbability(newPool, contract.p)
return outcome === 'NO' ? 1 - p : p
}
@ -25,14 +27,17 @@ function calculateCpmmShares(
pool: {
[outcome: string]: number
},
p: number,
bet: number,
betChoice: string
) {
const { YES: y, NO: n } = pool
const numerator = bet ** 2 + bet * (y + n)
const denominator = betChoice === 'YES' ? bet + n : bet + y
const shares = numerator / denominator
return shares
const k = y ** (1 - p) * n ** p
return betChoice === 'YES'
? // https://www.wolframalpha.com/input?i=%28y%2Bb-s%29%5E%281-p%29*%28n%2Bb%29%5Ep+%3D+k%2C+solve+s
y + bet - (k * (bet + n) ** -p) ** (1 / (1 - p))
: n + bet - (k * (bet + y) ** (p - 1)) ** (1 / p)
}
export function getCpmmLiquidityFee(
@ -40,7 +45,7 @@ export function getCpmmLiquidityFee(
bet: number,
outcome: string
) {
const p = getCpmmProbability(contract.pool)
const p = getCpmmProbability(contract.pool, contract.p)
const betP = outcome === 'YES' ? 1 - p : p
const liquidityFee = LIQUIDITY_FEE * betP * bet
@ -59,10 +64,10 @@ export function calculateCpmmSharesAfterFee(
bet: number,
outcome: string
) {
const { pool } = contract
const { remainingBet } = getCpmmLiquidityFee(contract, bet, outcome)
const { pool, p } = contract
// const { remainingBet } = getCpmmLiquidityFee(contract, bet, outcome)
return calculateCpmmShares(pool, remainingBet, outcome)
return calculateCpmmShares(pool, p, bet, outcome)
}
export function calculateCpmmPurchase(
@ -70,10 +75,12 @@ export function calculateCpmmPurchase(
bet: number,
outcome: string
) {
const { pool } = contract
const { remainingBet, fees } = getCpmmLiquidityFee(contract, bet, outcome)
const { pool, p } = contract
// const { remainingBet, fees } = getCpmmLiquidityFee(contract, bet, outcome)
const remainingBet = bet
const fees = noFees
const shares = calculateCpmmShares(pool, remainingBet, outcome)
const shares = calculateCpmmShares(pool, p, remainingBet, outcome)
const { YES: y, NO: n } = pool
const { liquidityFee: fee } = fees
@ -84,6 +91,7 @@ export function calculateCpmmPurchase(
: [y + remainingBet + fee, n - shares + remainingBet + fee]
const newPool = { YES: newY, NO: newN }
// console.log(getCpmmLiquidity(pool, p), getCpmmLiquidity(newPool, p))
return { shares, newPool, fees }
}
@ -96,6 +104,7 @@ export function calculateCpmmShareValue(
const { pool } = contract
const { YES: y, NO: n } = pool
// TODO: calculate using new function
const poolChange = outcome === 'YES' ? shares + y - n : shares + n - y
const k = y * n
const shareValue = 0.5 * (shares + y + n - Math.sqrt(4 * k + poolChange ** 2))
@ -136,63 +145,57 @@ export function getCpmmProbabilityAfterSale(
bet: Bet
) {
const { newPool } = calculateCpmmSale(contract, bet)
return getCpmmProbability(newPool)
return getCpmmProbability(newPool, contract.p)
}
export const calcCpmmInitialPool = (initialProbInt: number, ante: number) => {
const p = initialProbInt / 100.0
const [poolYes, poolNo] =
p >= 0.5 ? [ante * (1 / p - 1), ante] : [ante, ante * (1 / (1 - p) - 1)]
return { poolYes, poolNo }
}
export function getCpmmLiquidity(pool: { [outcome: string]: number }) {
// For binary contracts only.
export function getCpmmLiquidity(
pool: { [outcome: string]: number },
p: number
) {
const { YES, NO } = pool
return Math.sqrt(YES * NO)
return YES ** (1 - p) * NO ** p
}
export function addCpmmLiquidity(
contract: FullContract<CPMM, Binary>,
amount: number
) {
const { YES, NO } = contract.pool
const p = getCpmmProbability({ YES, NO })
// TODO: use new pricing equation
// export function addCpmmLiquidity(
// contract: FullContract<CPMM, Binary>,
// amount: number
// ) {
// const { YES, NO } = contract.pool
// const p = getCpmmProbability({ YES, NO }, contract.p)
const [newYes, newNo] =
p >= 0.5
? [amount * (1 / p - 1), amount]
: [amount, amount * (1 / (1 - p) - 1)]
// const [newYes, newNo] =
// p >= 0.5
// ? [amount * (1 / p - 1), amount]
// : [amount, amount * (1 / (1 - p) - 1)]
const betAmount = Math.abs(newYes - newNo)
const betOutcome = p >= 0.5 ? 'YES' : 'NO'
// const betAmount = Math.abs(newYes - newNo)
// const betOutcome = p >= 0.5 ? 'YES' : 'NO'
const poolLiquidity = getCpmmLiquidity({ YES, NO })
const newPool = { YES: YES + newYes, NO: NO + newNo }
const resultingLiquidity = getCpmmLiquidity(newPool)
const liquidity = resultingLiquidity - poolLiquidity
// const poolLiquidity = getCpmmLiquidity({ YES, NO })
// const newPool = { YES: YES + newYes, NO: NO + newNo }
// const resultingLiquidity = getCpmmLiquidity(newPool)
// const liquidity = resultingLiquidity - poolLiquidity
return { newPool, liquidity, betAmount, betOutcome }
}
// return { newPool, liquidity, betAmount, betOutcome }
// }
export function removeCpmmLiquidity(
contract: FullContract<CPMM, Binary>,
liquidity: number
) {
const { YES, NO } = contract.pool
const poolLiquidity = getCpmmLiquidity({ YES, NO })
const p = getCpmmProbability({ YES, NO })
// export function removeCpmmLiquidity(
// contract: FullContract<CPMM, Binary>,
// liquidity: number
// ) {
// const { YES, NO } = contract.pool
// const poolLiquidity = getCpmmLiquidity({ YES, NO })
// const p = getCpmmProbability({ YES, NO }, contract.p)
const f = liquidity / poolLiquidity
const [payoutYes, payoutNo] = [f * YES, f * NO]
// const f = liquidity / poolLiquidity
// const [payoutYes, payoutNo] = [f * YES, f * NO]
const betAmount = Math.abs(payoutYes - payoutNo)
const betOutcome = p >= 0.5 ? 'NO' : 'YES' // opposite side as adding liquidity
const payout = Math.min(payoutYes, payoutNo)
// const betAmount = Math.abs(payoutYes - payoutNo)
// const betOutcome = p >= 0.5 ? 'NO' : 'YES' // opposite side as adding liquidity
// const payout = Math.min(payoutYes, payoutNo)
const newPool = { YES: YES - payoutYes, NO: NO - payoutNo }
// const newPool = { YES: YES - payoutYes, NO: NO - payoutNo }
return { newPool, payout, betAmount, betOutcome }
}
// return { newPool, payout, betAmount, betOutcome }
// }

View File

@ -21,7 +21,7 @@ import { Binary, Contract, CPMM, DPM, FullContract } from './contract'
export function getProbability(contract: FullContract<DPM | CPMM, Binary>) {
return contract.mechanism === 'cpmm-1'
? getCpmmProbability(contract.pool)
? getCpmmProbability(contract.pool, contract.p)
: getDpmProbability(contract.totalShares)
}
@ -31,14 +31,14 @@ export function getInitialProbability(
return (
contract.initialProbability ??
(contract.mechanism === 'cpmm-1'
? getCpmmProbability(contract.pool)
? getCpmmProbability(contract.pool, contract.p)
: getDpmProbability(contract.phantomShares ?? contract.totalShares))
)
}
export function getOutcomeProbability(contract: Contract, outcome: string) {
return contract.mechanism === 'cpmm-1'
? getCpmmProbability(contract.pool)
? getCpmmProbability(contract.pool, contract.p)
: getDpmOutcomeProbability(contract.totalShares, outcome)
}

View File

@ -49,6 +49,7 @@ export type DPM = {
export type CPMM = {
mechanism: 'cpmm-1'
p: number // probability constant in y^(1-p) * n^p = k
pool: { [outcome: string]: number }
}

View File

@ -8,4 +8,5 @@ export type LiquidityProvision = {
amount: number // M$ quantity
liquidity: number // sqrt(k)
probability: number
}

View File

@ -34,8 +34,9 @@ export const getNewBinaryCpmmBetInfo = (
const newBalance = user.balance - (amount - loanAmount)
const probBefore = getCpmmProbability(contract.pool)
const probAfter = getCpmmProbability(newPool)
const { pool, p } = contract
const probBefore = getCpmmProbability(pool, p)
const probAfter = getCpmmProbability(newPool, p)
const newBet: Bet = {
id: newBetId,

View File

@ -10,7 +10,6 @@ import {
import { User } from './user'
import { parseTags } from './util/parse'
import { removeUndefinedProps } from './util/object'
import { calcCpmmInitialPool } from './calculate-cpmm'
import { calcDpmInitialPool } from './calculate-dpm'
export function getNewContract(
@ -86,13 +85,14 @@ const getBinaryDpmProps = (initialProb: number, ante: number) => {
}
const getBinaryCpmmProps = (initialProb: number, ante: number) => {
const { poolYes, poolNo } = calcCpmmInitialPool(initialProb, ante)
const pool = { YES: poolYes, NO: poolNo }
const pool = { YES: ante, NO: ante }
const p = initialProb / 100
const system: CPMM & Binary = {
mechanism: 'cpmm-1',
outcomeType: 'BINARY',
initialProbability: initialProb / 100,
initialProbability: p,
p,
pool: pool,
}

View File

@ -89,13 +89,13 @@ export const getCpmmSellBetInfo = (
contract: FullContract<CPMM, Binary>,
newBetId: string
) => {
const { pool } = contract
const { pool, p } = contract
const { id: betId, amount, shares, outcome } = bet
const { saleValue, newPool, fees } = calculateCpmmSale(contract, bet)
const probBefore = getCpmmProbability(pool)
const probAfter = getCpmmProbability(newPool)
const probBefore = getCpmmProbability(pool, p)
const probAfter = getCpmmProbability(newPool, p)
console.log(
'SELL M$',

View File

@ -20,7 +20,6 @@ import { randomString } from '../../common/util/random'
import { getNewContract } from '../../common/new-contract'
import {
getAnteBets,
getCpmmAnteBet,
getCpmmInitialLiquidity,
getFreeAnswerAnte,
MINIMUM_ANTE,
@ -131,27 +130,6 @@ export const createContract = functions
await yesBetDoc.set(yesBet)
await noBetDoc.set(noBet)
} else if (outcomeType === 'BINARY') {
const { YES: y, NO: n } = contract.pool
const anteBet = Math.abs(y - n)
if (anteBet) {
const betDoc = firestore
.collection(`contracts/${contract.id}/bets`)
.doc()
const outcome = y > n ? 'NO' : 'YES' // more in YES pool if prob leans NO
const bet = getCpmmAnteBet(
creator,
contract as FullContract<CPMM, Binary>,
betDoc.id,
anteBet,
outcome
)
await betDoc.set(bet)
}
const liquidityDoc = firestore
.collection(`contracts/${contract.id}/liquidity`)
.doc()

View File

@ -20,7 +20,6 @@ import { Avatar } from './avatar'
import { Spacer } from './layout/spacer'
import { useState } from 'react'
import { TweetButton } from './tweet-button'
import { getCpmmLiquidity } from '../../common/calculate-cpmm'
export function ContractCard(props: {
contract: Contract

View File

@ -43,17 +43,17 @@ export function contractMetrics(contract: Contract) {
const liquidityLabel =
contract.mechanism === 'dpm-2'
? `${formatMoney(truePool)} pool`
: `${formatMoney(getCpmmLiquidity(contract.pool))} liquidity`
: `${formatMoney(getCpmmLiquidity(pool, contract.p))} liquidity`
return { truePool, liquidityLabel, createdDate, resolvedDate }
}
export function getBinaryProbPercent(contract: FullContract<any, Binary>) {
const { totalShares, pool, resolutionProbability, mechanism } = contract
const { totalShares, pool, p, resolutionProbability, mechanism } = contract
const prob =
resolutionProbability ?? mechanism === 'cpmm-1'
? getCpmmProbability(pool)
? getCpmmProbability(pool, p)
: getDpmProbability(totalShares)
const probPercent = Math.round(prob * 100) + '%'