Fill in more of placebet

This commit is contained in:
James Grugett 2022-06-28 19:24:09 -05:00
parent 53e2ff7327
commit fe0b26669a
2 changed files with 104 additions and 35 deletions

View File

@ -37,17 +37,19 @@ export type BetInfo = {
const computeFill = ( const computeFill = (
betAmount: number, betAmount: number,
outcome: 'YES' | 'NO', outcome: 'YES' | 'NO',
limitProb: number, limitProb: number | undefined,
cpmmState: CpmmState, cpmmState: CpmmState,
matchedBet: LimitBet matchedBet: LimitBet
) => { ) => {
const prob = getCpmmProbability(cpmmState.pool, cpmmState.p) const prob = getCpmmProbability(cpmmState.pool, cpmmState.p)
if ( if (
outcome === 'YES' limitProb !== undefined &&
(outcome === 'YES'
? Math.min(prob, matchedBet.limitProb) > limitProb ? Math.min(prob, matchedBet.limitProb) > limitProb
: Math.max(prob, matchedBet.limitProb) < limitProb : Math.max(prob, matchedBet.limitProb) < limitProb)
) { ) {
// No fill.
return undefined return undefined
} }
@ -59,20 +61,19 @@ const computeFill = (
// Fill from pool. // Fill from pool.
const limit = const limit =
outcome === 'YES' outcome === 'YES'
? Math.min(matchedBet.limitProb, limitProb) ? Math.min(matchedBet.limitProb, limitProb ?? Infinity)
: Math.max(matchedBet.limitProb, limitProb) : Math.max(matchedBet.limitProb, limitProb ?? -Infinity)
const amount = calculateCpmmAmount(cpmmState, limit, 'YES') const amount = calculateCpmmAmount(cpmmState, limit, outcome)
const { shares, newPool, newP, fees } = calculateCpmmPurchase( const { shares, newPool, newP, fees } = calculateCpmmPurchase(
cpmmState, cpmmState,
amount, amount,
'YES' outcome
) )
const newState = { pool: newPool, p: newP } const newState = { pool: newPool, p: newP }
return { return {
maker: { maker: {
betId: 'bet',
matchedBetId: null, matchedBetId: null,
shares, shares,
amount, amount,
@ -80,7 +81,6 @@ const computeFill = (
fees, fees,
}, },
taker: { taker: {
betId: 'bet',
matchedBetId: null, matchedBetId: null,
shares, shares,
amount, amount,
@ -88,17 +88,16 @@ const computeFill = (
} }
} }
// Fill from bet. // Fill from matchedBet.
const amount = Math.min(betAmount, matchedBet.amount) const amount = Math.min(betAmount, matchedBet.amount)
const shares = matchedBet.shares * (amount / matchedBet.amount) const shares = matchedBet.shares * (amount / matchedBet.amount)
const maker = { const maker = {
betId: matchedBet.id, bet: matchedBet,
matchedBetId: 'bet', matchedBetId: 'taker',
amount, amount,
shares, shares,
} }
const taker = { const taker = {
betId: 'bet',
matchedBetId: matchedBet.id, matchedBetId: matchedBet.id,
amount, amount,
shares, shares,
@ -106,20 +105,33 @@ const computeFill = (
return { maker, taker } return { maker, taker }
} }
export const getBinaryCpmmLimitBetInfo = ( export const getBinaryCpmmBetInfo = (
outcome: 'YES' | 'NO', outcome: 'YES' | 'NO',
betAmount: number, betAmount: number,
contract: CPMMBinaryContract, contract: CPMMBinaryContract,
limitProb: number, limitProb: number | undefined,
unfilledBets: LimitBet[] // Sorted by limitProb, createdTime unfilledBets: LimitBet[] // Sorted by limitProb, createdTime
) => { ) => {
const fills: LimitBet['fills'] = [] const takers: {
matchedBetId: string | null
amount: number
shares: number
}[] = []
const makers: { bet: LimitBet; amount: number; shares: number }[] = []
let cpmmState = { pool: contract.pool, p: contract.p } let cpmmState = { pool: contract.pool, p: contract.p }
let totalFees = noFees let totalFees = noFees
for (const bet of unfilledBets) { let i = 0
const fill = computeFill(betAmount, outcome, limitProb, cpmmState, bet) while (i < unfilledBets.length) {
const matchedBet = unfilledBets[i]
const fill = computeFill(
betAmount,
outcome,
limitProb,
cpmmState,
matchedBet
)
if (!fill) break if (!fill) break
const { maker, taker } = fill const { maker, taker } = fill
@ -130,12 +142,43 @@ export const getBinaryCpmmLimitBetInfo = (
cpmmState = maker.state cpmmState = maker.state
totalFees = addObjects(totalFees, maker.fees) totalFees = addObjects(totalFees, maker.fees)
} else { } else {
fills.push(maker) makers.push(maker)
i++
} }
fills.push(taker) takers.push(taker)
} }
return { fills, cpmmState, totalFees } const probBefore = getCpmmProbability(contract.pool, contract.p)
const probAfter = getCpmmProbability(cpmmState.pool, cpmmState.p)
const takerAmount = sumBy(takers, 'amount')
const takerShares = sumBy(takers, 'shares')
const isFilled = Math.abs(betAmount - takerAmount) < 0.000000001
const newBet = {
amount: betAmount,
isFilled,
fills: takers,
contractId: contract.id,
shares: takerShares,
outcome,
probBefore,
probAfter,
loanAmount: 0,
createdTime: Date.now(),
fees: totalFees,
}
const { liquidityFee } = totalFees
const newTotalLiquidity = (contract.totalLiquidity ?? 0) + liquidityFee
return {
newBet,
newPool: cpmmState.pool,
newP: cpmmState.p,
newTotalLiquidity,
makers,
}
} }
export const getNewBinaryCpmmBetInfo = ( export const getNewBinaryCpmmBetInfo = (

View File

@ -6,8 +6,7 @@ import { Contract, CPMM_MIN_POOL_QTY } from '../../common/contract'
import { User } from '../../common/user' import { User } from '../../common/user'
import { import {
BetInfo, BetInfo,
getBinaryCpmmLimitBetInfo, getBinaryCpmmBetInfo,
getNewBinaryCpmmBetInfo,
getNewBinaryDpmBetInfo, getNewBinaryDpmBetInfo,
getNewMultiBetInfo, getNewMultiBetInfo,
getNumericBetsInfo, getNumericBetsInfo,
@ -17,6 +16,7 @@ import { redeemShares } from './redeem-shares'
import { log } from './utils' import { log } from './utils'
import { LimitBet } from 'common/bet' import { LimitBet } from 'common/bet'
import { Query } from 'firebase-admin/firestore' import { Query } from 'firebase-admin/firestore'
import { sumBy } from 'lodash'
const bodySchema = z.object({ const bodySchema = z.object({
contractId: z.string(), contractId: z.string(),
@ -70,18 +70,28 @@ export const placebet = newEndpoint(['POST'], async (req, auth) => {
newTotalBets, newTotalBets,
newTotalLiquidity, newTotalLiquidity,
newP, newP,
} = await (async (): Promise<BetInfo> => { makers,
} = await (async (): Promise<
BetInfo & {
makers?: {
bet: LimitBet
amount: number
shares: number
}[]
}
> => {
if (outcomeType == 'BINARY' && mechanism == 'dpm-2') { if (outcomeType == 'BINARY' && mechanism == 'dpm-2') {
const { outcome } = validate(binarySchema, req.body) const { outcome } = validate(binarySchema, req.body)
return getNewBinaryDpmBetInfo(outcome, amount, contract, loanAmount) return getNewBinaryDpmBetInfo(outcome, amount, contract, loanAmount)
} else if (outcomeType == 'BINARY' && mechanism == 'cpmm-1') { } else if (outcomeType == 'BINARY' && mechanism == 'cpmm-1') {
const { outcome, limitProb } = validate(binarySchema, req.body) const { outcome, limitProb } = validate(binarySchema, req.body)
const boundedLimitProb = limitProb ?? (outcome === 'YES' ? 1 : 0)
const unfilledBetsQuery = contractDoc const unfilledBetsQuery = contractDoc
.collection('bets') .collection('bets')
.where('outcome', '==', outcome === 'YES' ? 'NO' : 'YES') .where('outcome', '==', outcome === 'YES' ? 'NO' : 'YES')
.where('isFilled', '==', false) .where('isFilled', '==', false)
.where('isCancelled', '==', false) .where('isCancelled', '==', false)
.where('limitProb', outcome === 'YES' ? '<=' : '>=', limitProb) .where('limitProb', outcome === 'YES' ? '<=' : '>=', boundedLimitProb)
.orderBy('createdTime', 'desc') .orderBy('createdTime', 'desc')
.orderBy( .orderBy(
'limitProb', 'limitProb',
@ -91,16 +101,13 @@ export const placebet = newEndpoint(['POST'], async (req, auth) => {
const unfilledBetsSnap = await trans.get(unfilledBetsQuery) const unfilledBetsSnap = await trans.get(unfilledBetsQuery)
const unfilledBets = unfilledBetsSnap.docs.map((doc) => doc.data()) const unfilledBets = unfilledBetsSnap.docs.map((doc) => doc.data())
if (limitProb !== undefined) { return getBinaryCpmmBetInfo(
getBinaryCpmmLimitBetInfo( outcome,
outcome, amount,
amount, contract,
contract, limitProb,
limitProb, unfilledBets
unfilledBets, )
)
}
return getNewBinaryCpmmBetInfo(outcome, amount, contract, loanAmount)
} else if (outcomeType == 'FREE_RESPONSE' && mechanism == 'dpm-2') { } else if (outcomeType == 'FREE_RESPONSE' && mechanism == 'dpm-2') {
const { outcome } = validate(freeResponseSchema, req.body) const { outcome } = validate(freeResponseSchema, req.body)
const answerDoc = contractDoc.collection('answers').doc(outcome) const answerDoc = contractDoc.collection('answers').doc(outcome)
@ -129,6 +136,25 @@ export const placebet = newEndpoint(['POST'], async (req, auth) => {
const betDoc = contractDoc.collection('bets').doc() const betDoc = contractDoc.collection('bets').doc()
trans.create(betDoc, { id: betDoc.id, userId: user.id, ...newBet }) trans.create(betDoc, { id: betDoc.id, userId: user.id, ...newBet })
log('Created new bet document.') log('Created new bet document.')
if (makers) {
for (const maker of makers) {
const { bet, amount, shares } = maker
const newFill = { amount, shares, matchedBetId: betDoc.id }
const fills = [...bet.fills, newFill]
const totalShares = sumBy(fills, 'shares')
const isFilled =
Math.abs(sumBy(fills, 'amount') - bet.amount) < 0.0000001
log('Updated a matched limit bet.')
trans.update(contractDoc.collection('bets').doc(bet.id), {
fills,
isFilled,
shares: totalShares,
})
}
}
trans.update(userDoc, { balance: newBalance }) trans.update(userDoc, { balance: newBalance })
log('Updated user balance.') log('Updated user balance.')
trans.update( trans.update(