136 lines
4.0 KiB
Vue
136 lines
4.0 KiB
Vue
<template>
|
|
<!-- eslint-disable -->
|
|
<div class="my-3">
|
|
<pre>
|
|
_ _
|
|
_ __ ___ __ _ _ __| | _____| |_
|
|
| '_ ` _ \ / _` | '__| |/ / _ \ __|
|
|
| | | | | | (_| | | | ( __/ |_
|
|
|_| |_| |_|\__,_|_| |_|\_\___|\__|</pre>
|
|
</div>
|
|
<div class="font-mono">{{ market.Description }}</div>
|
|
<!-- eslint-enable -->
|
|
<button type="button" :class="yesClass" class="label success font-mono mx-1 my-3"
|
|
@click.prevent="toggleYes">YES</button>
|
|
<button type="button" :class="noClass" class="label error font-mono mx-1 my-3" @click.prevent="toggleNo">NO</button>
|
|
<form v-show="showForm" @submit.prevent="submitForm">
|
|
<label for="stake">how much?</label>
|
|
<input name="stake" v-model="stake" type="number" min="0" placeholder="🗲 sats" />
|
|
<label for="certainty">how sure?</label>
|
|
<input name="certainty" v-model="certainty" type="number" min="0" max="1" step="0.001"
|
|
placeholder="fraction like 0.5" />
|
|
<label>you receive:</label>
|
|
<label>{{ format(shares) }} {{ selected }} shares @ 🗲{{ format(price) }}</label>
|
|
<label>you pay:</label>
|
|
<label>🗲{{ format(cost) }}</label>
|
|
<label>if you win:</label>
|
|
<label>+🗲{{ format(profit) }}</label>
|
|
<button class="col-span-2" type="submit">submit order</button>
|
|
</form>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const marketId = route.params.id
|
|
const selected = ref(null)
|
|
const showForm = computed(() => selected.value !== null)
|
|
const yesClass = computed(() => selected.value === 'YES' ? ['active'] : [])
|
|
const noClass = computed(() => selected.value === 'NO' ? ['active'] : [])
|
|
|
|
// how much wants the user bet?
|
|
const stake = ref(null)
|
|
// how sure is the user he will win?
|
|
const certainty = ref(null)
|
|
// price per share: more risk, lower price, higher reward
|
|
const price = computed(() => certainty.value * 100)
|
|
// how many (full) shares can be bought?
|
|
const shares = computed(() => {
|
|
const val = price.value > 0 ? stake.value / price.value : null
|
|
// only full shares can be bought
|
|
return Math.round(val)
|
|
})
|
|
// how much does this order cost?
|
|
const cost = computed(() => {
|
|
return shares.value * price.value
|
|
})
|
|
// how high is the potential reward?
|
|
const profit = computed(() => {
|
|
// shares expire at 10 or 0 sats
|
|
const val = (100 * shares.value) - cost.value
|
|
return isNaN(val) ? 0 : val
|
|
})
|
|
|
|
const format = (x, i = 3) => x === null ? null : x >= 1 ? Math.round(x) : x.toFixed(i)
|
|
|
|
const market = ref(null)
|
|
const url = '/api/market/' + marketId
|
|
await fetch(url)
|
|
.then(r => r.json())
|
|
.then(body => {
|
|
market.value = body
|
|
})
|
|
.catch(console.error)
|
|
// Currently, we only support binary markets.
|
|
// (only events which can be answered with YES and NO)
|
|
const yesShareId = computed(() => {
|
|
return market?.value.Shares.find(s => s.Description === 'YES').Id
|
|
})
|
|
const noShareId = computed(() => {
|
|
return market?.value.Shares.find(s => s.Description === 'NO').Id
|
|
})
|
|
const shareId = computed(() => {
|
|
return selected.value === 'YES' ? yesShareId.value : noShareId.value
|
|
})
|
|
|
|
const toggleYes = () => {
|
|
selected.value = selected.value === 'YES' ? null : 'YES'
|
|
}
|
|
|
|
const toggleNo = () => {
|
|
selected.value = selected.value === 'NO' ? null : 'NO'
|
|
}
|
|
|
|
const submitForm = async () => {
|
|
// TODO validate form
|
|
const url = window.origin + '/api/order'
|
|
const body = JSON.stringify({
|
|
sid: shareId.value,
|
|
quantity: shares.value,
|
|
price: price.value,
|
|
// TODO support selling
|
|
side: 'BUY'
|
|
})
|
|
const res = await fetch(url, { method: 'POST', headers: { 'Content-type': 'application/json' }, body })
|
|
const resBody = await res.json()
|
|
const invoiceId = resBody.id
|
|
router.push('/invoice/' + invoiceId)
|
|
}
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
.success.active {
|
|
background-color: #35df8d;
|
|
color: white;
|
|
}
|
|
|
|
.error.active {
|
|
background-color: #ff7386;
|
|
color: white;
|
|
}
|
|
|
|
form {
|
|
margin: 0 auto;
|
|
display: grid;
|
|
grid-template-columns: auto auto;
|
|
}
|
|
|
|
form>* {
|
|
margin: 0.5em 1em;
|
|
}
|
|
</style>
|