237 lines
6.3 KiB
Vue
237 lines
6.3 KiB
Vue
<template>
|
|
<rung-builder :name="(builder.breakout?'Breakout':'Limit')"
|
|
:description="description"
|
|
:order="order" :builder="builder"
|
|
v-model="priceEndpoints" :mode="0" :flip="flipped"
|
|
:shape="HLine"
|
|
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
|
:set-values="setPrices" :set-weights="setWeights"
|
|
:std-width="stdWidth" :build-tranches="buildTranches">
|
|
<table>
|
|
<tbody>
|
|
<template v-if="prices.length>1">
|
|
<tr>
|
|
<td>
|
|
<v-text-field type="number" v-model="higherPrice" min="0"
|
|
density="compact" hide-details class="mx-1 my-2" variant="outlined"
|
|
label="Price"
|
|
:color="color" :base-color="color"
|
|
style="flex: 6em"
|
|
/>
|
|
</td>
|
|
<td class="weight">{{ allocationTexts[higherIndex] }}</td>
|
|
</tr>
|
|
<tr v-for="i in innerIndexes" class="ml-5">
|
|
<td class="pl-5">{{ prices[i] }}</td>
|
|
<td class="weight">{{ allocationTexts[i] }}</td>
|
|
</tr>
|
|
</template>
|
|
<tr>
|
|
<td>
|
|
<v-text-field type="number" v-model="lowerPrice" min="0"
|
|
density="compact" hide-details class="mx-1 my-2" variant="outlined"
|
|
label="Price"
|
|
:color="color" :base-color="color"
|
|
style="flex: 6em"
|
|
/>
|
|
</td>
|
|
<td class="weight">{{ weights.length ? allocationTexts[lowerIndex] : '' }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</rung-builder>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {applyLinePoint, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
|
|
import {sideColor} from "@/misc.js";
|
|
import {useOrderStore, useStore} from "@/store/store.js";
|
|
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
|
import RungBuilder from "@/components/chart/RungBuilder.vue";
|
|
import {computed, ref} from "vue";
|
|
import {allocationText, HLine} from "@/charts/shape.js";
|
|
|
|
const s = useStore()
|
|
const os = useOrderStore()
|
|
const co = useChartOrderStore()
|
|
const props = defineProps(['order', 'builder'])
|
|
const emit = defineEmits(['update:builder'])
|
|
|
|
function computeDefaultColor() {
|
|
const index = props.order.builders.indexOf(props.builder)
|
|
return sideColor(props.order.buy, index)
|
|
}
|
|
|
|
const defaultColor = computeDefaultColor()
|
|
|
|
// Fields must be defined in order to be reactive
|
|
builderDefaults(props.builder, {
|
|
start: null, // todo
|
|
end: null, // todo
|
|
priceA: null,
|
|
priceB: null,
|
|
rungs: 1,
|
|
skew: 0,
|
|
breakout: false,
|
|
color: defaultColor,
|
|
buy: true,
|
|
})
|
|
|
|
function buildTranches() {
|
|
const order = props.order
|
|
const builder = props.builder
|
|
const tranches = []
|
|
const warnings = []
|
|
|
|
console.log('buildTranches', builder, order, tranches)
|
|
const ps = prices.value
|
|
const ws = weights.value
|
|
for(let i=0; i<ps.length; i++) {
|
|
let p = ps[i]
|
|
const w = ws[i]
|
|
const t = newTranche({
|
|
// todo start/end
|
|
// todo check expired
|
|
// if (endTime <= s.clock)
|
|
// warnings.push(`Tranche already expired at ${new Date(endTime*1000)}`)
|
|
fraction: w * MAX_FRACTION,
|
|
})
|
|
const symbol = co.selectedSymbol
|
|
console.log('symbol', symbol, p)
|
|
applyLinePoint(t, symbol, order.buy, p, builder.breakout)
|
|
tranches.push(t)
|
|
}
|
|
if (!flipped.value)
|
|
tranches.reverse()
|
|
return {tranches, warnings}
|
|
}
|
|
|
|
|
|
const priceA = computed({
|
|
get() { return priceEndpoints.value[0] },
|
|
set(v) {
|
|
if (v!==null)
|
|
v = Number(v)
|
|
update(v, priceEndpoints.value[1])
|
|
}
|
|
})
|
|
|
|
const priceB = computed({
|
|
get() { return priceEndpoints.value[1] },
|
|
set(v) {
|
|
if (v!==null)
|
|
v = Number(v)
|
|
update(priceEndpoints.value[0], v)
|
|
}
|
|
})
|
|
|
|
|
|
const _priceEndpoints = ref([props.builder.priceA, props.builder.priceB])
|
|
const priceEndpoints = computed({
|
|
get() { return _priceEndpoints.value},
|
|
set(v) {
|
|
const [a, b] = v
|
|
update(a,b)
|
|
}
|
|
})
|
|
|
|
|
|
function update(a, b) {
|
|
_priceEndpoints.value = [a, b]
|
|
const newBuilder = {...props.builder}
|
|
newBuilder.priceA = a
|
|
newBuilder.priceB = b
|
|
emit('update:builder', newBuilder)
|
|
}
|
|
|
|
const flipped = computed(()=>{
|
|
const a = props.builder.priceA
|
|
const b = props.builder.priceB
|
|
return a !== null && b !== null && a > b
|
|
})
|
|
|
|
const higherPrice = computed({
|
|
get() { return flipped.value ? priceA.value : priceB.value },
|
|
set(v) {
|
|
if (flipped.value)
|
|
priceA.value = v
|
|
else
|
|
priceB.value = v
|
|
}
|
|
})
|
|
|
|
const higherIndex = computed(()=>flipped.value ? 0 : weights.value.length-1)
|
|
const lowerIndex = computed(()=>!flipped.value ? 0 : weights.value.length-1)
|
|
const innerIndexes = computed(()=>{
|
|
const n = prices.value.length
|
|
const f = flipped.value
|
|
const result = []
|
|
for (let i=1; i<n-1; i++)
|
|
result.push(f?i:n-1-i)
|
|
return result
|
|
})
|
|
|
|
const lowerPrice = computed({
|
|
get() {
|
|
return !flipped.value ? priceA.value : priceB.value
|
|
},
|
|
set(v) {
|
|
if (!flipped.value)
|
|
priceA.value = v
|
|
else
|
|
priceB.value = v
|
|
}
|
|
})
|
|
|
|
const start = computed({
|
|
get() {return props.builder.start || 0},
|
|
set(v) {props.builder.start=v; },
|
|
})
|
|
|
|
const end = computed({
|
|
get() {return props.builder.end || 0},
|
|
set(v) {props.builder.end=v; },
|
|
})
|
|
|
|
|
|
const prices = ref([])
|
|
const weights = ref([])
|
|
function setPrices(ps) {prices.value = ps}
|
|
function setWeights(ws) { weights.value = ws }
|
|
|
|
const amountSymbol = computed(()=>props.order.amountIsTokenA ? co.selectedSymbol.base.s : co.selectedSymbol.quote.s )
|
|
const allocationTexts = computed(()=>weights.value.map((w)=>allocationText(props.order.buy, w, w * props.order.amount, co.selectedSymbol.base.s, amountSymbol.value)))
|
|
const color = computed(()=>props.builder.color ? props.builder.color : defaultColor)
|
|
const stdWidth = computed(()=>co.meanRange)
|
|
const description = computed(()=>{
|
|
const buy = props.order.buy
|
|
const above = buy === props.builder.breakout
|
|
return (buy?'Buy ':'Sell ')+(above?'above':'below')+' the line'
|
|
})
|
|
|
|
function getModelValue(model) {
|
|
if(!model)
|
|
return null
|
|
return model.price
|
|
}
|
|
|
|
|
|
function setModelValue(model, value) {
|
|
// console.log('setModelValue->', model.price, value)
|
|
if (model.price !== value)
|
|
model.price = value
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
td.weight {
|
|
width: 11em;
|
|
padding-left: 0.5em;
|
|
padding-right: 0.5em;
|
|
text-align: right;
|
|
}
|
|
</style>
|
|
|