155 lines
5.1 KiB
JavaScript
155 lines
5.1 KiB
JavaScript
import {routeInverted, timestamp} from "@/misc.js";
|
|
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
|
|
import {useOrderStore} from "@/store/store.js";
|
|
import {encodeIEE754} from "@/common.js";
|
|
import {defineStore} from "pinia";
|
|
import {computed, ref} from "vue";
|
|
|
|
|
|
function unimplemented() { throw Error('Unimplemented') }
|
|
|
|
// Builders are data objects which store a configuration state
|
|
function TrancheBuilder( component, options = {}) {
|
|
const id = crypto.randomUUID()
|
|
return {id, component, options, points: {}, shapes: {}, props: {}, build: unimplemented}
|
|
}
|
|
|
|
|
|
export const useChartOrderStore = defineStore('chart_orders', () => {
|
|
const builderIdList = ref([]) // this is where we keep the UI ordering
|
|
const builderList = computed(()=>{
|
|
console.log('builder list', builderIdList.value.map((id)=>builderDict.value[id]))
|
|
return builderIdList.value.map((id)=>builderDict.value[id])
|
|
}) // convenience
|
|
const builderDict = ref({}) // builders stored by id
|
|
|
|
const drawing = ref(false)
|
|
const drawingCallbacks = ref(null) // only during draw mode
|
|
|
|
function addBuilder(component, options={}) {
|
|
const b = TrancheBuilder(component,options)
|
|
builderIdList.value.push(b.id)
|
|
builderDict.value[b.id] = b
|
|
}
|
|
|
|
function touchBuilder(builder) {
|
|
// noinspection SillyAssignmentJS
|
|
builderIdList.value = builderIdList.value
|
|
builderDict.value[builder.id] = builder
|
|
}
|
|
|
|
function removeBuilder(builder) {
|
|
builderIdList.value = builderIdList.value.filter((v)=>v!==builder.id)
|
|
delete builderDict.value[builder.id]
|
|
}
|
|
|
|
return { builderList, builderDict, drawing, drawingCallbacks, addBuilder, removeBuilder, touchBuilder }
|
|
})
|
|
|
|
|
|
export function applyLimit(tranche, price = null, isMinimum = null) {
|
|
if (price === null) {
|
|
const os = useOrderStore()
|
|
price = os.limitPrice
|
|
if (!price)
|
|
return
|
|
}
|
|
|
|
applyLine(tranche, price, 0, isMinimum)
|
|
}
|
|
|
|
|
|
function computeInterceptSlope(time0, price0, time1, price1) {
|
|
if (!time0 || !price0 && price0 !== 0 || !time1 || !price1 && price1 !== 0)
|
|
throw Error(`invalid line points data ${time0} ${price0} ${time1} ${price1}`)
|
|
const t0 = time0
|
|
const t1 = time1
|
|
if (t0 === t1)
|
|
throw Error("line points' times must be different")
|
|
const slope = (price1 - price0) / (t1 - t0)
|
|
const intercept = price1 - slope * t1
|
|
return [intercept, slope]
|
|
}
|
|
|
|
|
|
export function linePointsValue(time0, price0, time1, price1, unixTime = null) {
|
|
if (unixTime === null)
|
|
unixTime = timestamp()
|
|
try {
|
|
const [intercept, slope] = computeInterceptSlope(time0, price0, time1, price1)
|
|
return intercept + unixTime * slope
|
|
} catch (e) {
|
|
console.log('error computing line', e)
|
|
return null
|
|
}
|
|
}
|
|
|
|
|
|
export function applyLinePoints(tranche, time0, price0, time1, price1, isMinimum = null) {
|
|
const [intercept, slope] = computeInterceptSlope(time0, price0, time1, price1);
|
|
applyLine(tranche, intercept, slope, isMinimum)
|
|
}
|
|
|
|
|
|
export function applyLine(tranche, intercept, slope, isMinimum = null) {
|
|
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.decimals - os.tokenB.decimals)
|
|
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 timesliceTranches() {
|
|
const ts = []
|
|
const os = useOrderStore()
|
|
const n = os.tranches // num tranches
|
|
const interval = os.interval;
|
|
const timeUnitIndex = os.timeUnitIndex;
|
|
let duration =
|
|
timeUnitIndex === 0 ? interval * 60 : // minutes
|
|
timeUnitIndex === 1 ? interval * 60 * 60 : // hours
|
|
interval * 24 * 60 * 60; // days
|
|
let window
|
|
if (!os.intervalIsTotal) {
|
|
window = duration
|
|
duration *= n // duration is the total time for all tranches
|
|
} else {
|
|
window = Math.round(duration / n)
|
|
}
|
|
if (window < 60)
|
|
window = 60 // always allow at least one minute for execution
|
|
const amtPerTranche = Math.ceil(MAX_FRACTION / n)
|
|
duration -= 15 // subtract 15 seconds so the last tranche completes before the deadline
|
|
for (let i = 0; i < n; i++) {
|
|
const start = Math.floor(i * (duration / Math.max((n - 1), 1)))
|
|
const end = start + window
|
|
ts.push(newTranche({
|
|
fraction: amtPerTranche,
|
|
startTimeIsRelative: true,
|
|
startTime: start,
|
|
endTimeIsRelative: true,
|
|
endTime: end,
|
|
}))
|
|
}
|
|
return ts
|
|
}
|
|
|