From bda0518a6a5bf3011bb910856733239889e103af Mon Sep 17 00:00:00 2001 From: kienvt Date: Mon, 14 Jul 2025 08:25:08 +0700 Subject: [PATCH] update --- src/services/indicatorService.ts | 103 +++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/src/services/indicatorService.ts b/src/services/indicatorService.ts index 75bf5f9..1ec5b24 100644 --- a/src/services/indicatorService.ts +++ b/src/services/indicatorService.ts @@ -1,6 +1,10 @@ -import { EMA, MACD } from "technicalindicators"; +import { BollingerBands, EMA, MACD } from "technicalindicators"; import { Candle } from "../dao/candles"; -import { analyzeCandleSequence, isHighVolatilityCandle, isPinBar } from "../helpers/candles"; +import { + analyzeCandleSequence, + isHighVolatilityCandle, + isPinBar, +} from "../helpers/candles"; import { Analysis } from "../dao/analysis"; import { KlineIntervalV3 } from "bybit-api"; import { Order } from "../dao/order"; @@ -48,6 +52,14 @@ export class IndicatorService { SimpleMASignal: false, reversedInput: true, }); + + const bb = BollingerBands.calculate({ + period: 20, + stdDev: 2, + values: close, + reversedInput: true, + }); + const candle = candles[0]; const analysis: Analysis = { @@ -65,9 +77,9 @@ export class IndicatorService { isSell: false, isTouch200: false, isReverse200: false, - lowHight: wave.lowOrHighPrice, + lowHight: wave.lowOrHighPrice, numberTouch200: wave.numberTouchEma, - numberMacdCrossUp: wave.numberMacdCrossUp, + numberMacdCrossUp: wave.numberMacdCrossUp, numberMacdCrossDown: wave.numberMacdCrossDown, isMacdUpper: false, isMacdLower: false, @@ -76,26 +88,22 @@ export class IndicatorService { if (ema34[0] > ema200[0]) { if (wave.trend === "Bearish") { analysis.numberTouch200 = 0; + analysis.numberMacdCrossDown = 0; + analysis.numberMacdCrossUp = 1; } analysis.emaDirection = "Bullish"; } else { if (wave.trend === "Bullish") { analysis.numberTouch200 = 0; + analysis.numberMacdCrossDown = 1; + analysis.numberMacdCrossUp = 0; } analysis.emaDirection = "Bearish"; } if (macd[0].MACD! > macd[0].signal!) { - if (wave.trend === "Bearish") { - analysis.numberMacdCrossUp = 0; - analysis.numberMacdCrossDown = 0; - } analysis.macdDirection = "Bullish"; } else { - if (wave.trend === "Bullish") { - analysis.numberMacdCrossDown = 0; - analysis.numberMacdCrossUp = 0; - } analysis.macdDirection = "Bearish"; } @@ -118,7 +126,10 @@ export class IndicatorService { if (macd[0].MACD! > macd[0].signal! && macd[1].MACD! < macd[1].signal!) { analysis.isMacdCrossUp = true; analysis.numberMacdCrossUp++; - } else if (macd[0].MACD! < macd[0].signal! && macd[1].MACD! > macd[1].signal!) { + } else if ( + macd[0].MACD! < macd[0].signal! && + macd[1].MACD! > macd[1].signal! + ) { analysis.isMacdCrossDown = true; analysis.numberMacdCrossDown++; } @@ -159,7 +170,11 @@ export class IndicatorService { analysis.isTouch200 = true; } - if (candle.open < ema200[0] && candle.close > ema200[0] && analysis.emaDirection === "Bullish") { + if ( + candle.open < ema200[0] && + candle.close > ema200[0] && + analysis.emaDirection === "Bullish" + ) { const candlesCheck = [candles[3], candles[2], candles[1], candles[0]]; const ema200Check = [ema200[3], ema200[2], ema200[1], ema200[0]]; const candleCheck = candlesCheck.find( @@ -171,7 +186,11 @@ export class IndicatorService { } } - if (candle.open > ema200[0] && candle.close < ema200[0] && analysis.emaDirection === "Bearish") { + if ( + candle.open > ema200[0] && + candle.close < ema200[0] && + analysis.emaDirection === "Bearish" + ) { const candlesCheck = [candles[3], candles[2], candles[1], candles[0]]; const ema200Check = [ema200[3], ema200[2], ema200[1], ema200[0]]; const candleCheck = candlesCheck.find( @@ -188,10 +207,20 @@ export class IndicatorService { return analysis; } - makeOrder(analysis: Analysis, candles: Candle[], side: "buy" | "sell"): Order { + makeOrder( + analysis: Analysis, + candles: Candle[], + side: "buy" | "sell" + ): Order { const last10Candles = candles.slice(0, 12); - const lowestPrice = last10Candles.reduce((min, c) => Math.min(min, c.low), Number.MAX_SAFE_INTEGER); - const highestPrice = last10Candles.reduce((max, c) => Math.max(max, c.high), Number.MIN_SAFE_INTEGER); + const lowestPrice = last10Candles.reduce( + (min, c) => Math.min(min, c.low), + Number.MAX_SAFE_INTEGER + ); + const highestPrice = last10Candles.reduce( + (max, c) => Math.max(max, c.high), + Number.MIN_SAFE_INTEGER + ); const order: Order = { symbol: analysis.symbol, side, @@ -202,7 +231,11 @@ export class IndicatorService { return order; } - handleEvent(analysis: Analysis, candles: Candle[], eventHandler: EventHandler) { + handleEvent( + analysis: Analysis, + candles: Candle[], + eventHandler: EventHandler + ) { if (analysis.isTouch200 && analysis.emaDirection === "Bullish") { const order = this.makeOrder(analysis, candles, "buy"); eventHandler.onBuy(order, "Follow trend EMA Touch 200"); @@ -211,34 +244,42 @@ export class IndicatorService { const order = this.makeOrder(analysis, candles, "sell"); eventHandler.onSell(order, "Follow trend EMA Touch 200"); } - if (analysis.isMacdCrossUp && analysis.isMacdUpper) { + if (analysis.isMacdCrossUp && analysis.emaDirection === "Bullish") { const order = this.makeOrder(analysis, candles, "buy"); eventHandler.onBuy(order, "Follow trend MACD Cross Up"); } - if (analysis.isMacdCrossDown && analysis.isMacdLower) { + if (analysis.isMacdCrossDown && analysis.emaDirection === "Bearish") { const order = this.makeOrder(analysis, candles, "sell"); eventHandler.onSell(order, "Follow trend MACD Cross Down"); } - if (analysis.isMacdCrossUp && analysis.isMacdLower && analysis.numberMacdCrossUp >= 2) { + if ( + analysis.isMacdCrossUp && + analysis.isMacdLower && + analysis.numberMacdCrossUp >= 2 + ) { const order = this.makeOrder(analysis, candles, "buy"); eventHandler.onBuy(order, "Counter trend rủi ro cao MACD Cross Up"); } - if (analysis.isMacdCrossDown && analysis.isMacdUpper && analysis.numberMacdCrossDown >= 2) { + if ( + analysis.isMacdCrossDown && + analysis.isMacdUpper && + analysis.numberMacdCrossDown >= 2 + ) { const order = this.makeOrder(analysis, candles, "sell"); eventHandler.onSell(order, "Counter trend rủi ro cao MACD Cross Down"); } - } + } /** * Lấy bản ghi wave theo symbol và interval */ async getWave(symbol: string, interval: string) { const { data, error } = await supabase - .from('waves') - .select('*') - .eq('symbol', symbol) - .eq('interval', interval) + .from("waves") + .select("*") + .eq("symbol", symbol) + .eq("interval", interval) .single(); if (error) return null; return data; @@ -249,10 +290,8 @@ export class IndicatorService { */ async upsertWave(wave: Wave) { const { data, error } = await supabase - .from('waves') - .upsert([ - wave - ], { onConflict: 'symbol,interval' }); + .from("waves") + .upsert([wave], { onConflict: "symbol,interval" }); if (error) { console.error(error); }