Switch to a functional implementation
Pros: More extensible Cons: Slower than the reactive version
This commit is contained in:
parent
220df309c3
commit
b04134c9c5
|
@ -6,7 +6,7 @@
|
||||||
type="range"
|
type="range"
|
||||||
v-model.number="steps"
|
v-model.number="steps"
|
||||||
min="1"
|
min="1"
|
||||||
:max="allEntries.length"
|
:max="bids.length"
|
||||||
/>
|
/>
|
||||||
<!-- Two-column layout (on large screen sizes) -->
|
<!-- Two-column layout (on large screen sizes) -->
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2">
|
<div class="grid grid-cols-1 lg:grid-cols-2">
|
||||||
|
@ -21,9 +21,9 @@
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Bid</th>
|
<th>Bid</th>
|
||||||
<th>Weight</th>
|
<th>Weight</th>
|
||||||
<th>Implied Probability</th>
|
<th>Probability</th>
|
||||||
<th>Payout</th>
|
<th>Payout</th>
|
||||||
<th>Return on win</th>
|
<th>Return</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -34,16 +34,16 @@
|
||||||
<td>{{ entry.yesBid }}</td>
|
<td>{{ entry.yesBid }}</td>
|
||||||
<td>{{ entry.yesWeight.toFixed(2) }}</td>
|
<td>{{ entry.yesWeight.toFixed(2) }}</td>
|
||||||
<td>{{ entry.prob.toFixed(2) }}</td>
|
<td>{{ entry.prob.toFixed(2) }}</td>
|
||||||
<td>{{ entry.yesPayout.value.toFixed(2) }}</td>
|
<td>{{ entry.yesPayout.toFixed(2) }}</td>
|
||||||
<td>{{ (entry.yesReturn.value * 100).toFixed(2) }}%</td>
|
<td>{{ (entry.yesReturn * 100).toFixed(2) }}%</td>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<td><div class="badge badge-error">NO</div></td>
|
<td><div class="badge badge-error">NO</div></td>
|
||||||
<td>{{ entry.noBid }}</td>
|
<td>{{ entry.noBid }}</td>
|
||||||
<td>{{ entry.noWeight.toFixed(2) }}</td>
|
<td>{{ entry.noWeight.toFixed(2) }}</td>
|
||||||
<td>{{ entry.prob.toFixed(2) }}</td>
|
<td>{{ entry.prob.toFixed(2) }}</td>
|
||||||
<td>{{ entry.noPayout.value.toFixed(2) }}</td>
|
<td>{{ entry.noPayout.toFixed(2) }}</td>
|
||||||
<td>{{ (entry.noReturn.value * 100).toFixed(2) }}%</td>
|
<td>{{ (entry.noReturn * 100).toFixed(2) }}%</td>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -55,71 +55,19 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Chart from 'chart.js/auto'
|
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 { ref, computed } from '@vue/reactivity'
|
||||||
import { onMounted, watch } from '@vue/runtime-core'
|
import { onMounted, watch } from '@vue/runtime-core'
|
||||||
|
|
||||||
const allEntries = [] as any
|
// Need this import so script setup will export 'bids' lol
|
||||||
// Constants. TODO: Pull these from the orders instead of hardcoding.
|
const BIDS_LENGTH = bids.length
|
||||||
const YES_SEED = 1
|
|
||||||
const NO_SEED = 9
|
|
||||||
// Regular variables
|
|
||||||
let yesPot = 0
|
|
||||||
let noPot = 0
|
|
||||||
// UI parameters
|
// UI parameters
|
||||||
const steps = ref(10)
|
const steps = ref(10)
|
||||||
|
|
||||||
// Computed variables: stop the simulation at the appropriate number of steps
|
// Computed variables: stop the simulation at the appropriate number of steps
|
||||||
const entries = computed(() => allEntries.slice(0, steps.value))
|
const entries = computed(() => makeEntries(bids.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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Graph the probabilities over time
|
// Graph the probabilities over time
|
||||||
const probs = computed(() => entries.value.map((entry) => entry.prob))
|
const probs = computed(() => entries.value.map((entry) => entry.prob))
|
||||||
|
|
60
market-simulator/src/components/entries.ts
Normal file
60
market-simulator/src/components/entries.ts
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user