Simple dpm (#46)

* simpler payout mechanism; lower phantom ante to $1

* deductFees

* reduce phantom ante to 0.01

* PHANTOM_ANTE = 0.001

* payouts: pay back winner losses with fees

* simplify payouts
This commit is contained in:
mantikoros 2022-02-12 19:19:17 -06:00 committed by GitHub
parent 2d66be5208
commit e2de257372
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 125 deletions

View File

@ -3,7 +3,7 @@ import { getProbability } from './calculate'
import { Contract } from './contract' import { Contract } from './contract'
import { User } from './user' import { User } from './user'
export const PHANTOM_ANTE = 100 export const PHANTOM_ANTE = 0.001
export const MINIMUM_ANTE = 10 export const MINIMUM_ANTE = 10
export const calcStartPool = (initialProbInt: number, ante = 0) => { export const calcStartPool = (initialProbInt: number, ante = 0) => {

View File

@ -133,19 +133,15 @@ export function calculateStandardPayout(
const { amount, outcome: betOutcome, shares } = bet const { amount, outcome: betOutcome, shares } = bet
if (betOutcome !== outcome) return 0 if (betOutcome !== outcome) return 0
const { totalShares, totalBets, phantomShares } = contract const { totalShares, phantomShares } = contract
if (totalShares[outcome] === 0) return 0 if (totalShares[outcome] === 0) return 0
const truePool = contract.pool.YES + contract.pool.NO const pool = contract.pool.YES + contract.pool.NO
const total = totalShares[outcome] - phantomShares[outcome]
if (totalBets[outcome] >= truePool) const winnings = (shares / total) * pool
return (amount / totalBets[outcome]) * truePool // profit can be negative if using phantom shares
return amount + (1 - FEES) * Math.max(0, winnings - amount)
const total =
totalShares[outcome] - phantomShares[outcome] - totalBets[outcome]
const winningsPool = truePool - totalBets[outcome]
return amount + (1 - FEES) * ((shares - amount) / total) * winningsPool
} }
export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) { export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) {
@ -179,35 +175,18 @@ function calculateMktPayout(contract: Contract, bet: Bet) {
? contract.resolutionProbability ? contract.resolutionProbability
: getProbability(contract.totalShares) : getProbability(contract.totalShares)
const weightedTotal = const pool = contract.pool.YES + contract.pool.NO
p * contract.totalBets.YES + (1 - p) * contract.totalBets.NO
const truePool = contract.pool.YES + contract.pool.NO
const betP = bet.outcome === 'YES' ? p : 1 - p
if (weightedTotal >= truePool) {
return ((betP * bet.amount) / weightedTotal) * truePool
}
const winningsPool = truePool - weightedTotal
const weightedShareTotal = const weightedShareTotal =
p * p * (contract.totalShares.YES - contract.phantomShares.YES) +
(contract.totalShares.YES - (1 - p) * (contract.totalShares.NO - contract.phantomShares.NO)
contract.phantomShares.YES -
contract.totalBets.YES) +
(1 - p) *
(contract.totalShares.NO -
contract.phantomShares.NO -
contract.totalBets.NO)
return ( const { outcome, amount, shares } = bet
betP * bet.amount +
(1 - FEES) * const betP = outcome === 'YES' ? p : 1 - p
((betP * (bet.shares - bet.amount)) / weightedShareTotal) * const winnings = ((betP * shares) / weightedShareTotal) * pool
winningsPool
) return deductFees(amount, winnings)
} }
export function resolvedPayout(contract: Contract, bet: Bet) { export function resolvedPayout(contract: Contract, bet: Bet) {
@ -224,3 +203,9 @@ export function currentValue(contract: Contract, bet: Bet) {
return prob * yesPayout + (1 - prob) * noPayout return prob * yesPayout + (1 - prob) * noPayout
} }
export const deductFees = (betAmount: number, winnings: number) => {
return winnings > betAmount
? betAmount + (1 - FEES) * (winnings - betAmount)
: winnings
}

View File

@ -1,5 +1,7 @@
import * as _ from 'lodash'
import { Bet } from './bet' import { Bet } from './bet'
import { getProbability } from './calculate' import { deductFees, getProbability } from './calculate'
import { Contract, outcome } from './contract' import { Contract, outcome } from './contract'
import { CREATOR_FEE, FEES } from './fees' import { CREATOR_FEE, FEES } from './fees'
@ -8,7 +10,7 @@ export const getCancelPayouts = (contract: Contract, bets: Bet[]) => {
const poolTotal = pool.YES + pool.NO const poolTotal = pool.YES + pool.NO
console.log('resolved N/A, pool M$', poolTotal) console.log('resolved N/A, pool M$', poolTotal)
const betSum = sumBy(bets, (b) => b.amount) const betSum = _.sumBy(bets, (b) => b.amount)
return bets.map((bet) => ({ return bets.map((bet) => ({
userId: bet.userId, userId: bet.userId,
@ -21,42 +23,38 @@ export const getStandardPayouts = (
contract: Contract, contract: Contract,
bets: Bet[] bets: Bet[]
) => { ) => {
const [yesBets, noBets] = partition(bets, (bet) => bet.outcome === 'YES') const [yesBets, noBets] = _.partition(bets, (bet) => bet.outcome === 'YES')
const winningBets = outcome === 'YES' ? yesBets : noBets const winningBets = outcome === 'YES' ? yesBets : noBets
const betSum = sumBy(winningBets, (b) => b.amount) const pool = contract.pool.YES + contract.pool.NO
const totalShares = _.sumBy(winningBets, (b) => b.shares)
const poolTotal = contract.pool.YES + contract.pool.NO const payouts = winningBets.map(({ userId, amount, shares }) => {
const winnings = (shares / totalShares) * pool
const profit = winnings - amount
if (betSum >= poolTotal) return getCancelPayouts(contract, winningBets) // profit can be negative if using phantom shares
const payout = amount + (1 - FEES) * Math.max(0, profit)
return { userId, profit, payout }
})
const shareDifferenceSum = sumBy(winningBets, (b) => b.shares - b.amount) const profits = _.sumBy(payouts, (po) => Math.max(0, po.profit))
const creatorPayout = CREATOR_FEE * profits
const winningsPool = poolTotal - betSum
const winnerPayouts = winningBets.map((bet) => ({
userId: bet.userId,
payout:
bet.amount +
(1 - FEES) *
((bet.shares - bet.amount) / shareDifferenceSum) *
winningsPool,
}))
const creatorPayout = CREATOR_FEE * winningsPool
console.log( console.log(
'resolved', 'resolved',
outcome, outcome,
'pool: M$', 'pool',
poolTotal, pool,
'creator fee: M$', 'profits',
profits,
'creator fee',
creatorPayout creatorPayout
) )
return winnerPayouts.concat([ return payouts
{ userId: contract.creatorId, payout: creatorPayout }, .map(({ userId, payout }) => ({ userId, payout }))
]) // add creator fee .concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
} }
export const getMktPayouts = ( export const getMktPayouts = (
@ -69,56 +67,37 @@ export const getMktPayouts = (
? getProbability(contract.totalShares) ? getProbability(contract.totalShares)
: resolutionProbability : resolutionProbability
const poolTotal = contract.pool.YES + contract.pool.NO const weightedShareTotal = _.sumBy(bets, (b) =>
console.log('Resolved MKT at p=', p, 'pool: $M', poolTotal) b.outcome === 'YES' ? p * b.shares : (1 - p) * b.shares
)
const [yesBets, noBets] = partition(bets, (bet) => bet.outcome === 'YES') const pool = contract.pool.YES + contract.pool.NO
const weightedBetTotal = const payouts = bets.map(({ userId, outcome, amount, shares }) => {
p * sumBy(yesBets, (b) => b.amount) + const betP = outcome === 'YES' ? p : 1 - p
(1 - p) * sumBy(noBets, (b) => b.amount) const winnings = ((betP * shares) / weightedShareTotal) * pool
const profit = winnings - amount
const payout = deductFees(amount, winnings)
return { userId, profit, payout }
})
if (weightedBetTotal >= poolTotal) { const profits = _.sumBy(payouts, (po) => Math.max(0, po.profit))
return bets.map((bet) => ({ const creatorPayout = CREATOR_FEE * profits
userId: bet.userId,
payout:
(((bet.outcome === 'YES' ? p : 1 - p) * bet.amount) /
weightedBetTotal) *
poolTotal,
}))
}
const winningsPool = poolTotal - weightedBetTotal console.log(
'resolved MKT',
p,
'pool',
pool,
'profits',
profits,
'creator fee',
creatorPayout
)
const weightedShareTotal = return payouts
p * sumBy(yesBets, (b) => b.shares - b.amount) + .map(({ userId, payout }) => ({ userId, payout }))
(1 - p) * sumBy(noBets, (b) => b.shares - b.amount) .concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
const yesPayouts = yesBets.map((bet) => ({
userId: bet.userId,
payout:
p * bet.amount +
(1 - FEES) *
((p * (bet.shares - bet.amount)) / weightedShareTotal) *
winningsPool,
}))
const noPayouts = noBets.map((bet) => ({
userId: bet.userId,
payout:
(1 - p) * bet.amount +
(1 - FEES) *
(((1 - p) * (bet.shares - bet.amount)) / weightedShareTotal) *
winningsPool,
}))
const creatorPayout = CREATOR_FEE * winningsPool
return [
...yesPayouts,
...noPayouts,
{ userId: contract.creatorId, payout: creatorPayout },
]
} }
export const getPayouts = ( export const getPayouts = (
@ -137,20 +116,3 @@ export const getPayouts = (
return getCancelPayouts(contract, bets) return getCancelPayouts(contract, bets)
} }
} }
const partition = <T>(array: T[], f: (t: T) => boolean) => {
const yes = []
const no = []
for (let t of array) {
if (f(t)) yes.push(t)
else no.push(t)
}
return [yes, no] as [T[], T[]]
}
const sumBy = <T>(array: T[], f: (t: T) => number) => {
const values = array.map(f)
return values.reduce((prev, cur) => prev + cur, 0)
}