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 ( | ||||
|     <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 | ||||
|       )} | ||||
|     > | ||||
|  |  | |||
|  | @ -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} /> | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										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' | ||||
| 
 | ||||
| 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) | ||||
|   }) | ||||
| } | ||||
|  |  | |||
|  | @ -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" /> | ||||
|         <div className="mt-12 md:mt-0" /> | ||||
| 
 | ||||
|           <BetPanel className="self-start" contract={contract} /> | ||||
|         </Col> | ||||
|       </div> | ||||
|         <BetPanel className="self-start" contract={contract} /> | ||||
|       </Col> | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user