Graph bets by afterProb.
This commit is contained in:
parent
e34f1dbcc9
commit
b216236503
|
@ -64,7 +64,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
|
||||||
return (
|
return (
|
||||||
<Col
|
<Col
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'bg-gray-200 shadow-xl px-8 py-6 rounded w-full md:w-auto',
|
'bg-gray-200 shadow-xl px-8 py-6 rounded-md w-full md:w-auto',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,51 +1,22 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Line } from 'react-chartjs-2'
|
|
||||||
import {
|
|
||||||
CategoryScale,
|
|
||||||
Chart,
|
|
||||||
LinearScale,
|
|
||||||
PointElement,
|
|
||||||
LineElement,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
} from 'chart.js'
|
|
||||||
import { Contract } from '../lib/firebase/contracts'
|
import { Contract } from '../lib/firebase/contracts'
|
||||||
import { Col } from './layout/col'
|
import { Col } from './layout/col'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { Spacer } from './layout/spacer'
|
import { Spacer } from './layout/spacer'
|
||||||
import { formatWithCommas } from '../lib/util/format'
|
import { formatWithCommas } from '../lib/util/format'
|
||||||
|
import { ContractProbGraph } from './contract-prob-graph'
|
||||||
|
|
||||||
// Auto import doesn't work for some reason...
|
export const ContractOverview = (props: {
|
||||||
// So we manually register ChartJS components instead:
|
contract: Contract
|
||||||
Chart.register(
|
className?: string
|
||||||
CategoryScale,
|
}) => {
|
||||||
LinearScale,
|
const { contract, className } = props
|
||||||
PointElement,
|
|
||||||
LineElement,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
Legend
|
|
||||||
)
|
|
||||||
const chartData = {
|
|
||||||
labels: Array.from({ length: 0 }, (_, i) => i + 1),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: 'Implied probability',
|
|
||||||
data: [],
|
|
||||||
borderColor: 'rgb(75, 192, 192)',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ContractOverview = (props: { contract: Contract }) => {
|
|
||||||
const { contract } = props
|
|
||||||
const { pot, seedAmounts } = contract
|
const { pot, seedAmounts } = contract
|
||||||
|
|
||||||
const volume = pot.YES + pot.NO - seedAmounts.YES - seedAmounts.NO
|
const volume = pot.YES + pot.NO - seedAmounts.YES - seedAmounts.NO
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className="max-w-3xl w-full">
|
<Col className={className}>
|
||||||
<div className="text-3xl font-medium p-2">{contract.question}</div>
|
<div className="text-3xl font-medium p-2">{contract.question}</div>
|
||||||
|
|
||||||
<Row className="flex-wrap text-sm text-gray-600">
|
<Row className="flex-wrap text-sm text-gray-600">
|
||||||
|
@ -53,12 +24,14 @@ export const ContractOverview = (props: { contract: Contract }) => {
|
||||||
<div className="py-2">•</div>
|
<div className="py-2">•</div>
|
||||||
<div className="p-2 whitespace-nowrap">Dec 9</div>
|
<div className="p-2 whitespace-nowrap">Dec 9</div>
|
||||||
<div className="py-2">•</div>
|
<div className="py-2">•</div>
|
||||||
<div className="p-2 whitespace-nowrap">{formatWithCommas(volume)} volume</div>
|
<div className="p-2 whitespace-nowrap">
|
||||||
|
{formatWithCommas(volume)} volume
|
||||||
|
</div>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Spacer h={4} />
|
<Spacer h={4} />
|
||||||
|
|
||||||
<Line data={chartData} height={150} />
|
<ContractProbGraph contract={contract} />
|
||||||
|
|
||||||
<Spacer h={12} />
|
<Spacer h={12} />
|
||||||
|
|
||||||
|
|
52
web/components/contract-prob-graph.tsx
Normal file
52
web/components/contract-prob-graph.tsx
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { Line } from 'react-chartjs-2'
|
||||||
|
import {
|
||||||
|
CategoryScale,
|
||||||
|
Chart,
|
||||||
|
LinearScale,
|
||||||
|
PointElement,
|
||||||
|
LineElement,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
} from 'chart.js'
|
||||||
|
|
||||||
|
import { useBets } from '../hooks/use-bets'
|
||||||
|
import { Contract } from '../lib/firebase/contracts'
|
||||||
|
|
||||||
|
// Auto import doesn't work for some reason...
|
||||||
|
// So we manually register ChartJS components instead:
|
||||||
|
Chart.register(
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
PointElement,
|
||||||
|
LineElement,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend
|
||||||
|
)
|
||||||
|
|
||||||
|
export function ContractProbGraph(props: { contract: Contract }) {
|
||||||
|
const { contract } = props
|
||||||
|
const { id, seedAmounts } = contract
|
||||||
|
|
||||||
|
let bets = useBets(id)
|
||||||
|
if (bets === 'loading') bets = []
|
||||||
|
|
||||||
|
const seedProb =
|
||||||
|
seedAmounts.YES ** 2 / (seedAmounts.YES ** 2 + seedAmounts.NO ** 2)
|
||||||
|
|
||||||
|
const probs = [seedProb, ...bets.map((bet) => bet.probAfter)]
|
||||||
|
|
||||||
|
const chartData = {
|
||||||
|
labels: Array.from({ length: probs.length }, (_, i) => i + 1),
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Implied probability',
|
||||||
|
data: probs,
|
||||||
|
borderColor: 'rgb(75, 192, 192)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Line data={chartData} height={150} />
|
||||||
|
}
|
12
web/hooks/use-bets.ts
Normal file
12
web/hooks/use-bets.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { Bet, listenForBets } from '../lib/firebase/bets'
|
||||||
|
|
||||||
|
export const useBets = (contractId: string) => {
|
||||||
|
const [bets, setBets] = useState<Bet[] | 'loading'>('loading')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (contractId) return listenForBets(contractId, setBets)
|
||||||
|
}, [contractId])
|
||||||
|
|
||||||
|
return bets
|
||||||
|
}
|
|
@ -1,22 +1,32 @@
|
||||||
import { doc, setDoc } from 'firebase/firestore'
|
import { collection, onSnapshot } from 'firebase/firestore'
|
||||||
import { db } from './init'
|
import { db } from './init'
|
||||||
|
|
||||||
export type Bet = {
|
export type Bet = {
|
||||||
id: string
|
id: string
|
||||||
userId: string
|
userId: string
|
||||||
contractId: string
|
contractId: string
|
||||||
|
amount: number // Amount of bet
|
||||||
amount: number // Amount of USD bid
|
|
||||||
outcome: 'YES' | 'NO' // Chosen outcome
|
outcome: 'YES' | 'NO' // Chosen outcome
|
||||||
|
|
||||||
// Calculate and replace these on server?
|
|
||||||
createdTime: number
|
|
||||||
dpmWeight: number // Dynamic Parimutuel weight
|
dpmWeight: number // Dynamic Parimutuel weight
|
||||||
|
probBefore: number
|
||||||
|
probAverage: number
|
||||||
|
probAfter: number
|
||||||
|
createdTime: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push bet to Firestore
|
function getBetsCollection(contractId: string) {
|
||||||
// TODO: Should bets be subcollections under its contract?
|
return collection(db, 'contracts', contractId, 'bets')
|
||||||
export async function saveBet(bet: Bet) {
|
}
|
||||||
const docRef = doc(db, 'contracts', bet.contractId, 'bets', bet.id)
|
|
||||||
await setDoc(docRef, bet)
|
export function listenForBets(
|
||||||
|
contractId: string,
|
||||||
|
setBets: (bets: Bet[]) => void
|
||||||
|
) {
|
||||||
|
return onSnapshot(getBetsCollection(contractId), (snap) => {
|
||||||
|
const bets = snap.docs.map((doc) => doc.data() as Bet)
|
||||||
|
|
||||||
|
bets.sort((bet1, bet2) => bet1.createdTime - bet2.createdTime)
|
||||||
|
|
||||||
|
setBets(bets)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,13 @@ export default function ContractPage() {
|
||||||
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<div className="w-full flex flex-col p-4 mt-4">
|
<Col className="w-full md:justify-between md:flex-row p-4 mt-4">
|
||||||
<Col className="md:justify-between md:flex-row">
|
<ContractOverview contract={contract} className="max-w-4xl w-full" />
|
||||||
<ContractOverview contract={contract} />
|
|
||||||
|
|
||||||
<div className="mt-12 md:mt-0" />
|
<div className="mt-12 md:mt-0" />
|
||||||
|
|
||||||
<BetPanel className="self-start" contract={contract} />
|
<BetPanel className="self-start" contract={contract} />
|
||||||
</Col>
|
</Col>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user