From f361a5e9fa5a081c12f8394cccfde17e6ccc542a Mon Sep 17 00:00:00 2001 From: bangae1 Date: Tue, 26 Aug 2025 10:02:17 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=B8=ED=84=B0=EB=B2=8C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 255 +++++++++++++++++++++++++++++---------------- src/utils/sig.ts | 42 ++++++-- types/imports.d.ts | 1 + 3 files changed, 201 insertions(+), 97 deletions(-) diff --git a/src/App.vue b/src/App.vue index 0cd676a..a32c418 100644 --- a/src/App.vue +++ b/src/App.vue @@ -24,15 +24,20 @@ const { width, height } = useWindowSize() let socket; const lazyLock = ref(false) -const positionData = ref('') +const positionHtml = ref('') +const rsiHtml = ref('') +const macdHtml = ref('') +const bbHtml = ref('') +const emaHtml = ref('') const scrollContainer1 = ref() const scrollContainer2 = ref() const signal1 = ref([]) const signal2 = ref([]) -const contract = ref('ETH_USDT') +const contract = ref(window.sessionStorage.getItem('contract') || 'ETH_USDT') + /* Interval : "10s", "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "7d"*/ -const time = ref('5m') +const time = ref(window.sessionStorage.getItem('time')|| '10s') const chartOptions = ref({ layout: { textColor: 'black', @@ -89,7 +94,6 @@ const line_color = [ const emaLineOptions = ref({ lineWidth: 2, color: '#AD81FF', - title: 'EMA', }); const candleOptions = ref({ @@ -103,46 +107,39 @@ const candleOptions = ref({ const macdLineOptions = ref({ lineWidth: 2, color: '#FFBAB5', - title: 'MACD', }); const macdSignalOptions = ref({ lineWidth: 2, color: '#AD81FF', - title: 'SIGNAL', }); const macdHistogramOptions = ref({ lineWidth: 2, color: '#27FFE6', - title: 'HISTOGRAM', }); 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 rsiLineOptions = ref({ lineWidth: 2, color: '#AD81FF', - title: 'RSI', }); const chartType = ref('candlestick'); @@ -154,7 +151,7 @@ onMounted(() => { }) const init = (cont, ti) => { - socket = new WebSocket("wss://fx-ws.gateio.ws/v4/ws/usdt"); + // socket = new WebSocket("wss://fx-ws.gateio.ws/v4/ws/usdt"); const dt = new Date() getCandleList(cont, ti, Math.round(dt.getTime()/1000)).then(data => { ema.value = calculateEMA(data, 20) @@ -165,7 +162,7 @@ const init = (cont, ti) => { // console.table(entrySignals(data)) candleTick.value = data }) - candleSocket(cont, ti) + socket = candleSocket(cont, ti) } const distroy = () => { @@ -187,73 +184,98 @@ const lazyLoad = async (ti) => { } let loopIdx = 0 + + + const candleSocket = (cont, ti) => { - socket.addEventListener('open', (event) => { - // socket.send(JSON.stringify({"type":"subscribe", "channel": cont, "time": ti})) - socket.send(JSON.stringify({"time" : curToUnix(), "channel" : "futures.candlesticks","event": "subscribe", "payload" : [ti, cont]})) - socket.send(JSON.stringify({"time" : curToUnix(), "channel" : "futures.trades","event": "subscribe", "payload" : [cont]})) - }) + return useWebSocket('wss://fx-ws.gateio.ws/v4/ws/usdt', { + onConnected: async ws => { + ws.send(JSON.stringify({"time" : curToUnix(), "channel" : "futures.candlesticks","event": "subscribe", "payload" : [ti, cont]})) + ws.send(JSON.stringify({"time" : curToUnix(), "channel" : "futures.tickers","event": "subscribe", "payload" : [cont]})) + }, + onDisconnected: (ws, event) => { + }, + onMessage: (ws, message) => { + const msg = JSON.parse(message.data) + const ticks = candleTick.value + if(msg.channel === 'futures.candlesticks') { + if(msg.event === 'update') { + const item = msg.result[0] + // console.log(ticks[ticks.length - 1].t, item.t, new Date().getTime() /1000) - socket.addEventListener('message', (message) => { - const msg = JSON.parse(message.data) - if(msg.channel === 'futures.candlesticks') { - if(msg.event === 'update') { - const item = msg.result[0] - - const ticks = candleTick.value - if(item.t === ticks[ticks.length - 1].t) { - ticks[ticks.length - 1] = item - candleTick.value = [...ticks] - } else { - ticks.push(item) - candleTick.value = [...ticks] - } - - } - } else { - if(msg.event === 'update') { - const item = msg.result[0] - // console.log(item) - const ticks = candleTick.value - try { - let diff = 0 - if(time.value === '10s') diff = 10 - else if(time.value === '1m') diff = 60 - else if(time.value === '5m') diff = (60 * 5) - else if(time.value === '15m') diff = (60 * 15) - else if(time.value === '30m') diff = (60 * 30) - else if(time.value === '1h') diff = (60 * 60) - else if(time.value === '4h') diff = (60 * 60 * 4) - else if(time.value === '8h') diff = (60 * 60 * 8) - else if(time.value === '1d') diff = (60 * 60 * 24) - else if(time.value === '7d') diff = (60 * 60 * 24 * 7) - if(item.create_time >= ticks[ticks.length - 1].t && item.create_time <= (ticks[ticks.length - 1].t + diff)) { - ticks[ticks.length - 1].c = item.price - if(ticks[ticks.length - 1].h < item.price) ticks[ticks.length - 1].h = item.price - if(ticks[ticks.length - 1].l > item.price) ticks[ticks.length - 1].l = item.price + if(item.t === ticks[ticks.length - 1].t) { + ticks[ticks.length - 1] = item candleTick.value = [...ticks] - ema.value = calculateEMA(ticks, 20) - macd.value = calculateMACD(ticks) - bb.value = calculateBollingerBands(ticks) - rsi.value = calculateRSI(ticks) - // console.table(entrySignals(ticks)) - const dd = entrySignals(ticks) - if(dd.length) signal2.value = [...signal2.value, entrySignals(ticks)] - const tt = swingSignal(ticks) - console.log(tt) - if(tt[0] !== 'HOLD') signal1.value = [...signal1.value, swingSignal(ticks)] } - } catch(error) {} - - loopIdx++; - if(loopIdx > 1000) { - console.clear(); - loopIdx = 0; + // else { + // ticks.push(item) + // candleTick.value = [...ticks] + // } } - // console.log('trade', socketLock) } - } - lazyLock.value = false + if(msg.channel === 'futures.tickers') { + if(msg.event === 'update') { + const item = msg.result[0] + try { + let diff = 0 + if(time.value === '10s') diff = 10 + else if(time.value === '1m') diff = 60 + else if(time.value === '5m') diff = (60 * 5) + else if(time.value === '15m') diff = (60 * 15) + else if(time.value === '30m') diff = (60 * 30) + else if(time.value === '1h') diff = (60 * 60) + else if(time.value === '4h') diff = (60 * 60 * 4) + else if(time.value === '8h') diff = (60 * 60 * 8) + else if(time.value === '1d') diff = (60 * 60 * 24) + else if(time.value === '7d') diff = (60 * 60 * 24 * 7) + if(msg.time > ticks[ticks.length - 1].t && msg.time < (ticks[ticks.length - 1].t + diff)) { + ticks[ticks.length - 1].c = item.last + if(ticks[ticks.length - 1].h < item.last) ticks[ticks.length - 1].h = item.last + if(ticks[ticks.length - 1].l > item.last) ticks[ticks.length - 1].l = item.last + candleTick.value = [...ticks] + ema.value = calculateEMA(ticks, 20) + emaHtml.value = `EMA${Math.round(ema.value[ema.value.length - 1].value * 100)/ 100}` + macd.value = calculateMACD(ticks) + macdHtml.value = `RSI + H${Math.round(macd.value.h[macd.value.h.length - 1].value * 100)/ 100} + M${Math.round(macd.value.m[macd.value.m.length - 1].value * 100)/ 100} + S${Math.round(macd.value.s[macd.value.s.length - 1].value * 100)/ 100}` + bb.value = calculateBollingerBands(ticks) + bbHtml.value = `BB + U${Math.round(bb.value.u[bb.value.u.length - 1].value * 100)/ 100} + M${Math.round(bb.value.m[bb.value.m.length - 1].value * 100)/ 100} + L${Math.round(bb.value.l[bb.value.l.length - 1].value * 100)/ 100}` + rsi.value = calculateRSI(ticks) + rsiHtml.value = `BB${Math.round(rsi.value[rsi.value.length - 1].value * 100)/ 100}` + // console.table(entrySignals(ticks)) + const dd = entrySignals(ticks) + if(dd.length) signal2.value = [...signal2.value, entrySignals(ticks)] + const tt = swingSignal(ticks) + // console.log(tt) + if(tt[0] !== 'HOLD') signal1.value = [...signal1.value, swingSignal(ticks)] + } else if(msg.time >= (ticks[ticks.length - 1].t + diff)) { + const newTick = JSON.parse(JSON.stringify(ticks[ticks.length - 1])) + newTick.t = newTick.t + diff + newTick.c = item.last + newTick.o = item.last + newTick.l = item.last + newTick.h = item.last + ticks.push(newTick) + candleTick.value = [...ticks] + } + } catch(error) {} + + // loopIdx++; + // if(loopIdx > 1000) { + // console.clear(); + // loopIdx = 0; + // } + // console.log('trade', socketLock) + } + } + lazyLock.value = false + }, + onError: (ws, msg) => {}, }) } @@ -304,7 +326,7 @@ const colorsTypeMap = { }; const mouseMove = (data) => { - positionData.value = ` + positionHtml.value = ` O${data == null ? 0 : data.open} C${data == null ? 0 : data.close} L${data == null ? 0 : data.low} @@ -315,11 +337,13 @@ const mouseMove = (data) => { watch(contract, newVal => { distroy() + window.sessionStorage.setItem('contract', newVal) init(newVal, time.value) }) watch(time, newVal => { distroy() + window.sessionStorage.setItem('time', newVal) init(contract.value, newVal) }) @@ -341,7 +365,7 @@ watch(signal2, newVal => {
- +