initial diagonal work (unfinished)
This commit is contained in:
@@ -27,6 +27,7 @@ function changeSymbol(symbol) {
|
|||||||
lastSymbolChangedArgs = info
|
lastSymbolChangedArgs = info
|
||||||
symbolChangedCbs.forEach((cb)=>cb(info))
|
symbolChangedCbs.forEach((cb)=>cb(info))
|
||||||
co.selectedSymbol = info
|
co.selectedSymbol = info
|
||||||
|
co.meanRange = chartMeanRange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -364,3 +365,21 @@ export function deleteShapeId(id) {
|
|||||||
// console.log('removing entity', id)
|
// console.log('removing entity', id)
|
||||||
chart.removeEntity(id)
|
chart.removeEntity(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chartMeanRange() {
|
||||||
|
let range = 0
|
||||||
|
const series = chart.getSeries()
|
||||||
|
const bars = series.data().bars();
|
||||||
|
const final = Math.max(bars.size() - 50, 0)
|
||||||
|
let count = 0
|
||||||
|
for (let barIndex = bars.size() - 1; barIndex >= final; barIndex--) {
|
||||||
|
count++
|
||||||
|
const [_time, _open, high, low, _close, _volume, _ms] = bars.valueAt(barIndex)
|
||||||
|
range += (high - low)
|
||||||
|
}
|
||||||
|
if (count > 0)
|
||||||
|
range /= count
|
||||||
|
else
|
||||||
|
range = 1
|
||||||
|
return range
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// noinspection JSPotentiallyInvalidUsageOfThis
|
// noinspection JSPotentiallyInvalidUsageOfThis
|
||||||
|
|
||||||
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, draggingShapeIds, drawShape, widget} from "@/charts/chart.js";
|
||||||
import {unique} from "@/misc.js";
|
import {pointsToOhlcStart, unique} from "@/misc.js";
|
||||||
import {allocationText, useChartOrderStore} from "@/orderbuild.js";
|
import {allocationText} from "@/orderbuild.js";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
|
|
||||||
|
|
||||||
@@ -203,11 +203,11 @@ export class Shape {
|
|||||||
// createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
// createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
||||||
options = {...options}
|
options = {...options}
|
||||||
options['overrides'] = props
|
options['overrides'] = props
|
||||||
this.tvPoints = [...points]
|
this.tvPoints = pointsToOhlcStart(points)
|
||||||
this.tvCallbacks = new ShapeTVCallbacks(this);
|
this.tvCallbacks = new ShapeTVCallbacks(this);
|
||||||
const id = createShape(this.type, points, options, this.tvCallbacks)
|
const id = createShape(this.type, this.tvPoints, options, this.tvCallbacks)
|
||||||
// todo set id?
|
// todo set id?
|
||||||
if (this.debug) console.log('created', this.type.name, points, id)
|
if (this.debug) console.log('created', this.type.name, this.tvPoints, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
onCreate(points, props) {
|
onCreate(points, props) {
|
||||||
@@ -241,14 +241,15 @@ export class Shape {
|
|||||||
// 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', this.id, this.ourPoints, points)
|
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()
|
||||||
else {
|
else {
|
||||||
if (this.id === null)
|
if (this.id === null)
|
||||||
this.create()
|
this.create()
|
||||||
else if (dirtyPoints(this.tvPoints, points)) {
|
else {
|
||||||
|
points = pointsToOhlcStart(points)
|
||||||
|
if (dirtyPoints(this.tvPoints, points)) {
|
||||||
const s = this.tvShape();
|
const s = this.tvShape();
|
||||||
const lbe = s._model._lineBeingEdited
|
const lbe = s._model._lineBeingEdited
|
||||||
const lpbc = s._model._linePointBeingChanged
|
const lpbc = s._model._linePointBeingChanged
|
||||||
@@ -261,6 +262,7 @@ export class Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onPoints(points) {} // the control points of an existing shape were changed
|
onPoints(points) {} // the control points of an existing shape were changed
|
||||||
|
|
||||||
@@ -376,15 +378,15 @@ class ShapeTVCallbacks {
|
|||||||
onPoints(shapeId, _tvShape, points) {
|
onPoints(shapeId, _tvShape, points) {
|
||||||
if (!this.enabled) return // possible when shape is deleted and re-created
|
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.onPoints(points)
|
this.shape.onPoints(points)
|
||||||
|
this.shape.tvPoints = points
|
||||||
}
|
}
|
||||||
|
|
||||||
onProps(shapeId, _tvShape, props) {
|
onProps(shapeId, _tvShape, props) {
|
||||||
if (!this.enabled) return // possible when shape is deleted and re-created
|
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)
|
||||||
this.shape.tvProps = props
|
|
||||||
this.shape.onProps(props)
|
this.shape.onProps(props)
|
||||||
|
this.shape.tvProps = props
|
||||||
}
|
}
|
||||||
|
|
||||||
onDraw() {
|
onDraw() {
|
||||||
@@ -492,12 +494,6 @@ export class HLine extends Line {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function nearestOhlcStart(time) {
|
|
||||||
const period = useChartOrderStore().intervalSecs
|
|
||||||
return Math.round(time/period) * period
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class VLine extends Line {
|
export class VLine extends Line {
|
||||||
constructor(model, onModel=null, onDelete=null, props=null) {
|
constructor(model, onModel=null, onDelete=null, props=null) {
|
||||||
super(ShapeType.VLine, onModel, onDelete, props)
|
super(ShapeType.VLine, onModel, onDelete, props)
|
||||||
@@ -505,23 +501,12 @@ export class VLine extends Line {
|
|||||||
// Model
|
// Model
|
||||||
this.model.time = null
|
this.model.time = null
|
||||||
|
|
||||||
// since VLines must be on the start of an OHLC boundry, we track that value separately
|
|
||||||
this.shapeTime = null
|
|
||||||
|
|
||||||
this.setModel(model) // call setModel at the end
|
this.setModel(model) // call setModel at the end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
doCreate(points, props, options = {}) {
|
|
||||||
this.shapeTime = nearestOhlcStart(points[0].time);
|
|
||||||
points = [{time: this.shapeTime, price:0}]
|
|
||||||
if (this.debug) console.log('VLine.doCreate', this.shapeTime, points)
|
|
||||||
super.doCreate(points, props, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.model.time = null
|
this.model.time = null
|
||||||
this.shapeTime = null
|
|
||||||
super.delete()
|
super.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,26 +522,9 @@ export class VLine extends Line {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPoints(points) {
|
|
||||||
// if (this.debug) console.error('VLine setPoints...', points)
|
|
||||||
if (points !== null && points.length) {
|
|
||||||
// adjust shape to ohlc boundry
|
|
||||||
const time = nearestOhlcStart(points[0].time);
|
|
||||||
if (time !== this.shapeTime) {
|
|
||||||
this.shapeTime = time
|
|
||||||
super.setPoints([{time, price:0}]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.shapeTime = null
|
|
||||||
super.setPoints(points);
|
|
||||||
}
|
|
||||||
// if (this.debug) console.error('VLine setPoints', points)
|
|
||||||
}
|
|
||||||
|
|
||||||
onPoints(points) {
|
onPoints(points) {
|
||||||
const time = points[0].time;
|
const time = points[0].time;
|
||||||
if ( time !== this.shapeTime ) {
|
if ( time !== this.tvPoints[0].time ) {
|
||||||
super.onPoints(points);
|
super.onPoints(points);
|
||||||
this.updateModel({time: time})
|
this.updateModel({time: time})
|
||||||
}
|
}
|
||||||
@@ -564,3 +532,50 @@ export class VLine extends Line {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class DLine extends Line {
|
||||||
|
constructor(model, onModel=null, onDelete=null, props=null) {
|
||||||
|
super(ShapeType.Line, onModel, onDelete, props)
|
||||||
|
|
||||||
|
this.debug = true // todo debug
|
||||||
|
|
||||||
|
// Model
|
||||||
|
this.model.pointA = null // {time:..., price:...}
|
||||||
|
this.model.pointB = null
|
||||||
|
|
||||||
|
// since VLines must be on the start of an OHLC boundry, we track those value separately
|
||||||
|
this.shapeTimes = null
|
||||||
|
|
||||||
|
this.setModel(model) // call setModel at the end
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
this.model.pointA = null
|
||||||
|
this.model.pointB = null
|
||||||
|
super.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
setModel(model) {
|
||||||
|
super.setModel(model)
|
||||||
|
if (model.pointA === null || model.pointB === null)
|
||||||
|
this.delete()
|
||||||
|
else if (dirtyPoints(this.model.pointA, model.pointA) || dirtyPoints(this.model.pointB, model.pointB)) {
|
||||||
|
this.model.pointA = model.pointA
|
||||||
|
this.model.pointB = model.pointB
|
||||||
|
this.setPoints([model.pointA, model.pointB])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPoints(points) {
|
||||||
|
let dirty = this.tvPoints === null
|
||||||
|
for (let i=0; !dirty && i<points.length; i++) {
|
||||||
|
if( points[i].time !== this.tvPoints[i].time)
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
if (dirty) {
|
||||||
|
super.onPoints(points);
|
||||||
|
this.updateModel({pointA: points[0], pointB: points[0]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const emit = defineEmits(['update:modelValue'])
|
|||||||
|
|
||||||
const hideDetails = true
|
const hideDetails = true
|
||||||
|
|
||||||
const now = computed(()=>{console.log('ate now',props.modelValue); return DateTime.fromSeconds(props.modelValue).setZone(s.timeZone)})
|
const now = computed(()=>DateTime.fromSeconds(props.modelValue).setZone(s.timeZone))
|
||||||
|
|
||||||
const year = computed({
|
const year = computed({
|
||||||
get() { return now.value.year },
|
get() { return now.value.year },
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ watchEffect(()=>{
|
|||||||
const absTimeA = computed({
|
const absTimeA = computed({
|
||||||
get() { return _timeEndpoints.value[0] },
|
get() { return _timeEndpoints.value[0] },
|
||||||
set(v) {
|
set(v) {
|
||||||
console.log('set A', v)
|
|
||||||
if (v!==null)
|
if (v!==null)
|
||||||
v = Number(v)
|
v = Number(v)
|
||||||
updateA(v)
|
updateA(v)
|
||||||
|
|||||||
181
src/components/chart/DiagonalBuilder.vue
Normal file
181
src/components/chart/DiagonalBuilder.vue
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
<template>
|
||||||
|
<rung-builder name="Diagonal" :order="order" :builder="builder" v-model="endpoints"
|
||||||
|
:shape="DLine" :mode="0"
|
||||||
|
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
||||||
|
:get-points-value="getPointsValue"
|
||||||
|
:set-values="setLines" :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">{{ allocationText(weights[higherIndex]) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="i in innerIndexes" class="ml-5">
|
||||||
|
<td class="pl-5">{{ prices[i] }}</td>
|
||||||
|
<td class="weight">{{ allocationText(weights[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 ? allocationText(weights[lowerIndex]) : '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</rung-builder>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {allocationText, applyLine, applyLinePoints, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
|
||||||
|
import {interpolate, 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 {DLine} from "@/charts/shape.js";
|
||||||
|
import {vectorInterpolate} from "@/vector.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, {
|
||||||
|
lineA: [null, null], // [{time, price}, {time, price}]
|
||||||
|
lineB: [null, null],
|
||||||
|
rungs: 1,
|
||||||
|
skew: 0,
|
||||||
|
color: defaultColor,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function buildTranches() {
|
||||||
|
throw Error('unimplemented') // todo
|
||||||
|
const order = props.order
|
||||||
|
const builder = props.builder
|
||||||
|
const tranches = []
|
||||||
|
|
||||||
|
console.log('buildTranches', builder, order, tranches)
|
||||||
|
const la = buildLine(_endpoints[0])
|
||||||
|
const lb = buildLine(_endpoints[1])
|
||||||
|
const ws = weights.value
|
||||||
|
for (let i = 0; i < ws.length; i++) {
|
||||||
|
const w = ws[i]
|
||||||
|
const line = vectorInterpolate(la, lb, i/(ws.length-1))
|
||||||
|
const t = newTranche({fraction: w * MAX_FRACTION})
|
||||||
|
const symbol = co.selectedSymbol
|
||||||
|
console.log('symbol', symbol)
|
||||||
|
applyLinePoints(t, order.buy, ...line, symbol.decimals, symbol.inverted)
|
||||||
|
tranches.push(t)
|
||||||
|
}
|
||||||
|
return tranches
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function flattenLine(l) {
|
||||||
|
return l === null ? [null, null, null, null] : [l[0].time, l[0].price, l[1].time, l[1].price]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildLine(f) {
|
||||||
|
return f[0] === null ? null : [{time: f[0], price: f[1]}, {time: f[2], price: f[3]}]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _endpoints = ref([flattenLine(props.builder.lineA), flattenLine(props.builder.lineB)])
|
||||||
|
const endpoints = computed({
|
||||||
|
get() {
|
||||||
|
return _endpoints.value
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
const [a, b] = v
|
||||||
|
update(a, b)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function update(a, b) { // a and b are lines of two points
|
||||||
|
_endpoints.value = [flattenLine(a), flattenLine(b)]
|
||||||
|
const newBuilder = {...props.builder}
|
||||||
|
newBuilder.lineA = a
|
||||||
|
newBuilder.lineB = b
|
||||||
|
emit('update:builder', newBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const innerIndexes = computed(() => {
|
||||||
|
const n = flatLines.value.length
|
||||||
|
const result = []
|
||||||
|
for (let i = 1; i < n - 1; i++)
|
||||||
|
result.push(n - 1 - i)
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const flatLines = ref([])
|
||||||
|
const weights = ref([])
|
||||||
|
|
||||||
|
function setLines(ls) {
|
||||||
|
flatLines.value = ls
|
||||||
|
}
|
||||||
|
|
||||||
|
function setWeights(ws) {
|
||||||
|
weights.value = ws
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const color = computed(() => props.builder.color ? props.builder.color : defaultColor)
|
||||||
|
|
||||||
|
const stdWidth = [2 * co.meanRange, 2 * co.meanRange]
|
||||||
|
|
||||||
|
|
||||||
|
function getModelValue(model) {
|
||||||
|
if (!model)
|
||||||
|
return null
|
||||||
|
return [flattenLine(model.lineA), flattenLine(model.lineB)]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPointsValue(points) {
|
||||||
|
return points[0].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>
|
||||||
|
|
||||||
@@ -42,14 +42,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {applyLine2, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
|
import {allocationText, applyLine, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
|
||||||
import {sideColor} from "@/misc.js";
|
import {sideColor} from "@/misc.js";
|
||||||
import {useTheme} from "vuetify";
|
|
||||||
import {useOrderStore, useStore} from "@/store/store.js";
|
import {useOrderStore, useStore} from "@/store/store.js";
|
||||||
import {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, watchEffect} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import {chart} from "@/charts/chart.js";
|
import {chartMeanRange} from "@/charts/chart.js";
|
||||||
import {HLine} from "@/charts/shape.js";
|
import {HLine} from "@/charts/shape.js";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
@@ -93,7 +92,7 @@ function buildTranches() {
|
|||||||
})
|
})
|
||||||
const symbol = co.selectedSymbol
|
const symbol = co.selectedSymbol
|
||||||
console.log('symbol', symbol)
|
console.log('symbol', symbol)
|
||||||
applyLine2(t, !order.buy, p, 0, symbol.decimals, symbol.inverted)
|
applyLine(t, , p, 0, symbol.decimals, symbol.inverted)
|
||||||
tranches.push(t)
|
tranches.push(t)
|
||||||
}
|
}
|
||||||
return tranches
|
return tranches
|
||||||
@@ -195,39 +194,8 @@ function setWeights(ws) { weights.value = ws }
|
|||||||
|
|
||||||
const color = computed(()=>props.builder.color ? props.builder.color : defaultColor)
|
const color = computed(()=>props.builder.color ? props.builder.color : defaultColor)
|
||||||
|
|
||||||
function computeRange() {
|
const stdWidth = 2*co.meanRange
|
||||||
let range = 0
|
|
||||||
const series = chart.getSeries()
|
|
||||||
const bars = series.data().bars();
|
|
||||||
const final = Math.max(bars.size() - 50, 0)
|
|
||||||
let count = 0
|
|
||||||
for (let barIndex = bars.size() - 1; barIndex >= final; barIndex--) {
|
|
||||||
count++
|
|
||||||
const [_time, _open, high, low, _close, _volume, _ms] = bars.valueAt(barIndex)
|
|
||||||
range += (high - low)
|
|
||||||
}
|
|
||||||
if (count > 0)
|
|
||||||
range /= count
|
|
||||||
else
|
|
||||||
range = 1
|
|
||||||
return range
|
|
||||||
}
|
|
||||||
|
|
||||||
const stdWidth = 2*computeRange() // todo make reactive
|
|
||||||
|
|
||||||
|
|
||||||
const amountSymbol = computed(()=>props.order.amountIsTokenA ? co.selectedSymbol.base.s : co.selectedSymbol.quote.s )
|
|
||||||
|
|
||||||
|
|
||||||
// todo move into misc and use in shape as well
|
|
||||||
function allocationText(weight) {
|
|
||||||
const alloc = props.builder.allocation
|
|
||||||
if (alloc===null) return ''
|
|
||||||
const w = weight * alloc
|
|
||||||
// console.log('weight', weight, alloc, props.amount)
|
|
||||||
const a = props.order.amount * w
|
|
||||||
return `${(w*100).toFixed(1)}% = ${a.toLocaleString('fullwide')} ${amountSymbol.value}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function getModelValue(model) {
|
function getModelValue(model) {
|
||||||
if(!model)
|
if(!model)
|
||||||
|
|||||||
@@ -41,7 +41,16 @@ import {linspace, sideColor} from "@/misc.js";
|
|||||||
import {computed, watchEffect} from "vue";
|
import {computed, watchEffect} from "vue";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
import {cancelDrawing} from "@/charts/chart.js";
|
import {cancelDrawing} from "@/charts/chart.js";
|
||||||
import {devectorize, vectorAdd, vectorDiv, vectorMul, vectorSub, vectorIsNull, vectorize} from "@/vector.js";
|
import {
|
||||||
|
devectorize,
|
||||||
|
vectorAdd,
|
||||||
|
vectorDiv,
|
||||||
|
vectorMul,
|
||||||
|
vectorSub,
|
||||||
|
vectorIsNull,
|
||||||
|
vectorize,
|
||||||
|
vectorIsZero
|
||||||
|
} from "@/vector.js";
|
||||||
|
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
@@ -99,9 +108,8 @@ const rungs = computed({
|
|||||||
r = Number(r)
|
r = Number(r)
|
||||||
const prevR = Number(props.builder.rungs)
|
const prevR = Number(props.builder.rungs)
|
||||||
props.builder.rungs = r
|
props.builder.rungs = r
|
||||||
console.log('set rungs', prevR, r, a, b)
|
// console.log('set rungs', prevR, r, a, b)
|
||||||
if ( r > 0 && vectorIsNull(b) ) {
|
if ( r > 0 && vectorIsNull(b) ) {
|
||||||
console.log('convert to range')
|
|
||||||
// convert single shape to a range
|
// convert single shape to a range
|
||||||
if (props.mode===0) {
|
if (props.mode===0) {
|
||||||
const width = props.stdWidth
|
const width = props.stdWidth
|
||||||
@@ -126,7 +134,6 @@ const rungs = computed({
|
|||||||
else {
|
else {
|
||||||
// from multi to multi
|
// from multi to multi
|
||||||
if (props.mode===1) {
|
if (props.mode===1) {
|
||||||
console.log('multi-multi mode 1')
|
|
||||||
const width = vectorDiv(vectorSub(b, a), (prevR-1))
|
const width = vectorDiv(vectorSub(b, a), (prevR-1))
|
||||||
b = vectorAdd(a, vectorMul(width, (r-1)))
|
b = vectorAdd(a, vectorMul(width, (r-1)))
|
||||||
setEndpoints(a,b)
|
setEndpoints(a,b)
|
||||||
@@ -222,18 +229,18 @@ function translateOnModel(shape) {
|
|||||||
const oldOnModel = shape.onModel
|
const oldOnModel = shape.onModel
|
||||||
shape.onModel = function (model, oldModel) {
|
shape.onModel = function (model, oldModel) {
|
||||||
oldOnModel.call(this, ...arguments)
|
oldOnModel.call(this, ...arguments)
|
||||||
// console.log('translateOnDrag', this.beingDragged(), shape.ourPoints)
|
|
||||||
if (!this.beingDragged())
|
if (!this.beingDragged())
|
||||||
return
|
return
|
||||||
const prev = getModelValue(oldModel)
|
const prev = getModelValue(oldModel)
|
||||||
const cur = getModelValue(this.model)
|
const cur = vectorize(getModelValue(this.model))
|
||||||
const delta = cur - prev
|
const delta = vectorSub(cur, prev)
|
||||||
// console.log('delta', shape.id, prev, cur, delta)
|
// console.log('delta', shape.id, prev, cur, delta)
|
||||||
let [a, b] = endpoints.value
|
let [a, b] = endpoints.value
|
||||||
if (delta !== 0) {
|
a = vectorize(a)
|
||||||
|
if (!vectorIsZero(delta)) {
|
||||||
a = vectorAdd(a, delta)
|
a = vectorAdd(a, delta)
|
||||||
if (rungs.value > 1)
|
if (rungs.value > 1)
|
||||||
b = vectorAdd(b, delta)
|
b = vectorAdd(vectorize(b), delta)
|
||||||
setEndpoints(a,b)
|
setEndpoints(a,b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-main>
|
<v-main>
|
||||||
<v-alert text="WARNING! TESTNET! FAKE COINS! • UNI • ARB • WETH • WBTC • LINK • USDC •"
|
<v-alert text="TESTNET FAKE COINS • UNI • ARB • WETH • WBTC • LINK • USDC •"
|
||||||
color="red" :closable="false" rounded="0" height="0"/>
|
color="red" :closable="false" rounded="0" height="0"/>
|
||||||
<Alerts/>
|
<Alerts/>
|
||||||
<chart-view/>
|
<chart-view/>
|
||||||
|
|||||||
18
src/misc.js
18
src/misc.js
@@ -4,6 +4,7 @@ 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
|
||||||
@@ -250,3 +251,20 @@ 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) {
|
||||||
|
const d = (b-a)
|
||||||
|
return a + d * zeroToOne
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import {routeInverted, timestamp, uuid} from "@/misc.js";
|
import {timestamp, uuid} from "@/misc.js";
|
||||||
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
||||||
import {useOrderStore, useStore} from "@/store/store.js";
|
import {useOrderStore, useStore} from "@/store/store.js";
|
||||||
import {encodeIEE754} from "@/common.js";
|
import {encodeIEE754} from "@/common.js";
|
||||||
import {defineStore} from "pinia";
|
import {defineStore} from "pinia";
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
|
import {chartMeanRange} from "@/charts/chart.js";
|
||||||
|
|
||||||
|
|
||||||
export const MIN_EXECUTION_TIME = 60 // give at least one full minute for each tranche to trigger
|
export const MIN_EXECUTION_TIME = 60 // give at least one full minute for each tranche to trigger
|
||||||
@@ -64,6 +65,7 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
|
|||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const meanRange = ref(1)
|
||||||
|
|
||||||
const drawing = ref(false)
|
const drawing = ref(false)
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
chartReady, selectedSymbol, selectedPool, intervalSecs, baseToken, quoteToken, price,
|
chartReady, selectedSymbol, selectedPool, intervalSecs, baseToken, quoteToken, price,
|
||||||
orders, drawing, newOrder, removeOrder, resetOrders,
|
orders, drawing, newOrder, removeOrder, resetOrders, meanRange,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -138,40 +140,13 @@ export function linePointsValue(time0, price0, time1, price1, unixTime = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function applyLinePoints(tranche, time0, price0, time1, price1, isMinimum = null) {
|
export function applyLinePoints(tranche, buy, time0, price0, time1, price1, poolDecimals, inverted) {
|
||||||
const [intercept, slope] = computeInterceptSlope(time0, price0, time1, price1);
|
const [intercept, slope] = computeInterceptSlope(time0, price0, time1, price1);
|
||||||
applyLine(tranche, intercept, slope, isMinimum)
|
applyLine(tranche, buy, intercept, slope, poolDecimals, inverted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function applyLine(tranche, intercept, slope, isMinimum = null) {
|
export function applyLine(tranche, buy, intercept, slope, poolDecimals, inverted) {
|
||||||
console.log('intercept, slope', intercept, slope)
|
|
||||||
// intercept and slope are still in "human" units of decimal-adjusted prices
|
|
||||||
const os = useOrderStore()
|
|
||||||
const route = os.route
|
|
||||||
const inverted = routeInverted(route)
|
|
||||||
const scale = 10 ** (os.tokenA.d - os.tokenB.d)
|
|
||||||
let m = inverted ? -scale / slope : slope / scale
|
|
||||||
let b = inverted ? scale / intercept : intercept / scale
|
|
||||||
const cur = b + timestamp() * m
|
|
||||||
console.log('inverted b, m, cur', inverted, b, m, cur)
|
|
||||||
m = encodeIEE754(m)
|
|
||||||
b = encodeIEE754(b)
|
|
||||||
if (isMinimum === null)
|
|
||||||
isMinimum = os.limitIsMinimum
|
|
||||||
console.log('limit is minimum', isMinimum)
|
|
||||||
if (isMinimum) {
|
|
||||||
tranche.minIntercept = b;
|
|
||||||
tranche.minSlope = m;
|
|
||||||
} else {
|
|
||||||
tranche.maxIntercept = b;
|
|
||||||
tranche.maxSlope = m;
|
|
||||||
}
|
|
||||||
tranche.marketOrder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function applyLine2(tranche, isMinimum, intercept, slope, poolDecimals, inverted) {
|
|
||||||
console.log('intercept, slope', intercept, slope)
|
console.log('intercept, slope', intercept, slope)
|
||||||
// intercept and slope are still in "human" units of decimal-adjusted prices
|
// intercept and slope are still in "human" units of decimal-adjusted prices
|
||||||
const scale = 10 ** -poolDecimals
|
const scale = 10 ** -poolDecimals
|
||||||
@@ -181,8 +156,7 @@ export function applyLine2(tranche, isMinimum, intercept, slope, poolDecimals, i
|
|||||||
console.log('inverted b, m, cur', inverted, b, m, cur)
|
console.log('inverted b, m, cur', inverted, b, m, cur)
|
||||||
m = encodeIEE754(m)
|
m = encodeIEE754(m)
|
||||||
b = encodeIEE754(b)
|
b = encodeIEE754(b)
|
||||||
if (inverted)
|
let isMinimum = !(buy ^ inverted)
|
||||||
isMinimum = !isMinimum
|
|
||||||
if (isMinimum) {
|
if (isMinimum) {
|
||||||
tranche.minIntercept = b;
|
tranche.minIntercept = b;
|
||||||
tranche.minSlope = m;
|
tranche.minSlope = m;
|
||||||
|
|||||||
@@ -16,17 +16,23 @@ export function devectorize(value) {
|
|||||||
|
|
||||||
|
|
||||||
export function vectorIsNull(value) {
|
export function vectorIsNull(value) {
|
||||||
console.log('vectorIsNull', value, value === null || value.length === 1 && value[0] === null)
|
|
||||||
return value === null || value.length === 1 && value[0] === null
|
return value === null || value.length === 1 && value[0] === null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function vectorIsZero(value) {
|
||||||
|
for (let i = 0; i < value.length; i++)
|
||||||
|
if (value[i] !== 0)
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function vectorAdd(a, b) {
|
export function vectorAdd(a, b) {
|
||||||
const result = []
|
const result = []
|
||||||
const scalarB = b.length === undefined
|
const scalarB = b.length === undefined
|
||||||
for (let i = 0; i < a.length; i++)
|
for (let i = 0; i < a.length; i++)
|
||||||
result.push(a[i] + (scalarB ? b : b[i]))
|
result.push(a[i] + (scalarB ? b : b[i]))
|
||||||
console.log('vectorAdd', a, b, result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +41,6 @@ export function vectorSub(a, b) {
|
|||||||
const scalarB = b.length === undefined
|
const scalarB = b.length === undefined
|
||||||
for (let i = 0; i < a.length; i++)
|
for (let i = 0; i < a.length; i++)
|
||||||
result.push(a[i] - (scalarB ? b : b[i]))
|
result.push(a[i] - (scalarB ? b : b[i]))
|
||||||
console.log('vectorSub', a, b, result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +49,6 @@ export function vectorMul(a, b) {
|
|||||||
const scalarB = b.length === undefined
|
const scalarB = b.length === undefined
|
||||||
for (let i = 0; i < a.length; i++)
|
for (let i = 0; i < a.length; i++)
|
||||||
result.push(a[i] * (scalarB ? b : b[i]))
|
result.push(a[i] * (scalarB ? b : b[i]))
|
||||||
console.log('vectorMul', a, b, result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +57,13 @@ export function vectorDiv(a, b) {
|
|||||||
const scalarB = b.length === undefined
|
const scalarB = b.length === undefined
|
||||||
for (let i = 0; i < a.length; i++)
|
for (let i = 0; i < a.length; i++)
|
||||||
result.push(a[i] / (scalarB ? b : b[i]))
|
result.push(a[i] / (scalarB ? b : b[i]))
|
||||||
console.log('vectorDiv', a, b, result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function vectorInterpolate(a, b, zeroToOne) {
|
||||||
|
const d = vectorSub(b, a)
|
||||||
|
const offset = vectorMul(d, zeroToOne)
|
||||||
|
return vectorAdd(a, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user