포트폴리오 서비스(Entity 구성 및 DB Service 구현)

·2023년 12월 7일
0

Portfolio Backtest

목록 보기
5/31

Entity 구성하기

받아온 json 파일 분석하기

주식당 총 15개의 데이터가 넘어온다. 두 개를 일자을 기준으로 변하는 것과 변하지 않는것으로 분류하였다.

변하는 것

  1. clpr: 종가
  2. vs: 전일 대비 등락
  3. fltRt: 전일 대비 등락에 따른 비율
  4. mkp: 시가
  5. hipr: 고가
  6. lopr: 저가
  7. trqu: 거래량
  8. trPrc: 거래대금
  9. IstgStcnt: 상장주식수(크게 변하지 않지만, 유상증자 등..)
  10. mkrtTotAmt: 시가 총액
  11. basDt: 기준일자

변하지 않는 것

  1. itmsNm: 종목명
  2. mrktCtg: 주식 시장 구분
  3. srtnCd: 종목 코드
  4. isinCd: 고유번호

Entity 구성계획

  1. srtnCd를 외부키로 사용하여 두개의 table을 구성한다. -> 필요할 때, 사용한다.
  2. StockData / StockPrice의 두개의 table을 구성한다.

StockInfo

Entity

@Getter
@Setter
@Entity
public class StockInfo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // 종목코드
    @Column(unique = true)
    private String itmsNm;
    // 시장구분
    private String mrktCtg;
    // 종목명
    private String srtnCd;
    // 고유번호
    private String isinCd;

}

중복저장을 방지하기 위해서 itmsNm에 unique 속성을 부여하였다.

StockInfoRepository

public interface StockInfoRepository extends JpaRepository<StockInfo, Long> {
    StockInfo findByItmsNm(String itmsNm);
    StockInfo findBySrtnCd(String srtnCd);
}

StockInfoService

@Service
public class StockInfoService {
    private final StockInfoRepository stockInfoRepository;
    public StockInfoService(StockInfoRepository stockInfoRepository) {
        this.stockInfoRepository = stockInfoRepository;
    }

    public StockInfo save(StockInfo stockInfo) {
        if(stockInfoRepository.findByItmsNm(stockInfo.getItmsNm()) == null) {
            return stockInfoRepository.save(stockInfo);
        }
        return null;
    }

    public StockInfo findByItmsNm(String itmsNm) {
        return stockInfoRepository.findByItmsNm(itmsNm);
    }

    public StockInfo findBySrtnCd(String srtnCd) {
        return stockInfoRepository.findBySrtnCd(srtnCd);
    }
    
}

save를 하면 unique인 itmsNm에 따라서 중복이 방지되는데 테스트 결과 ID 값이 중복 저장을 시도할때 증가하는 경우가 발생하였다. 그래서, DB에 해당 정보가 있는지 확인한 후 저장하는 방식을 선택하였는데 사실 좋은 방법인지 모르겠다.. 좀 더 찾아봐야할거 같다.

JPA Test

@SpringBootTest
public class StockInfoTest {
    @Autowired
    private StockInfoRepository stockInfoRepository;

    @Test
    void testStockInfoSaveJpa() {
        StockInfo s1 = new StockInfo();
        s1.setItmsNm("900110");
        s1.setMrktCtg("KOSDAQ");
        s1.setSrtnCd("이스트아시아홀딩스");
        s1.setIsinCd("HK0000057197");
        if(stockInfoRepository.findByItmsNm(s1.getItmsNm()) == null) {
            assertThat(s1).isEqualTo(this.stockInfoRepository.save(s1));
        }

        StockInfo s2 = new StockInfo();
        s2.setItmsNm("900110");
        s2.setMrktCtg("KOSDAQ");
        s2.setSrtnCd("이스트아시아홀딩스");
        s2.setIsinCd("HK0000057197");
        if(stockInfoRepository.findByItmsNm(s2.getItmsNm()) == null) {
            assertThat(s2).isEqualTo(this.stockInfoRepository.save(s2));
        }

        StockInfo s3 = new StockInfo();
        s3.setItmsNm("900270");
        s3.setMrktCtg("KOSDAQ");
        s3.setSrtnCd("헝셩그룹");
        s3.setIsinCd("HK0000214814");
        if(stockInfoRepository.findByItmsNm(s3.getItmsNm()) == null) {
            assertThat(s3).isEqualTo(this.stockInfoRepository.save(s3));
        }

        assertEquals("1", "1");
    }

    @Test
    void testStockInfoFindAllJpa() {
        List<StockInfo> all = this.stockInfoRepository.findAll();

        assertEquals(all.size(), 2);

        StockInfo s = all.get(0);
        assertEquals("900110", s.getItmsNm());
    }

    @Test
    void testStockInfoFindItmsNmJpa() {
        StockInfo s = this.stockInfoRepository.findByItmsNm("900110");
        assertEquals("이스트아시아홀딩스", s.getSrtnCd());
    }

    @Test
    void testStockInfoFindSrtnCdJpa() {
        StockInfo s = this.stockInfoRepository.findBySrtnCd("이스트아시아홀딩스");
        assertEquals("900110", s.getItmsNm());
    }
}

해당 4가지 테스트 케이스를 모두 통과하였다.

StockPrice

Entity

@Entity
@Getter
@Setter
public class StockPrice {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // 종목코드
    private String itmsNm;
    // 시가
    private Long mkp;
    // 종가
    private Long clpr;
    // 고가
    private Long hipr;
    // 저가
    private Long lopr;
    // 거래량
    private Long trqu;
    // 거래대금
    private Long trPrc;
    // 시가총액
    private Long mkrtTotAmt;
    // 기준일자
    private LocalDate basDt;

}

LocalDateTime의 경우 뒤에 시간이 붙는다. 해당 Entity에 시간을 필요없어서 LocalDate의 형식으로 지정하였다.

StockPriceRepository

public interface StockPriceRepository extends JpaRepository<StockPrice, Long> {
    List<StockPrice> findByItmsNm(String itmsNm);

    List<StockPrice> findByBasDt(LocalDate basDt);

    List<StockPrice> findByItmsNmAndBasDtBetween(String itmsNm, LocalDate startDate, LocalDate endDate);
}

일단은 종목코드, 기준날짜, 종목코드 및 기간으로 조회하는 기능을 추가하였다.

StockPriceService

@Service
public class StockPriceService {
    private final StockPriceRepository stockPriceRepository;
    public StockPriceService(StockPriceRepository stockPriceRepository) {
        this.stockPriceRepository = stockPriceRepository;
    }

    public StockPrice save(StockPrice stockPrice) {
        return stockPriceRepository.save(stockPrice);
    }
    
    public List<StockPrice> findByItmsNm(String itmsNm) {
        return stockPriceRepository.findByItmsNm(itmsNm);
    }
    
    public List<StockPrice> findByBasDt(LocalDate basDt) {
        return stockPriceRepository.findByBasDt(basDt);
    }

    public List<StockPrice> findByItmsNmAndBasDtBetween(String itmsNm, LocalDate startDate, LocalDate endDate) {
        return stockPriceRepository.findByItmsNmAndBasDtBetween(itmsNm, startDate, endDate);
    }

}

JPA Test

해당 부분을 테스트하면서 테스트는 클래스를 만든 순서가 아닌 클래스 이름을 기준으로 실행한다는 것을 배울 수 있었다. 데이터를 추가하는 함수를 가장 먼저 시행하도록 @Order 어노테이션을 사용하였다.

@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class StockPriceTest {
    @Autowired
    private StockPriceRepository stockPriceRepository;

    @Test
    @Order(1)
    public void testSaveStockPrice() {
        StockPrice stockPrice1 = createSampleStockPrice("ABC", LocalDate.of(2023, 12, 1), 1000L, 1200L, 900L, 800L, 15000L, 300000L, 5000000L);
        StockPrice stockPrice2 = createSampleStockPrice("ABC", LocalDate.of(2023, 12, 2), 1500L, 1300L, 1100L, 1000L, 18000L, 400000L, 6000000L);
        StockPrice stockPrice3 = createSampleStockPrice("ABC", LocalDate.of(2023, 12, 3), 2000L, 1800L, 1500L, 1400L, 20000L, 450000L, 7000000L);
        StockPrice stockPrice4 = createSampleStockPrice("GHI", LocalDate.of(2023, 12, 4), 2500L, 2200L, 1900L, 1800L, 22000L, 500000L, 7500000L);
        StockPrice stockPrice5 = createSampleStockPrice("JKL", LocalDate.of(2023, 12, 1), 3000L, 2700L, 2300L, 2200L, 25000L, 550000L, 8000000L);


        assertThat(stockPrice1).isEqualTo(this.stockPriceRepository.save(stockPrice1));
        assertThat(stockPrice2).isEqualTo(this.stockPriceRepository.save(stockPrice2));
        assertThat(stockPrice3).isEqualTo(this.stockPriceRepository.save(stockPrice3));
        assertThat(stockPrice4).isEqualTo(this.stockPriceRepository.save(stockPrice4));
        assertThat(stockPrice5).isEqualTo(this.stockPriceRepository.save(stockPrice5));

    }

    @Test
    @Order(3)
    public void testFindByItmsNm() {
        String itmsNm = "ABC";
        List<StockPrice> stockPrices = this.stockPriceRepository.findByItmsNm(itmsNm);

        assertEquals(3, stockPrices.size());

    }

    @Test
    @Order(2)
    public void testFindByBasDt() {
        LocalDate basDt = LocalDate.of(2023, 12, 1); // 날짜 설정

        List<StockPrice> stockPrices = this.stockPriceRepository.findByBasDt(basDt);

        assertEquals(2, stockPrices.size());

    }

    @Test
    @Order(4)
    public void testFindByItmsNmAndBasDtBetween() {
        String itmsNm = "ABC"; // 종목명 설정
        LocalDate startDate = LocalDate.of(2023, 11, 1); // 시작 날짜 설정
        LocalDate endDate = LocalDate.of(2023, 12, 2); // 끝 날짜 설정

        List<StockPrice> stockPrices = this.stockPriceRepository.findByItmsNmAndBasDtBetween(itmsNm, startDate, endDate);

        assertEquals(2, stockPrices.size());

    }

    public static StockPrice createSampleStockPrice(String itmsNm, LocalDate basDt, Long mkp, Long clpr, Long hipr, Long lopr,
                                                    Long trqu, Long trPrc, Long mkrtTotAmt) {
        StockPrice stockPrice = new StockPrice();
        stockPrice.setItmsNm(itmsNm);
        stockPrice.setBasDt(basDt);
        stockPrice.setMkp(mkp);
        stockPrice.setClpr(clpr);
        stockPrice.setHipr(hipr);
        stockPrice.setLopr(lopr);
        stockPrice.setTrqu(trqu);
        stockPrice.setTrPrc(trPrc);
        stockPrice.setMkrtTotAmt(mkrtTotAmt);

        return stockPrice;

    }

}

다음에는 이제 데이터를 추가하여 보겠다.

profile
백엔드 개발자가 꿈인 컴공과

0개의 댓글

관련 채용 정보