interface Bet { who: string; outcome: number; // 1 for A, 2 for B shares: number; // Number of shares allocated money: number; // Money placed for given shares } interface Pool { initialMoney: number; // Initial pool initialProb: number; // Initial probability bets: Bet[]; } function initPool(money: number, prob: number): Pool { return { initialMoney: money, initialProb: prob, bets: [], }; } function sum(nums: number[]) { return nums.reduce((p, c) => p + c, 0); } function poolInfo(pool: Pool): any { const result: any = { poolSize: pool.initialMoney + sum(pool.bets.map((b) => b.money)), moneyOnA: pool.initialMoney * pool.initialProb + sum(pool.bets.filter((b) => b.outcome === 1).map((b) => b.money)), moneyOnB: pool.initialMoney * (1 - pool.initialProb) + sum(pool.bets.filter((b) => b.outcome === 2).map((b) => b.money)), sharesOfA: 1 + sum(pool.bets.filter((b) => b.outcome === 1).map((b) => b.shares)), sharesOfB: 1 + sum(pool.bets.filter((b) => b.outcome === 2).map((b) => b.shares)), }; result.totalMoney = result.moneyOnA + result.moneyOnB; result.impliedProb = result.moneyOnA / result.totalMoney; result.bets = pool.bets.map((b) => { let profitOnWin = b.shares * (b.outcome === 1 ? result.moneyOnB / result.sharesOfA : result.moneyOnA / result.sharesOfB); return { ...b, profitOnWin, returnOnWin: b.money + profitOnWin, betIPForChosenOutcome: b.money / (b.money + profitOnWin), }; }); return result; } function bet(pool: Pool, who: string, outcome: number, money: number) { const pi = poolInfo(pool); const moneyOnOutcome = outcome === 1 ? pi.moneyOnA : pi.moneyOnB; const sharesOfOther = outcome === 1 ? pi.sharesOfB : pi.sharesOfA; const shares = Math.log(money / moneyOnOutcome + 1) * sharesOfOther; pool.bets.push({ who, money, shares, outcome, }); } const pool = initPool(100, 0.6); for (let i = 0; i < 10; i++) { bet(pool, "player" +i, Math.ceil(Math.random() * 2), Math.ceil(Math.random() * 20)); } console.log(poolInfo(pool));