import React, { Fragment, useEffect, useMemo, useState } from 'react' import { CategoryScale, Chart, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, } from 'chart.js' import { ChartData } from 'chart.js' import { Line } from 'react-chartjs-2' import { bids as sampleBids } from './sample-bids' import { Entry, makeEntries } from './entries' // Auto import doesn't work for some reason... // So we manually register ChartJS components instead: Chart.register( CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend ) function toTable(entries: Entry[]) { return entries.map((entry, i) => { return ( {i + 1} {toRowStart(entry)} {toRowEnd(entry)} ) }) } function toRowStart(entry: Entry) { if (entry.yesBid && entry.noBid) { return (
SEED
{entry.yesBid} / {entry.noBid}
) } else if (entry.yesBid) { return (
YES
{entry.yesBid}
) } else if (entry.noBid) { return (
NO
{entry.noBid}
) } } function toRowEnd(entry: Entry | null) { if (!entry) { return ( N/A N/A N/A N/A ) } else if (entry.yesBid && entry.noBid) { return ( N/A {entry.prob.toFixed(2)} N/A N/A ) } else if (entry.yesBid) { return ( {entry.yesWeight.toFixed(2)} {entry.prob.toFixed(2)} {entry.yesPayout.toFixed(2)} {(entry.yesReturn * 100).toFixed(2)}% ) } else { return ( {entry.noWeight.toFixed(2)} {entry.prob.toFixed(2)} {entry.noPayout.toFixed(2)} {(entry.noReturn * 100).toFixed(2)}% ) } } function newBidTable( steps: number, newBid: number, nextEntryElement: JSX.Element, newBidType: String, toggleBidType: () => void, setNewBid: (newBid: number) => void, submitBid: () => void ) { return ( {nextEntryElement}
Order # Type Bid Weight Probability Payout Return
{steps + 1}
YES

NO
setNewBid(parseInt(e.target.value) || 0)} onKeyUp={(e) => { if (e.key === 'Enter') { submitBid() } }} onFocus={(e) => e.target.select()} />
) } // Show a hello world React page export default function Simulator() { const [steps, setSteps] = useState(10) const [bids, setBids] = useState(sampleBids) const entries = useMemo( () => makeEntries(bids.slice(0, steps)), [bids, steps] ) const probs = useMemo(() => entries.map((entry) => entry.prob), [entries]) // Set up chart const [chartData, setChartData] = useState({ datasets: [] } as ChartData) useEffect(() => { setChartData({ labels: Array.from({ length: steps }, (_, i) => i + 1), datasets: [ { label: 'Implied probability', data: probs, borderColor: 'rgb(75, 192, 192)', }, ], }) }, [steps]) // Prepare for new bids const [newBid, setNewBid] = useState(0) const [newBidType, setNewBidType] = useState('YES') function makeBid(type: string, bid: number) { return { yesBid: type == 'YES' ? bid : 0, noBid: type == 'YES' ? 0 : bid, } } function submitBid() { if (newBid <= 0) return const bid = makeBid(newBidType, newBid) bids.splice(steps, 0, bid) setBids(bids) setSteps(steps + 1) setNewBid(0) } function toggleBidType() { setNewBidType(newBidType === 'YES' ? 'NO' : 'YES') } const nextEntry = useMemo(() => { if (newBid) { const nextBid = makeBid(newBidType, newBid) const fakeBids = [...bids.slice(0, steps), nextBid] const entries = makeEntries(fakeBids) return entries[entries.length - 1] } return null }, [newBid, newBidType, entries, steps]) return (
{/* Left column */}

Dynamic Parimutuel Market Simulator

{/* Range slider that sets the current step */} setSteps(parseInt(e.target.value))} /> {/* New bid table */} {newBidTable( steps, newBid, toRowEnd(nextEntry), newBidType, toggleBidType, setNewBid, submitBid )} {/* History of bids */}
{toTable(entries)}
Order # Type Bid Weight Prob Max Payout Return
{/* Right column */}

Probability of
YES

) }