diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx
index 4f934290..d17f02da 100644
--- a/web/components/bet-panel.tsx
+++ b/web/components/bet-panel.tsx
@@ -14,7 +14,7 @@ import {
getProbability,
calculateShares,
getProbabilityAfterBet,
-} from '../lib/calculation/contract'
+} from '../lib/calculate'
import { firebaseLogin } from '../lib/firebase/users'
export function BetPanel(props: { contract: Contract; className?: string }) {
diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx
index 3a977363..dab70bb0 100644
--- a/web/components/bets-list.tsx
+++ b/web/components/bets-list.tsx
@@ -13,11 +13,13 @@ import { Row } from './layout/row'
import { UserLink } from './user-page'
import {
calculatePayout,
+ calculateSaleAmount,
currentValue,
resolvedPayout,
-} from '../lib/calculation/contract'
+} from '../lib/calculate'
import clsx from 'clsx'
import { cloudFunction } from '../lib/firebase/api-call'
+import { ConfirmationButton } from './confirmation-button'
export function BetsList(props: { user: User }) {
const { user } = props
@@ -229,6 +231,11 @@ export function ContractBetsTable(props: {
}) {
const { contract, bets, className } = props
+ const [sales, buys] = _.partition(bets, (bet) => bet.sale)
+ const salesDict = _.fromPairs(
+ sales.map((sale) => [sale.sale?.betId ?? '', sale])
+ )
+
const { isResolved } = contract
return (
@@ -238,16 +245,21 @@ export function ContractBetsTable(props: {
Date |
Outcome |
- Bet |
+ Amount |
Probability |
{!isResolved && Est. max payout | }
{isResolved ? <>Payout> : <>Current value>} |
- {!isResolved && | }
+ |
- {bets.map((bet) => (
-
+ {buys.map((bet) => (
+
))}
@@ -255,8 +267,8 @@ export function ContractBetsTable(props: {
)
}
-function BetRow(props: { bet: Bet; contract: Contract }) {
- const { bet, contract } = props
+function BetRow(props: { bet: Bet; contract: Contract; sale?: Bet }) {
+ const { bet, sale, contract } = props
const {
amount,
outcome,
@@ -264,14 +276,13 @@ function BetRow(props: { bet: Bet; contract: Contract }) {
probBefore,
probAfter,
shares,
- sale,
isSold,
} = bet
const { isResolved } = contract
return (
- {dayjs(createdTime).format('MMM D, H:mma')} |
+ {dayjs(createdTime).format('MMM D, h:mma')} |
|
@@ -281,25 +292,39 @@ function BetRow(props: { bet: Bet; contract: Contract }) {
{!isResolved && {formatMoney(shares)} | }
- {formatMoney(
- isResolved
- ? resolvedPayout(contract, bet)
- : currentValue(contract, bet)
- )}
+ {bet.isSold
+ ? 'N/A'
+ : formatMoney(
+ isResolved
+ ? resolvedPayout(contract, bet)
+ : bet.sale
+ ? bet.sale.amount ?? 0
+ : currentValue(contract, bet)
+ )}
|
- {!isResolved && !sale && !isSold && (
-
-
- |
+ {sale ? (
+ SOLD for {formatMoney(Math.abs(sale.amount))} |
+ ) : (
+ !isResolved &&
+ !isSold && (
+
+ {
+ await sellBet({ contractId: contract.id, betId: bet.id })
+ }}
+ >
+ Sell
+
+ Do you want to sell your {formatMoney(bet.amount)} bet for{' '}
+ {formatMoney(calculateSaleAmount(contract, bet))}?
+
+
+ |
+ )
)}
)
diff --git a/web/lib/calculation/contract.ts b/web/lib/calculate.ts
similarity index 53%
rename from web/lib/calculation/contract.ts
rename to web/lib/calculate.ts
index 869c1c8f..cb4b6163 100644
--- a/web/lib/calculation/contract.ts
+++ b/web/lib/calculate.ts
@@ -1,5 +1,5 @@
-import { Bet } from '../firebase/bets'
-import { Contract } from '../firebase/contracts'
+import { Bet } from './firebase/bets'
+import { Contract } from './firebase/contracts'
const fees = 0.02
@@ -44,16 +44,24 @@ export function calculatePayout(
if (outcome === 'CANCEL') return amount
if (betOutcome !== outcome) return 0
- let { totalShares } = contract
+ const { totalShares } = contract
- // Fake data if not set.
- // if (!totalShares) totalShares = { YES: 100, NO: 100 }
+ if (totalShares[outcome] === 0) return 0
const startPool = contract.startPool.YES + contract.startPool.NO
const pool = contract.pool.YES + contract.pool.NO - startPool
+ console.log(
+ 'calcPayout',
+ 'shares',
+ shares,
+ 'totalShares',
+ totalShares,
+ 'pool'
+ )
return (1 - fees) * (shares / totalShares[outcome]) * pool
}
+
export function resolvedPayout(contract: Contract, bet: Bet) {
if (contract.resolution)
return calculatePayout(contract, bet, contract.resolution)
@@ -65,5 +73,51 @@ export function currentValue(contract: Contract, bet: Bet) {
const yesPayout = calculatePayout(contract, bet, 'YES')
const noPayout = calculatePayout(contract, bet, 'NO')
+ console.log('calculate value', {
+ prob,
+ yesPayout,
+ noPayout,
+ amount: bet.amount,
+ })
+
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 f = outcome === 'YES' ? pool / yesShares : pool / 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
+}