From 5dcd43f5b2fc1833f396fd75d584418778142b85 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Sun, 3 Apr 2022 14:48:53 -0500 Subject: [PATCH] Refactor tricky bet calculations to one function --- common/calculate.ts | 60 +++++++++ web/components/bets-list.tsx | 249 +++++++++++++---------------------- 2 files changed, 149 insertions(+), 160 deletions(-) diff --git a/common/calculate.ts b/common/calculate.ts index f3adf46f..361606e4 100644 --- a/common/calculate.ts +++ b/common/calculate.ts @@ -1,3 +1,4 @@ +import _ from 'lodash' import { Bet } from './bet' import { calculateCpmmSale, @@ -110,3 +111,62 @@ export function resolvedPayout(contract: Contract, bet: Bet) { ? calculateFixedPayout(contract, bet, outcome) : calculateDpmPayout(contract, bet, outcome) } + +export function getContractBetMetrics(contract: Contract, yourBets: Bet[]) { + const { resolution } = contract + + let invested = 0 + let salesInvested = 0 + let payout = 0 + let loan = 0 + let sellProfit = 0 + let redeemed = 0 + + for (const bet of yourBets) { + const { isSold, sale, amount, loanAmount, isRedemption } = bet + if (isSold) { + sellProfit -= amount + salesInvested += amount + } else if (sale) { + sellProfit += sale.amount + } else { + if (isRedemption) { + redeemed += -1 * amount + } else if (amount > 0) { + invested += amount + } + + loan += loanAmount ?? 0 + payout += resolution + ? calculatePayout(contract, bet, resolution) + : calculatePayout(contract, bet, 'MKT') + } + } + + const investedIncludingSales = invested + salesInvested + + const totalValue = payout + sellProfit + redeemed + const profit = totalValue - invested + const profitPercent = (profit / investedIncludingSales) * 100 + const netInvestment = payout - loan + + return { + invested, + payout, + totalValue, + profit, + profitPercent, + netInvestment, + } +} + +export function getContractBetNullMetrics() { + return { + invested: 0, + payout: 0, + totalValue: 0, + profit: 0, + profitPercent: 0, + netInvestment: 0, + } +} diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index 97b7a4a2..81286f06 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -34,7 +34,9 @@ import { getOutcomeProbability, getProbability, getProbabilityAfterSale, + getContractBetMetrics, resolvedPayout, + getContractBetNullMetrics, } from '../../common/calculate' type BetSort = 'newest' | 'profit' | 'resolutionTime' | 'value' | 'closeTime' @@ -76,34 +78,10 @@ export function BetsList(props: { user: User }) { const contractBets = _.groupBy(bets, 'contractId') const contractsById = _.fromPairs(contracts.map((c) => [c.id, c])) - const contractsCurrentValue = _.mapValues( - contractBets, - (bets, contractId) => { - return _.sumBy(bets, (bet) => { - const contract = contractsById[contractId] - if (!contract) return 0 - if (bet.isSold || bet.sale) return 0 - - return contract.resolution - ? calculatePayout(contract, bet, contract.resolution) - : calculatePayout(contract, bet, 'MKT') - }) - } - ) - const contractsInvestment = _.mapValues(contractBets, (bets) => { - return _.sumBy(bets, (bet) => { - if (bet.isSold || bet.sale || bet.isRedemption) return 0 - return bet.amount - }) - }) - - const contractsSaleOrRedemption = _.mapValues(contractBets, (bets) => { - return _.sumBy(bets, (bet) => { - if (bet.isSold) return -1 * bet.amount - if (bet.sale) return bet.sale.amount - if (bet.isRedemption) return -1 * bet.amount - return 0 - }) + const contractsMetrics = _.mapValues(contractBets, (bets, contractId) => { + const contract = contractsById[contractId] + if (!contract) return getContractBetNullMetrics() + return getContractBetMetrics(contract, bets) }) const FILTERS: Record boolean> = { @@ -115,11 +93,8 @@ export function BetsList(props: { user: User }) { // Pepe notes: most users want "settled", to see when their bets or sold; or "realized profit" } const SORTS: Record number> = { - profit: (c) => - contractsCurrentValue[c.id] - - contractsInvestment[c.id] + - contractsSaleOrRedemption[c.id], - value: (c) => contractsCurrentValue[c.id] + contractsSaleOrRedemption[c.id], + profit: (c) => contractsMetrics[c.id].profit, + value: (c) => contractsMetrics[c.id].totalValue, newest: (c) => Math.max(...contractBets[c.id].map((bet) => bet.createdTime)), resolutionTime: (c) => -(c.resolutionTime ?? c.closeTime ?? Infinity), @@ -131,32 +106,28 @@ export function BetsList(props: { user: User }) { const [settled, unsettled] = _.partition( contracts, - (c) => c.isResolved || contractsInvestment[c.id] === 0 + (c) => c.isResolved || contractsMetrics[c.id].invested === 0 ) - const currentInvestment = _.sumBy(unsettled, (c) => contractsInvestment[c.id]) - + const currentInvested = _.sumBy( + unsettled, + (c) => contractsMetrics[c.id].invested + ) const currentBetsValue = _.sumBy( unsettled, - (c) => contractsCurrentValue[c.id] + (c) => contractsMetrics[c.id].payout ) - const currentBetsValueMinusLoans = _.sumBy( + const currentNetInvestment = _.sumBy( unsettled, - (c) => - contractsCurrentValue[c.id] - - // Subtract loans you haven't paid. - _.sumBy(contractBets[c.id], (bet) => { - if (bet.isSold || bet.sale) return 0 - return bet.loanAmount ?? 0 - }) + (c) => contractsMetrics[c.id].netInvestment ) - const totalPortfolio = currentBetsValueMinusLoans + user.balance + const totalPortfolio = currentNetInvestment + user.balance const totalPnl = totalPortfolio - user.totalDeposits const totalProfitPercent = (totalPnl / user.totalDeposits) * 100 const investedProfitPercent = - ((currentBetsValue - currentInvestment) / currentInvestment) * 100 + ((currentBetsValue - currentInvested) / currentInvested) * 100 return ( @@ -165,7 +136,7 @@ export function BetsList(props: { user: User }) {
Investment value
- {formatMoney(currentBetsValueMinusLoans)}{' '} + {formatMoney(currentNetInvestment)}{' '}
@@ -244,6 +215,11 @@ function MyContractBets(props: { const isBinary = outcomeType === 'BINARY' const probPercent = getBinaryProbPercent(contract) + const { totalValue, profit, profitPercent } = getContractBetMetrics( + contract, + bets + ) + return (
- + + +
+ {formatMoney(metric === 'profit' ? profit : totalValue)} +
+
+ +
+ +
!b.isSold && !b.sale) - const excludeRedemptions = bets.filter((b) => !b.isRedemption) - const excludeSalesAndRedemptions = excludeSales.filter((b) => !b.isRedemption) - const betsTotal = _.sumBy(excludeSalesAndRedemptions, (bet) => bet.amount) - const invested = _.sumBy(excludeSalesAndRedemptions, (bet) => - bet.amount > 0 ? bet.amount : 0 - ) - const investedIncludingSales = _.sumBy(excludeRedemptions, (bet) => - bet.amount > 0 ? bet.amount : 0 - ) - const redemptionValue = _.sumBy(bets, (bet) => - bet.isRedemption ? -bet.amount : 0 - ) - - const betsPayout = resolution - ? _.sumBy(excludeSales, (bet) => resolvedPayout(contract, bet)) - : 0 - const yesWinnings = _.sumBy(excludeSales, (bet) => calculatePayout(contract, bet, 'YES') ) const noWinnings = _.sumBy(excludeSales, (bet) => calculatePayout(contract, bet, 'NO') ) - const marketWinnings = _.sumBy(excludeSales, (bet) => - calculatePayout(contract, bet, 'MKT') - ) - const salesWinnings = _.sumBy(bets, (bet) => - bet.isSold ? -bet.amount : bet.sale ? bet.sale.amount : 0 + const { invested, profitPercent, payout } = getContractBetMetrics( + contract, + bets ) - const currentValue = resolution ? betsPayout : marketWinnings - const totalValue = currentValue + redemptionValue + salesWinnings - const pnl = totalValue - betsTotal - const profit = (pnl / investedIncludingSales) * 100 + console.log(getContractBetMetrics(contract, bets)) return ( - - {onlyMetric ? ( - + + + +
+ Invested +
+
{formatMoney(invested)}
+ + {resolution ? ( -
- {formatMoney(onlyMetric === 'profit' ? pnl : totalValue)} -
-
- +
Payout
+
+ {formatMoney(payout)}{' '} +
- - ) : ( - - -
- Invested -
-
{formatMoney(invested)}
- - {resolution ? ( + ) : ( + <> + {isBinary && ( + <> + +
+ Payout if +
+
+ {formatMoney(yesWinnings)} +
+ + +
+ Payout if +
+
+ {formatMoney(noWinnings)} +
+ + + )} -
Payout
-
- {formatMoney(betsPayout)} +
+ {isBinary ? ( + <> + Payout at{' '} + + {formatPercent(getProbability(contract))} + + + ) : ( + <>Current payout + )}
+
{formatMoney(payout)}
- ) : ( - <> - {/* -
- Expectation -
-
- {formatMoney(expectation)} -
- */} - {isBinary && ( - <> - -
- Payout if -
-
- {formatMoney(yesWinnings)} -
- - -
- Payout if -
-
- {formatMoney(noWinnings)} -
- - - )} - -
- {isBinary ? ( - <> - Payout at{' '} - - {formatPercent(getProbability(contract))} - - - ) : ( - <>Current payout - )} -
-
- {formatMoney(marketWinnings)} -
- - - )} - - )} + + )} + ) }