Skip to content

Commit

Permalink
Merge pull request #56 from CSID-DGU/feature/#53/chart
Browse files Browse the repository at this point in the history
[feat] : OHLCV 차트 조회 API 구현 (GET)
  • Loading branch information
bbbang105 authored Jun 8, 2024
2 parents eebf331 + 2db3c17 commit 4036025
Show file tree
Hide file tree
Showing 26 changed files with 257 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.dgu.backend.common.constant;
package org.dgu.backend.constant;

public enum Coin {
BITCOIN("KRW-BTC", "비트코인"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.dgu.backend.common.constant;
package org.dgu.backend.constant;

public enum Provider {
GOOGLE_PROVIDER("google"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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<ApiResponse<Object>> 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<ApiResponse<Object>> 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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ApiResponse<List<ChartDto.OHLCVResponse>>> getOHLCVCharts(
@RequestParam("coin_name") String koreanName,
@RequestParam("candle_name") String candleName) {

List<ChartDto.OHLCVResponse> ohlcvResponses = chartService.getOHLCVCharts(koreanName, candleName);
return ApiResponse.onSuccess(SuccessStatus.SUCCESS_GET_OHLCV_CHART, ohlcvResponses);
}
}
2 changes: 1 addition & 1 deletion backend/src/main/java/org/dgu/backend/domain/Candle.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 1 addition & 10 deletions backend/src/main/java/org/dgu/backend/domain/Market.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import jakarta.persistence.*;
import lombok.*;
import org.dgu.backend.dto.UpbitDto;

import java.util.List;

Expand All @@ -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;
Expand All @@ -29,12 +28,4 @@ public class Market {

@OneToMany(mappedBy = "market", cascade = CascadeType.ALL, orphanRemoval = true)
private List<CandleInfo> candleInfos;

public static Market toEntity(UpbitDto.MarketResponse response) {
return Market.builder()
.name(response.getName())
.koreanName(response.getKoreanName())
.englishName(response.getEnglishName())
.build();
}
}
46 changes: 46 additions & 0 deletions backend/src/main/java/org/dgu/backend/dto/ChartDto.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
9 changes: 9 additions & 0 deletions backend/src/main/java/org/dgu/backend/dto/UpbitDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,10 @@ public ResponseEntity<ApiResponse<BaseErrorCode>> handleEncryptionException(Encr
EncryptionErrorResult errorResult = e.getEncryptionErrorResult();
return ApiResponse.onFailure(errorResult);
}
// Chart
@ExceptionHandler(ChartException.class)
public ResponseEntity<ApiResponse<BaseErrorCode>> handleChartException(ChartException e) {
ChartErrorResult errorResult = e.getChartErrorResult();
return ApiResponse.onFailure(errorResult);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -11,4 +12,7 @@
public interface CandleInfoRepository extends JpaRepository<CandleInfo,Long> {
@Query("SELECT c FROM CandleInfo c WHERE c.candle = :candle AND c.dateTime BETWEEN :startDate AND :endDate ORDER BY c.dateTime")
List<CandleInfo> 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<CandleInfo> findByMarketAndCandleAndDateTimeAfter(Market market, Candle candle, LocalDateTime startDate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
import org.springframework.data.jpa.repository.JpaRepository;

public interface CandleRepository extends JpaRepository<Candle,Long> {
Candle findByName(String candleName);
Candle findByCandleName(String candleName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down
Loading

0 comments on commit 4036025

Please sign in to comment.