Graph bets by afterProb.

This commit is contained in:
jahooma 2021-12-12 16:14:52 -06:00
parent e34f1dbcc9
commit b216236503
6 changed files with 102 additions and 57 deletions

View File

@ -64,7 +64,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) {
return (
<Col
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
)}
>

View File

@ -1,51 +1,22 @@
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 { Col } from './layout/col'
import { Row } from './layout/row'
import { Spacer } from './layout/spacer'
import { formatWithCommas } from '../lib/util/format'
import { ContractProbGraph } from './contract-prob-graph'
// Auto import doesn't work for some reason...
// So we manually register ChartJS components instead:
Chart.register(
CategoryScale,
LinearScale,
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
export const ContractOverview = (props: {
contract: Contract
className?: string
}) => {
const { contract, className } = props
const { pot, seedAmounts } = contract
const volume = pot.YES + pot.NO - seedAmounts.YES - seedAmounts.NO
return (
<Col className="max-w-3xl w-full">
<Col className={className}>
<div className="text-3xl font-medium p-2">{contract.question}</div>
<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="p-2 whitespace-nowrap">Dec 9</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>
<Spacer h={4} />
<Line data={chartData} height={150} />
<ContractProbGraph contract={contract} />
<Spacer h={12} />

View 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
View 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
}

View File

@ -1,22 +1,32 @@
import { doc, setDoc } from 'firebase/firestore'
import { collection, onSnapshot } from 'firebase/firestore'
import { db } from './init'
export type Bet = {
id: string
userId: string
contractId: string
amount: number // Amount of USD bid
amount: number // Amount of bet
outcome: 'YES' | 'NO' // Chosen outcome
// Calculate and replace these on server?
createdTime: number
dpmWeight: number // Dynamic Parimutuel weight
probBefore: number
probAverage: number
probAfter: number
createdTime: number
}
// Push bet to Firestore
// TODO: Should bets be subcollections under its contract?
export async function saveBet(bet: Bet) {
const docRef = doc(db, 'contracts', bet.contractId, 'bets', bet.id)
await setDoc(docRef, bet)
function getBetsCollection(contractId: string) {
return collection(db, 'contracts', contractId, 'bets')
}
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)
})
}

View File

@ -24,15 +24,13 @@ export default function ContractPage() {
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<Header />
<div className="w-full flex flex-col p-4 mt-4">
<Col className="md:justify-between md:flex-row">
<ContractOverview contract={contract} />
<Col className="w-full md:justify-between md:flex-row p-4 mt-4">
<ContractOverview contract={contract} className="max-w-4xl w-full" />
<div className="mt-12 md:mt-0" />
<BetPanel className="self-start" contract={contract} />
</Col>
</div>
</div>
)
}