From 561382819fc06a8a37ec65d75dc557e7cf8228db Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:20:09 +0900 Subject: [PATCH 01/12] =?UTF-8?q?[fix]=20:=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dgu/backend/exception/BackTestingErrorResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/org/dgu/backend/exception/BackTestingErrorResult.java b/backend/src/main/java/org/dgu/backend/exception/BackTestingErrorResult.java index 0c769bd..3254c37 100644 --- a/backend/src/main/java/org/dgu/backend/exception/BackTestingErrorResult.java +++ b/backend/src/main/java/org/dgu/backend/exception/BackTestingErrorResult.java @@ -9,7 +9,7 @@ @Getter @RequiredArgsConstructor public enum BackTestingErrorResult implements BaseErrorCode { - NOT_FOUND_START_INDEX(HttpStatus.CONFLICT, "404", "시작 인덱스를 찾을 수 없습니다."); + NOT_FOUND_START_INDEX(HttpStatus.NOT_FOUND, "404", "시작 인덱스를 찾을 수 없습니다."); private final HttpStatus httpStatus; private final String code; From d47518971cc11ae5ca915f97ad1457da748c818d Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:21:28 +0900 Subject: [PATCH 02/12] =?UTF-8?q?#53=20[rename]=20:=20candleName=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dgu/backend/domain/Candle.java | 2 +- .../backend/repository/CandleRepository.java | 2 +- .../service/BackTestingServiceImpl.java | 2 +- .../service/CandleInfoServiceImpl.java | 22 +++++++++---------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/org/dgu/backend/domain/Candle.java b/backend/src/main/java/org/dgu/backend/domain/Candle.java index e70fdac..241836c 100644 --- a/backend/src/main/java/org/dgu/backend/domain/Candle.java +++ b/backend/src/main/java/org/dgu/backend/domain/Candle.java @@ -18,7 +18,7 @@ public class Candle { private Long id; @Column(name = "candles_name") - private String name; + private String candleName; @Column(name = "korean_name") private String koreanName; diff --git a/backend/src/main/java/org/dgu/backend/repository/CandleRepository.java b/backend/src/main/java/org/dgu/backend/repository/CandleRepository.java index 519621c..62248fb 100644 --- a/backend/src/main/java/org/dgu/backend/repository/CandleRepository.java +++ b/backend/src/main/java/org/dgu/backend/repository/CandleRepository.java @@ -4,5 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface CandleRepository extends JpaRepository { - Candle findByName(String candleName); + Candle findByCandleName(String candleName); } \ No newline at end of file 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 706e7b9..f3f96b3 100644 --- a/backend/src/main/java/org/dgu/backend/service/BackTestingServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/BackTestingServiceImpl.java @@ -32,7 +32,7 @@ public class BackTestingServiceImpl implements BackTestingService { // 백테스팅 결과를 생성하는 메서드 @Override public BackTestingDto.BackTestingResponse createBackTestingResult(String authorizationHeader, BackTestingDto.StepInfo stepInfo) { - Candle candle = candleRepository.findByName(stepInfo.getCandleName()); + Candle candle = candleRepository.findByCandleName(stepInfo.getCandleName()); LocalDateTime startDate = dateUtil.convertToLocalDateTime(stepInfo.getStartDate()); LocalDateTime endDate = dateUtil.convertToLocalDateTime(stepInfo.getEndDate()); diff --git a/backend/src/main/java/org/dgu/backend/service/CandleInfoServiceImpl.java b/backend/src/main/java/org/dgu/backend/service/CandleInfoServiceImpl.java index 9699e9e..489285c 100644 --- a/backend/src/main/java/org/dgu/backend/service/CandleInfoServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/CandleInfoServiceImpl.java @@ -2,11 +2,12 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.dgu.backend.domain.Candle; import org.dgu.backend.domain.CandleInfo; import org.dgu.backend.domain.Market; import org.dgu.backend.dto.UpbitDto; +import org.dgu.backend.exception.UpbitErrorResult; +import org.dgu.backend.exception.UpbitException; import org.dgu.backend.repository.CandleInfoRepository; import org.dgu.backend.repository.CandleRepository; import org.dgu.backend.repository.MarketRepository; @@ -20,7 +21,6 @@ @Service @Transactional @RequiredArgsConstructor -@Slf4j public class CandleInfoServiceImpl implements CandleInfoService { private final CandleInfoRepository candleInfoRepository; @@ -29,19 +29,19 @@ public class CandleInfoServiceImpl implements CandleInfoService { private final RestTemplate restTemplate; @Override - public void getCandleInfo(String marketKoreanName, LocalDateTime to, int count, String candleType) { - Market market = marketRepository.findByKoreanName(marketKoreanName); - Candle candle = candleRepository.findByName(candleType); - String marketName = market.getName(); + public void getCandleInfo(String koreanName, LocalDateTime to, int count, String candleName) { + Market market = marketRepository.findByKoreanName(koreanName); + Candle candle = candleRepository.findByCandleName(candleName); + String marketName = market.getMarketName(); String url; - if (candleType.startsWith("minutes")) { + if (candleName.startsWith("minutes")) { // 분봉인 경우 - int unit = Integer.parseInt(candleType.substring(7)); - url = String.format("https://api.upbit.com/v1/candles/%s/%d?market=%s&count=%d", candleType.substring(0,7), unit, marketName, count); + int unit = Integer.parseInt(candleName.substring(7)); + url = String.format("https://api.upbit.com/v1/candles/%s/%d?market=%s&count=%d", candleName.substring(0,7), unit, marketName, count); } else { // 그 외 (일봉, 주봉, 월봉) - url = String.format("https://api.upbit.com/v1/candles/%s?market=%s&count=%d", candleType, marketName, count); + url = String.format("https://api.upbit.com/v1/candles/%s?market=%s&count=%d", candleName, marketName, count); } if (to != null) { @@ -67,7 +67,7 @@ public void getCandleInfo(String marketKoreanName, LocalDateTime to, int count, candleInfoRepository.save(candleInfo); } } else { - log.error("Failed to receive candle info"); + throw new UpbitException(UpbitErrorResult.FAIL_GET_CANDLE_INFO); } } } \ No newline at end of file From 69ce46ee723c0b7a9d0a6c4ae591c2be5e3b0938 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:23:04 +0900 Subject: [PATCH 03/12] =?UTF-8?q?#53=20[style]=20:=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dgu/backend/auth/info/GoogleUserInfo.java | 2 +- .../src/main/java/org/dgu/backend/auth/info/KakaoUserInfo.java | 2 +- .../src/main/java/org/dgu/backend/auth/info/NaverUserInfo.java | 2 +- .../java/org/dgu/backend/{common => }/constant/Provider.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename backend/src/main/java/org/dgu/backend/{common => }/constant/Provider.java (87%) diff --git a/backend/src/main/java/org/dgu/backend/auth/info/GoogleUserInfo.java b/backend/src/main/java/org/dgu/backend/auth/info/GoogleUserInfo.java index ca8fca2..46a13c2 100644 --- a/backend/src/main/java/org/dgu/backend/auth/info/GoogleUserInfo.java +++ b/backend/src/main/java/org/dgu/backend/auth/info/GoogleUserInfo.java @@ -1,7 +1,7 @@ package org.dgu.backend.auth.info; import lombok.AllArgsConstructor; -import org.dgu.backend.common.constant.Provider; +import org.dgu.backend.constant.Provider; import java.util.Map; diff --git a/backend/src/main/java/org/dgu/backend/auth/info/KakaoUserInfo.java b/backend/src/main/java/org/dgu/backend/auth/info/KakaoUserInfo.java index f9a8b07..9d7b11f 100644 --- a/backend/src/main/java/org/dgu/backend/auth/info/KakaoUserInfo.java +++ b/backend/src/main/java/org/dgu/backend/auth/info/KakaoUserInfo.java @@ -1,7 +1,7 @@ package org.dgu.backend.auth.info; import lombok.AllArgsConstructor; -import org.dgu.backend.common.constant.Provider; +import org.dgu.backend.constant.Provider; import java.util.Map; diff --git a/backend/src/main/java/org/dgu/backend/auth/info/NaverUserInfo.java b/backend/src/main/java/org/dgu/backend/auth/info/NaverUserInfo.java index 93e2ffc..12e76e7 100644 --- a/backend/src/main/java/org/dgu/backend/auth/info/NaverUserInfo.java +++ b/backend/src/main/java/org/dgu/backend/auth/info/NaverUserInfo.java @@ -1,7 +1,7 @@ package org.dgu.backend.auth.info; import lombok.AllArgsConstructor; -import org.dgu.backend.common.constant.Provider; +import org.dgu.backend.constant.Provider; import java.util.Map; diff --git a/backend/src/main/java/org/dgu/backend/common/constant/Provider.java b/backend/src/main/java/org/dgu/backend/constant/Provider.java similarity index 87% rename from backend/src/main/java/org/dgu/backend/common/constant/Provider.java rename to backend/src/main/java/org/dgu/backend/constant/Provider.java index f0f2302..2d1b466 100644 --- a/backend/src/main/java/org/dgu/backend/common/constant/Provider.java +++ b/backend/src/main/java/org/dgu/backend/constant/Provider.java @@ -1,4 +1,4 @@ -package org.dgu.backend.common.constant; +package org.dgu.backend.constant; public enum Provider { GOOGLE_PROVIDER("google"), From 404b674e4a9b115cf1c84fa82392b70c42e8254c Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:24:28 +0900 Subject: [PATCH 04/12] =?UTF-8?q?#53=20[refactor]=20:=20startDate=20?= =?UTF-8?q?=EC=9D=B8=EC=9E=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CandleInfoController.java | 17 ++++++++--------- .../dgu/backend/util/CandleDataCollector.java | 18 ++++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/backend/src/main/java/org/dgu/backend/controller/CandleInfoController.java b/backend/src/main/java/org/dgu/backend/controller/CandleInfoController.java index a23131f..8deb250 100644 --- a/backend/src/main/java/org/dgu/backend/controller/CandleInfoController.java +++ b/backend/src/main/java/org/dgu/backend/controller/CandleInfoController.java @@ -3,7 +3,6 @@ import lombok.RequiredArgsConstructor; import org.dgu.backend.common.ApiResponse; import org.dgu.backend.common.constant.SuccessStatus; -import org.dgu.backend.service.CandleInfoService; import org.dgu.backend.util.CandleDataCollector; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; @@ -15,10 +14,9 @@ @RequestMapping("/api/v1") @RequiredArgsConstructor public class CandleInfoController { - private final CandleInfoService candleInfoService; private final CandleDataCollector candleDataCollector; - // 업비트에서 캔들차트를 가져오는 API + /* 업비트에서 캔들차트를 가져오는 API @GetMapping("/candle/info") public void getCandleInfo( @RequestParam("market") String koreanName, @@ -27,16 +25,17 @@ public void getCandleInfo( @RequestParam("candle_type") String candleType) { candleInfoService.getCandleInfo(koreanName, to, count, candleType); - } + } */ // 원하는 가상화폐 & 기간 & 캔들 종류에 따른 데이터를 가져오는 API @GetMapping("/candle/info/all") - public ResponseEntity> collectBitcoinCandleData( - @RequestParam("market") String koreanName, - @RequestParam(value = "to", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime to, - @RequestParam("candle_type") String candleType) { + public ResponseEntity> collectCandleData( + @RequestParam("coin_name") String koreanName, + @RequestParam("start_date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate, + @RequestParam("end_date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate, + @RequestParam("candle_name") String candleName) { - candleDataCollector.collectData(koreanName, to, candleType); + candleDataCollector.collectCandleData(koreanName, startDate, endDate, candleName); return ApiResponse.onSuccess(SuccessStatus.SUCCESS_CANDLE_INFOS); } diff --git a/backend/src/main/java/org/dgu/backend/util/CandleDataCollector.java b/backend/src/main/java/org/dgu/backend/util/CandleDataCollector.java index e424924..db953d3 100644 --- a/backend/src/main/java/org/dgu/backend/util/CandleDataCollector.java +++ b/backend/src/main/java/org/dgu/backend/util/CandleDataCollector.java @@ -6,7 +6,6 @@ import java.time.Duration; import java.time.LocalDateTime; -import java.time.Month; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -17,16 +16,15 @@ public class CandleDataCollector { private final CandleInfoService candleInfoService; private final int batchSize = 200; - private final LocalDateTime startTime = LocalDateTime.of(2018, Month.JANUARY, 1, 0, 0); private final RateLimiter rateLimiter = RateLimiter.create(10.0); // 초당 요청 허용량 10개로 제한 private final long retryDelayMillis = 100; // 재시도 대기 시간 (0.1초) - public void collectData(String marketKoreanName, LocalDateTime to, String candleType) { + public void collectCandleData(String koreanName, LocalDateTime startDate, LocalDateTime endDate, String candleName) { // 캔들을 분 기준으로 변환 - int candleInterval = calculateCandleInterval(candleType); + int candleInterval = calculateCandleInterval(candleName); // 시작 시간부터 종료 시간까지의 총 분 수 계산 - long totalMinutes = Duration.between(startTime, to).toMinutes(); + long totalMinutes = Duration.between(startDate, endDate).toMinutes(); // 한 번의 API 요청에서 지나는 시간 long oneAPI = (long) candleInterval * batchSize; @@ -37,12 +35,12 @@ public void collectData(String marketKoreanName, LocalDateTime to, String candle CompletableFuture[] futures = new CompletableFuture[(int) numIterations]; for (int i = 0; i < numIterations; i++) { - LocalDateTime currentStartTime = startTime.plusMinutes((long) i * oneAPI); + LocalDateTime currentStartTime = startDate.plusMinutes((long) i * oneAPI); LocalDateTime currentEndTime = currentStartTime.plusMinutes(oneAPI); - // 종료 시간이 endTime을 넘어가면 endTime으로 설정 - if (currentEndTime.isAfter(to)) { - currentEndTime = to; + // 종료 시간이 endDate을 넘어가면 endDate으로 설정 + if (currentEndTime.isAfter(endDate)) { + currentEndTime = endDate; } final LocalDateTime intervalEnd = currentEndTime; @@ -55,7 +53,7 @@ public void collectData(String marketKoreanName, LocalDateTime to, String candle rateLimiter.acquire(); try { - candleInfoService.getCandleInfo(marketKoreanName, intervalEnd, batchSize, candleType); + candleInfoService.getCandleInfo(koreanName, intervalEnd, batchSize, candleName); requestSuccess = true; // 성공적으로 완료됨 } catch (Exception e) { // 오류 발생 시 재시도 From b0c33b1d831dc759b167e9aab818361f9a6dd7a8 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:24:48 +0900 Subject: [PATCH 05/12] =?UTF-8?q?#53=20[refactor]=20:=20to=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dgu/backend/domain/Market.java | 11 +---------- .../src/main/java/org/dgu/backend/dto/UpbitDto.java | 9 +++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/src/main/java/org/dgu/backend/domain/Market.java b/backend/src/main/java/org/dgu/backend/domain/Market.java index 6ea98f5..915ef20 100644 --- a/backend/src/main/java/org/dgu/backend/domain/Market.java +++ b/backend/src/main/java/org/dgu/backend/domain/Market.java @@ -2,7 +2,6 @@ import jakarta.persistence.*; import lombok.*; -import org.dgu.backend.dto.UpbitDto; import java.util.List; @@ -19,7 +18,7 @@ public class Market { private Long id; @Column(name = "markets_name") - private String name; + private String marketName; @Column(name = "korean_name") private String koreanName; @@ -29,12 +28,4 @@ public class Market { @OneToMany(mappedBy = "market", cascade = CascadeType.ALL, orphanRemoval = true) private List candleInfos; - - public static Market toEntity(UpbitDto.MarketResponse response) { - return Market.builder() - .name(response.getName()) - .koreanName(response.getKoreanName()) - .englishName(response.getEnglishName()) - .build(); - } } diff --git a/backend/src/main/java/org/dgu/backend/dto/UpbitDto.java b/backend/src/main/java/org/dgu/backend/dto/UpbitDto.java index 0789944..35b65e3 100644 --- a/backend/src/main/java/org/dgu/backend/dto/UpbitDto.java +++ b/backend/src/main/java/org/dgu/backend/dto/UpbitDto.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import lombok.*; +import org.dgu.backend.domain.Market; public class UpbitDto { @Builder @@ -21,6 +22,14 @@ public static class MarketResponse { @JsonProperty("english_name") private String englishName; + + public Market to() { + return Market.builder() + .marketName(name) + .koreanName(koreanName) + .englishName(englishName) + .build(); + } } @Builder From efe0579e2a502edc9b9c7afcbaeb438908e4618d Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:26:04 +0900 Subject: [PATCH 06/12] =?UTF-8?q?#53=20[style]=20:=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dgu/backend/{common => }/constant/Coin.java | 2 +- .../java/org/dgu/backend/service/DashBoardServiceImpl.java | 2 +- .../main/java/org/dgu/backend/service/MarketServiceImpl.java | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) rename backend/src/main/java/org/dgu/backend/{common => }/constant/Coin.java (93%) diff --git a/backend/src/main/java/org/dgu/backend/common/constant/Coin.java b/backend/src/main/java/org/dgu/backend/constant/Coin.java similarity index 93% rename from backend/src/main/java/org/dgu/backend/common/constant/Coin.java rename to backend/src/main/java/org/dgu/backend/constant/Coin.java index 26600ff..9b27820 100644 --- a/backend/src/main/java/org/dgu/backend/common/constant/Coin.java +++ b/backend/src/main/java/org/dgu/backend/constant/Coin.java @@ -1,4 +1,4 @@ -package org.dgu.backend.common.constant; +package org.dgu.backend.constant; public enum Coin { BITCOIN("KRW-BTC", "비트코인"), diff --git a/backend/src/main/java/org/dgu/backend/service/DashBoardServiceImpl.java b/backend/src/main/java/org/dgu/backend/service/DashBoardServiceImpl.java index 11bf17f..ae4bcb5 100644 --- a/backend/src/main/java/org/dgu/backend/service/DashBoardServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/DashBoardServiceImpl.java @@ -3,7 +3,7 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.dgu.backend.common.constant.Coin; +import org.dgu.backend.constant.Coin; import org.dgu.backend.domain.UpbitKey; import org.dgu.backend.domain.User; import org.dgu.backend.domain.UserCoin; diff --git a/backend/src/main/java/org/dgu/backend/service/MarketServiceImpl.java b/backend/src/main/java/org/dgu/backend/service/MarketServiceImpl.java index 9dc455d..cfe24af 100644 --- a/backend/src/main/java/org/dgu/backend/service/MarketServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/MarketServiceImpl.java @@ -3,7 +3,6 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.dgu.backend.domain.Market; import org.dgu.backend.dto.UpbitDto; import org.dgu.backend.repository.MarketRepository; import org.springframework.http.*; @@ -39,8 +38,7 @@ public void getAllMarkets() { for (UpbitDto.MarketResponse marketResponse : responseBody) { // "KRW-"로 시작하는 가상화폐만 저장 if (marketResponse.getName().startsWith("KRW-")) { - Market market = Market.toEntity(marketResponse); - marketRepository.save(market); + marketRepository.save(marketResponse.to()); } } } else { From 9f888bb3baad505af9f28baa720d49812ef4db46 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:26:32 +0900 Subject: [PATCH 07/12] =?UTF-8?q?#53=20[feat]=20:=20=EC=97=85=EB=B9=84?= =?UTF-8?q?=ED=8A=B8=20=EC=BA=94=EB=93=A4=20=EC=B0=A8=ED=8A=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=8B=A4=ED=8C=A8=20Enum=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dgu/backend/exception/UpbitErrorResult.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/org/dgu/backend/exception/UpbitErrorResult.java b/backend/src/main/java/org/dgu/backend/exception/UpbitErrorResult.java index bd9d980..b9674e5 100644 --- a/backend/src/main/java/org/dgu/backend/exception/UpbitErrorResult.java +++ b/backend/src/main/java/org/dgu/backend/exception/UpbitErrorResult.java @@ -10,7 +10,8 @@ @RequiredArgsConstructor public enum UpbitErrorResult implements BaseErrorCode { FAIL_ACCESS_USER_ACCOUNT(HttpStatus.NOT_FOUND, "404", "업비트에서 유저 잔고를 가져오는 데 실패했습니다."), - FAIL_ACCESS_COIN_INFO(HttpStatus.NOT_FOUND, "404", "업비트에서 코인 정보를 가져오는 데 실패했습니다."); + FAIL_ACCESS_COIN_INFO(HttpStatus.NOT_FOUND, "404", "업비트에서 코인 정보를 가져오는 데 실패했습니다."), + FAIL_GET_CANDLE_INFO(HttpStatus.NOT_FOUND, "404", "업비트에서 캔들 정보를 가져오는 데 실패했습니다."); private final HttpStatus httpStatus; private final String code; From ed8773e64c26d914b955a84b043f058aac01dbee Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:26:56 +0900 Subject: [PATCH 08/12] =?UTF-8?q?#53=20[feat]=20:=20OHLCV=20=EC=B0=A8?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EC=84=B1=EA=B3=B5=20Enum=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dgu/backend/common/constant/SuccessStatus.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java b/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java index 8e2a758..3cac3a9 100644 --- a/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java +++ b/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java @@ -37,7 +37,9 @@ public enum SuccessStatus implements BaseCode { SUCCESS_GET_USER_COINS(HttpStatus.OK, "200", "유저 보유 코인 조회에 성공했습니다"), SUCCESS_GET_REPRESENTATIVE_COINS(HttpStatus.OK, "200", "대표 코인 조회에 성공했습니다"), // Upbit-Key - SUCCESS_ADD_UPBIT_KEYS(HttpStatus.CREATED, "201", "업비트 키 등록에 성공했습니다"); + SUCCESS_ADD_UPBIT_KEYS(HttpStatus.CREATED, "201", "업비트 키 등록에 성공했습니다"), + // Chart + SUCCESS_GET_OHLCV_CHART(HttpStatus.OK, "200", "OHLCV 차트 조회에 성공했습니다."); private final HttpStatus httpStatus; private final String code; From 5bf4b46e8a389bc21f587a6a4a2852653223a845 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:27:13 +0900 Subject: [PATCH 09/12] =?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=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/exception/ChartErrorResult.java | 36 +++++++++++++++++++ .../dgu/backend/exception/ChartException.java | 15 ++++++++ .../exception/GlobalExceptionHandler.java | 6 ++++ 3 files changed, 57 insertions(+) create mode 100644 backend/src/main/java/org/dgu/backend/exception/ChartErrorResult.java create mode 100644 backend/src/main/java/org/dgu/backend/exception/ChartException.java diff --git a/backend/src/main/java/org/dgu/backend/exception/ChartErrorResult.java b/backend/src/main/java/org/dgu/backend/exception/ChartErrorResult.java new file mode 100644 index 0000000..f18cfd2 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/exception/ChartErrorResult.java @@ -0,0 +1,36 @@ +package org.dgu.backend.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.dgu.backend.common.code.BaseErrorCode; +import org.dgu.backend.common.dto.ErrorReasonDto; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum ChartErrorResult implements BaseErrorCode { + NOT_FOUND_CHARTS(HttpStatus.NOT_FOUND, "404", "차트가 존재하지 않습니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ErrorReasonDto getReason() { + return ErrorReasonDto.builder() + .isSuccess(false) + .code(code) + .message(message) + .build(); + } + + @Override + public ErrorReasonDto getReasonHttpStatus() { + return ErrorReasonDto.builder() + .isSuccess(false) + .httpStatus(httpStatus) + .code(code) + .message(message) + .build(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/ChartException.java b/backend/src/main/java/org/dgu/backend/exception/ChartException.java new file mode 100644 index 0000000..9334d6d --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/exception/ChartException.java @@ -0,0 +1,15 @@ +package org.dgu.backend.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class ChartException extends RuntimeException { + private final ChartErrorResult chartErrorResult; + + @Override + public String getMessage() { + return chartErrorResult.getMessage(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java b/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java index b677f8e..c63f72a 100644 --- a/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java +++ b/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java @@ -62,4 +62,10 @@ public ResponseEntity> handleEncryptionException(Encr EncryptionErrorResult errorResult = e.getEncryptionErrorResult(); return ApiResponse.onFailure(errorResult); } + // Chart + @ExceptionHandler(ChartException.class) + public ResponseEntity> handleChartException(ChartException e) { + ChartErrorResult errorResult = e.getChartErrorResult(); + return ApiResponse.onFailure(errorResult); + } } \ No newline at end of file From a267b979c1608c6da555ddcce6114f8c8648e444 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:27:55 +0900 Subject: [PATCH 10/12] =?UTF-8?q?#53=20[feat]=20:=20=EC=BD=94=EC=9D=B8=20&?= =?UTF-8?q?=20=EB=B4=89=20&=20=EA=B8=B0=EA=B0=84=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=BA=94=EB=93=A4=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dgu/backend/repository/CandleInfoRepository.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/main/java/org/dgu/backend/repository/CandleInfoRepository.java b/backend/src/main/java/org/dgu/backend/repository/CandleInfoRepository.java index b62b33f..bf4c496 100644 --- a/backend/src/main/java/org/dgu/backend/repository/CandleInfoRepository.java +++ b/backend/src/main/java/org/dgu/backend/repository/CandleInfoRepository.java @@ -2,6 +2,7 @@ import org.dgu.backend.domain.Candle; import org.dgu.backend.domain.CandleInfo; +import org.dgu.backend.domain.Market; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -11,4 +12,7 @@ public interface CandleInfoRepository extends JpaRepository { @Query("SELECT c FROM CandleInfo c WHERE c.candle = :candle AND c.dateTime BETWEEN :startDate AND :endDate ORDER BY c.dateTime") List findFilteredCandleInfo(Candle candle, LocalDateTime startDate, LocalDateTime endDate); + + @Query("SELECT c FROM CandleInfo c WHERE c.market = :market AND c.candle = :candle AND c.dateTime > :startDate ORDER BY c.dateTime") + List findByMarketAndCandleAndDateTimeAfter(Market market, Candle candle, LocalDateTime startDate); } \ No newline at end of file From 97149b73da5667cad6407bc8fd645fb93e74a052 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:28:19 +0900 Subject: [PATCH 11/12] =?UTF-8?q?#53=20[feat]=20:=20=EC=B0=A8=ED=8A=B8=20D?= =?UTF-8?q?TO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dgu/backend/dto/ChartDto.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 backend/src/main/java/org/dgu/backend/dto/ChartDto.java diff --git a/backend/src/main/java/org/dgu/backend/dto/ChartDto.java b/backend/src/main/java/org/dgu/backend/dto/ChartDto.java new file mode 100644 index 0000000..1680820 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/dto/ChartDto.java @@ -0,0 +1,46 @@ +package org.dgu.backend.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import org.dgu.backend.domain.CandleInfo; +import org.dgu.backend.util.BigDecimalSerializer; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class ChartDto { + @Builder + @Getter + @AllArgsConstructor + @JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class OHLCVResponse { + private String date; + @JsonSerialize(using = BigDecimalSerializer.class) + private BigDecimal openingPrice; + @JsonSerialize(using = BigDecimalSerializer.class) + private BigDecimal highPrice; + @JsonSerialize(using = BigDecimalSerializer.class) + private BigDecimal lowPrice; + @JsonSerialize(using = BigDecimalSerializer.class) + private BigDecimal closePrice; + @JsonSerialize(using = BigDecimalSerializer.class) + private BigDecimal volume; + + public static ChartDto.OHLCVResponse of(CandleInfo candleInfo) { + return OHLCVResponse.builder() + .date(String.valueOf(candleInfo.getDateTime())) + .openingPrice(BigDecimal.valueOf(candleInfo.getOpeningPrice())) + .lowPrice(BigDecimal.valueOf(candleInfo.getLowPrice())) + .highPrice(BigDecimal.valueOf(candleInfo.getHighPrice())) + .closePrice(BigDecimal.valueOf(candleInfo.getTradePrice())) + .volume(BigDecimal.valueOf(candleInfo.getAccTradeVolume()).setScale(3, RoundingMode.HALF_UP)) + .build(); + } + } +} \ No newline at end of file From 2db3c1755e954f2437efc234759c993c2b0be3a2 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Sun, 9 Jun 2024 03:28:32 +0900 Subject: [PATCH 12/12] =?UTF-8?q?#53=20[feat]=20:=20OHLCV=20=EC=B0=A8?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC=ED=98=84=20(GE?= =?UTF-8?q?T)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/controller/ChartController.java | 28 +++++++++ .../org/dgu/backend/service/ChartService.java | 9 +++ .../dgu/backend/service/ChartServiceImpl.java | 60 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 backend/src/main/java/org/dgu/backend/controller/ChartController.java create mode 100644 backend/src/main/java/org/dgu/backend/service/ChartService.java create mode 100644 backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java diff --git a/backend/src/main/java/org/dgu/backend/controller/ChartController.java b/backend/src/main/java/org/dgu/backend/controller/ChartController.java new file mode 100644 index 0000000..a986d17 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/controller/ChartController.java @@ -0,0 +1,28 @@ +package org.dgu.backend.controller; + +import lombok.RequiredArgsConstructor; +import org.dgu.backend.common.ApiResponse; +import org.dgu.backend.common.constant.SuccessStatus; +import org.dgu.backend.dto.ChartDto; +import org.dgu.backend.service.ChartService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/charts") +@RequiredArgsConstructor +public class ChartController { + private final ChartService chartService; + + // OHLCV 차트를 조회하는 API + @GetMapping + public ResponseEntity>> getOHLCVCharts( + @RequestParam("coin_name") String koreanName, + @RequestParam("candle_name") String candleName) { + + List ohlcvResponses = chartService.getOHLCVCharts(koreanName, candleName); + return ApiResponse.onSuccess(SuccessStatus.SUCCESS_GET_OHLCV_CHART, ohlcvResponses); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/service/ChartService.java b/backend/src/main/java/org/dgu/backend/service/ChartService.java new file mode 100644 index 0000000..8346141 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/service/ChartService.java @@ -0,0 +1,9 @@ +package org.dgu.backend.service; + +import org.dgu.backend.dto.ChartDto; + +import java.util.List; + +public interface ChartService { + List getOHLCVCharts(String koreanName, String candleType); +} \ 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 new file mode 100644 index 0000000..d8d9f05 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java @@ -0,0 +1,60 @@ +package org.dgu.backend.service; + +import jakarta.transaction.Transactional; +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.dto.ChartDto; +import org.dgu.backend.exception.ChartErrorResult; +import org.dgu.backend.exception.ChartException; +import org.dgu.backend.repository.CandleInfoRepository; +import org.dgu.backend.repository.CandleRepository; +import org.dgu.backend.repository.MarketRepository; +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"); + + // OHLCV 차트를 반환하는 메서드 + @Override + public List getOHLCVCharts(String koreanName, String candleName) { + Market market = marketRepository.findByKoreanName(koreanName); + Candle candle = candleRepository.findByCandleName(candleName); + + LocalDateTime startDate = getStartDateByCandleName(candleName); + + List candleInfos = candleInfoRepository.findByMarketAndCandleAndDateTimeAfter(market, candle, startDate); + if (candleInfos.isEmpty()) { + throw new ChartException(ChartErrorResult.NOT_FOUND_CHARTS); + } + 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