initial chart checkin
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "tradingview"]
|
||||||
|
path = tradingview
|
||||||
|
url = git@git.tolson.net:dexorder/advanced_charts.git
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
<!-- todo times -->
|
<!-- todo times -->
|
||||||
<div class="title">Line Point A</div>
|
<div class="title">Line Point A</div>
|
||||||
<v-divider/>
|
<v-divider/>
|
||||||
<time-entry v-model="time1" class="mb-0" hide-details="true"/>
|
<time-entry v-model="date1" class="mb-0" hide-details="true"/>
|
||||||
<limit-price v-model="price1" label="Price A" :required="true" :show-price="false"/>
|
<limit-price v-model="price1" label="Price A" :required="true" :show-price="false"/>
|
||||||
<div class="title">Line Point B</div>
|
<div class="title">Line Point B</div>
|
||||||
<v-divider/>
|
<v-divider/>
|
||||||
<time-entry v-model="time2" hide-details="true"/>
|
<time-entry v-model="date2" hide-details="true"/>
|
||||||
<limit-price v-model="price2" label="Price B" :required="true" :show-price="false"/>
|
<limit-price v-model="price2" label="Price B" :required="true" :show-price="false"/>
|
||||||
<div v-if="curLimit">
|
<div v-if="curLimit">
|
||||||
<v-row>
|
<v-row>
|
||||||
@@ -32,15 +32,18 @@ import {applyLinePoints, linePointsValue} from "@/orderbuild.js";
|
|||||||
import {newTranche} from "@/blockchain/orderlib.js";
|
import {newTranche} from "@/blockchain/orderlib.js";
|
||||||
import TimeEntry from "@/components/TimeEntry.vue";
|
import TimeEntry from "@/components/TimeEntry.vue";
|
||||||
import RoutePrice from "@/components/RoutePrice.vue";
|
import RoutePrice from "@/components/RoutePrice.vue";
|
||||||
|
import {timestamp} from "@/misc.js";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
|
|
||||||
const time1 = ref(new Date())
|
const date1 = ref(new Date())
|
||||||
const price1 = ref(null)
|
const price1 = ref(null)
|
||||||
const time2 = ref(new Date())
|
const date2 = ref(new Date())
|
||||||
const price2 = ref(null)
|
const price2 = ref(null)
|
||||||
const curLimit = computed(()=>linePointsValue(time1.value, price1.value, time2.value, price2.value, s.time))
|
const time1 = computed(()=>timestamp(date1.value))
|
||||||
|
const time2 = computed(()=>timestamp(date2.value))
|
||||||
|
const curLimit = computed(()=>linePointsValue(time1.value, price1.value, time2.value, price2.value, s.clock))
|
||||||
|
|
||||||
function buildTranches() {
|
function buildTranches() {
|
||||||
const t = newTranche();
|
const t = newTranche();
|
||||||
@@ -49,7 +52,7 @@ function buildTranches() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validOrder() {
|
function validOrder() {
|
||||||
return time1.value && (price1.value || price1.value===0) && time2.value && (price2.value || price2.value===0)
|
return date1.value && (price1.value || price1.value===0) && date2.value && (price2.value || price2.value===0)
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-footer class="text-center d-flex flex-column">
|
<v-footer class="text-center d-flex flex-column mb-12" location="bottom">
|
||||||
<div>
|
<div>
|
||||||
<v-btn icon="mdi-facebook" @click="window.open('https://facebook.com','facebook')"/>
|
<v-btn variant="plain" icon="mdi-facebook" @click="window.open('https://facebook.com','facebook')"/>
|
||||||
<v-btn icon="mdi-twitter" @click="window.open('https://x.com','twitter')"/>
|
<v-btn variant="plain" icon="mdi-twitter" @click="window.open('https://x.com','twitter')"/>
|
||||||
<v-btn icon="mdi-reddit" @click="window.open('https://reddit.com','reddit')"/>
|
<v-btn variant="plain" icon="mdi-reddit" @click="window.open('https://reddit.com','reddit')"/>
|
||||||
<v-btn icon="mdi-discord" @click="window.open('https://discord.com','discord')"/>
|
<v-btn variant="plain" icon="mdi-discord" @click="window.open('https://discord.com','discord')"/>
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Dexorder
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="text-grey logo" style="font-size: small; margin-bottom: 0;">dexorder</div>
|
||||||
|
<div class="text-grey" style="font-size: x-small">©{{ new Date().getFullYear() }}</div>
|
||||||
</v-footer>
|
</v-footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -21,5 +20,10 @@ const s = useStore()
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use "src/styles/vars" as *;
|
@use "src/styles/vars" as *;
|
||||||
|
.v-btn {
|
||||||
|
margin: 0 1em 0 1em;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ function describeTrancheLine(st, isMin, b, m) {
|
|||||||
const t0 = inverted ? st.order.tokenIn : st.order.tokenOut
|
const t0 = inverted ? st.order.tokenIn : st.order.tokenOut
|
||||||
const t1 = !inverted ? st.order.tokenIn : st.order.tokenOut
|
const t1 = !inverted ? st.order.tokenIn : st.order.tokenOut
|
||||||
if( m !== 0 ) {
|
if( m !== 0 ) {
|
||||||
const limit = b + m * s.time
|
const limit = b + m * s.clock
|
||||||
const price = pairPriceAddr(t0, t1, limit);
|
const price = pairPriceAddr(t0, t1, limit);
|
||||||
return 'diagonal ' + (price === null ? null : price.toPrecision(5))
|
return 'diagonal ' + (price === null ? null : price.toPrecision(5))
|
||||||
}
|
}
|
||||||
|
|||||||
146
src/components/SplitPane.vue
Normal file
146
src/components/SplitPane.vue
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
<!-- Adapted from https://phuoc.ng/collection/html-dom/create-resizable-split-views/ -->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="top">
|
||||||
|
<slot name="top"/>
|
||||||
|
</div>
|
||||||
|
<div class="resizer bg-grey-lighten-2" :data-direction="horizontal?'horizontal':'vertical'" ref="resizerElement"></div>
|
||||||
|
<div class="bottom">
|
||||||
|
<slot name="bottom"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
|
||||||
|
const resizerElement = ref()
|
||||||
|
const props = defineProps(['horizontal'])
|
||||||
|
|
||||||
|
function resizable() {
|
||||||
|
const resizer = resizerElement.value
|
||||||
|
const direction = resizer.getAttribute('data-direction') || 'horizontal';
|
||||||
|
const prevSibling = resizer.previousElementSibling;
|
||||||
|
const nextSibling = resizer.nextElementSibling;
|
||||||
|
|
||||||
|
// The current position of mouse
|
||||||
|
let x = 0;
|
||||||
|
let y = 0;
|
||||||
|
let prevSiblingHeight = 0;
|
||||||
|
let prevSiblingWidth = 0;
|
||||||
|
|
||||||
|
// Handle the mousedown event
|
||||||
|
// that's triggered when user drags the resizer
|
||||||
|
const mouseDownHandler = function (e) {
|
||||||
|
// Get the current mouse position
|
||||||
|
x = e.clientX;
|
||||||
|
y = e.clientY;
|
||||||
|
const rect = prevSibling.getBoundingClientRect();
|
||||||
|
prevSiblingHeight = rect.height;
|
||||||
|
prevSiblingWidth = rect.width;
|
||||||
|
|
||||||
|
// Attach the listeners to document
|
||||||
|
document.addEventListener('mousemove', mouseMoveHandler);
|
||||||
|
document.addEventListener('mouseup', mouseUpHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseMoveHandler = function (e) {
|
||||||
|
// How far the mouse has been moved
|
||||||
|
const dx = e.clientX - x;
|
||||||
|
const dy = e.clientY - y;
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case 'vertical':
|
||||||
|
const h =
|
||||||
|
((prevSiblingHeight + dy) * 100) /
|
||||||
|
resizer.parentNode.getBoundingClientRect().height;
|
||||||
|
prevSibling.style.height = h + '%';
|
||||||
|
break;
|
||||||
|
case 'horizontal':
|
||||||
|
default:
|
||||||
|
const w =
|
||||||
|
((prevSiblingWidth + dx) * 100) / resizer.parentNode.getBoundingClientRect().width;
|
||||||
|
prevSibling.style.width = w + '%';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize';
|
||||||
|
resizer.style.cursor = cursor;
|
||||||
|
document.body.style.cursor = cursor;
|
||||||
|
|
||||||
|
prevSibling.style.userSelect = 'none';
|
||||||
|
prevSibling.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
nextSibling.style.userSelect = 'none';
|
||||||
|
nextSibling.style.pointerEvents = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseUpHandler = function () {
|
||||||
|
resizer.style.removeProperty('cursor');
|
||||||
|
document.body.style.removeProperty('cursor');
|
||||||
|
|
||||||
|
prevSibling.style.removeProperty('user-select');
|
||||||
|
prevSibling.style.removeProperty('pointer-events');
|
||||||
|
|
||||||
|
nextSibling.style.removeProperty('user-select');
|
||||||
|
nextSibling.style.removeProperty('pointer-events');
|
||||||
|
|
||||||
|
// Remove the handlers of mousemove and mouseup
|
||||||
|
document.removeEventListener('mousemove', mouseMoveHandler);
|
||||||
|
document.removeEventListener('mouseup', mouseUpHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attach the handler
|
||||||
|
resizer.addEventListener('mousedown', mouseDownHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(resizable)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use 'src/styles/vars' as *;
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resizer[data-direction='horizontal'] {
|
||||||
|
background-color: #cbd5e0;
|
||||||
|
cursor: ew-resize;
|
||||||
|
height: 100%;
|
||||||
|
width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resizer[data-direction='vertical'] {
|
||||||
|
cursor: ns-resize;
|
||||||
|
height: 4px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
height: 68%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
102
src/components/chart/Chart.vue
Normal file
102
src/components/chart/Chart.vue
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="element" class="chart"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import "/tradingview/charting_library/charting_library.js"
|
||||||
|
import "/tradingview/datafeeds/udf/dist/bundle.js"
|
||||||
|
import {onMounted, reactive, ref} from "vue";
|
||||||
|
import {useShapeStore} from "@/store/store.js";
|
||||||
|
|
||||||
|
const element = ref()
|
||||||
|
|
||||||
|
let widget = null;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const el = element.value;
|
||||||
|
widget = window.tvWidget = new TradingView.widget({
|
||||||
|
library_path: "/tradingview/charting_library/",
|
||||||
|
// debug: true,
|
||||||
|
autosize: true,
|
||||||
|
symbol: 'AAPL',
|
||||||
|
interval: '1D',
|
||||||
|
container: el,
|
||||||
|
datafeed: new Datafeeds.UDFCompatibleDatafeed("https://demo-feed-data.tradingview.com"),
|
||||||
|
locale: "en",
|
||||||
|
disabled_features: [],
|
||||||
|
enabled_features: [],
|
||||||
|
drawings_access: {
|
||||||
|
type: 'white',
|
||||||
|
tools: [
|
||||||
|
{name: 'Ray'},
|
||||||
|
{name: 'Trend Line'},
|
||||||
|
{name: 'Horizontal Line'},
|
||||||
|
{name: 'Horizontal Ray'},
|
||||||
|
{name: 'Vertical Line'},
|
||||||
|
{name: 'Extended Line'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
widget.subscribe('drawing_event', handleDrawingEvent)
|
||||||
|
initShapes()
|
||||||
|
})
|
||||||
|
|
||||||
|
const ss = useShapeStore()
|
||||||
|
|
||||||
|
function initShapes() {
|
||||||
|
// const c = widget.activeChart()
|
||||||
|
// for( const s of ss.shapes ) {
|
||||||
|
// const type = s.type.toLowerCase().replace(' ','_')
|
||||||
|
// console.log('create type', type)
|
||||||
|
// c.createMultipointShape(s.points, {shape:type})
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrawingEvent(id, event) {
|
||||||
|
if (event === 'create') {
|
||||||
|
const shape = widget.activeChart().getShapeById(id);
|
||||||
|
const points = shape.getPoints()
|
||||||
|
const props = shape.getProperties()
|
||||||
|
let type;
|
||||||
|
if (points.length === 1)
|
||||||
|
// vertical or horizontal line
|
||||||
|
type = props.textOrientation === 'vertical' ? 'Vertical Line' : props.extendLeft || props.extendRight ? 'Horizontal Ray' : 'Horizontal Line'
|
||||||
|
else if (points.length === 2) {
|
||||||
|
type = !props.extendLeft && !props.extendRight ? 'Trend Line' : props.extendLeft && props.extendRight ? 'Extended Line' : 'Ray'
|
||||||
|
} else
|
||||||
|
console.log('unknown shape', points, props)
|
||||||
|
console.log('create shape', type, points)
|
||||||
|
ss.shapes.push({id, type, points, props})
|
||||||
|
} else if (event === 'points_changed') {
|
||||||
|
const s = ss.shape(id)
|
||||||
|
if( !s ) {
|
||||||
|
console.log('warning: ignoring drawing event for non-existant shape')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const points = widget.activeChart().getShapeById(id).getPoints()
|
||||||
|
if (s.points_changed)
|
||||||
|
s.points_changed(points)
|
||||||
|
ss.shape(id).points = points
|
||||||
|
} else if (event === 'properties_changed') {
|
||||||
|
const s = ss.shape(id)
|
||||||
|
if( !s ) {
|
||||||
|
const props = widget.activeChart().getShapeById(id).getProperties()
|
||||||
|
console.log('warning: ignoring drawing event for non-existant shape', props)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const props = widget.activeChart().getShapeById(id).getProperties()
|
||||||
|
if (s.properties_changed)
|
||||||
|
s.properties_changed(props)
|
||||||
|
ss.shape(id).props = props
|
||||||
|
} else
|
||||||
|
console.log('unknown drawing event', event)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
src/components/chart/ChartOrder.vue
Normal file
17
src/components/chart/ChartOrder.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-expansion-panels class="d-flex">
|
||||||
|
<chart-tranche v-for="s in ss.shapes" :shape="s"/>
|
||||||
|
<!-- <v-expansion-panel v-for="s in ss.shapes" :title="s.type" :text="JSON.stringify(s)"/>-->
|
||||||
|
</v-expansion-panels>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {useShapeStore} from "@/store/store.js";
|
||||||
|
import ChartTranche from "@/components/chart/ChartTranche.vue";
|
||||||
|
const ss = useShapeStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
</style>
|
||||||
18
src/components/chart/ChartTranche.vue
Normal file
18
src/components/chart/ChartTranche.vue
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<limit-tranche v-if="shape?.type==='Horizontal Line' || shape?.type==='Horizontal Ray'" :shape="shape"/>
|
||||||
|
<line-tranche v-if="shape?.type==='Trend Line' || shape?.type==='Extended Line' || shape?.type==='Ray'" :shape="shape"/>
|
||||||
|
<market-tranche v-if="shape?.type==='Vertical Line'" :shape="shape"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import LimitTranche from "@/components/chart/LimitTranche.vue";
|
||||||
|
import LineTranche from "@/components/chart/LineTranche.vue";
|
||||||
|
import MarketTranche from "@/components/chart/MarketTranche.vue";
|
||||||
|
|
||||||
|
const props = defineProps(['shape'])
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
15
src/components/chart/LimitTranche.vue
Normal file
15
src/components/chart/LimitTranche.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<tranche-panel :shape="shape">
|
||||||
|
<template v-slot:title>
|
||||||
|
<span>Limit {{shape.points[0].price}}</span>
|
||||||
|
</template>
|
||||||
|
</tranche-panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import TranchePanel from "@/components/chart/TranchePanel.vue";
|
||||||
|
const props = defineProps(['shape'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
</style>
|
||||||
34
src/components/chart/LineTranche.vue
Normal file
34
src/components/chart/LineTranche.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<tranche-panel :shape="shape">
|
||||||
|
<template v-slot:title>
|
||||||
|
<span>Diagonal Limit (current value {{curValue.toPrecision(5)}})</span>
|
||||||
|
</template>
|
||||||
|
<template v-slot:text>
|
||||||
|
<div>{{shape.points}}</div>
|
||||||
|
<div>{{s.clock}}</div>
|
||||||
|
<div>{{JSON.stringify(shape.props)}}</div>
|
||||||
|
</template>
|
||||||
|
</tranche-panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import TranchePanel from "@/components/chart/TranchePanel.vue";
|
||||||
|
import {computed} from "vue";
|
||||||
|
import {linePointsValue} from "@/orderbuild.js";
|
||||||
|
import {useStore} from "@/store/store.js";
|
||||||
|
|
||||||
|
const props = defineProps(['shape'])
|
||||||
|
|
||||||
|
const s = useStore()
|
||||||
|
|
||||||
|
const curValue = computed(()=>{
|
||||||
|
if( ! props.shape?.points )
|
||||||
|
return 'N/A'
|
||||||
|
const p0 = props.shape.points[0]
|
||||||
|
const p1 = props.shape.points[1]
|
||||||
|
return linePointsValue(p0.time, p0.price, p1.time, p1.price, s.clock)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
</style>
|
||||||
16
src/components/chart/MarketTranche.vue
Normal file
16
src/components/chart/MarketTranche.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<tranche-panel :shape="shape">
|
||||||
|
<template v-slot:title>
|
||||||
|
<span>Market Order at {{dateString(shape.points[0].time)}}</span>
|
||||||
|
</template>
|
||||||
|
</tranche-panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import TranchePanel from "@/components/chart/TranchePanel.vue";
|
||||||
|
import {dateString} from "@/misc.js";
|
||||||
|
const props = defineProps(['shape'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
</style>
|
||||||
21
src/components/chart/TranchePanel.vue
Normal file
21
src/components/chart/TranchePanel.vue
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<v-expansion-panel rounded="0">
|
||||||
|
<v-expansion-panel-title :color="shape.props.linecolor">
|
||||||
|
<slot name="title"><span>{{shape.type}}</span></slot>
|
||||||
|
</v-expansion-panel-title>
|
||||||
|
<v-expansion-panel-text>
|
||||||
|
<slot name="text">
|
||||||
|
<div>{{shape.points}}</div>
|
||||||
|
<div>{{JSON.stringify(shape.props)}}</div>
|
||||||
|
</slot>
|
||||||
|
</v-expansion-panel-text>
|
||||||
|
</v-expansion-panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps(['shape'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
16
src/layouts/chart/ChartLayout.vue
Normal file
16
src/layouts/chart/ChartLayout.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<v-app>
|
||||||
|
<nav-drawer/>
|
||||||
|
<main-view/>
|
||||||
|
<footer/>
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import MainView from './MainView.vue'
|
||||||
|
import NavDrawer from "@/components/NavDrawer.vue";
|
||||||
|
import Footer from "@/components/Footer.vue";
|
||||||
|
import {useStore} from "@/store/store.js";
|
||||||
|
|
||||||
|
const s = useStore()
|
||||||
|
</script>
|
||||||
15
src/layouts/chart/MainView.vue
Normal file
15
src/layouts/chart/MainView.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<v-main>
|
||||||
|
<Alerts/>
|
||||||
|
<chart-view/>
|
||||||
|
</v-main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Alerts from "@/components/Alerts.vue";
|
||||||
|
import ChartView from "@/views/ChartView.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use 'src/styles/vars' as *;
|
||||||
|
</style>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app>
|
<v-app>
|
||||||
<app-bar/>
|
<app-bar/>
|
||||||
<nav-drawer/>
|
|
||||||
<main-view/>
|
<main-view/>
|
||||||
<footer/>
|
<nav-drawer/>
|
||||||
|
<Footer/>
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-main>
|
<v-main>
|
||||||
<v-container class="pa-0">
|
<v-container class="pa-0 ma-0">
|
||||||
<div>
|
<div>
|
||||||
<Alerts/>
|
<Alerts/>
|
||||||
<!-- <Breakpoints/>-->
|
|
||||||
<router-view/>
|
<router-view/>
|
||||||
<v-skeleton-loader v-if="!store.chainInfo" type="card" class="order-card"/> <!--todo static chainInfo -->
|
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-main>
|
</v-main>
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ export function applyLimit(tranche, price=null, isMinimum=null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function computeInterceptSlope(date0, price0, date1, price1) {
|
function computeInterceptSlope(time0, price0, time1, price1) {
|
||||||
if (!date0 || !price0 && price0 !== 0 || !date1 || !price1 && price1 !== 0)
|
if (!time0 || !price0 && price0 !== 0 || !time1 || !price1 && price1 !== 0)
|
||||||
throw Error(`invalid line points data ${date0} ${price0} ${date1} ${price1}`)
|
throw Error(`invalid line points data ${time0} ${price0} ${time1} ${price1}`)
|
||||||
const t0 = timestamp(date0);
|
const t0 = time0
|
||||||
const t1 = timestamp(date1);
|
const t1 = time1
|
||||||
if (t0 === t1)
|
if (t0 === t1)
|
||||||
throw Error("line points' times must be different")
|
throw Error("line points' times must be different")
|
||||||
const slope = (price1 - price0) / (t1 - t0)
|
const slope = (price1 - price0) / (t1 - t0)
|
||||||
@@ -29,21 +29,22 @@ function computeInterceptSlope(date0, price0, date1, price1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function linePointsValue(date0, price0, date1, price1, unixTime=null) {
|
export function linePointsValue(time0, price0, time1, price1, unixTime=null) {
|
||||||
if(unixTime===null)
|
if(unixTime===null)
|
||||||
unixTime = timestamp()
|
unixTime = timestamp()
|
||||||
try {
|
try {
|
||||||
const [intercept, slope] = computeInterceptSlope(date0, price0, date1, price1)
|
const [intercept, slope] = computeInterceptSlope(time0, price0, time1, price1)
|
||||||
return intercept + unixTime * slope
|
return intercept + unixTime * slope
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
console.log('error computing line',e)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function applyLinePoints(tranche, date0, price0, date1, price1, isMinimum=null) {
|
export function applyLinePoints(tranche, time0, price0, time1, price1, isMinimum=null) {
|
||||||
const [intercept, slope] = computeInterceptSlope(date0, price0, date1, price1);
|
const [intercept, slope] = computeInterceptSlope(time0, price0, time1, price1);
|
||||||
applyLine(tranche, intercept, slope, isMinimum)
|
applyLine(tranche, intercept, slope, isMinimum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// Plugins
|
// Plugins
|
||||||
import { loadFonts } from './webfontloader'
|
import { loadFonts } from './webfontloader'
|
||||||
import vuetify from './vuetify'
|
import vuetify from './vuetify'
|
||||||
import pinia from '../store'
|
import pinia from '../store/pinia.js'
|
||||||
import router from '../router'
|
import router from '../router'
|
||||||
|
|
||||||
export function registerPlugins (app) {
|
export function registerPlugins (app) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { createRouter, createWebHistory } from 'vue-router'
|
|||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('@/layouts/default/Layout.vue'),
|
component: () => import('@/layouts/chart/ChartLayout.vue'),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
@@ -12,8 +12,12 @@ const routes = [
|
|||||||
// route level code-splitting
|
// route level code-splitting
|
||||||
// this generates a separate chunk (about.[hash].js) for this route
|
// this generates a separate chunk (about.[hash].js) for this route
|
||||||
// which is lazy-loaded when the route is visited.
|
// which is lazy-loaded when the route is visited.
|
||||||
// component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue'),
|
component: () => import(/* webpackChunkName: "create" */ '@/components/chart/ChartOrder.vue'),
|
||||||
component: () => import(/* webpackChunkName: "vaultview" */ '@/views/VaultView.vue'),
|
},
|
||||||
|
{
|
||||||
|
path: '/create',
|
||||||
|
name: 'Create',
|
||||||
|
component: () => import(/* webpackChunkName: "create" */ '@/components/chart/ChartOrder.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/vault',
|
path: '/vault',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Utilities
|
// Utilities
|
||||||
import { defineStore } from 'pinia'
|
import {defineStore} from 'pinia'
|
||||||
import {knownTokens} from "@/knownTokens.js";
|
import {knownTokens} from "@/knownTokens.js";
|
||||||
import {computed, ref} from "vue";
|
import {computed, reactive, ref} from "vue";
|
||||||
|
|
||||||
// USING THE STORE:
|
// USING THE STORE:
|
||||||
//
|
//
|
||||||
@@ -35,12 +35,10 @@ const version = await response.json()
|
|||||||
console.log('version', version)
|
console.log('version', version)
|
||||||
|
|
||||||
export const useStore = defineStore('app', ()=> {
|
export const useStore = defineStore('app', ()=> {
|
||||||
const time = ref(timestamp())
|
const clock = ref(timestamp())
|
||||||
console.log('starting clock')
|
|
||||||
setInterval(()=>{
|
setInterval(()=>{
|
||||||
const now = timestamp();
|
clock.value= timestamp()
|
||||||
// console.log('clock', now)
|
console.log('triggered clock', clock.value)
|
||||||
time.value= now
|
|
||||||
}, 10*1000)
|
}, 10*1000)
|
||||||
|
|
||||||
const nav = ref(false) // controls opening navigation drawer
|
const nav = ref(false) // controls opening navigation drawer
|
||||||
@@ -126,7 +124,7 @@ export const useStore = defineStore('app', ()=> {
|
|||||||
return {
|
return {
|
||||||
nav, chainId, chainInfo, chain, provider, vaultInitCodeHash, account, vaults, transactionSenders, errors,
|
nav, chainId, chainInfo, chain, provider, vaultInitCodeHash, account, vaults, transactionSenders, errors,
|
||||||
extraTokens, poolPrices, vaultBalances, orders, vault, tokens, factory, helper, mockenv, mockCoins,
|
extraTokens, poolPrices, vaultBalances, orders, vault, tokens, factory, helper, mockenv, mockCoins,
|
||||||
removeTransactionSender, error, closeError, addToken, time, balances,
|
removeTransactionSender, error, closeError, addToken, clock, balances,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -192,3 +190,15 @@ export const usePrefStore = defineStore('prefs', ()=> {
|
|||||||
return {inverted,}
|
return {inverted,}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const useShapeStore = defineStore('shapes', ()=> {
|
||||||
|
const shapes = reactive([])
|
||||||
|
|
||||||
|
function shape(id) {
|
||||||
|
for (const s of shapes) {
|
||||||
|
if (s.id === id)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return {shapes, shape}
|
||||||
|
})
|
||||||
|
|||||||
24
src/views/ChartView.vue
Normal file
24
src/views/ChartView.vue
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<split-pane class="splitpane">
|
||||||
|
<template v-slot:top>
|
||||||
|
<chart/>
|
||||||
|
</template>
|
||||||
|
<template v-slot:bottom>
|
||||||
|
<router-view/>
|
||||||
|
</template>
|
||||||
|
</split-pane>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import SplitPane from "@/components/SplitPane.vue";
|
||||||
|
import Chart from "@/components/chart/Chart.vue";
|
||||||
|
import {useShapeStore} from "@/store/store.js";
|
||||||
|
|
||||||
|
const ss = useShapeStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.splitpane {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1
tradingview
Submodule
1
tradingview
Submodule
Submodule tradingview added at a0bd039ed4
Reference in New Issue
Block a user