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