ladder orders!

This commit is contained in:
Tim Olson
2023-11-27 17:00:54 -04:00
parent d2db5dc4f7
commit 1dff2da3fe
8 changed files with 145 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
<template>
<v-btn variant="outlined">
<v-icon v-if="icon" :icon="icon" :color="color"></v-icon>&nbsp;
<v-icon v-if="icon" :icon="icon" :color="color"></v-icon>&nbsp{{text}}
<slot/>
</v-btn>
</template>
@@ -10,7 +10,7 @@ import {useStore} from "@/store/store";
import {useAttrs} from "vue";
const s = useStore()
const props = defineProps(['icon', 'color'])
const props = defineProps(['icon', 'color', 'text'])
const attrs = useAttrs()
</script>

View File

@@ -1,22 +1,96 @@
<template>
<order :tranches="buildTranches">
<limit-price :required="true" label=""/>
<limit-price :show-price="false" store-var="limitPrice2" :required="true" label=""/>
<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"/>
<v-text-field label='Parts' type="number" step="1" aria-valuemin="0" min="1" variant="outlined"
v-model="num" />
<v-text-field label='Skew' type="number" step="10" aria-valuemin="0" min="-100" max="100" variant="outlined"
v-model="skew" clearable @click:clear="skew=0" suffix="%"/>
<!-- todo deadline -->
<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>
</order>
</template>
<script setup>
import {useStore} from "@/store/store";
import {useOrderStore} from "@/store/store";
import LimitPrice from "@/components/LimitPrice.vue";
import Order from "@/components/Order.vue";
import {computed, ref} from "vue";
import {newTimeConstraint, TimeMode} from "@/blockchain/orderlib.js";
import {limitConstraint, maxFraction} from "@/orderbuild.js";
import {validateMax} from "@/validate.js";
const s = useStore()
const os = useOrderStore()
const num = ref(3)
const skew = ref(0)
const rungs = computed(()=>{
const n = num.value;
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 = num.value
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.amount) )
function buildTranches() {
const ts = []
const n = num.value
const mf = Number(maxFraction)
for( let i=0; i<n; i++ ) {
// todo optional deadline
const cs = [limitConstraint(rungs.value[i])]
const fraction = Math.min(mf, Math.ceil(mf * fractions.value[i]) )
ts.push([fraction, cs])
}
return ts
}
function validOrder() {
return os.validOrder
}
</script>
<style scoped lang="scss">

View File

@@ -7,7 +7,7 @@
{{ os.pairSymbol }}
</v-btn>
</template>
<template #details style="flex-direction: column-reverse">
<template v-if="showPrice" #details style="flex-direction: column-reverse">
<div>
Current price&nbsp;<route-price :inverted="routeInverted(os.route)" :route="os.route" class="text-green"/>
</div>

View File

@@ -1,15 +1,51 @@
<template>
<v-btn prepend-icon="mdi-plus" text="New Order"/>
<div class="d-inline-flex">
<btn icon="mdi-plus" color="green" @click="show=true">New Order</btn>
<v-dialog v-model="show" width="auto">
<v-card>
<v-card-item class="d-flex">
<v-card variant="elevated"
prepend-icon="mdi-clock-outline" title="DCA"
subtitle="Spread order across time"
text="The DCA order gives you a Dollar Cost Average (DCA) or a Time Weighted Average
Price (TWAP) by splitting the order amount into multiple parts executed at regular time intervals.">
<v-card-actions><btn icon="mdi-clock-outline" text="DCA" @click="$router.push('/twap')"/></v-card-actions>
</v-card>
<v-card variant="elevated"
prepend-icon="mdi-menu" title="Ladder"
subtitle="Multiple price levels"
text="The Ladder order helps catch wicks and other reversals by splitting the order amount across
multiple price levels. The amounts may be weighted towards one end of the ladder, to either have
a larger filled amount on a shallow reversal, or a larger amount at a better price that might not
be reached.">
<v-card-actions><btn icon="mdi-menu" text="Ladder" @click="$router.push('/ladder')"/></v-card-actions>
</v-card>
</v-card-item>
<v-card-item class="mb-3"><v-btn variant="outlined" prepend-icon="mdi-cancel" color="red" @click="show=false">Cancel</v-btn></v-card-item>
</v-card>
</v-dialog>
</div>
</template>
<script setup>
import {useStore} from "@/store/store";
import {ref} from "vue";
import Btn from "@/components/Btn.vue";
const s = useStore()
const show = ref(false)
</script>
<style scoped lang="scss">
@use "src/styles/vars" as *;
.v-card .v-card {
width: 20em;
margin: 2em;
}
</style>