DCA redraw hacks
This commit is contained in:
@@ -77,6 +77,8 @@ function initChart() {
|
|||||||
chart.crossHairMoved().subscribe(null, (point)=>setTimeout(()=>handleCrosshairMovement(point),0) )
|
chart.crossHairMoved().subscribe(null, (point)=>setTimeout(()=>handleCrosshairMovement(point),0) )
|
||||||
chart.onSymbolChanged().subscribe(null, changeSymbol)
|
chart.onSymbolChanged().subscribe(null, changeSymbol)
|
||||||
chart.onIntervalChanged().subscribe(null, changeInterval)
|
chart.onIntervalChanged().subscribe(null, changeInterval)
|
||||||
|
// chart.onHoveredSourceChanged().subscribe(null, ()=>console.log('hovered source changed', arguments))
|
||||||
|
// chart.selection().onChanged().subscribe(null, s => console.log('selection', chart.selection().allSources()));
|
||||||
changeSymbol(chart.symbolExt())
|
changeSymbol(chart.symbolExt())
|
||||||
changeInterval(widget.symbolInterval().interval)
|
changeInterval(widget.symbolInterval().interval)
|
||||||
useChartOrderStore().chartReady = true
|
useChartOrderStore().chartReady = true
|
||||||
@@ -205,6 +207,7 @@ export let draggingShapeIds = []
|
|||||||
|
|
||||||
|
|
||||||
function handleCrosshairMovement(point) {
|
function handleCrosshairMovement(point) {
|
||||||
|
// console.log('crosshair moved')
|
||||||
crosshairPoint = point
|
crosshairPoint = point
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
if (co.drawing)
|
if (co.drawing)
|
||||||
|
|||||||
@@ -61,12 +61,14 @@ export class Shape {
|
|||||||
this.id = null // TradingView shapeId, or null if no TV shape created yet (drawing mode)
|
this.id = null // TradingView shapeId, or null if no TV shape created yet (drawing mode)
|
||||||
this.type = type // ShapeType
|
this.type = type // ShapeType
|
||||||
this.model = {} // set to nothing at first
|
this.model = {} // set to nothing at first
|
||||||
|
this.tvCallbacks = null
|
||||||
this.ourPoints = null
|
this.ourPoints = null
|
||||||
this.tvPoints = null
|
this.tvPoints = null
|
||||||
|
this.creationOptions = {disableSave:true, disableUndo:false, disableSelection:false}
|
||||||
this.ourProps = {}
|
this.ourProps = {}
|
||||||
if (props !== null)
|
if (props !== null)
|
||||||
this.ourProps = mixin(props, this.ourProps)
|
this.ourProps = mixin(props, this.ourProps)
|
||||||
this.tvProps = null
|
this.tvProps = {}
|
||||||
if (onModel !== null)
|
if (onModel !== null)
|
||||||
this.onModel = onModel
|
this.onModel = onModel
|
||||||
if (onDelete !== null )
|
if (onDelete !== null )
|
||||||
@@ -129,7 +131,9 @@ export class Shape {
|
|||||||
newProps.linecolor = color
|
newProps.linecolor = color
|
||||||
|
|
||||||
// text label
|
// text label
|
||||||
const text = allocationText(this.model.allocation, this.model.amount, this.model.amountSymbol)
|
const text =
|
||||||
|
// `${this.id} ` +
|
||||||
|
allocationText(this.model.allocation, this.model.amount, this.model.amountSymbol)
|
||||||
if (!text.length)
|
if (!text.length)
|
||||||
newProps.showLabel = false
|
newProps.showLabel = false
|
||||||
else {
|
else {
|
||||||
@@ -197,8 +201,11 @@ export class Shape {
|
|||||||
|
|
||||||
doCreate() {
|
doCreate() {
|
||||||
// createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
// createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
||||||
|
const options = {...this.creationOptions}
|
||||||
|
options['overrides'] = this.ourProps
|
||||||
this.tvPoints = [...this.ourPoints]
|
this.tvPoints = [...this.ourPoints]
|
||||||
createShape(this.type, this.ourPoints, {overrides:this.ourProps}, new ShapeTVCallbacks(this))
|
this.tvCallbacks = new ShapeTVCallbacks(this);
|
||||||
|
createShape(this.type, this.ourPoints, options, this.tvCallbacks)
|
||||||
if (this.debug) console.log('created', this.type.name, this.ourPoints, this.id)
|
if (this.debug) console.log('created', this.type.name, this.ourPoints, this.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +226,8 @@ export class Shape {
|
|||||||
setPoints(points) {
|
setPoints(points) {
|
||||||
// setting points to null will delete the shape from the chart. setting points to a valid value will cause the
|
// setting points to null will delete the shape from the chart. setting points to a valid value will cause the
|
||||||
// shape to be drawn.
|
// shape to be drawn.
|
||||||
if (this.debug) console.log('setPoints', points, this.id)
|
if (this.debug) console.log('setPoints', this.id, this.ourPoints, points)
|
||||||
|
const oldPoints = this.ourPoints
|
||||||
this.ourPoints = points
|
this.ourPoints = points
|
||||||
if (points === null || !points.length)
|
if (points === null || !points.length)
|
||||||
this.delete()
|
this.delete()
|
||||||
@@ -228,8 +236,32 @@ export class Shape {
|
|||||||
this.doCreate()
|
this.doCreate()
|
||||||
else if (dirtyPoints(this.tvPoints, points)) {
|
else if (dirtyPoints(this.tvPoints, points)) {
|
||||||
const s = this.tvShape();
|
const s = this.tvShape();
|
||||||
if (this.debug) console.log('adjusting tv points', s, this.tvPoints, points)
|
let sbm = false
|
||||||
if (!dragging) {
|
if( draggingShapeIds.length ) {
|
||||||
|
const dragShape = chart.getShapeById(draggingShapeIds[0])
|
||||||
|
const sbms = [...dragShape._model._sourcesBeingMoved]
|
||||||
|
// console.log('shape setPoints', this.id, dragShape, sbm)
|
||||||
|
sbm = !sbms.length
|
||||||
|
// if (!sbms.length) {
|
||||||
|
// console.log('shape setPoints SBM return')
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (this.debug) console.log('adjusting tv points', this.tvPoints, points, dragging, this.beingDragged())
|
||||||
|
// if ( dragging && !this.beingDragged())
|
||||||
|
// s.setSelectionEnabled(false)
|
||||||
|
// s.setPoints(points)
|
||||||
|
// if ( dragging && !this.beingDragged())
|
||||||
|
// s.setSelectionEnabled(true)
|
||||||
|
|
||||||
|
// best so far
|
||||||
|
if (sbm && this.type === ShapeType.VLine) {
|
||||||
|
// console.log('sbm: re-create shape')
|
||||||
|
this.delete()
|
||||||
|
this.ourPoints = points
|
||||||
|
this.create()
|
||||||
|
} else
|
||||||
|
if (!dragging || this.type !== ShapeType.HLine) {
|
||||||
if (this.debug) console.log('not dragging. use setPoints.')
|
if (this.debug) console.log('not dragging. use setPoints.')
|
||||||
s.setPoints(points)
|
s.setPoints(points)
|
||||||
}
|
}
|
||||||
@@ -276,7 +308,13 @@ export class Shape {
|
|||||||
delete() {
|
delete() {
|
||||||
if (this.debug) console.log('shape.delete', this.id)
|
if (this.debug) console.log('shape.delete', this.id)
|
||||||
this.ourPoints = null
|
this.ourPoints = null
|
||||||
|
this.tvPoints = null
|
||||||
|
this.tvProps = null
|
||||||
if (this.id === null) return
|
if (this.id === null) return
|
||||||
|
if (this.tvCallbacks !== null) {
|
||||||
|
this.tvCallbacks.enabled = false
|
||||||
|
this.tvCallbacks = null
|
||||||
|
}
|
||||||
deleteShapeId(this.id)
|
deleteShapeId(this.id)
|
||||||
this.id = null
|
this.id = null
|
||||||
}
|
}
|
||||||
@@ -341,21 +379,25 @@ class ShapeTVCallbacks {
|
|||||||
constructor(shape) {
|
constructor(shape) {
|
||||||
this.shape = shape
|
this.shape = shape
|
||||||
this.creating = false
|
this.creating = false
|
||||||
|
this.enabled = true // gets disabled when the shape is deleted, squelching any further callbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
onCreate(shapeId, _tvShape, points, props) {
|
onCreate(shapeId, _tvShape, points, props) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
this.creating = true
|
this.creating = true
|
||||||
this.shape.id = shapeId
|
this.shape.id = shapeId
|
||||||
invokeCallback(this.shape, 'onCreate', points, props)
|
invokeCallback(this.shape, 'onCreate', points, props)
|
||||||
}
|
}
|
||||||
|
|
||||||
onPoints(shapeId, _tvShape, points) {
|
onPoints(shapeId, _tvShape, points) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
if (this.shape.debug) console.log('tvcb onPoints', points)
|
if (this.shape.debug) console.log('tvcb onPoints', points)
|
||||||
this.shape.tvPoints = points
|
this.shape.tvPoints = points
|
||||||
this.shape.onPoints(points)
|
this.shape.onPoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
onProps(shapeId, _tvShape, props) {
|
onProps(shapeId, _tvShape, props) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
if (this.shape.debug) console.log('tvOnProps', props)
|
if (this.shape.debug) console.log('tvOnProps', props)
|
||||||
if (this.creating) { // todo still useful?
|
if (this.creating) { // todo still useful?
|
||||||
this.creating = false
|
this.creating = false
|
||||||
@@ -366,43 +408,53 @@ class ShapeTVCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDraw() {
|
onDraw() {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onDraw')
|
invokeCallback(this.shape, 'onDraw')
|
||||||
}
|
}
|
||||||
|
|
||||||
onRedraw() {
|
onRedraw() {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onRedraw')
|
invokeCallback(this.shape, 'onRedraw')
|
||||||
}
|
}
|
||||||
|
|
||||||
onUndraw() {
|
onUndraw() {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onUndraw')
|
invokeCallback(this.shape, 'onUndraw')
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddPoint() {
|
onAddPoint() {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onAddPoint')
|
invokeCallback(this.shape, 'onAddPoint')
|
||||||
}
|
}
|
||||||
|
|
||||||
onMove(_shapeId, _tvShape, points) {
|
onMove(shapeId, _tvShape, points) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onMove',points)
|
invokeCallback(this.shape, 'onMove',points)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDrag(_shapeId, _tvShape, points) {
|
onDrag(shapeId, _tvShape, points) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
if (this.shape.debug) console.log('onDrag')
|
if (this.shape.debug) console.log('onDrag')
|
||||||
invokeCallback(this.shape, 'onDrag', points)
|
invokeCallback(this.shape, 'onDrag', points)
|
||||||
}
|
}
|
||||||
|
|
||||||
onHide(_shapeId, _tvShape, props) {
|
onHide(shapeId, _tvShape, props) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onHide',props)
|
invokeCallback(this.shape, 'onHide',props)
|
||||||
}
|
}
|
||||||
|
|
||||||
onShow(_shapeId, _tvShape, props) {
|
onShow(shapeId, _tvShape, props) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onShow',props)
|
invokeCallback(this.shape, 'onShow',props)
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(_shapeId, _tvShape) {
|
onClick(shapeId, _tvShape) {
|
||||||
|
if (!this.enabled) return // possible when shape is deleted and re-created
|
||||||
invokeCallback(this.shape, 'onClick')
|
invokeCallback(this.shape, 'onClick')
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete(shapeId) {
|
onDelete(shapeId) {
|
||||||
|
this.enabled = false
|
||||||
this.shape.id = null
|
this.shape.id = null
|
||||||
invokeCallback(this.shape, 'onDelete', shapeId)
|
invokeCallback(this.shape, 'onDelete', shapeId)
|
||||||
}
|
}
|
||||||
@@ -481,7 +533,6 @@ export class VLine extends Line {
|
|||||||
|
|
||||||
// Model
|
// Model
|
||||||
this.model.time = null
|
this.model.time = null
|
||||||
this.debug=true
|
|
||||||
|
|
||||||
this.setModel(model) // call setModel at the end
|
this.setModel(model) // call setModel at the end
|
||||||
}
|
}
|
||||||
@@ -493,25 +544,30 @@ export class VLine extends Line {
|
|||||||
|
|
||||||
|
|
||||||
setModel(model) {
|
setModel(model) {
|
||||||
|
// console.log('VLine setModel', this.id, {...this.model}, model)
|
||||||
super.setModel(model)
|
super.setModel(model)
|
||||||
if (model.time === null) {
|
if (model.time === null) {
|
||||||
this.model.time = null
|
this.model.time = null
|
||||||
this.delete()
|
this.delete()
|
||||||
}
|
}
|
||||||
else {
|
else if (model.time !== this.model.time) {
|
||||||
this.model.time = model.time
|
this.model.time = model.time
|
||||||
const time = nearestOhlcStart(model.time);
|
const time = nearestOhlcStart(model.time);
|
||||||
this.setPoints([{time, price:0}])
|
this.setPoints([{time, price:0}])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPoints(points) {
|
setPoints(points) {
|
||||||
super.onPoints(points);
|
// console.error('VLine setPoints', points)
|
||||||
const orig = this.ourPoints && this.ourPoints.length ? this.ourPoints[0].time : null
|
super.setPoints(points);
|
||||||
const time = points[0].time;
|
|
||||||
if (!timeAdjustmentTooSmall(orig, time)) {
|
|
||||||
this.updateModel({time: time})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPoints(points) {
|
||||||
|
const orig = this.ourPoints && this.ourPoints.length ? this.ourPoints[0].time : null
|
||||||
|
super.onPoints(points);
|
||||||
|
const time = points[0].time;
|
||||||
|
if (!timeAdjustmentTooSmall(orig, time))
|
||||||
|
this.updateModel({time: time})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<rung-builder name='DCA' :order="order" :builder="builder"
|
<rung-builder name='DCA' :order="order" :builder="builder"
|
||||||
v-model:value-a="absTimeA" v-model:value-b="absTimeB" :mode="1" :shape="VLine"
|
v-model:value-a="absTimeA" v-model:value-b="absTimeB" :mode="1" :flip="flipped"
|
||||||
:get-model-value="getModelValue" :set-model-value="setModelValue" :set-values="setValues"
|
:shape="VLine"
|
||||||
|
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
||||||
|
:get-points-value="getPointsValue"
|
||||||
|
:set-values="setValues" :set-weights="setWeights"
|
||||||
:std-width="stdWidth" :build-tranches="buildTranches">
|
:std-width="stdWidth" :build-tranches="buildTranches">
|
||||||
<v-list style="background-color: inherit">
|
<v-list style="background-color: inherit">
|
||||||
<v-list-item v-for="t in absoluteTimes">{{t}}</v-list-item>
|
<v-list-item v-for="t in absoluteTimes">{{t}}</v-list-item>
|
||||||
@@ -17,7 +20,8 @@ import {useTheme} from "vuetify";
|
|||||||
import {useOrderStore, useStore} from "@/store/store.js";
|
import {useOrderStore, useStore} from "@/store/store.js";
|
||||||
import {DISTANT_FUTURE, MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
import {DISTANT_FUTURE, MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
||||||
import RungBuilder from "@/components/chart/RungBuilder.vue";
|
import RungBuilder from "@/components/chart/RungBuilder.vue";
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref, watchEffect} from "vue";
|
||||||
|
import {chart, dragging} from "@/charts/chart.js";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
@@ -25,7 +29,8 @@ const co = useChartOrderStore()
|
|||||||
const theme = useTheme().current
|
const theme = useTheme().current
|
||||||
const props = defineProps(['order', 'builder'])
|
const props = defineProps(['order', 'builder'])
|
||||||
|
|
||||||
const stdWidth = computed(()=>10 * co.intervalSecs)
|
const minWidth = computed(()=>co.intervalSecs)
|
||||||
|
const stdWidth = computed(()=>10 * minWidth.value)
|
||||||
|
|
||||||
function computeDefaultColor() {
|
function computeDefaultColor() {
|
||||||
const index = props.order.builders.indexOf(props.builder)
|
const index = props.order.builders.indexOf(props.builder)
|
||||||
@@ -46,6 +51,8 @@ builderDefaults(props.builder, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const rawTimes = ref([])
|
const rawTimes = ref([])
|
||||||
|
const weights = ref([])
|
||||||
|
|
||||||
const times = computed(()=>rawTimes.value.map((t)=>Math.round(t)))
|
const times = computed(()=>rawTimes.value.map((t)=>Math.round(t)))
|
||||||
const endTimes = computed(()=>{
|
const endTimes = computed(()=>{
|
||||||
if (props.builder.rungs === 1)
|
if (props.builder.rungs === 1)
|
||||||
@@ -55,27 +62,49 @@ const endTimes = computed(()=>{
|
|||||||
return ts.map((t)=>t+window)
|
return ts.map((t)=>t+window)
|
||||||
})
|
})
|
||||||
const absoluteTimes = computed(()=>{
|
const absoluteTimes = computed(()=>{
|
||||||
console.log('absoluteTimes', props.builder.relative, times.value)
|
// console.log('absoluteTimes', props.builder.relative, times.value)
|
||||||
if (!props.builder.relative)
|
if (!props.builder.relative)
|
||||||
return times.value
|
return times.value
|
||||||
const now = s.clock
|
const now = s.clock
|
||||||
return times.value.map((t)=>now+t)
|
return times.value.map((t)=>now+t)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
watchEffect(()=>{
|
||||||
|
// auto scroll
|
||||||
|
if (!dragging && absoluteTimes.value.length) {
|
||||||
|
const endTime = absoluteTimes.value[absoluteTimes.value.length-1]
|
||||||
|
const range = chart.getVisibleRange()
|
||||||
|
const width = range.to - range.from
|
||||||
|
const now = s.clock
|
||||||
|
const extra = (Math.max(0,endTime - now) + minWidth.value) / width
|
||||||
|
// console.log('visrange', range, width, absV)
|
||||||
|
if (range.to < endTime) {
|
||||||
|
// console.log('scrolling')
|
||||||
|
chart.setVisibleRange({from: now - width, to: now}, {
|
||||||
|
percentRightMargin: Math.round(100 * extra),
|
||||||
|
applyDefaultRightMargin: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const absTimeA = computed({
|
const absTimeA = computed({
|
||||||
get() {
|
get() {
|
||||||
let result = props.builder.timeA
|
let result = props.builder.timeA
|
||||||
if (props.builder.relative)
|
if (props.builder.relative)
|
||||||
result += s.clock
|
result += s.clock
|
||||||
console.log('absTimeA', result)
|
// console.log('absTimeA', result)
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
set(v) {
|
set(v) {
|
||||||
console.log('set absTimeA', props.builder.timeA, v)
|
// console.log('set absTimeA', props.builder.timeA, v)
|
||||||
if (props.builder.relative)
|
if (props.builder.relative)
|
||||||
v -= s.clock
|
v -= s.clock
|
||||||
props.builder.timeA = v
|
props.builder.timeA = v
|
||||||
console.log('absTimeA=',props.builder.timeA)
|
// console.log('absTimeA=',props.builder.timeA)
|
||||||
|
scroll()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const absTimeB = computed({
|
const absTimeB = computed({
|
||||||
@@ -83,15 +112,57 @@ const absTimeB = computed({
|
|||||||
let result = props.builder.timeB
|
let result = props.builder.timeB
|
||||||
if (props.builder.relative)
|
if (props.builder.relative)
|
||||||
result += s.clock
|
result += s.clock
|
||||||
console.log('absTimeB', result)
|
// console.log('absTimeB', result)
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
set(v) {
|
set(v) {
|
||||||
console.log('set absTimeB', props.builder.timeB, v)
|
// console.log('set absTimeB', props.builder.timeB, v)
|
||||||
|
const absV = v
|
||||||
if ( v !== null && props.builder.relative )
|
if ( v !== null && props.builder.relative )
|
||||||
v -= s.clock
|
v -= s.clock
|
||||||
props.builder.timeB = v
|
props.builder.timeB = v
|
||||||
console.log('absTimeB=',props.builder.timeB)
|
const maxA = v - minWidth.value;
|
||||||
|
if (props.builder.timeA > maxA)
|
||||||
|
props.builder.timeA = maxA
|
||||||
|
// console.log('absTimeB=',props.builder.timeB)
|
||||||
|
scroll()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const flipped = computed(()=>{
|
||||||
|
const a = props.builder.timeA
|
||||||
|
const b = props.builder.timeB
|
||||||
|
return a !== null && b !== null && a > b
|
||||||
|
})
|
||||||
|
|
||||||
|
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 = times.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 earlierTime = computed({
|
||||||
|
get() { return !flipped.value ? props.builder.timeA : props.builder.timeB },
|
||||||
|
set(v) {
|
||||||
|
if (!flipped.value)
|
||||||
|
props.builder.timeA = v
|
||||||
|
else
|
||||||
|
props.builder.timeB = v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const laterTime = computed({
|
||||||
|
get() { return !flipped.value ? props.builder.timeA : props.builder.timeB },
|
||||||
|
set(v) {
|
||||||
|
if (!flipped.value)
|
||||||
|
props.builder.timeA = v
|
||||||
|
else
|
||||||
|
props.builder.timeB = v
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -124,11 +195,15 @@ function getModelValue(model) {
|
|||||||
return model.time
|
return model.time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPointsValue(points) {
|
||||||
|
return points[0].price
|
||||||
|
}
|
||||||
|
|
||||||
function setModelValue(model, value) {
|
function setModelValue(model, value) {
|
||||||
console.log('DCA set model value', model, value)
|
// console.log('DCA set model value', model, value)
|
||||||
const v = value === null ? null : props.builder.relative ? s.clock + Math.round(value) : Math.round(value)
|
const v = value === null ? null : props.builder.relative ? s.clock + Math.round(value) : Math.round(value)
|
||||||
if (model.time !== v) {
|
if (model.time !== v) {
|
||||||
console.log('DCA do set time', v)
|
// console.log('DCA do set time', v)
|
||||||
model.time = v
|
model.time = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,18 +213,11 @@ function setValues(values) {
|
|||||||
rawTimes.value = values
|
rawTimes.value = values
|
||||||
else {
|
else {
|
||||||
const now = s.clock
|
const now = s.clock
|
||||||
const vs = []
|
rawTimes.value = values.map((v)=>v-now)
|
||||||
for (let i = 0; i < values.length; i++)
|
|
||||||
vs.push(values[i] - now)
|
|
||||||
rawTimes.value = vs
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function valueFromPoints(points) {
|
function setWeights(ws) { weights.value = ws }
|
||||||
const result = points[0].time;
|
|
||||||
console.log('valueFromPoints', points, result);
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<rung-builder :name="prices.length>1?'Ladder':'Limit'" :order="order" :builder="builder"
|
<rung-builder :name="prices.length>1?'Ladder':'Limit'" :order="order" :builder="builder"
|
||||||
v-model:value-a="priceA" v-model:value-b="priceB" :mode="0" :shape="HLine"
|
v-model:value-a="priceA" v-model:value-b="priceB" :mode="0" :flip="flipped"
|
||||||
|
:shape="HLine"
|
||||||
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
||||||
|
:get-points-value="getPointsValue"
|
||||||
:set-values="setPrices" :set-weights="setWeights"
|
:set-values="setPrices" :set-weights="setWeights"
|
||||||
:std-width="stdWidth" :build-tranches="buildTranches">
|
:std-width="stdWidth" :build-tranches="buildTranches">
|
||||||
<table>
|
<table>
|
||||||
@@ -131,9 +133,9 @@ const higherPrice = computed({
|
|||||||
const higherIndex = computed(()=>flipped.value ? 0 : weights.value.length-1)
|
const higherIndex = computed(()=>flipped.value ? 0 : weights.value.length-1)
|
||||||
const lowerIndex = computed(()=>!flipped.value ? 0 : weights.value.length-1)
|
const lowerIndex = computed(()=>!flipped.value ? 0 : weights.value.length-1)
|
||||||
const innerIndexes = computed(()=>{
|
const innerIndexes = computed(()=>{
|
||||||
const result = []
|
|
||||||
const n = prices.value.length
|
const n = prices.value.length
|
||||||
const f = flipped.value
|
const f = flipped.value
|
||||||
|
const result = []
|
||||||
for (let i=1; i<n-1; i++)
|
for (let i=1; i<n-1; i++)
|
||||||
result.push(f?i:n-1-i)
|
result.push(f?i:n-1-i)
|
||||||
return result
|
return result
|
||||||
@@ -210,6 +212,10 @@ function getModelValue(model) {
|
|||||||
return model.price
|
return model.price
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPointsValue(points) {
|
||||||
|
return points[0].price
|
||||||
|
}
|
||||||
|
|
||||||
function setModelValue(model, value) {
|
function setModelValue(model, value) {
|
||||||
// console.log('setModelValue->', {...model}, value)
|
// console.log('setModelValue->', {...model}, value)
|
||||||
if (model.price !== value)
|
if (model.price !== value)
|
||||||
@@ -220,12 +226,6 @@ function setModelValue(model, value) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
:deep(.v-slider.v-input--vertical > .v-input__control) {
|
|
||||||
min-height: 5em !important;
|
|
||||||
}
|
|
||||||
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
|
|
||||||
background-color: inherit !important;
|
|
||||||
}
|
|
||||||
td.weight {
|
td.weight {
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
padding-right: 0.5em;
|
padding-right: 0.5em;
|
||||||
|
|||||||
@@ -36,12 +36,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BuilderPanel from "@/components/chart/BuilderPanel.vue";
|
import BuilderPanel from "@/components/chart/BuilderPanel.vue";
|
||||||
import {useOrderStore} from "@/store/store.js";
|
import {useOrderStore} from "@/store/store.js";
|
||||||
import {allocationText, deleteBuilder, linearWeights, useChartOrderStore, weightColors} from "@/orderbuild.js";
|
import {deleteBuilder, linearWeights, useChartOrderStore} from "@/orderbuild.js";
|
||||||
import {useTheme} from "vuetify";
|
import {useTheme} from "vuetify";
|
||||||
import {linspace, sideColor} from "@/misc.js";
|
import {linspace, sideColor} from "@/misc.js";
|
||||||
import {computed, onUnmounted, watchEffect} from "vue";
|
import {computed, onUnmounted, watchEffect} from "vue";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
import {cancelDrawing} from "@/charts/chart.js";
|
import {cancelDrawing, chart} from "@/charts/chart.js";
|
||||||
|
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
@@ -56,14 +56,15 @@ const props = defineProps({
|
|||||||
stdWidth: Number,
|
stdWidth: Number,
|
||||||
shape: Function, // shape() -> Shape
|
shape: Function, // shape() -> Shape
|
||||||
mode: { type: Number, default: 0 }, // rung addition mode: 0 = split, 1 = extend
|
mode: { type: Number, default: 0 }, // rung addition mode: 0 = split, 1 = extend
|
||||||
|
flip: { type: Boolean, default: false }, // if true, the skew slider is flipped upside-down
|
||||||
getModelValue: Function, // getModelValue(model) -> value
|
getModelValue: Function, // getModelValue(model) -> value
|
||||||
setModelValue: Function, // setModelValue(model,value) -> void
|
setModelValue: Function, // setModelValue(model,value) -> void
|
||||||
|
getPointsValue: Function, // getValueFromPoints(points) -> value
|
||||||
setValues: Function, // setValues(values:Array) -> void
|
setValues: Function, // setValues(values:Array) -> void
|
||||||
setWeights: Function, // setValues(values:Array) -> void
|
setWeights: Function, // setValues(values:Array) -> void
|
||||||
})
|
})
|
||||||
|
|
||||||
const flipped = computed(() => valueA.value !== null && valueB.value !== null && valueA.value > valueB.value)
|
const flippedSign = computed(()=>props.flip?-1:1)
|
||||||
const flippedSign = computed(()=>flipped.value?-1:1)
|
|
||||||
|
|
||||||
const skew100 = computed( {
|
const skew100 = computed( {
|
||||||
get() {return flippedSign.value*props.builder.skew*100},
|
get() {return flippedSign.value*props.builder.skew*100},
|
||||||
@@ -73,9 +74,9 @@ const skew100 = computed( {
|
|||||||
// validity checks
|
// validity checks
|
||||||
watchEffect(()=>{
|
watchEffect(()=>{
|
||||||
const rungs = props.builder.rungs
|
const rungs = props.builder.rungs
|
||||||
const prev = props.builder.valid
|
// const prev = props.builder.valid
|
||||||
props.builder.valid = rungs >= 1 && valueA.value && (rungs < 2 || valueB.value)
|
props.builder.valid = rungs >= 1 && valueA.value && (rungs < 2 || valueB.value)
|
||||||
console.log('valid?', prev, props.builder.valid, rungs, valueA.value, valueB.value)
|
// console.log('valid?', prev, props.builder.valid, rungs, valueA.value, valueB.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ const values = computed(()=>{
|
|||||||
|
|
||||||
|
|
||||||
const weights = computed(() => {
|
const weights = computed(() => {
|
||||||
// const skew = flipped.value ? -props.builder.skew : props.builder.skew
|
// const skew = props.flip ? -props.builder.skew : props.builder.skew
|
||||||
const ws = linearWeights(props.builder.rungs, -props.builder.skew)
|
const ws = linearWeights(props.builder.rungs, -props.builder.skew)
|
||||||
if (props.setWeights)
|
if (props.setWeights)
|
||||||
props.setWeights(ws)
|
props.setWeights(ws)
|
||||||
@@ -184,6 +185,7 @@ function createShape(value, model, onModel, onDelete) {
|
|||||||
function translateOnDrag(shape) {
|
function translateOnDrag(shape) {
|
||||||
const oldOnPoints = shape.onPoints
|
const oldOnPoints = shape.onPoints
|
||||||
shape.onPoints = function (points) {
|
shape.onPoints = function (points) {
|
||||||
|
// console.log('translateOnDrag', this.beingDragged(), shape.ourPoints)
|
||||||
if (!this.beingDragged()) {
|
if (!this.beingDragged()) {
|
||||||
oldOnPoints.call(this, points)
|
oldOnPoints.call(this, points)
|
||||||
return
|
return
|
||||||
@@ -192,6 +194,7 @@ function translateOnDrag(shape) {
|
|||||||
oldOnPoints.call(this, points)
|
oldOnPoints.call(this, points)
|
||||||
const cur = props.getModelValue(this.model)
|
const cur = props.getModelValue(this.model)
|
||||||
const delta = cur - prev
|
const delta = cur - prev
|
||||||
|
// console.log('delta', points, shape.ourPoints, prev, cur, delta)
|
||||||
if (delta !== 0) {
|
if (delta !== 0) {
|
||||||
valueA.value += delta
|
valueA.value += delta
|
||||||
valueB.value += delta
|
valueB.value += delta
|
||||||
@@ -199,6 +202,28 @@ function translateOnDrag(shape) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function translateOnDrag(shape) {
|
||||||
|
// const oldOnPoints = shape.onPoints
|
||||||
|
// shape.onPoints = function (points) {
|
||||||
|
// console.log('translateOnDrag', this.beingDragged(), shape.ourPoints)
|
||||||
|
// if (!this.beingDragged()) {
|
||||||
|
// oldOnPoints.call(this, points)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // todo vectorize
|
||||||
|
// const prev = props.getPointsValue(shape.ourPoints)
|
||||||
|
// const cur = props.getPointsValue(points)
|
||||||
|
// const delta = cur - prev
|
||||||
|
// console.log('delta', points, shape.ourPoints, prev, cur, delta)
|
||||||
|
// if (delta !== 0) {
|
||||||
|
// valueA.value += delta
|
||||||
|
// valueB.value += delta
|
||||||
|
// }
|
||||||
|
// oldOnPoints.call(this, points)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
const shapeA = createShape(valueA.value, {color: defaultColor},
|
const shapeA = createShape(valueA.value, {color: defaultColor},
|
||||||
function (model) {
|
function (model) {
|
||||||
@@ -258,10 +283,42 @@ function makeModel(index) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let group = null
|
||||||
function adjustShapes() {
|
function adjustShapes() {
|
||||||
// this is where all the shapes are created or adjusted
|
// this is where all the shapes are created or adjusted
|
||||||
// console.log('adjustShapes()', valueA.value, valueB.value)
|
// console.log('adjustShapes()', valueA.value, valueB.value)
|
||||||
const vs = values.value
|
const vs = values.value
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// const selection = []
|
||||||
|
// if (shapeA.id !== null)
|
||||||
|
// selection.push(shapeA.id)
|
||||||
|
// if (shapeB.id !== null)
|
||||||
|
// selection.push(shapeB.id)
|
||||||
|
// for( const s of interiorShapes ) {
|
||||||
|
// if (s.id !== null)
|
||||||
|
// selection.push(s.id)
|
||||||
|
// }
|
||||||
|
// if (group===null) {
|
||||||
|
// if (selection.length) {
|
||||||
|
// const gc = chart.shapesGroupController();
|
||||||
|
// group = gc.createGroupFromSelection(selection)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// const gc = chart.shapesGroupController();
|
||||||
|
// const shapes = gc.shapesInGroup(group)
|
||||||
|
//
|
||||||
|
// console.log('shapes', group, shapes)
|
||||||
|
// for (const s of selection)
|
||||||
|
// if (!shapes.includes(s)) {
|
||||||
|
// console.log('add shape to group', group, s)
|
||||||
|
// gc.addShapeToGroup(group, s)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
if (vs.length)
|
if (vs.length)
|
||||||
cancelDrawing()
|
cancelDrawing()
|
||||||
// shape properties
|
// shape properties
|
||||||
@@ -306,10 +363,13 @@ function adjustShapes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteSelf() {
|
function deleteSelf() {
|
||||||
|
if (valueA.value===null)
|
||||||
|
cancelDrawing()
|
||||||
deleteBuilder(props.order, props.builder);
|
deleteBuilder(props.order, props.builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteShapes() {
|
function deleteShapes() {
|
||||||
|
cancelDrawing()
|
||||||
shapeA.delete()
|
shapeA.delete()
|
||||||
shapeB.delete()
|
shapeB.delete()
|
||||||
for (const shape of interiorShapes)
|
for (const shape of interiorShapes)
|
||||||
@@ -325,5 +385,10 @@ if (!valueA.value)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
:deep(.v-slider.v-input--vertical > .v-input__control) {
|
||||||
|
min-height: 5em !important;
|
||||||
|
}
|
||||||
|
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
|
||||||
|
background-color: inherit !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -272,7 +272,7 @@ export function allocationText(weight, amount, symbol) {
|
|||||||
const hasWeight = weight!==null && weight!==undefined
|
const hasWeight = weight!==null && weight!==undefined
|
||||||
if (hasWeight)
|
if (hasWeight)
|
||||||
text += `${(weight * 100).toFixed(1)}%`
|
text += `${(weight * 100).toFixed(1)}%`
|
||||||
const hasAmount = amount!==null && amount!==undefined
|
const hasAmount = amount!==null && amount!==undefined && amount > 0
|
||||||
const hasSymbol = symbol!==null && symbol!==undefined
|
const hasSymbol = symbol!==null && symbol!==undefined
|
||||||
if (hasAmount && hasSymbol) {
|
if (hasAmount && hasSymbol) {
|
||||||
if (hasWeight)
|
if (hasWeight)
|
||||||
@@ -284,6 +284,4 @@ export function allocationText(weight, amount, symbol) {
|
|||||||
|
|
||||||
export function deleteBuilder(order, builder) {
|
export function deleteBuilder(order, builder) {
|
||||||
order.builders = order.builders.filter((b) => b !== builder)
|
order.builders = order.builders.filter((b) => b !== builder)
|
||||||
// if (props.deleteShapes) // todo is this redundant?
|
|
||||||
// props.deleteShapes()
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user