diagonal order form

This commit is contained in:
Tim Olson
2023-12-16 16:54:05 -04:00
parent 206fb21687
commit 9199d31e77
11 changed files with 143 additions and 93 deletions

View File

@@ -1,23 +1,15 @@
<template>
<order title="Diagonal" subtitle="Trade trends and channels" :tranches="buildTranches" :valid="validOrder">
<order title="Diagonal" subtitle="Trends and channels" :tranches="buildTranches" :valid="validOrder">
<!-- todo times -->
<span><i>Coming soon!</i></span>
<!--
<limit-price :required="true" label="start price" :show-price="false"/>
<limit-price store-var="limitPrice2" :required="true" label="end price"/>
<v-table>
<thead>
<tr><td>Fraction</td><td>Amount</td><td>Price</td></tr>
</thead>
<tbody>
<tr v-for="(r,i) in rungsFmt">
<td>{{(100*fractions[i]).toFixed(1)}}%</td>
<td>{{(amounts[i]).toPrecision(5)}} {{os.amountToken.symbol}}</td>
<td>{{r}}</td>
</tr>
</tbody>
</v-table>
-->
<div class="title">Line Point A</div>
<v-divider/>
<time-entry v-model="time1" class="mb-0" hide-details="true"/>
<limit-price v-model="price1" label="Price A" :required="true"/>
<div class="title">Line Point B</div>
<v-divider/>
<time-entry v-model="time2" hide-details="true"/>
<limit-price v-model="price2" label="Price B" :required="true"/>
<div><i>Backend support for diagonal lines is coming soon...</i></div>
</order>
</template>
@@ -26,65 +18,22 @@ import {useOrderStore} from "@/store/store";
import LimitPrice from "@/components/LimitPrice.vue";
import Order from "@/components/Order.vue";
import {computed, ref} from "vue";
import {applyLimit} from "@/orderbuild.js";
import {applyLimit, applyLinePoints} from "@/orderbuild.js";
import {validateRequired, validateTranches} from "@/validate.js";
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
import TimeEntry from "@/components/TimeEntry.vue";
const os = useOrderStore()
const skew = ref(0)
const rungs = computed(()=>{
if( !os.limitPrice || !os.limitPrice2 )
return []
const n = os.tranches;
const a = parseFloat(os.limitPrice);
const b = parseFloat(os.limitPrice2);
if( n < 1 || !a || !b ) return []
if( n === 1 ) return [(a+b)/2]
// num >= 2
const result = []
const delta = (b-a)/(n-1)
for( let i=0; i<n; i++ )
result.push(a+i*delta)
return result
})
const rungsFmt = computed(()=>{
return rungs.value.map((r)=>r.toPrecision(5)) // todo precisions
})
const fractions = computed(()=>{
const n = os.tranches
const s = skew.value / 100
const result = []
if( s === 1 ) {
result.push(1)
for( let i=1; i<n; i++ )
result.push(0)
}
else if( s === -1 ) {
for( let i=1; i<n; i++ )
result.push(0)
result.push(1)
}
else {
const mean = 1/n
for( let i=0; i<n; i++ )
result.push( mean * ( 1 - s * (2*i/(n-1)-1) ) )
}
return result
})
const amounts = computed( ()=>fractions.value.map((f)=>f*os.totalAmount) )
const time1 = ref(new Date())
const price1 = ref(null)
const time2 = ref(new Date())
const price2 = ref(null)
function buildTranches() {
const ts = []
const n = os.tranches
for( let i=0; i<n; i++ ) {
// todo optional deadline
const fraction = Math.min(MAX_FRACTION, Math.ceil(MAX_FRACTION * fractions.value[i]) )
const tranche = newTranche({fraction})
applyLimit(tranche, rungs.value[i])
ts.push(tranche)
}
return ts
const t = newTranche();
applyLinePoints(t, time1.value, price1.value, time2.value, price2.value)
return [t]
}
function validOrder() {

View File

@@ -1,7 +1,7 @@
<template>
<order title="Ladder" subtitle="Multiple price levels" :tranches="buildTranches" :valid="validOrder">
<limit-price :required="true" label="start price" :show-price="false"/>
<limit-price store-var="limitPrice2" :required="true" label="end price"/>
<limit-price v-model="os.limitPrice" :required="true" label="start price" :show-price="false"/>
<limit-price v-model="os.limitPrice2" :required="true" label="end price"/>
<v-text-field label="Tranches" type="number" variant="outlined" aria-valuemin="1" min="1" max="255"
v-model="os.tranches" :rules="[validateRequired,validateTranches]">
<template v-slot:append-inner>tranches</template>

View File

@@ -1,7 +1,7 @@
<template>
<v-text-field v-model="os[storeVar]" :label="getLabel" type="number"
<v-text-field v-model="mv" :label="getLabel" type="number"
variant="outlined" aria-valuemin="0" min="0"
clearable :rules="rules" v-auto-select>
:clearable="!required && clearable" :rules="rules" v-auto-select>
<template v-slot:append-inner>
<v-btn variant="outlined" @click="os.inverted=!os.inverted">
{{ os.pairSymbol }}
@@ -26,10 +26,17 @@ import {vAutoSelect} from "@/misc.js";
const os = useOrderStore()
const props = defineProps({
modelValue: {required: true},
required: {default: false},
label: {default: null},
storeVar: {default: 'limitPrice'},
showPrice: {default: true},
clearable: {default: true},
})
const emit = defineEmits(['update:modelValue'])
const mv = computed({
get() {return props.modelValue},
set(v) {emit('update:modelValue', v)}
})
const rules = computed(()=>props.required ? [validateAmount, validateRequired] : [validateAmount])

View File

@@ -7,7 +7,7 @@
<v-list-subheader title="Dexorders"/>
<v-list-item prepend-icon="mdi-clock-outline" title="DCA" subtitle="Spread order across time" @click="nav('twap')"></v-list-item>
<v-list-item prepend-icon="mdi-menu" title="Ladder" subtitle="Multiple price levels" @click="nav('ladder')"></v-list-item>
<v-list-item prepend-icon="mdi-vector-line" title="Diagonal" subtitle="Trade trends and channels" @click="nav('diagonal')"></v-list-item>
<v-list-item prepend-icon="mdi-vector-line" title="Diagonal" subtitle="Trends and channels" @click="nav('diagonal')"></v-list-item>
<v-list-item prepend-icon="mdi-hammer-wrench" title="Custom" subtitle="Create your own" @click="nav('custom')"></v-list-item>
</v-list>
</v-navigation-drawer>

View File

@@ -11,7 +11,7 @@
</div>
</v-card-item>
<v-card-actions class="d-flex justify-space-evenly mb-4">
<v-btn variant="outlined" color="red">Cancel</v-btn>
<v-btn variant="outlined" color="red" @click="$router.push('/vault')">Cancel</v-btn>
<v-btn variant="flat" color="green" :disabled="!valid()" @click="placeOrder">Place Dexorder</v-btn>
</v-card-actions>
</phone-card>

View File

@@ -0,0 +1,65 @@
<template>
<div class="d-flex">
<v-text-field type="number" min="1" max="31" v-model="day" :label="weekday" :hide-details="hideDetails" style="min-width: 3em; width: 3em" class="all"/>
<v-select v-model="month" :items="monthItems" :hide-details="hideDetails" style="min-width: 6em; width: 6em" class="all"/>
<v-text-field type="number" v-model="year" :hide-details="hideDetails" style="min-width: 5em; width: 5em" class="all"/>
<v-text-field type="time" v-model="time" :hide-details="hideDetails" style="min-width: 8em; width: 8em" class="all"/>
</div>
</template>
<script setup>
import {useStore} from "@/store/store";
import {computed} from "vue";
const s = useStore()
const props = defineProps(['modelValue', 'hideDetails'])
const emit = defineEmits(['update:modelValue'])
const day = computed({
get() { return s.utc ? props.modelValue.getUTCDate() : props.modelValue.getDate() },
set(v) { update(year.value, month.value, v, time.value)},
})
const weekdayFormat = computed(()=>new Intl.DateTimeFormat(s.utc ? 'utc':undefined,{weekday:"short"}))
const weekday = computed(()=>weekdayFormat.value.format(props.modelValue))
const month = computed({
get() { return s.utc ? props.modelValue.getUTCMonth() : props.modelValue.getMonth() },
set(v) { update(year.value, v, day.value, time.value)},
})
const year = computed({
get() { return s.utc ? props.modelValue.getUTCFullYear() : props.modelValue.getFullYear() },
set(v) { update(v, month.value, day.value, time.value)},
})
const time = computed({
get() { return '' + (s.utc ? `${props.modelValue.getUTCHours()}:${props.modelValue.getUTCMinutes()}` : `${props.modelValue.getHours()}:${props.modelValue.getMinutes()}` ) },
set(v) { update(year.value, month.value, day.value, v) }
})
function monthsForLocale(localeName = undefined, monthFormat = 'long') {
const format = new Intl.DateTimeFormat(localeName, {month: monthFormat}).format;
return [...Array(12).keys()]
.map((m) => format(new Date(Date.UTC(2000, m+1))));
}
let m=0
const monthItems = monthsForLocale(undefined, 'short').map((v)=>{return {title:v, value:m++}})
function buildDate(y, m, d, t) {
const [hours,minutes] = t.split(':')
console.log('buildDate', y, m, d, hours, minutes)
return s.utc ? new Date(Date.UTC(y, m, d, hours, minutes))
: new Date(y, m, d, hours, minutes);
}
function update(y,m,d,t) {
const date = buildDate(y, m, d, t);
emit('update:modelValue', date)
}
</script>
<style scoped lang="scss">
@use "src/styles/vars" as *;
.all {
margin-bottom: 0;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<order title="DCA / TWAP" subtitle="Multiple tranches over a time range" :tranches="buildTranches" :valid="validOrder">
<Tranches/>
<LimitPrice/>
<LimitPrice v-model="os.limitPrice"/>
</order>
</template>