From c844e1b6941a2104662e3276c9a9e09b2ec426d9 Mon Sep 17 00:00:00 2001 From: mantikoros Date: Tue, 11 Jan 2022 00:16:44 -0600 Subject: [PATCH] initial commit --- common/antes.ts | 19 ++-- common/calculate.ts | 160 ++++++++++++++++---------------- common/new-bet.ts | 10 +- common/new-contract.ts | 10 +- common/payouts.ts | 4 +- common/sell-bet.ts | 42 ++------- functions/src/resolve-market.ts | 3 +- web/components/bet-panel.tsx | 2 +- 8 files changed, 106 insertions(+), 144 deletions(-) diff --git a/common/antes.ts b/common/antes.ts index cfe2ede8..70857605 100644 --- a/common/antes.ts +++ b/common/antes.ts @@ -1,19 +1,14 @@ export const PHANTOM_ANTE = 200 -export const calcStartPool = (initialProbInt: number, ante?: number) => { +export const calcStartPool = (initialProbInt: number, ante = 0) => { const p = initialProbInt / 100.0 - const totalAnte = PHANTOM_ANTE + (ante || 0) + const totalAnte = PHANTOM_ANTE + ante - const poolYes = - p === 0.5 - ? p * totalAnte - : -(totalAnte * (-p + Math.sqrt((-1 + p) * -p))) / (-1 + 2 * p) + const sharesYes = Math.sqrt(p * totalAnte ** 2) + const sharesNo = Math.sqrt(totalAnte ** 2 - sharesYes ** 2) - const poolNo = totalAnte - poolYes + const poolYes = p * ante + const poolNo = (1 - p) * ante - const f = PHANTOM_ANTE / totalAnte - const startYes = f * poolYes - const startNo = f * poolNo - - return { startYes, startNo, poolYes, poolNo } + return { sharesYes, sharesNo, poolYes, poolNo } } diff --git a/common/calculate.ts b/common/calculate.ts index 5cf08088..a5c1e4a1 100644 --- a/common/calculate.ts +++ b/common/calculate.ts @@ -2,37 +2,80 @@ import { Bet } from './bet' import { Contract } from './contract' import { FEES } from './fees' -export const blah = () => 999 - -export const getProbability = (pool: { YES: number; NO: number }) => { - const [yesPool, noPool] = [pool.YES, pool.NO] - const numerator = Math.pow(yesPool, 2) - const denominator = Math.pow(yesPool, 2) + Math.pow(noPool, 2) - return numerator / denominator +export function getProbability(totalShares: { YES: number; NO: number }) { + const { YES: y, NO: n } = totalShares + return y ** 2 / (y ** 2 + n ** 2) } export function getProbabilityAfterBet( - pool: { YES: number; NO: number }, + totalShares: { YES: number; NO: number }, outcome: 'YES' | 'NO', bet: number ) { - const [YES, NO] = [ - pool.YES + (outcome === 'YES' ? bet : 0), - pool.NO + (outcome === 'NO' ? bet : 0), - ] + const shares = calculateShares(totalShares, bet, outcome) + + const [YES, NO] = + outcome === 'YES' + ? [totalShares.YES + shares, totalShares.NO] + : [totalShares.YES, totalShares.NO + shares] + return getProbability({ YES, NO }) } export function calculateShares( - pool: { YES: number; NO: number }, + totalShares: { YES: number; NO: number }, bet: number, betChoice: 'YES' | 'NO' ) { - const [yesPool, noPool] = [pool.YES, pool.NO] + const [yesShares, noShares] = [totalShares.YES, totalShares.NO] + + const c = 2 * bet * Math.sqrt(yesShares ** 2 + noShares ** 2) return betChoice === 'YES' - ? bet + (bet * noPool ** 2) / (yesPool ** 2 + bet * yesPool) - : bet + (bet * yesPool ** 2) / (noPool ** 2 + bet * noPool) + ? Math.sqrt(bet ** 2 + yesShares ** 2 + c) - yesShares + : Math.sqrt(bet ** 2 + noShares ** 2 + c) - noShares +} + +export function calculateRawShareValue( + totalShares: { YES: number; NO: number }, + shares: number, + betChoice: 'YES' | 'NO' +) { + const [yesShares, noShares] = [totalShares.YES, totalShares.NO] + const currentValue = Math.sqrt(yesShares ** 2 + noShares ** 2) + + const postSaleValue = + betChoice === 'YES' + ? Math.sqrt(Math.max(0, yesShares - shares) ** 2 + noShares ** 2) + : Math.sqrt(yesShares ** 2 + Math.max(0, noShares - shares) ** 2) + + return currentValue - postSaleValue +} + +export function calculateMoneyRatio(contract: Contract) { + const { totalShares, pool } = contract + const [yesShares, noShares] = [totalShares.YES, totalShares.NO] + + const actual = pool.YES + pool.NO + const expected = Math.sqrt(yesShares ** 2 + noShares ** 2) + return actual / expected +} + +export function calculateShareValue(contract: Contract, bet: Bet) { + const shareValue = calculateRawShareValue( + contract.totalShares, + bet.shares, + bet.outcome + ) + const f = calculateMoneyRatio(contract) + + const myPool = contract.pool[bet.outcome] + const adjShareValue = Math.min(Math.min(1, f) * shareValue, myPool) + return adjShareValue +} + +export function calculateSaleAmount(contract: Contract, bet: Bet) { + return (1 - FEES) * calculateShareValue(contract, bet) } export function calculatePayout( @@ -40,19 +83,31 @@ export function calculatePayout( bet: Bet, outcome: 'YES' | 'NO' | 'CANCEL' | 'MKT' ) { - const { amount, outcome: betOutcome, shares } = bet - - if (outcome === 'CANCEL') return amount + if (outcome === 'CANCEL') return calculateCancelPayout(contract, bet) if (outcome === 'MKT') return calculateMktPayout(contract, bet) + return calculateStandardPayout(contract, bet, outcome) +} + +export function calculateCancelPayout(contract: Contract, bet: Bet) { + const totalBets = contract.totalBets.YES + contract.totalBets.NO + const pool = contract.pool.YES + contract.pool.NO + + return (bet.amount / totalBets) * pool +} + +export function calculateStandardPayout( + contract: Contract, + bet: Bet, + outcome: 'YES' | 'NO' +) { + const { amount, outcome: betOutcome, shares } = bet if (betOutcome !== outcome) return 0 const { totalShares, totalBets } = contract - if (totalShares[outcome] === 0) return 0 - const startPool = contract.startPool.YES + contract.startPool.NO - const truePool = contract.pool.YES + contract.pool.NO - startPool + const truePool = contract.pool.YES + contract.pool.NO if (totalBets[outcome] >= truePool) return (amount / totalBets[outcome]) * truePool @@ -64,22 +119,7 @@ export function calculatePayout( } export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) { - const { amount, outcome, shares } = bet - const { totalShares, totalBets } = contract - - const startPool = contract.startPool.YES + contract.startPool.NO - const truePool = amount + contract.pool.YES + contract.pool.NO - startPool - - const totalBetsOutcome = totalBets[outcome] + amount - const totalSharesOutcome = totalShares[outcome] + shares - - if (totalBetsOutcome >= truePool) - return (amount / totalBetsOutcome) * truePool - - const total = totalSharesOutcome - totalBetsOutcome - const winningsPool = truePool - totalBetsOutcome - - return (1 - FEES) * (amount + ((shares - amount) / total) * winningsPool) + return calculateStandardPayout(contract, bet, bet.outcome) } function calculateMktPayout(contract: Contract, bet: Bet) { @@ -88,8 +128,7 @@ function calculateMktPayout(contract: Contract, bet: Bet) { const weightedTotal = p * contract.totalBets.YES + (1 - p) * contract.totalBets.NO - const startPool = contract.startPool.YES + contract.startPool.NO - const truePool = contract.pool.YES + contract.pool.NO - startPool + const truePool = contract.pool.YES + contract.pool.NO const betP = bet.outcome === 'YES' ? p : 1 - p @@ -123,44 +162,3 @@ export function currentValue(contract: Contract, bet: Bet) { return prob * yesPayout + (1 - prob) * noPayout } - -export function calculateSaleAmount(contract: Contract, bet: Bet) { - const { shares, outcome } = bet - - const { YES: yesPool, NO: noPool } = contract.pool - const { YES: yesStart, NO: noStart } = contract.startPool - const { YES: yesShares, NO: noShares } = contract.totalShares - - const [y, n, s] = [yesPool, noPool, shares] - - const shareValue = - outcome === 'YES' - ? // https://www.wolframalpha.com/input/?i=b+%2B+%28b+n%5E2%29%2F%28y+%28-b+%2B+y%29%29+%3D+c+solve+b - (n ** 2 + - s * y + - y ** 2 - - Math.sqrt( - n ** 4 + (s - y) ** 2 * y ** 2 + 2 * n ** 2 * y * (s + y) - )) / - (2 * y) - : (y ** 2 + - s * n + - n ** 2 - - Math.sqrt( - y ** 4 + (s - n) ** 2 * n ** 2 + 2 * y ** 2 * n * (s + n) - )) / - (2 * n) - - const startPool = yesStart + noStart - const pool = yesPool + noPool - startPool - - const probBefore = yesPool ** 2 / (yesPool ** 2 + noPool ** 2) - const f = pool / (probBefore * yesShares + (1 - probBefore) * noShares) - - const myPool = outcome === 'YES' ? yesPool - yesStart : noPool - noStart - - const adjShareValue = Math.min(Math.min(1, f) * shareValue, myPool) - - const saleAmount = (1 - FEES) * adjShareValue - return saleAmount -} diff --git a/common/new-bet.ts b/common/new-bet.ts index fe441aa4..61c72015 100644 --- a/common/new-bet.ts +++ b/common/new-bet.ts @@ -1,4 +1,5 @@ import { Bet } from './bet' +import { calculateShares, getProbability } from './calculate' import { Contract } from './contract' import { User } from './user' @@ -16,10 +17,7 @@ export const getNewBetInfo = ( ? { YES: yesPool + amount, NO: noPool } : { YES: yesPool, NO: noPool + amount } - const shares = - outcome === 'YES' - ? amount + (amount * noPool ** 2) / (yesPool ** 2 + amount * yesPool) - : amount + (amount * yesPool ** 2) / (noPool ** 2 + amount * noPool) + const shares = calculateShares(contract.totalShares, amount, outcome) const { YES: yesShares, NO: noShares } = contract.totalShares @@ -35,8 +33,8 @@ export const getNewBetInfo = ( ? { YES: yesBets + amount, NO: noBets } : { YES: yesBets, NO: noBets + amount } - const probBefore = yesPool ** 2 / (yesPool ** 2 + noPool ** 2) - const probAfter = newPool.YES ** 2 / (newPool.YES ** 2 + newPool.NO ** 2) + const probBefore = getProbability(contract.totalShares) + const probAfter = getProbability(newTotalShares) const newBet: Bet = { id: newBetId, diff --git a/common/new-contract.ts b/common/new-contract.ts index b8abdba7..f8e3225b 100644 --- a/common/new-contract.ts +++ b/common/new-contract.ts @@ -12,7 +12,7 @@ export function getNewContract( ante?: number, closeTime?: number ) { - const { startYes, startNo, poolYes, poolNo } = calcStartPool( + const { sharesYes, sharesNo, poolYes, poolNo } = calcStartPool( initialProb, ante ) @@ -29,10 +29,10 @@ export function getNewContract( question: question.trim(), description: description.trim(), - startPool: { YES: startYes, NO: startNo }, + startPool: { YES: poolYes, NO: poolNo }, pool: { YES: poolYes, NO: poolNo }, - totalShares: { YES: 0, NO: 0 }, - totalBets: { YES: 0, NO: 0 }, + totalShares: { YES: sharesYes, NO: sharesNo }, + totalBets: { YES: poolYes, NO: poolNo }, isResolved: false, createdTime: Date.now(), @@ -46,3 +46,5 @@ export function getNewContract( return contract } + +function getAnteBets() {} diff --git a/common/payouts.ts b/common/payouts.ts index e0225a27..37efb623 100644 --- a/common/payouts.ts +++ b/common/payouts.ts @@ -1,4 +1,5 @@ import { Bet } from './bet' +import { getProbability } from './calculate' import { Contract } from './contract' import { CREATOR_FEE, FEES } from './fees' @@ -58,8 +59,7 @@ export const getMktPayouts = ( contract: Contract, bets: Bet[] ) => { - const p = - contract.pool.YES ** 2 / (contract.pool.YES ** 2 + contract.pool.NO ** 2) + const p = getProbability(contract.totalShares) console.log('Resolved MKT at p=', p, 'pool: $M', truePool) const [yesBets, noBets] = partition(bets, (bet) => bet.outcome === 'YES') diff --git a/common/sell-bet.ts b/common/sell-bet.ts index 8aa2a709..eeeed355 100644 --- a/common/sell-bet.ts +++ b/common/sell-bet.ts @@ -1,6 +1,7 @@ import { Bet } from './bet' +import { calculateShareValue, getProbability } from './calculate' import { Contract } from './contract' -import { CREATOR_FEE, PLATFORM_FEE } from './fees' +import { CREATOR_FEE, FEES } from './fees' import { User } from './user' export const getSellBetInfo = ( @@ -12,40 +13,10 @@ export const getSellBetInfo = ( const { id: betId, amount, shares, outcome } = bet const { YES: yesPool, NO: noPool } = contract.pool - const { YES: yesStart, NO: noStart } = contract.startPool const { YES: yesShares, NO: noShares } = contract.totalShares const { YES: yesBets, NO: noBets } = contract.totalBets - const [y, n, s] = [yesPool, noPool, shares] - - const shareValue = - outcome === 'YES' - ? // https://www.wolframalpha.com/input/?i=b+%2B+%28b+n%5E2%29%2F%28y+%28-b+%2B+y%29%29+%3D+c+solve+b - (n ** 2 + - s * y + - y ** 2 - - Math.sqrt( - n ** 4 + (s - y) ** 2 * y ** 2 + 2 * n ** 2 * y * (s + y) - )) / - (2 * y) - : (y ** 2 + - s * n + - n ** 2 - - Math.sqrt( - y ** 4 + (s - n) ** 2 * n ** 2 + 2 * y ** 2 * n * (s + n) - )) / - (2 * n) - - const startPool = yesStart + noStart - const pool = yesPool + noPool - startPool - - const probBefore = yesPool ** 2 / (yesPool ** 2 + noPool ** 2) - - const f = pool / (probBefore * yesShares + (1 - probBefore) * noShares) - - const myPool = outcome === 'YES' ? yesPool - yesStart : noPool - noStart - - const adjShareValue = Math.min(Math.min(1, f) * shareValue, myPool) + const adjShareValue = calculateShareValue(contract, bet) const newPool = outcome === 'YES' @@ -62,10 +33,11 @@ export const getSellBetInfo = ( ? { YES: yesBets - amount, NO: noBets } : { YES: yesBets, NO: noBets - amount } - const probAfter = newPool.YES ** 2 / (newPool.YES ** 2 + newPool.NO ** 2) + const probBefore = getProbability(contract.totalShares) + const probAfter = getProbability(newTotalShares) const creatorFee = CREATOR_FEE * adjShareValue - const saleAmount = (1 - CREATOR_FEE - PLATFORM_FEE) * adjShareValue + const saleAmount = (1 - FEES) * adjShareValue console.log( 'SELL M$', @@ -73,8 +45,6 @@ export const getSellBetInfo = ( outcome, 'for M$', saleAmount, - 'M$/share:', - f, 'creator fee: M$', creatorFee ) diff --git a/functions/src/resolve-market.ts b/functions/src/resolve-market.ts index 8fdbe470..b9d2931e 100644 --- a/functions/src/resolve-market.ts +++ b/functions/src/resolve-market.ts @@ -61,8 +61,7 @@ export const resolveMarket = functions const bets = betsSnap.docs.map((doc) => doc.data() as Bet) const openBets = bets.filter((b) => !b.isSold && !b.sale) - const startPool = contract.startPool.YES + contract.startPool.NO - const truePool = contract.pool.YES + contract.pool.NO - startPool + const truePool = contract.pool.YES + contract.pool.NO const payouts = outcome === 'CANCEL' diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index 7a91e9da..c94f8d9c 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -94,7 +94,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) { const initialProb = getProbability(contract.pool) const resultProb = getProbabilityAfterBet( - contract.pool, + contract.totalShares, betChoice, betAmount ?? 0 )