mirror of
https://git.hmsn.ink/coin/chart.git
synced 2026-03-20 00:02:17 +09:00
차트 정의 완료
This commit is contained in:
296
src/App.vue
296
src/App.vue
@@ -10,104 +10,178 @@ import { ref } from 'vue';
|
||||
*/
|
||||
import LWChart from './components/LWChart.vue';
|
||||
import {getCandleList} from '/@src/utils/api'
|
||||
import {calculateMACD, calculateEMA, calculateBollingerBands} from "./utils/meter.js";
|
||||
/**
|
||||
* Generates sample data for the lightweight chart
|
||||
* @param {Boolean} ohlc Whether generated dat should include open, high, low, and close values
|
||||
* @returns {Array} sample data
|
||||
*/
|
||||
|
||||
const socket = new WebSocket("ws://127.0.0.1:8765");
|
||||
const sk = new WebSocket("wss://fx-ws.gateio.ws/v4/ws/usdt")
|
||||
let oldLow = 9999999999;
|
||||
let oldHigh = 0;
|
||||
let lock = false
|
||||
let socket;
|
||||
const lazyLock = ref(false)
|
||||
|
||||
const contract = ref('BTC_USDT')
|
||||
const time = ref('15m')
|
||||
const chartOptions = ref({
|
||||
layout: {
|
||||
textColor: 'black',
|
||||
background: { type: 'solid', color: 'white' },
|
||||
panes: {
|
||||
separatorColor: '#FF0000',
|
||||
},
|
||||
},
|
||||
height: 800,
|
||||
height: 1300,
|
||||
timeScale: {
|
||||
timeVisible: true, // 분/초까지 표시
|
||||
secondsVisible: false // 초 숨기고 싶으면 false
|
||||
},
|
||||
|
||||
});
|
||||
const candleTick = ref([]);
|
||||
const seriesOptions = ref({
|
||||
|
||||
const candleTick = ref([])
|
||||
const ema = ref([])
|
||||
const macd = ref({})
|
||||
const bb = ref({})
|
||||
|
||||
const selectCoins = [
|
||||
{ title: 'BTC_USDT'},
|
||||
{ title: 'ETH_USDT'},
|
||||
{ title: 'SOL_USDT'},
|
||||
{ title: 'XRP_USDT'},
|
||||
{ title: 'LINK_USDT'},
|
||||
]
|
||||
const selectTimes = [
|
||||
{ title: '5m'},
|
||||
{ title: '15m'},
|
||||
{ title: '30m'},
|
||||
{ title: '1h'},
|
||||
{ title: '4h'},
|
||||
{ title: '8h'},
|
||||
{ title: '1d'},
|
||||
{ title: '7d'},
|
||||
]
|
||||
|
||||
const line_color = [
|
||||
'#AD81FF',
|
||||
'#FFBAB5',
|
||||
'#6BFF74',
|
||||
'#FFFC7B',
|
||||
'#27FFE6',
|
||||
'#225EFF'
|
||||
]
|
||||
|
||||
|
||||
const emaLineOptions = ref({
|
||||
lineWidth: 2,
|
||||
color: '#AD81FF',
|
||||
title: 'EMA',
|
||||
});
|
||||
|
||||
const candleOptions = ref({
|
||||
upColor: '#26a69a',
|
||||
downColor: '#ef5350',
|
||||
borderVisible: false,
|
||||
wickUpColor: '#26a69a',
|
||||
wickDownColor: '#ef5350',
|
||||
});
|
||||
|
||||
const macdLineOptions = ref({
|
||||
lineWidth: 2,
|
||||
color: '#FFBAB5'
|
||||
});
|
||||
|
||||
const macdSignalOptions = ref({
|
||||
lineWidth: 2,
|
||||
color: '#AD81FF'
|
||||
});
|
||||
|
||||
const macdHistogramOptions = ref({
|
||||
lineWidth: 2,
|
||||
color: '#27FFE6'
|
||||
});
|
||||
|
||||
const upperBbOptions = ref({
|
||||
color: '#006AFF', // 주황색 계열
|
||||
lineStyle: 0, // 점선 스타일 (선택)
|
||||
lineWidth: 2,
|
||||
title: 'UpperBB',
|
||||
})
|
||||
|
||||
const middleBbOptions = ref({
|
||||
color: '#006AFF', // 주황색 계열
|
||||
lineStyle: 1, // 점선 스타일 (선택)
|
||||
lineWidth: 0,
|
||||
title: 'MiddleBB(SMA)',
|
||||
})
|
||||
|
||||
const lowerBbOptions = ref({
|
||||
color: '#006AFF', // 주황색 계열
|
||||
lineStyle: 0, // 점선 스타일 (선택)
|
||||
lineWidth: 2,
|
||||
title: 'LowerBB',
|
||||
})
|
||||
|
||||
const chartType = ref('candlestick');
|
||||
const lwChart = ref();
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
getCandleList('BTC_USDT', '1m').then(data => {
|
||||
candleTick.value = data
|
||||
})
|
||||
|
||||
|
||||
tradeSocket()
|
||||
candleSocket('1m')
|
||||
|
||||
init(contract.value, time.value)
|
||||
})
|
||||
|
||||
const tradeSocket = () => {
|
||||
sk.addEventListener('open', (event) => {
|
||||
sk.send(JSON.stringify({"time" : curToUnix(), "channel" : "futures.trades",
|
||||
"event": "subscribe", "payload" : [contract.value]}))
|
||||
const init = (cont, ti) => {
|
||||
socket = new WebSocket("ws://127.0.0.1:8765");
|
||||
const dt = new Date()
|
||||
getCandleList(cont, ti, Math.round(dt.getTime()/1000)).then(data => {
|
||||
ema.value = calculateEMA(data, 20)
|
||||
macd.value = calculateMACD(data)
|
||||
bb.value = calculateBollingerBands(data)
|
||||
candleTick.value = data
|
||||
console.log(bb.value)
|
||||
})
|
||||
|
||||
sk.addEventListener('message', (message) => {
|
||||
const getDa = JSON.parse(message.data)
|
||||
if (getDa.event === 'update') {
|
||||
// console.log(getDa.result[0].price)
|
||||
candleSocket(cont, ti)
|
||||
}
|
||||
|
||||
if(candleTick.value.length === 0) return
|
||||
const distroy = (cont) => {
|
||||
candleTick.value = []
|
||||
}
|
||||
|
||||
const lastCandle = candleTick.value[candleTick.value.length - 1]
|
||||
const lazyLoad = async (ti) => {
|
||||
lazyLock.value = true
|
||||
getCandleList(contract.value, time.value, ti).then(data => {
|
||||
candleTick.value = [...data, ...candleTick.value]
|
||||
ema.value = calculateEMA(data, 20)
|
||||
macd.value = calculateMACD(data)
|
||||
bb.value = calculateBollingerBands(data)
|
||||
setTimeout(() => {lazyLock.value = false}, 3000)
|
||||
|
||||
const price = parseFloat(getDa.result[0].price);
|
||||
lastCandle.close = price
|
||||
if(oldLow > candleTick.value[candleTick.value.length - 1].close) {
|
||||
lastCandle.low = price
|
||||
oldLow = price;
|
||||
}
|
||||
if(oldHigh < candleTick.value[candleTick.value.length - 1].open) {
|
||||
lastCandle.high = price
|
||||
oldHigh = price;
|
||||
}
|
||||
|
||||
candleTick.value[candleTick.value.length - 1] = lastCandle
|
||||
candleTick.value = [...candleTick.value]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const candleSocket = (time) => {
|
||||
const candleSocket = (cont, ti) => {
|
||||
socket.addEventListener('open', (event) => {
|
||||
socket.send(JSON.stringify({"type":"subscribe", "channel": contract.value, "time": time}))
|
||||
socket.send(JSON.stringify({"type":"subscribe", "channel": cont, "time": ti}))
|
||||
})
|
||||
|
||||
socket.addEventListener('message', (message) => {
|
||||
lock = true
|
||||
const getDa = JSON.parse(message.data)
|
||||
const msg = JSON.parse(getDa.msg)
|
||||
const tick = msg.data[0]
|
||||
const msg = JSON.parse(message.data)
|
||||
const item = JSON.parse(msg.msg)
|
||||
|
||||
const ticks = candleTick.value
|
||||
if(tick.time !== ticks[ticks.length - 1].time) {
|
||||
// ticks[ticks.length - 1] = tick
|
||||
// candleTick.value = [...ticks]
|
||||
// } else {
|
||||
const ticks = candleTick.value
|
||||
ticks.push(tick)
|
||||
if(item.t === ticks[ticks.length - 1].t) {
|
||||
ticks[ticks.length - 1] = item
|
||||
candleTick.value = [...ticks]
|
||||
} else {
|
||||
ticks.push(item)
|
||||
candleTick.value = [...ticks]
|
||||
}
|
||||
|
||||
ema.value = calculateEMA(ticks, 20)
|
||||
macd.value = calculateMACD(ticks)
|
||||
bb.value = calculateBollingerBands(ticks)
|
||||
lazyLock.value = false
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -120,14 +194,6 @@ const curToUnix = (() => {
|
||||
})
|
||||
|
||||
|
||||
function randomShade() {
|
||||
return Math.round(Math.random() * 255);
|
||||
}
|
||||
|
||||
const randomColor = (alpha = 1) => {
|
||||
return `rgba(${randomShade()}, ${randomShade()}, ${randomShade()}, ${alpha})`;
|
||||
};
|
||||
|
||||
const colorsTypeMap = {
|
||||
area: [
|
||||
['topColor', 0.4],
|
||||
@@ -158,64 +224,82 @@ const colorsTypeMap = {
|
||||
line: [['color', 1]],
|
||||
};
|
||||
|
||||
// Set a random colour for the series as an example of how
|
||||
// to apply new options to series. A similar appraoch will work on the
|
||||
// option properties.
|
||||
const changeColors = () => {
|
||||
const options = {};
|
||||
const colorsToSet = colorsTypeMap[chartType.value];
|
||||
colorsToSet.forEach((c) => {
|
||||
options[c[0]] = randomColor(c[1]);
|
||||
});
|
||||
seriesOptions.value = options;
|
||||
};
|
||||
watch(contract, newVal => {
|
||||
distroy()
|
||||
console.log(newVal);
|
||||
init(newVal, time.value)
|
||||
})
|
||||
|
||||
const changeData = () => {
|
||||
const candlestickTypeData = ['candlestick', 'bar'].includes(chartType.value);
|
||||
const newData = generateSampleData(candlestickTypeData);
|
||||
data.value = newData;
|
||||
if (chartType.value === 'baseline') {
|
||||
const average =
|
||||
newData.reduce((s, c) => {
|
||||
return s + c.value;
|
||||
}, 0) / newData.length;
|
||||
seriesOptions.value = { baseValue: { type: 'price', price: average, format: 'yyyy-MM-dd HH:mm' } };
|
||||
}
|
||||
};
|
||||
|
||||
const changeType = () => {
|
||||
const types = [
|
||||
'line',
|
||||
'area',
|
||||
'baseline',
|
||||
'histogram',
|
||||
'candlestick',
|
||||
'bar',
|
||||
].filter((t) => t !== chartType.value);
|
||||
const randIndex = Math.round(Math.random() * (types.length - 1));
|
||||
chartType.value = types[randIndex];
|
||||
changeData();
|
||||
|
||||
// call a method on the component.
|
||||
lwChart.value.fitContent();
|
||||
};
|
||||
watch(time, newVal => {
|
||||
distroy()
|
||||
console.log(newVal);
|
||||
init(contract.value, newVal)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="chart-container">
|
||||
<div class="container">
|
||||
<div class="d-flex justify-content-center">
|
||||
<v-menu>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn color="grey-lighten-5" min-width="100" size="small" v-bind="props">{{contract}}</v-btn>
|
||||
</template>
|
||||
<v-list v-model="contract">
|
||||
<v-list-item
|
||||
v-for="(item, idx) in selectCoins"
|
||||
:key="idx"
|
||||
:value="item.title"
|
||||
@click="() => {
|
||||
socket.send(JSON.stringify({'type':'unsubscribe', 'channel': contract, 'time': time}))
|
||||
contract = item.title
|
||||
}"
|
||||
>
|
||||
<v-list-item-title>{{ item.title }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-menu>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn color="grey-lighten-5" min-width="50" size="small" v-bind="props">{{time}}</v-btn>
|
||||
</template>
|
||||
<v-list v-model="time">
|
||||
<v-list-item
|
||||
v-for="(item, idx) in selectTimes"
|
||||
:key="idx"
|
||||
:value="item.title"
|
||||
@click="() => {
|
||||
socket.send(JSON.stringify({'type':'unsubscribe', 'channel': contract, 'time': time}))
|
||||
time = item.title
|
||||
}"
|
||||
>
|
||||
<v-list-item-title>{{ item.title }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
</div>
|
||||
<div class="chart-container" v-if="candleTick !== undefined">
|
||||
<LWChart
|
||||
:type="chartType"
|
||||
:data="candleTick"
|
||||
:ema="ema"
|
||||
:macd="macd"
|
||||
:bb="bb"
|
||||
:autosize="true"
|
||||
:chart-options="chartOptions"
|
||||
:series-options="seriesOptions"
|
||||
:ema-options="emaLineOptions"
|
||||
:candle-options="candleOptions"
|
||||
:macd-line-options="macdLineOptions"
|
||||
:macd-signal-options="macdSignalOptions"
|
||||
:macd-histogram-options="macdHistogramOptions"
|
||||
:lower-bb-options="lowerBbOptions"
|
||||
:middle-bb-options="middleBbOptions"
|
||||
:upper-bb-options="upperBbOptions"
|
||||
:lazyLock="lazyLock"
|
||||
@lazyLoad="lazyLoad"
|
||||
ref="lwChart"
|
||||
/>
|
||||
</div>
|
||||
<button type="button" @click="changeColors">Set Random Colors</button>
|
||||
<button type="button" @click="changeType">Change Chart Type</button>
|
||||
<button type="button" @click="changeData">Change Data</button>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user