Switch to a functional implementation

Pros: More extensible
Cons: Slower than the reactive version
This commit is contained in:
Austin Chen 2021-12-01 02:24:03 -08:00
parent 220df309c3
commit b04134c9c5
3 changed files with 73 additions and 65 deletions

View File

@ -6,7 +6,7 @@
type="range"
v-model.number="steps"
min="1"
:max="allEntries.length"
:max="bids.length"
/>
<!-- Two-column layout (on large screen sizes) -->
<div class="grid grid-cols-1 lg:grid-cols-2">
@ -21,9 +21,9 @@
<th>Type</th>
<th>Bid</th>
<th>Weight</th>
<th>Implied Probability</th>
<th>Probability</th>
<th>Payout</th>
<th>Return on win</th>
<th>Return</th>
</tr>
</thead>
<tbody>
@ -34,16 +34,16 @@
<td>{{ entry.yesBid }}</td>
<td>{{ entry.yesWeight.toFixed(2) }}</td>
<td>{{ entry.prob.toFixed(2) }}</td>
<td>{{ entry.yesPayout.value.toFixed(2) }}</td>
<td>{{ (entry.yesReturn.value * 100).toFixed(2) }}%</td>
<td>{{ entry.yesPayout.toFixed(2) }}</td>
<td>{{ (entry.yesReturn * 100).toFixed(2) }}%</td>
</template>
<template v-else>
<td><div class="badge badge-error">NO</div></td>
<td>{{ entry.noBid }}</td>
<td>{{ entry.noWeight.toFixed(2) }}</td>
<td>{{ entry.prob.toFixed(2) }}</td>
<td>{{ entry.noPayout.value.toFixed(2) }}</td>
<td>{{ (entry.noReturn.value * 100).toFixed(2) }}%</td>
<td>{{ entry.noPayout.toFixed(2) }}</td>
<td>{{ (entry.noReturn * 100).toFixed(2) }}%</td>
</template>
</tr>
</tbody>
@ -55,71 +55,19 @@
<script setup lang="ts">
import Chart from 'chart.js/auto'
import { bids } from './orders'
import { bids } from './sample-bids'
import { makeEntries } from './entries'
import { ref, computed } from '@vue/reactivity'
import { onMounted, watch } from '@vue/runtime-core'
const allEntries = [] as any
// Constants. TODO: Pull these from the orders instead of hardcoding.
const YES_SEED = 1
const NO_SEED = 9
// Regular variables
let yesPot = 0
let noPot = 0
// Need this import so script setup will export 'bids' lol
const BIDS_LENGTH = bids.length
// UI parameters
const steps = ref(10)
// Computed variables: stop the simulation at the appropriate number of steps
const entries = computed(() => allEntries.slice(0, steps.value))
const yesPotC = computed(() =>
entries.value.reduce((acc, entry) => acc + entry.yesBid, 0)
)
const noPotC = computed(() =>
entries.value.reduce((acc, entry) => acc + entry.noBid, 0)
)
const yesWeightsC = computed(() =>
entries.value.reduce((acc, entry) => acc + entry.yesWeight, 0)
)
const noWeightsC = computed(() =>
entries.value.reduce((acc, entry) => acc + entry.noWeight, 0)
)
// Calculations:
for (const bid of bids) {
const { yesBid, noBid } = bid
const yesWeight = noPot * (Math.log(yesBid + yesPot) - Math.log(yesPot)) || 0
const noWeight = yesPot * (Math.log(noBid + noPot) - Math.log(noPot)) || 0
// Note: Need to calculate weights BEFORE updating pot
yesPot += yesBid
noPot += noBid
const prob = yesPot / (yesPot + noPot)
// Payout: You get your initial bid back, as well as your share of the
// (noPot - seed) according to your yesWeight
const yesPayout = computed(
() => yesBid + (yesWeight / yesWeightsC.value) * (noPotC.value - NO_SEED)
)
const noPayout = computed(
() => noBid + (noWeight / noWeightsC.value) * (yesPotC.value - YES_SEED)
)
const yesReturn = computed(() => (yesPayout.value - yesBid) / yesBid)
const noReturn = computed(() => (noPayout.value - noBid) / noBid)
allEntries.push({
yesBid,
noBid,
// Show two decimal places
yesWeight,
noWeight,
prob,
yesPayout,
noPayout,
yesReturn,
noReturn,
})
}
const entries = computed(() => makeEntries(bids.slice(0, steps.value)))
// Graph the probabilities over time
const probs = computed(() => entries.value.map((entry) => entry.prob))

View File

@ -0,0 +1,60 @@
type Bid = { yesBid: number; noBid: number }
// An entry has a yes/no for bid, weight, payout, return. Also a current probability
type Entry = {
yesBid: number
noBid: number
yesWeight: number
noWeight: number
yesPayout: number
noPayout: number
yesReturn: number
noReturn: number
prob: number
}
export function makeEntries(bids: Bid[]): Entry[] {
const entries: Entry[] = []
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
// Note: Need to calculate weights BEFORE updating pot
yesPot += yesBid
noPot += noBid
const prob = yesPot / (yesPot + noPot)
entries.push({
yesBid,
noBid,
yesWeight,
noWeight,
prob,
// To be filled in below
yesPayout: 0,
noPayout: 0,
yesReturn: 0,
noReturn: 0,
})
}
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)
// Second pass: calculate all the payouts
for (const entry of entries) {
const { yesBid, noBid, yesWeight, noWeight } = entry
// 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
}
return entries
}