From 3196ffa21d0bb1302012cfe2a269d4130192b0df Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Mon, 10 Jun 2024 00:55:42 +0900 Subject: [PATCH] =?UTF-8?q?#53=20[feat]=20:=20=EC=B0=A8=ED=8A=B8=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=9A=94=EC=B2=AD=20=EC=8B=9C,=20?= =?UTF-8?q?=EC=B5=9C=EC=8B=A0=ED=99=94=20=ED=9B=84=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/BackTestingServiceImpl.java | 29 +++++++++-- .../backend/service/CandleInfoUpdater.java | 48 +++++++++++++++++++ .../dgu/backend/service/ChartServiceImpl.java | 41 ++++++++-------- 3 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 backend/src/main/java/org/dgu/backend/service/CandleInfoUpdater.java diff --git a/backend/src/main/java/org/dgu/backend/service/BackTestingServiceImpl.java b/backend/src/main/java/org/dgu/backend/service/BackTestingServiceImpl.java index f3f96b3..6bdb26b 100644 --- a/backend/src/main/java/org/dgu/backend/service/BackTestingServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/BackTestingServiceImpl.java @@ -7,6 +7,7 @@ import org.dgu.backend.exception.PortfolioErrorResult; import org.dgu.backend.exception.PortfolioException; import org.dgu.backend.repository.*; +import org.dgu.backend.util.CandleUtil; import org.dgu.backend.util.DateUtil; import org.dgu.backend.util.JwtUtil; import org.springframework.stereotype.Service; @@ -15,14 +16,16 @@ import java.util.*; @Service -@Transactional @RequiredArgsConstructor public class BackTestingServiceImpl implements BackTestingService { private final JwtUtil jwtUtil; private final DateUtil dateUtil; + private final CandleUtil candleUtil; private final BackTestingCalculator backTestingCalculator; + private final CandleInfoUpdater candleInfoUpdater; private final CandleInfoRepository candleInfoRepository; private final CandleRepository candleRepository; + private final MarketRepository marketRepository; private final PortfolioRepository portfolioRepository; private final PortfolioOptionRepository portfolioOptionRepository; private final TradingResultRepository tradingResultRepository; @@ -32,12 +35,27 @@ public class BackTestingServiceImpl implements BackTestingService { // 백테스팅 결과를 생성하는 메서드 @Override public BackTestingDto.BackTestingResponse createBackTestingResult(String authorizationHeader, BackTestingDto.StepInfo stepInfo) { + updateCandleInfo("비트코인", stepInfo.getCandleName()); + + return fetchBackTestingResult(authorizationHeader, stepInfo); + } + + // 캔들 정보 최신화 메서드 + @Transactional + protected void updateCandleInfo(String koreanName, String candleName) { + candleInfoUpdater.ensureCandleInfoUpToDate(koreanName, candleName); + } + + // 최신화된 캔들 정보를 사용해 백테스팅 결과를 생성하는 메서드 + @Transactional + protected BackTestingDto.BackTestingResponse fetchBackTestingResult(String authorizationHeader, BackTestingDto.StepInfo stepInfo) { + Market market = marketRepository.findByKoreanName("비트코인"); Candle candle = candleRepository.findByCandleName(stepInfo.getCandleName()); LocalDateTime startDate = dateUtil.convertToLocalDateTime(stepInfo.getStartDate()); LocalDateTime endDate = dateUtil.convertToLocalDateTime(stepInfo.getEndDate()); - List candles = candleInfoRepository.findFilteredCandleInfo(candle, startDate, endDate); - candles = backTestingCalculator.removeDuplicatedCandles(candles); // 중복 데이터 제거 + List candles = candleInfoRepository.findFilteredCandleInfo(market, candle, startDate, endDate); + candles = candleUtil.removeDuplicatedCandles(candles); // 골든 크로스 지점 찾기 List goldenCrossPoints = backTestingCalculator.findGoldenCrossPoints(candles, stepInfo); @@ -58,6 +76,7 @@ public BackTestingDto.BackTestingResponse createBackTestingResult(String authori // 백테스팅 결과를 저장하는 메서드 @Override + @Transactional public void saveBackTestingResult(String authorizationHeader, BackTestingDto.SavingRequest savingRequest) { User user = jwtUtil.getUserFromHeader(authorizationHeader); @@ -76,6 +95,7 @@ public void saveBackTestingResult(String authorizationHeader, BackTestingDto.Sav // 백테스팅 최근 결과를 반환하는 메서드 @Override + @Transactional public BackTestingDto.BackTestingResponse getRecentBackTestingResult(String authorizationHeader) { User user = jwtUtil.getUserFromHeader(authorizationHeader); @@ -90,7 +110,8 @@ public BackTestingDto.BackTestingResponse getRecentBackTestingResult(String auth } // 백테스팅 결과를 임시 저장하는 메서드 - private void saveTempBackTestingResult(String authorizationHeader, BackTestingDto.StepInfo stepInfo, BackTestingDto.BackTestingResponse backTestingResponse) { + @Transactional + protected void saveTempBackTestingResult(String authorizationHeader, BackTestingDto.StepInfo stepInfo, BackTestingDto.BackTestingResponse backTestingResponse) { User user = jwtUtil.getUserFromHeader(authorizationHeader); // 기존에 있던 거래 로그 삭제 diff --git a/backend/src/main/java/org/dgu/backend/service/CandleInfoUpdater.java b/backend/src/main/java/org/dgu/backend/service/CandleInfoUpdater.java new file mode 100644 index 0000000..149dfdc --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/service/CandleInfoUpdater.java @@ -0,0 +1,48 @@ +package org.dgu.backend.service; + +import lombok.RequiredArgsConstructor; +import org.dgu.backend.domain.Candle; +import org.dgu.backend.domain.CandleInfo; +import org.dgu.backend.domain.Market; +import org.dgu.backend.repository.CandleInfoRepository; +import org.dgu.backend.repository.CandleRepository; +import org.dgu.backend.repository.MarketRepository; +import org.dgu.backend.util.CandleDataCollector; +import org.dgu.backend.util.CandleUtil; +import org.dgu.backend.util.DateUtil; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Objects; + +@Component +@RequiredArgsConstructor +public class CandleInfoUpdater { + private final MarketRepository marketRepository; + private final CandleRepository candleRepository; + private final CandleInfoRepository candleInfoRepository; + private final CandleDataCollector candleDataCollector; + private final CandleUtil candleUtil; + private final DateUtil dateUtil; + + // 현재 시각을 기준으로 캔들 정보를 최신화하는 메서드 + public void ensureCandleInfoUpToDate(String koreanName, String candleName) { + Market market = marketRepository.findByKoreanName(koreanName); + Candle candle = candleRepository.findByCandleName(candleName); + + // 가장 최근 캔들 차트 + CandleInfo latestCandleInfo = candleInfoRepository.findTopByMarketAndCandleOrderByTimestampDesc(market, candle); + int candleInterval = candleUtil.calculateCandleInterval(candleName); + LocalDateTime startDate; + if (Objects.isNull(latestCandleInfo)) { + startDate = dateUtil.convertToLocalDateTime("2019-01-01T00:00:00"); + } else { + startDate = latestCandleInfo.getDateTime(); + if (startDate.plusMinutes(candleInterval).isAfter(LocalDateTime.now())) { + return; + } + } + + candleDataCollector.collectCandleData(koreanName, candleName, startDate, LocalDateTime.now()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java b/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java index d8d9f05..fd32db5 100644 --- a/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java @@ -11,50 +11,51 @@ import org.dgu.backend.repository.CandleInfoRepository; import org.dgu.backend.repository.CandleRepository; import org.dgu.backend.repository.MarketRepository; +import org.dgu.backend.util.CandleUtil; import org.springframework.stereotype.Service; import java.time.LocalDateTime; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Service -@Transactional @RequiredArgsConstructor public class ChartServiceImpl implements ChartService { private final MarketRepository marketRepository; private final CandleRepository candleRepository; private final CandleInfoRepository candleInfoRepository; - - private static final List SEVEN_DAY_CANDLES = Arrays.asList("minutes1", "minutes3", "minutes5", "minutes10", "minutes15", "minutes30"); - private static final List SIX_MONTH_CANDLES = Arrays.asList("minutes60", "minutes240"); + private final CandleInfoUpdater candleInfoUpdater; + private final CandleUtil candleUtil; // OHLCV 차트를 반환하는 메서드 @Override public List getOHLCVCharts(String koreanName, String candleName) { + updateCandleInfo(koreanName, candleName); + + return fetchUpdatedCandleInfo(koreanName, candleName); + } + + // 캔들 정보 최신화 메서드 + @Transactional + protected void updateCandleInfo(String koreanName, String candleName) { + candleInfoUpdater.ensureCandleInfoUpToDate(koreanName, candleName); + } + + // 최신화된 캔들 정보를 반환하는 메서드 + @Transactional + protected List fetchUpdatedCandleInfo(String koreanName, String candleName) { Market market = marketRepository.findByKoreanName(koreanName); Candle candle = candleRepository.findByCandleName(candleName); - - LocalDateTime startDate = getStartDateByCandleName(candleName); + LocalDateTime startDate = candleUtil.getStartDateByCandleName(candleName); List candleInfos = candleInfoRepository.findByMarketAndCandleAndDateTimeAfter(market, candle, startDate); if (candleInfos.isEmpty()) { throw new ChartException(ChartErrorResult.NOT_FOUND_CHARTS); } + candleInfos = candleUtil.removeDuplicatedCandles(candleInfos); + return candleInfos.stream() .map(ChartDto.OHLCVResponse::of) .collect(Collectors.toList()); } - - // 캔들 종류에 따라 시작 기간을 계산해 반환하는 메서드 - private LocalDateTime getStartDateByCandleName(String candleName) { - LocalDateTime now = LocalDateTime.now(); - if (SEVEN_DAY_CANDLES.contains(candleName)) { - return now.minusDays(7); - } else if (SIX_MONTH_CANDLES.contains(candleName)) { - return now.minusMonths(6); - } else { - return LocalDateTime.of(2019, 1, 1, 0, 0); - } - } -} \ No newline at end of file +}