Kaynağa Gözat

add range to portfolio history endpoint

Daniel Bohry 3 hafta önce
ebeveyn
işleme
739cf1514b

+ 5 - 3
src/main/java/com/danielbohry/stocks/api/portfolio/PortfolioHistoryController.java

@@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.*;
 import java.util.List;
 
 import static com.danielbohry.stocks.service.portfolio.PortfolioHistoryService.DEFAULT_CURRENCY;
+import static org.springframework.http.HttpStatus.CREATED;
 
 @RestController
 @RequestMapping("api/portfolios/{portfolioId}")
@@ -21,15 +22,16 @@ public class PortfolioHistoryController {
 
     @GetMapping("history")
     public ResponseEntity<?> getPortfolioHistory(@PathVariable String portfolioId,
-                                                 @RequestParam(value = "currency", defaultValue = DEFAULT_CURRENCY) String currency) {
-        List<PortfolioHistory> response = service.getSnapshots(portfolioId, currency);
+                                                 @RequestParam(value = "currency", defaultValue = DEFAULT_CURRENCY) String currency,
+                                                 @RequestParam(defaultValue = "12m", required = false) String range) {
+        List<PortfolioHistory> response = service.getSnapshots(portfolioId, currency, range);
         return ResponseEntity.ok(response);
     }
 
     @PostMapping("history")
     public ResponseEntity<Void> savePortfolioHistory(@PathVariable String portfolioId) {
         service.createSnapshot(portfolioId);
-        return ResponseEntity.status(HttpStatus.CREATED).build();
+        return ResponseEntity.status(CREATED).build();
     }
 
 }

+ 3 - 0
src/main/java/com/danielbohry/stocks/repository/portfolio/PortfolioHistoryRepository.java

@@ -3,6 +3,7 @@ package com.danielbohry.stocks.repository.portfolio;
 import org.springframework.data.mongodb.repository.MongoRepository;
 import org.springframework.stereotype.Repository;
 
+import java.time.Instant;
 import java.util.List;
 
 @Repository
@@ -10,4 +11,6 @@ public interface PortfolioHistoryRepository extends MongoRepository<PortfolioHis
 
     List<PortfolioHistoryEntity> findAllByPortfolioId(String portfolioId);
 
+    List<PortfolioHistoryEntity> findAllByPortfolioIdAndCreatedAtBetween(String portfolioId, Instant start, Instant end);
+
 }

+ 37 - 26
src/main/java/com/danielbohry/stocks/service/portfolio/PortfolioHistoryService.java

@@ -2,6 +2,7 @@ package com.danielbohry.stocks.service.portfolio;
 
 import com.danielbohry.stocks.domain.Portfolio;
 import com.danielbohry.stocks.domain.PortfolioHistory;
+import com.danielbohry.stocks.exception.BadRequestException;
 import com.danielbohry.stocks.repository.portfolio.PortfolioHistoryEntity;
 import com.danielbohry.stocks.repository.portfolio.PortfolioHistoryRepository;
 import com.danielbohry.stocks.service.ExchangeService;
@@ -14,12 +15,14 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.time.Instant;
 import java.util.List;
 import java.util.Map;
 
 import static java.math.BigDecimal.ONE;
 import static java.math.RoundingMode.HALF_UP;
 import static java.time.Instant.now;
+import static java.time.temporal.ChronoUnit.DAYS;
 
 @Slf4j
 @Service
@@ -38,21 +41,29 @@ public class PortfolioHistoryService {
     @SchedulerLock(name = "SnapshotService_createSnapshots", lockAtLeastFor = "PT2M", lockAtMostFor = "PT10M")
     public void createSnapshots() {
         List<Portfolio> portfolios = service.getAllIds().stream()
-            .map(portfolioId -> service.get(portfolioId, DEFAULT_CURRENCY))
-            .toList();
+                .map(portfolioId -> service.get(portfolioId, DEFAULT_CURRENCY))
+                .toList();
 
         saveSnapshots(portfolios);
     }
 
-    @Cacheable(value = "portfolioHistory", key = "#portfolioId + '-' + #currency")
-    public List<PortfolioHistory> getSnapshots(String portfolioId, String currency) {
-        List<PortfolioHistory> history = repository.findAllByPortfolioId(portfolioId).stream()
-            .map(entity -> PortfolioHistory.builder()
-                .portfolioId(entity.getPortfolioId())
-                .stocks(encryptService.decryptStocks(entity.getEncryptedStocks()))
-                .createdAt(entity.getCreatedAt())
-                .build()
-            ).toList();
+    @Cacheable(value = "portfolioHistory", key = "#portfolioId + '-' + #currency + '-' + #range")
+    public List<PortfolioHistory> getSnapshots(String portfolioId, String currency, String range) {
+        Instant end = now();
+        Instant start = switch (range) {
+            case "3m" -> end.minus(90, DAYS);
+            case "6m" -> end.minus(180, DAYS);
+            case "12m" -> end.minus(365, DAYS);
+            default -> throw new BadRequestException("Unsupported range: " + range);
+        };
+
+        List<PortfolioHistory> history = repository.findAllByPortfolioIdAndCreatedAtBetween(portfolioId, start, end).stream()
+                .map(entity -> PortfolioHistory.builder()
+                        .portfolioId(entity.getPortfolioId())
+                        .stocks(encryptService.decryptStocks(entity.getEncryptedStocks()))
+                        .createdAt(entity.getCreatedAt())
+                        .build()
+                ).toList();
 
         ExchangeService.ExchangeRateResponse exchangeRate = exchangeService.getCurrentRate(currency);
         Map<String, BigDecimal> rates = exchangeRate.getConversionRates();
@@ -61,15 +72,15 @@ public class PortfolioHistoryService {
         history.forEach(h -> {
             BigDecimal quoteRate = rates.getOrDefault(DEFAULT_CURRENCY, ONE);
             BigDecimal convertedPriceTotalValue = h.getTotalValueInUSD()
-                .divide(quoteRate, 2, HALF_UP)
-                .multiply(targetRate);
+                    .divide(quoteRate, 2, HALF_UP)
+                    .multiply(targetRate);
 
             h.setTotalValue(convertedPriceTotalValue);
 
             h.getStocks().forEach(s -> {
                 BigDecimal convertedStockPrice = s.getPrice()
-                    .divide(quoteRate, 2, HALF_UP)
-                    .multiply(targetRate);
+                        .divide(quoteRate, 2, HALF_UP)
+                        .multiply(targetRate);
 
                 s.setPrice(convertedStockPrice);
                 s.setTotal(convertedStockPrice.multiply(BigDecimal.valueOf(s.getQuantity())));
@@ -89,17 +100,17 @@ public class PortfolioHistoryService {
         if (portfolios.isEmpty()) return;
 
         List<PortfolioHistoryEntity> snapshots = portfolios.stream()
-            .filter(portfolio -> !portfolio.getStocks().isEmpty())
-            .map(portfolio -> new PortfolioHistory(portfolio.getId(), portfolio.getTotalValue(), portfolio.getTotalAssets(), portfolio.getStocks(), now()))
-            .map(portfolio -> {
-                String encryptedStocks = encryptService.encryptStocks(portfolio.getStocks());
-                return PortfolioHistoryEntity.builder()
-                    .portfolioId(portfolio.getPortfolioId())
-                    .encryptedStocks(encryptedStocks)
-                    .createdAt(now())
-                    .build();
-            })
-            .toList();
+                .filter(portfolio -> !portfolio.getStocks().isEmpty())
+                .map(portfolio -> new PortfolioHistory(portfolio.getId(), portfolio.getTotalValue(), portfolio.getTotalAssets(), portfolio.getStocks(), now()))
+                .map(portfolio -> {
+                    String encryptedStocks = encryptService.encryptStocks(portfolio.getStocks());
+                    return PortfolioHistoryEntity.builder()
+                            .portfolioId(portfolio.getPortfolioId())
+                            .encryptedStocks(encryptedStocks)
+                            .createdAt(now())
+                            .build();
+                })
+                .toList();
 
         repository.saveAll(snapshots);
     }