diagonals working
This commit is contained in:
13
src/charts/chart-misc.js
Normal file
13
src/charts/chart-misc.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
|
|
||||||
|
export function nearestOhlcStart(time) {
|
||||||
|
// todo subtract OHLC root time
|
||||||
|
const period = useChartOrderStore().intervalSecs
|
||||||
|
return Math.round(time / period) * period
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pointsToOhlcStart(points) {
|
||||||
|
return points === null ? null : points.map((p) => {
|
||||||
|
return {time: nearestOhlcStart(p.time), price: p.price}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
import {invokeCallback, mixin} from "@/common.js";
|
import {invokeCallback, mixin} from "@/common.js";
|
||||||
import {chart, createShape, deleteShapeId, dragging, draggingShapeIds, drawShape, widget} from "@/charts/chart.js";
|
import {chart, createShape, deleteShapeId, dragging, draggingShapeIds, drawShape, widget} from "@/charts/chart.js";
|
||||||
import {pointsToOhlcStart, unique} from "@/misc.js";
|
import {unique} from "@/misc.js";
|
||||||
import {allocationText} from "@/orderbuild.js";
|
import {allocationText} from "@/orderbuild.js";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
|
import {pointsToOhlcStart} from "@/charts/chart-misc.js";
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -544,6 +545,8 @@ export class DLine extends Line {
|
|||||||
// Model
|
// Model
|
||||||
this.model.pointA = null // {time:..., price:...}
|
this.model.pointA = null // {time:..., price:...}
|
||||||
this.model.pointB = null
|
this.model.pointB = null
|
||||||
|
this.model.extendLeft = false
|
||||||
|
this.model.extendRight = false
|
||||||
|
|
||||||
this.setModel(model) // call setModel at the end
|
this.setModel(model) // call setModel at the end
|
||||||
}
|
}
|
||||||
@@ -551,8 +554,8 @@ export class DLine extends Line {
|
|||||||
|
|
||||||
drawingOverrides() {
|
drawingOverrides() {
|
||||||
const result = super.drawingOverrides();
|
const result = super.drawingOverrides();
|
||||||
result.extendLeft = false
|
result.extendLeft = this.model.extendLeft
|
||||||
result.extendRight = false
|
result.extendRight = this.model.extendRight
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +570,8 @@ export class DLine extends Line {
|
|||||||
super.setModel(model)
|
super.setModel(model)
|
||||||
if (model.pointA === null && model.pointB === null)
|
if (model.pointA === null && model.pointB === null)
|
||||||
this.delete()
|
this.delete()
|
||||||
else if ('pointA' in model && 'pointB' in model) {
|
else {
|
||||||
|
if ('pointA' in model && 'pointB' in model) {
|
||||||
const newPoints = [model.pointA, model.pointB];
|
const newPoints = [model.pointA, model.pointB];
|
||||||
const oldPoints = [this.model.pointA, this.model.pointB];
|
const oldPoints = [this.model.pointA, this.model.pointB];
|
||||||
if (dirtyPoints(oldPoints, newPoints)) {
|
if (dirtyPoints(oldPoints, newPoints)) {
|
||||||
@@ -576,6 +580,8 @@ export class DLine extends Line {
|
|||||||
this.setPoints(newPoints)
|
this.setPoints(newPoints)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.setProps({extendLeft:model.extendLeft, extendRight: model.extendRight})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPoints(points) {
|
onPoints(points) {
|
||||||
@@ -589,4 +595,9 @@ export class DLine extends Line {
|
|||||||
this.updateModel({pointA: points[0], pointB: points[1]})
|
this.updateModel({pointA: points[0], pointB: points[1]})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onProps(props) {
|
||||||
|
super.onProps(props);
|
||||||
|
this.updateModel({extendLeft: props.extendLeft, extendRight: props.extendRight})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,27 @@
|
|||||||
:shape="DLine" :mode="0"
|
:shape="DLine" :mode="0"
|
||||||
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
||||||
:set-values="setLines" :set-weights="setWeights"
|
:set-values="setLines" :set-weights="setWeights"
|
||||||
|
:set-shapes="setShapes"
|
||||||
:std-width="stdWidth" :build-tranches="buildTranches">
|
:std-width="stdWidth" :build-tranches="buildTranches">
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2" class="label">Line A</td>
|
<td> </td>
|
||||||
|
<td colspan="3">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<v-switch class="d-inline-flex" v-model="extendLeft" inline
|
||||||
|
:true-value="false" :false-value="true"
|
||||||
|
true-icon="mdi-circle-outline" false-icon="mdi-arrow-left"
|
||||||
|
/>
|
||||||
|
<span class="mx-3">Extend</span>
|
||||||
|
<v-switch class="d-inline-flex" v-model="extendRight" inline
|
||||||
|
false-icon="mdi-circle-outline" true-icon="mdi-arrow-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" rowspan="2">Line A</td>
|
||||||
<td>
|
<td>
|
||||||
<absolute-time-entry v-model="time1A"/>
|
<absolute-time-entry v-model="time1A"/>
|
||||||
</td>
|
</td>
|
||||||
@@ -19,7 +35,10 @@
|
|||||||
label="Price"
|
label="Price"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2" class="weight" style="vertical-align: bottom">{{ allocationTexts[weights.length-1] }}</td>
|
<td rowspan="2" class="weight"
|
||||||
|
:style="'vertical-align: '+(price2A!==null?'bottom':'center')">
|
||||||
|
{{ allocationTexts[weights.length-1] }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
@@ -75,16 +94,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {allocationText, applyLinePoints, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
|
import {allocationText, applyLinePoints, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
|
||||||
import {sideColor} from "@/misc.js";
|
import {sideColor} from "@/misc.js";
|
||||||
import {useOrderStore, useStore} from "@/store/store.js";
|
import {DISTANT_FUTURE, DISTANT_PAST, MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
||||||
import {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} from "vue";
|
||||||
import {DLine} from "@/charts/shape.js";
|
import {DLine} from "@/charts/shape.js";
|
||||||
import {vectorEquals, vectorInterpolate} from "@/vector.js";
|
import {vectorEquals, vectorInterpolate} from "@/vector.js";
|
||||||
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
|
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
|
||||||
|
|
||||||
const s = useStore()
|
|
||||||
const os = useOrderStore()
|
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
const props = defineProps(['order', 'builder'])
|
const props = defineProps(['order', 'builder'])
|
||||||
const emit = defineEmits(['update:builder'])
|
const emit = defineEmits(['update:builder'])
|
||||||
@@ -102,6 +118,8 @@ const color = computed(()=>props.builder.color ? props.builder.color : defaultCo
|
|||||||
builderDefaults(props.builder, {
|
builderDefaults(props.builder, {
|
||||||
lineA: null, // [{time, price}, {time, price}]
|
lineA: null, // [{time, price}, {time, price}]
|
||||||
lineB: null,
|
lineB: null,
|
||||||
|
extendLeft: false,
|
||||||
|
extendRight: false,
|
||||||
rungs: 1,
|
rungs: 1,
|
||||||
skew: 0,
|
skew: 0,
|
||||||
color: defaultColor,
|
color: defaultColor,
|
||||||
@@ -123,7 +141,18 @@ function buildTranches() {
|
|||||||
const isMinimum = inverted === order.buy
|
const isMinimum = inverted === order.buy
|
||||||
for (let i = 0; i < ws.length; i++) {
|
for (let i = 0; i < ws.length; i++) {
|
||||||
const w = ws[i]
|
const w = ws[i]
|
||||||
|
const t = newTranche({fraction: w * MAX_FRACTION})
|
||||||
const line = ws.length === 1 ? la : vectorInterpolate(la, lb, i/(ws.length-1))
|
const line = ws.length === 1 ? la : vectorInterpolate(la, lb, i/(ws.length-1))
|
||||||
|
const el = extendLeft.value
|
||||||
|
const er = extendRight.value
|
||||||
|
const reversed = line[0] > line[2]
|
||||||
|
if (reversed ? !er : !el)
|
||||||
|
t.startTime = reversed ? line[2] : line[0]
|
||||||
|
if (reversed ? !el : !er)
|
||||||
|
t.endTime = reversed ? line[0] : line[2]
|
||||||
|
// console.log('tranche start/end',
|
||||||
|
// t.startTime === DISTANT_PAST ? 'PAST' : t.startTime,
|
||||||
|
// t.endTime === DISTANT_FUTURE ? 'FUTURE' : t.endTime)
|
||||||
if (inverted) {
|
if (inverted) {
|
||||||
// invert prices
|
// invert prices
|
||||||
line[1] = 1/line[1]
|
line[1] = 1/line[1]
|
||||||
@@ -132,7 +161,6 @@ function buildTranches() {
|
|||||||
// scale to pool decimals
|
// scale to pool decimals
|
||||||
line[1] *= scale
|
line[1] *= scale
|
||||||
line[3] *= scale
|
line[3] *= scale
|
||||||
const t = newTranche({fraction: w * MAX_FRACTION})
|
|
||||||
applyLinePoints(t, isMinimum, ...line)
|
applyLinePoints(t, isMinimum, ...line)
|
||||||
tranches.push(t)
|
tranches.push(t)
|
||||||
}
|
}
|
||||||
@@ -262,6 +290,49 @@ function update(a, b) { // a and b are lines of two points
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let shapeA = null
|
||||||
|
let shapeB = null
|
||||||
|
|
||||||
|
function setShapes(a,b) {
|
||||||
|
shapeA = a
|
||||||
|
shapeB = b
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const _extendLeft = ref(false)
|
||||||
|
const extendLeft = computed({
|
||||||
|
get() {return _extendLeft.value},
|
||||||
|
set(v) {
|
||||||
|
console.log('set extendLeft', v)
|
||||||
|
if (v !== _extendLeft.value) {
|
||||||
|
console.log('DO set extendLeft')
|
||||||
|
_extendLeft.value = v;
|
||||||
|
const b = {...props.builder}
|
||||||
|
b.extendLeft = v
|
||||||
|
// shapeA.setModel({extendLeft: v})
|
||||||
|
// shapeB.setModel({extendLeft: v})
|
||||||
|
emit('update:builder', b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const _extendRight = ref(false)
|
||||||
|
const extendRight = computed({
|
||||||
|
get() {return _extendRight.value},
|
||||||
|
set(v) {
|
||||||
|
if (v !== _extendRight.value) {
|
||||||
|
_extendRight.value = v;
|
||||||
|
const b = {...props.builder}
|
||||||
|
b.extendRight = v
|
||||||
|
// shapeA.setModel({extendRight: v})
|
||||||
|
// shapeB.setModel({extendRight: v})
|
||||||
|
emit('update:builder', b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const innerIndexes = computed(() => {
|
const innerIndexes = computed(() => {
|
||||||
const n = flatLines.value.length
|
const n = flatLines.value.length
|
||||||
const result = []
|
const result = []
|
||||||
@@ -294,6 +365,10 @@ function getModelValue(model) {
|
|||||||
// model is the DLine shape's model object
|
// model is the DLine shape's model object
|
||||||
if (!model.pointA || !model.pointB)
|
if (!model.pointA || !model.pointB)
|
||||||
return null
|
return null
|
||||||
|
if (model.extendLeft !== _extendLeft.value)
|
||||||
|
extendLeft.value = model.extendLeft
|
||||||
|
if (model.extendRight !== _extendRight.value)
|
||||||
|
extendRight.value = model.extendRight
|
||||||
const result = flattenLine([model.pointA, model.pointB]);
|
const result = flattenLine([model.pointA, model.pointB]);
|
||||||
// console.log('getModelValue', {...model}, result)
|
// console.log('getModelValue', {...model}, result)
|
||||||
return result // this is the vector the RungBuilder will interpolate
|
return result // this is the vector the RungBuilder will interpolate
|
||||||
@@ -301,7 +376,7 @@ function getModelValue(model) {
|
|||||||
|
|
||||||
|
|
||||||
function setModelValue(model, value) {
|
function setModelValue(model, value) {
|
||||||
const oldModel = {...model};
|
// const oldModel = {...model};
|
||||||
// console.log('setModelValue', oldModel, value)
|
// console.log('setModelValue', oldModel, value)
|
||||||
const oldLine = !model.pointA || !model.pointB ? null : [model.pointA, model.pointB]
|
const oldLine = !model.pointA || !model.pointB ? null : [model.pointA, model.pointB]
|
||||||
const line = buildLine(value)
|
const line = buildLine(value)
|
||||||
@@ -315,6 +390,10 @@ function setModelValue(model, value) {
|
|||||||
model.pointB = line[1]
|
model.pointB = line[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (model.extendLeft !== _extendLeft.value)
|
||||||
|
model.extendLeft = _extendLeft.value
|
||||||
|
if (model.extendRight !== _extendRight.value)
|
||||||
|
model.extendRight = _extendRight.value
|
||||||
// console.log('setModelValue end', oldModel, value, model)
|
// console.log('setModelValue end', oldModel, value, model)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
class="no-slider-bg ml-2 mr-4" hide-details/>
|
class="no-slider-bg ml-2 mr-4" hide-details/>
|
||||||
<v-text-field type="number" v-model="skew100" min="-100" max="100"
|
<v-text-field type="number" v-model="skew100" min="-100" max="100"
|
||||||
density="compact" hide-details variant="outlined" label="Skew" step="5"
|
density="compact" hide-details variant="outlined" label="Skew" step="5"
|
||||||
:color="color" :base-color="color">
|
:color="color" :base-color="color" class="skew">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-btn icon="mdi-scale-balance" variant="plain" @click="builder.skew=0" :color="color"/>
|
<v-btn icon="mdi-scale-balance" variant="plain" @click="builder.skew=0" :color="color"/>
|
||||||
</template>
|
</template>
|
||||||
@@ -68,6 +68,7 @@ const props = defineProps({
|
|||||||
setModelValue: Function, // setModelValue(model,value) -> void
|
setModelValue: Function, // setModelValue(model,value) -> void
|
||||||
setValues: Function, // setValues(values:Array) -> void
|
setValues: Function, // setValues(values:Array) -> void
|
||||||
setWeights: Function, // setWeights(values:Array) -> void
|
setWeights: Function, // setWeights(values:Array) -> void
|
||||||
|
setShapes: Function, // setShapes([shapeA, innerShape, ..., shapeB]) -> void
|
||||||
})
|
})
|
||||||
|
|
||||||
const flippedSign = computed(()=>props.flip?-1:1)
|
const flippedSign = computed(()=>props.flip?-1:1)
|
||||||
@@ -329,6 +330,7 @@ function adjustShapes() {
|
|||||||
for( const shape of interiorShapes )
|
for( const shape of interiorShapes )
|
||||||
shape.delete()
|
shape.delete()
|
||||||
interiorShapes = []
|
interiorShapes = []
|
||||||
|
props.setShapes([])
|
||||||
}
|
}
|
||||||
else if (vs.length === 1) {
|
else if (vs.length === 1) {
|
||||||
//
|
//
|
||||||
@@ -341,6 +343,7 @@ function adjustShapes() {
|
|||||||
shape.delete()
|
shape.delete()
|
||||||
interiorShapes = []
|
interiorShapes = []
|
||||||
}
|
}
|
||||||
|
props.setShapes([shapeA])
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//
|
//
|
||||||
@@ -359,9 +362,11 @@ function adjustShapes() {
|
|||||||
else
|
else
|
||||||
interiorShapes[i-1].setModel(makeModel(i))
|
interiorShapes[i-1].setModel(makeModel(i))
|
||||||
}
|
}
|
||||||
|
props.setShapes([shapeA, ...interiorShapes, shapeB])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deleteSelf() {
|
function deleteSelf() {
|
||||||
if (endpoints.value[0]===null)
|
if (endpoints.value[0]===null)
|
||||||
cancelDrawing()
|
cancelDrawing()
|
||||||
@@ -375,6 +380,7 @@ function deleteShapes() {
|
|||||||
for (const shape of interiorShapes)
|
for (const shape of interiorShapes)
|
||||||
shape.delete()
|
shape.delete()
|
||||||
interiorShapes = []
|
interiorShapes = []
|
||||||
|
props.setShapes([])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -393,4 +399,8 @@ if (!endpoints.value[0])
|
|||||||
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
|
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
|
||||||
background-color: inherit !important;
|
background-color: inherit !important;
|
||||||
}
|
}
|
||||||
|
.skew {
|
||||||
|
min-width: 9em;
|
||||||
|
max-width: 12em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
12
src/misc.js
12
src/misc.js
@@ -4,7 +4,6 @@ import {token} from "@/blockchain/token.js";
|
|||||||
import Color from "color";
|
import Color from "color";
|
||||||
import {DateTime} from "luxon";
|
import {DateTime} from "luxon";
|
||||||
import router from "@/router/index.js";
|
import router from "@/router/index.js";
|
||||||
import {useChartOrderStore} from "@/orderbuild.js";
|
|
||||||
|
|
||||||
export function nav(name) {
|
export function nav(name) {
|
||||||
// noinspection JSIgnoredPromiseFromCall
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
@@ -251,17 +250,6 @@ export function intervalToSeconds(interval) {
|
|||||||
: 60 // if no unit char, then it's minutes
|
: 60 // if no unit char, then it's minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
function nearestOhlcStart(time) {
|
|
||||||
// todo subtract OHLC root time
|
|
||||||
const period = useChartOrderStore().intervalSecs
|
|
||||||
return Math.round(time / period) * period
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function pointsToOhlcStart(points) {
|
|
||||||
return points === null ? null : points.map((p)=>{return{time:nearestOhlcStart(p.time), price:p.price}})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function interpolate(a, b, zeroToOne) {
|
export function interpolate(a, b, zeroToOne) {
|
||||||
const d = (b-a)
|
const d = (b-a)
|
||||||
|
|||||||
Reference in New Issue
Block a user