33import com .synergyx .trading .apiPayload .exception .GeneralException ;
44import com .synergyx .trading .dto .backtest .BacktestRequestDTO ;
55import com .synergyx .trading .dto .backtest .BacktestResponseDTO ;
6+ import com .synergyx .trading .dto .stockDetail .StockCandleResponseDTO ;
67import com .synergyx .trading .model .Backtest ;
78import com .synergyx .trading .model .Pattern ;
89import com .synergyx .trading .model .Stock ;
1112import com .synergyx .trading .repository .PatternRepository ;
1213import com .synergyx .trading .repository .StockRepository ;
1314import com .synergyx .trading .repository .UserRepository ;
15+ import com .synergyx .trading .service .stockService .candle .StockCandleQueryService ;
1416import lombok .RequiredArgsConstructor ;
1517import org .springframework .data .domain .Page ;
1618import org .springframework .data .domain .PageRequest ;
2123import com .synergyx .trading .service .backtestService .client .BacktestClientService ;
2224
2325import java .time .LocalDate ;
26+ import java .time .LocalDateTime ;
27+ import java .util .List ;
2428
2529@ Service
2630@ RequiredArgsConstructor
@@ -30,6 +34,7 @@ public class BacktestServiceImpl implements BacktestService {
3034 private final StockRepository stockRepository ;
3135 private final UserRepository userRepository ;
3236 private final BacktestClientService backtestClientService ;
37+ private final StockCandleQueryService stockCandleQueryService ;
3338
3439 // 백테스팅 실행
3540 @ Override
@@ -75,6 +80,14 @@ public BacktestResponseDTO.BacktestExecutionDTO runBacktest(Long userId, Long pa
7580 .lastMatchedDate (result .getLastMatchedDate ())
7681 .lastMatchedReturn (result .getLastMatchedReturn ())
7782 .totalReturn (result .getTotalReturn ())
83+ // null 허용
84+ .highlightFromDate (
85+ result .getHighlightRange () != null ? result .getHighlightRange ().getFromDate () : null
86+ )
87+ .highlightToDate (
88+ result .getHighlightRange () != null ? result .getHighlightRange ().getToDate () : null
89+ )
90+ .periodUnit (pattern .getPeriodUnit ())
7891 .build ());
7992
8093 return BacktestResponseDTO .BacktestExecutionDTO .builder ()
@@ -93,6 +106,15 @@ public BacktestResponseDTO.BacktestExecutionDTO runBacktest(Long userId, Long pa
93106 .totalReturn (saved .getTotalReturn ())
94107 .lastMatchedDate (saved .getLastMatchedDate ())
95108 .lastMatchedReturn (saved .getLastMatchedReturn ())
109+ .highlightRange (
110+ (saved .getHighlightFromDate () != null && saved .getHighlightToDate () != null )
111+ ? BacktestResponseDTO .HighlightRangeDTO .builder ()
112+ .fromDate (saved .getHighlightFromDate ())
113+ .toDate (saved .getHighlightToDate ())
114+ .build ()
115+ : null
116+ )
117+ .periodUnit (saved .getPeriodUnit ())
96118 .build ();
97119 }
98120
@@ -101,12 +123,13 @@ public BacktestResponseDTO.BacktestExecutionDTO runBacktest(Long userId, Long pa
101123 @ Transactional (readOnly = true )
102124 public BacktestResponseDTO .BacktestResultDetailDTO getBacktestResultDetail (Long userId , Long backtestId ) {
103125
104- // 사용자 조회
105- User user = userRepository .findById (userId )
106- .orElseThrow (() -> new GeneralException (ErrorStatus .USER_NOT_FOUND ));
126+ // 유저 존재 여부 확인
127+ if (!userRepository .existsById (userId )) {
128+ throw new GeneralException (ErrorStatus .USER_NOT_FOUND );
129+ }
107130
108131 // 백테스팅 조회
109- Backtest backtest = backtestRepository .findById (backtestId )
132+ Backtest backtest = backtestRepository .findByIdAndUserId (backtestId , userId )
110133 .orElseThrow (() -> new GeneralException (ErrorStatus .BACKTEST_NOT_FOUND ));
111134
112135 return BacktestResponseDTO .BacktestResultDetailDTO .builder ()
@@ -126,6 +149,15 @@ public BacktestResponseDTO.BacktestResultDetailDTO getBacktestResultDetail(Long
126149 .lastMatchedDate (backtest .getLastMatchedDate ())
127150 .lastMatchedReturn (backtest .getLastMatchedReturn ())
128151 .totalReturn (backtest .getTotalReturn ())
152+ .highlightRange (
153+ (backtest .getHighlightFromDate () != null && backtest .getHighlightToDate () != null )
154+ ? BacktestResponseDTO .HighlightRangeDTO .builder ()
155+ .fromDate (backtest .getHighlightFromDate ())
156+ .toDate (backtest .getHighlightToDate ())
157+ .build ()
158+ : null
159+ )
160+ .periodUnit (backtest .getPeriodUnit ())
129161 .build ();
130162 }
131163
@@ -134,9 +166,10 @@ public BacktestResponseDTO.BacktestResultDetailDTO getBacktestResultDetail(Long
134166 @ Transactional (readOnly = true )
135167 public Page <BacktestResponseDTO .BacktestSummaryDTO > getBacktestResultList (Long userId , int page , int size ) {
136168
137- // 사용자 조회
138- User user = userRepository .findById (userId )
139- .orElseThrow (() -> new GeneralException (ErrorStatus .USER_NOT_FOUND ));
169+ // 유저 존재 여부 확인
170+ if (!userRepository .existsById (userId )) {
171+ throw new GeneralException (ErrorStatus .USER_NOT_FOUND );
172+ }
140173
141174 Pageable pageable = PageRequest .of (page , size , Sort .by ("executedAt" ).descending ());
142175 Page <Backtest > resultPage = backtestRepository .findByUserId (userId , pageable );
@@ -151,4 +184,38 @@ public Page<BacktestResponseDTO.BacktestSummaryDTO> getBacktestResultList(Long u
151184 .build ());
152185 }
153186
154- }
187+ // 백테스팅 결과 차트 조회
188+ @ Override
189+ @ Transactional (readOnly = true )
190+ public List <StockCandleResponseDTO > getBacktestResultCandles (Long userId , Long backtestId , int margin ) {
191+
192+ // 유저 존재 여부 확인
193+ if (!userRepository .existsById (userId )) {
194+ throw new GeneralException (ErrorStatus .USER_NOT_FOUND );
195+ }
196+
197+ Backtest backtest = backtestRepository .findByIdAndUserId (backtestId , userId )
198+ .orElseThrow (() -> new GeneralException (ErrorStatus .BACKTEST_NOT_FOUND ));
199+
200+ if (backtest .getHighlightFromDate () == null || backtest .getHighlightToDate () == null ) {
201+ throw new GeneralException (ErrorStatus .HIGHLIGHT_RANGE_NOT_FOUND );
202+ }
203+
204+ Long stockId = backtest .getStock ().getId ();
205+ LocalDateTime from = backtest .getHighlightFromDate ();
206+ LocalDateTime to = backtest .getHighlightToDate ();
207+
208+ return switch (backtest .getPeriodUnit ()) {
209+ case DAY -> stockCandleQueryService .getBacktestDailyCandles (
210+ stockId ,
211+ from .toLocalDate ().minusDays (margin ),
212+ to .toLocalDate ().plusDays (margin )
213+ );
214+ case HOUR -> stockCandleQueryService .getBacktestHourlyCandles (
215+ stockId ,
216+ from .minusHours (margin ),
217+ to .plusHours (margin )
218+ );
219+ };
220+ }
221+ }
0 commit comments