55import com .synergyx .trading .converter .StockCandleConverter ;
66import com .synergyx .trading .dto .stockDetail .StockCandleResponseDTO ;
77import com .synergyx .trading .enums .CandleInterval ;
8+ import com .synergyx .trading .model .StockOhlcv ;
89import com .synergyx .trading .repository .StockOhlcv1dRepository ;
9- import com .synergyx .trading .repository .StockOhlcv1hRepository ;
10+ import com .synergyx .trading .repository .StockOhlcvRepository ;
1011import com .synergyx .trading .service .stockService .candle .strategy .CandleCompressionStrategy ;
1112import lombok .RequiredArgsConstructor ;
1213import lombok .extern .slf4j .Slf4j ;
14+ import java .util .TreeMap ;
1315
1416import java .time .LocalDate ;
1517import java .time .LocalDateTime ;
1618import java .util .List ;
19+ import java .util .Map ;
20+ import java .util .stream .Collectors ;
1721
1822import org .springframework .stereotype .Service ;
1923import org .springframework .transaction .annotation .Transactional ;
@@ -49,8 +53,8 @@ public List<StockCandleResponseDTO> getCandles(Long stockId, String intervalStr)
4953 .compress (stockId );
5054 }
5155
56+ private final StockOhlcvRepository stockOhlcvRepository ;
5257 private final StockOhlcv1dRepository stockOhlcv1dRepository ;
53- private final StockOhlcv1hRepository stockOhlcv1hRepository ;
5458 private final StockCandleConverter stockCandleConverter ;
5559
5660 /**
@@ -100,13 +104,36 @@ public List<StockCandleResponseDTO> getBacktestHourlyCandles(Long stockId, Local
100104 throw new GeneralException (ErrorStatus ._BAD_REQUEST );
101105 }
102106
103- var candles = stockOhlcv1hRepository
107+ // 15분봉 데이터 조회
108+ var candles15m = stockOhlcvRepository
104109 .findByStockIdAndTimestampBetweenOrderByTimestampAsc (stockId , startDate , endDate );
105110
106- if (candles == null || candles .isEmpty ()) {
111+ if (candles15m == null || candles15m .isEmpty ()) {
107112 throw new GeneralException (ErrorStatus .CANDLE_DATA_NOT_FOUND );
108113 }
109114
110- return stockCandleConverter .toDtoList (candles );
115+
116+ // 15분봉 -> 1시간봉 리샘플링
117+ Map <LocalDateTime , List <StockOhlcv >> grouped = candles15m .stream ()
118+ .collect (Collectors .groupingBy (
119+ c -> c .getTimestamp ().truncatedTo (java .time .temporal .ChronoUnit .HOURS ),
120+ TreeMap ::new ,
121+ Collectors .toList ()
122+ ));
123+
124+ return grouped .entrySet ().stream ()
125+ .map (entry -> {
126+ List <StockOhlcv > group = entry .getValue ();
127+ group .sort (java .util .Comparator .comparing (StockOhlcv ::getTimestamp ));
128+ return StockCandleResponseDTO .builder ()
129+ .time (entry .getKey ())
130+ .open (group .get (0 ).getOpen ())
131+ .high (group .stream ().mapToDouble (StockOhlcv ::getHigh ).max ().orElse (0 ))
132+ .low (group .stream ().mapToDouble (StockOhlcv ::getLow ).min ().orElse (0 ))
133+ .close (group .get (group .size () - 1 ).getClose ())
134+ .volume (group .stream ().mapToLong (StockOhlcv ::getVolume ).sum ())
135+ .build ();
136+ })
137+ .toList ();
111138 }
112139}
0 commit comments