remove simulator

This commit is contained in:
mantikoros 2022-09-03 14:55:37 -05:00
parent c0383bcf26
commit 085b9aeb2a
3 changed files with 0 additions and 463 deletions

View File

@ -1,73 +0,0 @@
type Bid = { yesBid: number; noBid: number }
// An entry has a yes/no for bid, weight, payout, return. Also a current probability
export type Entry = {
yesBid: number
noBid: number
yesWeight: number
noWeight: number
yesPayout: number
noPayout: number
yesReturn: number
noReturn: number
prob: number
}
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 =
yesBid +
(yesBid * Math.pow(noPot, 2)) /
(Math.pow(yesPot, 2) + yesBid * yesPot) || 0
const noWeight =
noBid +
(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 =
Math.pow(yesPot, 2) / (Math.pow(yesPot, 2) + Math.pow(noPot, 2))
weights.push({
yesBid,
noBid,
yesWeight,
noWeight,
prob,
})
}
return weights
}
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)
const potSize = yesPot + noPot - YES_SEED - NO_SEED
// Second pass: calculate all the payouts
const entries: Entry[] = []
for (const weight of weights) {
const { yesBid, noBid, yesWeight, noWeight } = weight
const yesPayout = (yesWeight / yesWeightsSum) * potSize
const noPayout = (noWeight / noWeightsSum) * potSize
const yesReturn = (yesPayout - yesBid) / yesBid
const noReturn = (noPayout - noBid) / noBid
entries.push({ ...weight, yesPayout, noPayout, yesReturn, noReturn })
}
return entries
}

View File

@ -1,58 +0,0 @@
const data = `1,9
8,
,1
1,
,1
1,
,5
5,
,5
5,
,1
1,
100,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,
,10
10,`
// Parse data into Yes/No orders
// E.g. `8,\n,1\n1,` =>
// [{yesBid: 8, noBid: 0}, {yesBid: 0, noBid: 1}, {yesBid: 1, noBid: 0}]
export const bids = data.split('\n').map((line) => {
const [yesBid, noBid] = line.split(',')
return {
yesBid: parseInt(yesBid || '0'),
noBid: parseInt(noBid || '0'),
}
})

View File

@ -1,332 +0,0 @@
import React, { useMemo, useState } from 'react'
import { DatumValue } from '@nivo/core'
import { ResponsiveLine } from '@nivo/line'
import { Entry, makeEntries } from 'web/lib/simulator/entries'
import { Col } from 'web/components/layout/col'
function TableBody(props: { entries: Entry[] }) {
return (
<tbody>
{props.entries.map((entry, i) => (
<tr key={i}>
<th>{props.entries.length - i}</th>
<TableRowStart entry={entry} />
<TableRowEnd entry={entry} />
</tr>
))}
</tbody>
)
}
function TableRowStart(props: { entry: Entry }) {
const { entry } = props
if (entry.yesBid && entry.noBid) {
return (
<>
<td>
<div className="badge">ANTE</div>
</td>
<td>
${entry.yesBid} / ${entry.noBid}
</td>
</>
)
} else if (entry.yesBid) {
return (
<>
<td>
<div className="badge badge-success">YES</div>
</td>
<td>${entry.yesBid}</td>
</>
)
} else {
return (
<>
<td>
<div className="badge badge-error">NO</div>
</td>
<td>${entry.noBid}</td>
</>
)
}
}
function TableRowEnd(props: { entry: Entry | null; isNew?: boolean }) {
const { entry } = props
if (!entry) {
return (
<>
<td>0</td>
<td>0</td>
{!props.isNew && (
<>
<td>N/A</td>
<td>N/A</td>
</>
)}
</>
)
} else if (entry.yesBid && entry.noBid) {
return (
<>
<td>{(entry.prob * 100).toFixed(1)}%</td>
<td>N/A</td>
{!props.isNew && (
<>
<td>N/A</td>
<td>N/A</td>
</>
)}
</>
)
} else if (entry.yesBid) {
return (
<>
<td>{(entry.prob * 100).toFixed(1)}%</td>
<td>${entry.yesWeight.toFixed(0)}</td>
{!props.isNew && (
<>
<td>${entry.yesPayout.toFixed(0)}</td>
<td>{(entry.yesReturn * 100).toFixed(0)}%</td>
</>
)}
</>
)
} else {
return (
<>
<td>{(entry.prob * 100).toFixed(1)}%</td>
<td>${entry.noWeight.toFixed(0)}</td>
{!props.isNew && (
<>
<td>${entry.noPayout.toFixed(0)}</td>
<td>{(entry.noReturn * 100).toFixed(0)}%</td>
</>
)}
</>
)
}
}
type Bid = { yesBid: number; noBid: number }
function NewBidTable(props: {
steps: number
bids: Array<Bid>
setSteps: (steps: number) => void
setBids: (bids: Array<Bid>) => 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 nextBid = makeBid(newBidType, newBid)
const fakeBids = [...bids.slice(0, steps), nextBid]
const entries = makeEntries(fakeBids)
const nextEntry = entries[entries.length - 1]
function randomBid() {
const bidType = Math.random() < 0.5 ? 'YES' : 'NO'
// const p = bidType === 'YES' ? nextEntry.prob : 1 - nextEntry.prob
const amount = Math.floor(Math.random() * 300) + 1
const bid = makeBid(bidType, amount)
bids.splice(steps, 0, bid)
setBids(bids)
setSteps(steps + 1)
setNewBid(0)
}
return (
<>
<table className="table-compact my-8 table w-full text-center">
<thead>
<tr>
<th>Order #</th>
<th>Type</th>
<th>Bet</th>
<th>Prob</th>
<th>Est Payout</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<th>{steps + 1}</th>
<td>
<div
className={
`badge hover:cursor-pointer ` +
(newBidType == 'YES' ? 'badge-success' : 'badge-ghost')
}
onClick={toggleBidType}
>
YES
</div>
<br />
<div
className={
`badge hover:cursor-pointer ` +
(newBidType == 'NO' ? 'badge-error' : 'badge-ghost')
}
onClick={toggleBidType}
>
NO
</div>
</td>
<td>
{/* Note: Would love to make this input smaller... */}
<input
type="number"
placeholder="0"
className="input input-bordered max-w-[100px]"
value={newBid.toString()}
onChange={(e) => setNewBid(parseInt(e.target.value) || 0)}
onKeyUp={(e) => {
if (e.key === 'Enter') {
submitBid()
}
}}
onFocus={(e) => e.target.select()}
/>
</td>
<TableRowEnd entry={nextEntry} isNew />
<button
className="btn btn-primary mt-2"
onClick={() => submitBid()}
disabled={newBid <= 0}
>
Submit
</button>
</tr>
</tbody>
</table>
<button className="btn btn-secondary mb-4" onClick={randomBid}>
Random bet!
</button>
</>
)
}
// Show a hello world React page
export default function Simulator() {
const [steps, setSteps] = useState(1)
const [bids, setBids] = useState([{ yesBid: 100, noBid: 100 }])
const entries = useMemo(
() => makeEntries(bids.slice(0, steps)),
[bids, steps]
)
const reversedEntries = [...entries].reverse()
const probs = entries.map((entry) => entry.prob)
const points = probs.map((prob, i) => ({ x: i + 1, y: prob * 100 }))
const data = [{ id: 'Yes', data: points, color: '#11b981' }]
const tickValues = [0, 25, 50, 75, 100]
return (
<Col>
<div className="mx-auto mt-8 grid w-full grid-cols-1 gap-4 p-2 text-center xl:grid-cols-2">
{/* Left column */}
<div>
<h1 className="mb-8 text-2xl font-bold">
Dynamic Parimutuel Market Simulator
</h1>
<NewBidTable {...{ steps, bids, setSteps, setBids }} />
{/* History of bids */}
<div className="overflow-x-auto">
<table className="table w-full text-center">
<thead>
<tr>
<th>Order #</th>
<th>Type</th>
<th>Bet</th>
<th>Prob</th>
<th>Est Payout</th>
<th>Payout</th>
<th>Return</th>
</tr>
</thead>
<TableBody entries={reversedEntries} />
</table>
</div>
</div>
{/* Right column */}
<Col>
<h1 className="mb-8 text-2xl font-bold">
Probability of
<div className="badge badge-success w-18 ml-3 h-8 text-2xl">
YES
</div>
</h1>
<div className="mb-10 h-[500px] w-full">
<ResponsiveLine
data={data}
yScale={{ min: 0, max: 100, type: 'linear' }}
yFormat={formatPercent}
gridYValues={tickValues}
axisLeft={{
tickValues,
format: formatPercent,
}}
enableGridX={false}
colors={{ datum: 'color' }}
pointSize={8}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableArea
margin={{ top: 20, right: 10, bottom: 20, left: 40 }}
/>
</div>
{/* Range slider that sets the current step */}
<label>Orders # 1 - {steps}</label>
<input
type="range"
className="range"
min="1"
max={bids.length}
value={steps}
onChange={(e) => setSteps(parseInt(e.target.value))}
/>
</Col>
</div>
</Col>
)
}
function formatPercent(y: DatumValue) {
return `${Math.round(+y.toString())}%`
}