diff --git a/web/pages/simulator/entries.ts b/web/lib/simulator/entries.ts
similarity index 60%
rename from web/pages/simulator/entries.ts
rename to web/lib/simulator/entries.ts
index 6f9103bf..6e3e587f 100644
--- a/web/pages/simulator/entries.ts
+++ b/web/lib/simulator/entries.ts
@@ -13,8 +13,8 @@ export type Entry = {
prob: number
}
-export function makeEntries(bids: Bid[]): Entry[] {
- const entries: Entry[] = []
+function makeWeights(bids: Bid[]) {
+ const weights = []
let yesPot = 0
let noPot = 0
// First pass: calculate all the weights
@@ -28,33 +28,36 @@ export function makeEntries(bids: Bid[]): Entry[] {
noPot += noBid
const prob = yesPot / (yesPot + noPot)
- entries.push({
+ weights.push({
yesBid,
noBid,
yesWeight,
noWeight,
prob,
- // To be filled in below
- yesPayout: 0,
- noPayout: 0,
- yesReturn: 0,
- noReturn: 0,
})
}
+ return weights
+}
+export function makeEntries(bids: Bid[]): Entry[] {
const YES_SEED = bids[0].yesBid
const NO_SEED = bids[0].noBid
- const yesWeightsSum = entries.reduce((sum, entry) => sum + entry.yesWeight, 0)
- const noWeightsSum = entries.reduce((sum, entry) => sum + entry.noWeight, 0)
+ 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
- for (const entry of entries) {
- const { yesBid, noBid, yesWeight, noWeight } = entry
+ 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
// (noPot - seed) according to your yesWeight
- entry.yesPayout = yesBid + (yesWeight / yesWeightsSum) * (noPot - NO_SEED)
- entry.noPayout = noBid + (noWeight / noWeightsSum) * (yesPot - YES_SEED)
- entry.yesReturn = (entry.yesPayout - yesBid) / yesBid
- entry.noReturn = (entry.noPayout - noBid) / noBid
+ const yesPayout = yesBid + (yesWeight / yesWeightsSum) * (noPot - NO_SEED)
+ const noPayout = noBid + (noWeight / noWeightsSum) * (yesPot - YES_SEED)
+ const yesReturn = (yesPayout - yesBid) / yesBid
+ const noReturn = (noPayout - noBid) / noBid
+ entries.push({ ...weight, yesPayout, noPayout, yesReturn, noReturn })
}
return entries
}
diff --git a/web/pages/simulator/sample-bids.ts b/web/lib/simulator/sample-bids.ts
similarity index 100%
rename from web/pages/simulator/sample-bids.ts
rename to web/lib/simulator/sample-bids.ts
diff --git a/web/pages/simulator/index.tsx b/web/pages/simulator/index.tsx
index eda62127..e2c4c253 100644
--- a/web/pages/simulator/index.tsx
+++ b/web/pages/simulator/index.tsx
@@ -1,4 +1,4 @@
-import React, { Fragment, useEffect, useMemo, useState } from 'react'
+import React, { useEffect, useMemo, useState } from 'react'
import {
CategoryScale,
Chart,
@@ -11,8 +11,8 @@ import {
} 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'
+import { bids as sampleBids } from '../../lib/simulator/sample-bids'
+import { Entry, makeEntries } from '../../lib/simulator/entries'
// Auto import doesn't work for some reason...
// So we manually register ChartJS components instead:
@@ -26,97 +26,136 @@ Chart.register(
Legend
)
-function toTable(entries: Entry[]) {
- return entries.map((entry, i) => {
- return (
-
- {i + 1}
- {toRowStart(entry)}
- {toRowEnd(entry)}
-
- )
- })
+function TableBody(props: { entries: Entry[] }) {
+ return (
+
+ {props.entries.map((entry, i) => (
+
+ {i + 1}
+
+
+
+ ))}
+
+ )
}
-function toRowStart(entry: Entry) {
+function TableRowStart(props: { entry: Entry }) {
+ const { entry } = props
if (entry.yesBid && entry.noBid) {
return (
-
+ <>
SEED
{entry.yesBid} / {entry.noBid}
-
+ >
)
} else if (entry.yesBid) {
return (
-
+ <>
YES
{entry.yesBid}
-
+ >
)
- } else if (entry.noBid) {
+ } else {
return (
-
+ <>
NO
{entry.noBid}
-
+ >
)
}
}
-function toRowEnd(entry: Entry) {
- if (!entry.yesBid && !entry.noBid) {
+function TableRowEnd(props: { entry: Entry | null }) {
+ const { entry } = props
+ 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,
- setNewBid: (newBid: number) => void,
- submitBid: () => void
-) {
+function NewBidTable(props: {
+ steps: number
+ bids: any[]
+ setSteps: (steps: number) => void
+ setBids: (bids: any[]) => void
+}) {
+ const { steps, bids, setSteps, setBids } = props
+ // 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, steps])
+
return (
@@ -137,16 +176,20 @@ function newBidTable(
YES
NO
@@ -166,7 +209,7 @@ function newBidTable(
onFocus={(e) => e.target.select()}
/>
- {/* */}
+
makeEntries(bids.slice(0, steps)),
[bids, steps]
)
-
- const probs = useMemo(() => entries.map((entry) => entry.prob), [entries])
+ const probs = entries.map((entry) => entry.prob)
// Set up chart
const [chartData, setChartData] = useState({ datasets: [] } as ChartData)
@@ -210,26 +252,6 @@ export default function Simulator() {
})
}, [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)
- }
-
return (
@@ -249,8 +271,7 @@ export default function Simulator() {
onChange={(e) => setSteps(parseInt(e.target.value))}
/>
- {/* New bid table */}
- {newBidTable(steps, newBid, setNewBid, submitBid)}
+
{/* History of bids */}
@@ -266,7 +287,8 @@ export default function Simulator() {
Return
- {toTable(entries)}
+
+