diff --git a/web/lib/simulator/entries.ts b/web/lib/simulator/entries.ts
index 6e3e587f..c280f8e2 100644
--- a/web/lib/simulator/entries.ts
+++ b/web/lib/simulator/entries.ts
@@ -17,16 +17,16 @@ function makeWeights(bids: Bid[]) {
const weights = []
let yesPot = 0
let noPot = 0
+
// First pass: calculate all the weights
for (const { yesBid, noBid } of bids) {
- const yesWeight =
- noPot * (Math.log(yesBid + yesPot) - Math.log(yesPot)) || 0
- const noWeight = yesPot * (Math.log(noBid + noPot) - Math.log(noPot)) || 0
+ const yesWeight = yesBid * Math.pow(noPot, 2) / (Math.pow(yesPot, 2) + yesBid * yesPot) || 0
+ const noWeight = noBid * Math.pow(yesPot, 2) / (Math.pow(noPot, 2) + noBid * noPot) || 0
// Note: Need to calculate weights BEFORE updating pot
yesPot += yesBid
noPot += noBid
- const prob = yesPot / (yesPot + noPot)
+ const prob = Math.pow(yesPot, 2) / (Math.pow(yesPot, 2) + Math.pow(noPot, 2))
weights.push({
yesBid,
@@ -42,13 +42,16 @@ function makeWeights(bids: Bid[]) {
export function makeEntries(bids: Bid[]): Entry[] {
const YES_SEED = bids[0].yesBid
const NO_SEED = bids[0].noBid
+
const weights = makeWeights(bids)
const yesPot = weights.reduce((sum, { yesBid }) => sum + yesBid, 0)
const noPot = weights.reduce((sum, { noBid }) => sum + noBid, 0)
const yesWeightsSum = weights.reduce((sum, entry) => sum + entry.yesWeight, 0)
const noWeightsSum = weights.reduce((sum, entry) => sum + entry.noWeight, 0)
+
// Second pass: calculate all the payouts
const entries: Entry[] = []
+
for (const weight of weights) {
const { yesBid, noBid, yesWeight, noWeight } = weight
// Payout: You get your initial bid back, as well as your share of the
diff --git a/web/pages/simulator/index.tsx b/web/pages/simulator/index.tsx
index 7697f6d6..4b61f40a 100644
--- a/web/pages/simulator/index.tsx
+++ b/web/pages/simulator/index.tsx
@@ -1,4 +1,5 @@
import React, { useEffect, useMemo, useState } from 'react'
+import { Line } from 'react-chartjs-2'
import {
CategoryScale,
Chart,
@@ -9,8 +10,7 @@ import {
Tooltip,
Legend,
} from 'chart.js'
-import { Line } from 'react-chartjs-2'
-import { bids as sampleBids } from '../../lib/simulator/sample-bids'
+
import { Entry, makeEntries } from '../../lib/simulator/entries'
import { Header } from '../../components/header'
@@ -31,7 +31,7 @@ function TableBody(props: { entries: Entry[] }) {
{props.entries.map((entry, i) => (
- {i + 1}
+ {props.entries.length - i}
@@ -46,10 +46,10 @@ function TableRowStart(props: { entry: Entry }) {
return (
<>
- SEED
+ ANTE
- {entry.yesBid} / {entry.noBid}
+ ${entry.yesBid} / ${entry.noBid}
>
)
@@ -59,7 +59,7 @@ function TableRowStart(props: { entry: Entry }) {
YES
- {entry.yesBid}
+ ${entry.yesBid}
>
)
} else {
@@ -68,48 +68,56 @@ function TableRowStart(props: { entry: Entry }) {
NO
- {entry.noBid}
+ ${entry.noBid}
>
)
}
}
-function TableRowEnd(props: { entry: Entry | null }) {
+function TableRowEnd(props: { entry: Entry | null, isNew?: boolean }) {
const { entry } = props
if (!entry) {
return (
<>
- N/A
- N/A
- N/A
- N/A
+ 0
+ 0
+ {!props.isNew && <>
+ N/A
+ N/A
+ >}
>
)
} else if (entry.yesBid && entry.noBid) {
return (
<>
+ {(entry.prob * 100).toFixed(1)}%
N/A
- {entry.prob.toFixed(2)}
- N/A
- N/A
+ {!props.isNew && <>
+ 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)}%
+ {(entry.prob * 100).toFixed(1)}%
+ ${(entry.yesBid + entry.yesWeight).toFixed(0)}
+ {!props.isNew && <>
+ ${entry.yesPayout.toFixed(0)}
+ {(entry.yesReturn * 100).toFixed(0)}%
+ >}
>
)
} else {
return (
<>
- {entry.noWeight.toFixed(2)}
- {entry.prob.toFixed(2)}
- {entry.noPayout.toFixed(2)}
- {(entry.noReturn * 100).toFixed(2)}%
+ {(entry.prob * 100).toFixed(1)}%
+ ${(entry.noBid + entry.noWeight).toFixed(0)}
+ {!props.isNew && <>
+ ${entry.noPayout.toFixed(0)}
+ {(entry.noReturn * 100).toFixed(0)}%
+ >}
>
)
}
@@ -142,30 +150,39 @@ function NewBidTable(props: {
setNewBid(0)
}
+
+
function toggleBidType() {
setNewBidType(newBidType === 'YES' ? 'NO' : 'YES')
}
- let nextEntry: Entry | null = null
+ const nextBid = makeBid(newBidType, newBid)
+ const fakeBids = [...bids.slice(0, steps), nextBid]
+ const entries = makeEntries(fakeBids)
+ const nextEntry = entries[entries.length - 1]
- if (newBid) {
- const nextBid = makeBid(newBidType, newBid)
- const fakeBids = [...bids.slice(0, steps), nextBid]
- const entries = makeEntries(fakeBids)
- nextEntry = entries[entries.length - 1]
+ function randomBid() {
+ const bidType = Math.random() < 0.5
+ ? 'YES'
+ : 'NO'
+ const amount = Math.round(Math.random() * 500)
+ const bid = makeBid(bidType, amount)
+
+ bids.splice(steps, 0, bid)
+ setBids(bids)
+ setSteps(steps + 1)
+ setNewBid(0)
}
- return (
+ return <>
Order #
Type
- Bid
- Weight
+ Bet
Prob
- Payout
- Return
+ Est Payout
@@ -200,7 +217,7 @@ function NewBidTable(props: {
placeholder="0"
className="input input-bordered"
style={{ maxWidth: 100 }}
- value={newBid}
+ value={newBid.toString()}
onChange={(e) => setNewBid(parseInt(e.target.value) || 0)}
onKeyUp={(e) => {
if (e.key === 'Enter') {
@@ -210,7 +227,12 @@ function NewBidTable(props: {
onFocus={(e) => e.target.select()}
/>
-
+
+
+
Submit
+
- )
+
+
+ Random bet!
+
+ >
}
// Show a hello world React page
export default function Simulator() {
- const [steps, setSteps] = useState(10)
- const [bids, setBids] = useState(sampleBids)
+ const [steps, setSteps] = useState(1)
+ const [bids, setBids] = useState([{ yesBid: 600, noBid: 400 }])
const entries = useMemo(
() => makeEntries(bids.slice(0, steps)),
[bids, steps]
)
+
+ const reversedEntries = [...entries].reverse()
+
const probs = entries.map((entry) => entry.prob)
const chartData = {
- labels: Array.from({ length: steps }, (_, i) => i + 1),
+ labels: Array.from({ length: steps }, (_, i) => 1 + i),
datasets: [
{
label: 'Implied probability',
@@ -257,16 +290,7 @@ export default function Simulator() {
Dynamic Parimutuel Market Simulator
- {/* Range slider that sets the current step */}
- Simulation step: {steps}
- setSteps(parseInt(e.target.value))}
- />
+
@@ -277,15 +301,15 @@ export default function Simulator() {
Order #
Type
- Bid
- Weight
+ Bet
Prob
- Max Payout
+ Est Payout
+ Payout
Return
-
+
@@ -297,6 +321,16 @@ export default function Simulator() {
YES
+ {/* Range slider that sets the current step */}
+ Orders # 1 - {steps}
+ setSteps(parseInt(e.target.value))}
+ />