develop에서 feature/portfolio 브랜치를 생성하였다.
-> public final class클래스로 만들어서 사용하자. 추가적인 확장이 없을 예정이기 때문이다.
수익률 = (현재 금액 - 구입 금액) / 구입 금액 * 100
로그 수익률 = ln(현재 금액) - ln(구입 금액)
public final class RorCalculator {
public static double getRor(double buyPrice, double sellPrice){
return (sellPrice - buyPrice) / buyPrice * 100;
}
public static List<Double> getRorList(List<Double> priceList){
List<Double> rorList = new ArrayList<>();
for(int i=1; i<priceList.size(); i++){
rorList.add(getRor(priceList.get(i-1), priceList.get(i)));
}
return rorList;
}
public static double getLogRor(double buyPrice, double sellPrice){
return Math.log(sellPrice / buyPrice);
}
}
추후 미국주식도 고려하기 위해서 double로 인자를 받기로 하였다. 로그 수익률의 경우 리스크 계산에서 사용할 수 있기때문에 추가하였다.
먼저 데이터를 가져와서 수익률을 구해보자!
List<StockPrice> priceList = stockPriceService.findByItmsNm("삼성전자");
List<Double> clprList = priceList.stream()
.map(stockPrice -> Double.valueOf(stockPrice.getClpr()))
.collect(Collectors.toList());
System.out.println(RorCalculator.getRorList(clprList));
해당 방식으로 먼저 DB에서 StockPrice를 가져온 후, clpr만을 배열로 만들어서 수익률을 구해보았다.
포트폴리오에서 가격을 월초 데이터를 기준으로 사용할 예정이다. 따라서, 월말 데이터를 가져와보자.
public Long getPriceByItmsNmAndMonth(String itmsNm, int year, int month) {
LocalDate startDate = LocalDate.of(year, month, 1);
LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());
List<StockPrice> stockPrices = stockPriceRepository.findByItmsNmAndBasDtBetween(itmsNm, startDate, endDate);
if(stockPrices.size() > 0) {
return stockPrices.get(0).getClpr();
}
return 0L;
}
해당 방식을 통해 월초 데이터를 가져오고 년도를 입력받아서 반복문을 통해 해당 함수를 12번 호출하여 년도의 데이터를 가져오고자 했다. 하지만, 실제로 만들어 사용해 보니 속도가 너무 느린 문제가 발생하였다.
그래서 연도별 데이터를 가져와서 반복문을 통해 처리하였다.
public List<StockPrice> findAllByItmsNmAndYear(String itmsNm, int year) {
LocalDate startDate = LocalDate.of(year, 1, 1);
LocalDate endDate = LocalDate.of(year, 12, 31);
return stockPriceRepository.findByItmsNmAndBasDtBetween(itmsNm, startDate, endDate);
}
public List<Long> getPricesByItmsNmAndYear(String itmsNm, int year) {
List<StockPrice> stockPrices = findAllByItmsNmAndYear(itmsNm, year);
List<Long> clprs = new ArrayList<>();
if (stockPrices != null && !stockPrices.isEmpty()) {
Map<Integer, Long> firstMonthPrices = new HashMap<>();
for (StockPrice stockPrice : stockPrices) {
LocalDate basDt = stockPrice.getBasDt();
int month = basDt.getMonthValue();
if (!firstMonthPrices.containsKey(month)) {
firstMonthPrices.put(month, stockPrice.getClpr());
}
}
for (int i = 1; i <= 12; i++) {
Long clpr = firstMonthPrices.get(i);
if (clpr != null) {
clprs.add(clpr);
}
}
}
return clprs;
}
해당 방식이 훨씬 더 빨리 작동하였다. 이 부분에 대해서는 추후 좀 더 알아보아야 할 것 같다.
포트폴리오 수익률 = (종목 수익률 * 종목 비중)의 합
배열로 종목별 수익률과 종목 비중을 받아서 계산하는 함수를 RorCalculator 클래스에 구현하였다.
public static double getPortfolioRor(List<Double> rorList, List<Double> weightList){
double portfolioRor = 0;
for(int i = 0; i < rorList.size(); i++){
portfolioRor += rorList.get(i) * weightList.get(i);
}
return portfolioRor;
}