protected static PortfolioOverview mockPortfolioOverview(final int balance) { final PortfolioOverview po = mock(PortfolioOverview.class); when(po.getCzkAvailable()).thenReturn(BigDecimal.valueOf(balance)); when(po.getCzkInvested()).thenReturn(BigDecimal.ZERO); when(po.getCzkInvested(any())).thenReturn(BigDecimal.ZERO); when(po.getCzkAtRisk()).thenReturn(BigDecimal.ZERO); when(po.getCzkAtRisk(any())).thenReturn(BigDecimal.ZERO); when(po.getShareAtRisk()).thenReturn(BigDecimal.ZERO); when(po.getShareOnInvestment(any())).thenReturn(BigDecimal.ZERO); when(po.getAtRiskShareOnInvestment(any())).thenReturn(BigDecimal.ZERO); when(po.getTimestamp()).thenReturn(ZonedDateTime.now()); return po; }
protected static PortfolioOverview mockPortfolioOverview(final int balance) { final PortfolioOverview po = mock(PortfolioOverview.class); when(po.getCzkAvailable()).thenReturn(BigDecimal.valueOf(balance)); when(po.getCzkInvested()).thenReturn(BigDecimal.ZERO); when(po.getCzkInvested(any())).thenReturn(BigDecimal.ZERO); when(po.getCzkAtRisk()).thenReturn(BigDecimal.ZERO); when(po.getCzkAtRisk(any())).thenReturn(BigDecimal.ZERO); when(po.getShareAtRisk()).thenReturn(BigDecimal.ZERO); when(po.getShareOnInvestment(any())).thenReturn(BigDecimal.ZERO); when(po.getAtRiskShareOnInvestment(any())).thenReturn(BigDecimal.ZERO); when(po.getTimestamp()).thenReturn(ZonedDateTime.now()); return po; }
static Stream<Rating> rankRatingsByDemand(final ParsedStrategy strategy, final Collection<Rating> ratings, final PortfolioOverview portfolio) { final SortedMap<BigDecimal, EnumSet<Rating>> mostWantedRatings = new TreeMap<>(Comparator.reverseOrder()); // put the ratings into buckets based on how much we're missing them ratings.forEach(r -> { final BigDecimal currentRatingShare = portfolio.getShareOnInvestment(r); final BigDecimal maximumAllowedShare = divide(strategy.getMaximumShare(r), ONE_HUNDRED); final BigDecimal undershare = maximumAllowedShare.subtract(currentRatingShare); if (undershare.signum() < 1) { // we over-invested into this rating; do not include final BigDecimal pp = undershare.multiply(ONE_HUNDRED).negate(); Decisions.report(logger -> logger.debug("Rating {} over-invested by {} percentage points.", r, pp)); return; } // rank the rating mostWantedRatings.computeIfAbsent(undershare, k -> EnumSet.noneOf(Rating.class)); mostWantedRatings.get(undershare).add(r); // inform that the rating is under-invested final BigDecimal minimumNeededShare = divide(strategy.getMinimumShare(r), ONE_HUNDRED); if (currentRatingShare.compareTo(minimumNeededShare) < 0) { final BigDecimal pp = minimumNeededShare.subtract(currentRatingShare).multiply(ONE_HUNDRED); Decisions.report(logger -> logger.debug("Rating {} under-invested by {} percentage points.", r, pp)); } }); return mostWantedRatings.values().stream().flatMap(Collection::stream); }
static Stream<Rating> rankRatingsByDemand(final ParsedStrategy strategy, final Collection<Rating> ratings, final PortfolioOverview portfolio) { final SortedMap<BigDecimal, EnumSet<Rating>> mostWantedRatings = new TreeMap<>(Comparator.reverseOrder()); // put the ratings into buckets based on how much we're missing them ratings.forEach(r -> { final BigDecimal currentRatingShare = portfolio.getShareOnInvestment(r); final BigDecimal maximumAllowedShare = divide(strategy.getMaximumShare(r), ONE_HUNDRED); final BigDecimal undershare = maximumAllowedShare.subtract(currentRatingShare); if (undershare.signum() < 1) { // we over-invested into this rating; do not include final BigDecimal pp = undershare.multiply(ONE_HUNDRED).negate(); Decisions.report(logger -> logger.debug("Rating {} over-invested by {} percentage points.", r, pp)); return; } // rank the rating mostWantedRatings.computeIfAbsent(undershare, k -> EnumSet.noneOf(Rating.class)); mostWantedRatings.get(undershare).add(r); // inform that the rating is under-invested final BigDecimal minimumNeededShare = divide(strategy.getMinimumShare(r), ONE_HUNDRED); if (currentRatingShare.compareTo(minimumNeededShare) < 0) { final BigDecimal pp = minimumNeededShare.subtract(currentRatingShare).multiply(ONE_HUNDRED); Decisions.report(logger -> logger.debug("Rating {} under-invested by {} percentage points.", r, pp)); } }); return mostWantedRatings.values().stream().flatMap(Collection::stream); }
@Test void emptyPortfolio() { final BigDecimal balance = BigDecimal.TEN; final PortfolioOverview po = new PortfolioOverviewImpl(balance, Collections.emptyMap(), Collections.emptyMap()); SoftAssertions.assertSoftly(softly -> { softly.assertThat(po.getCzkAvailable()).isEqualTo(balance); softly.assertThat(po.getCzkInvested()).isEqualTo(BigDecimal.ZERO); softly.assertThat(po.getCzkAtRisk()).isEqualTo(BigDecimal.ZERO); softly.assertThat(po.getShareAtRisk()).isEqualTo(BigDecimal.ZERO); for (final Rating r : Rating.values()) { softly.assertThat(po.getCzkInvested(r)).as(r + " invested").isEqualTo(BigDecimal.ZERO); softly.assertThat(po.getCzkAtRisk(r)).as(r + " at risk").isEqualTo(BigDecimal.ZERO); softly.assertThat(po.getShareOnInvestment(r)) .as(r + " as a share") .isEqualTo(BigDecimal.ZERO); softly.assertThat(po.getAtRiskShareOnInvestment(r)) .as(r + " at risk as a share") .isEqualTo(BigDecimal.ZERO); } }); }
@Test void emptyPortfolioWithAdjustmentsAndRisks() { final BigDecimal adj = BigDecimal.TEN; final Map<Rating, BigDecimal> in = Collections.singletonMap(Rating.D, adj); final PortfolioOverview po = new PortfolioOverviewImpl(BigDecimal.ZERO, in, in); SoftAssertions.assertSoftly(softly -> { softly.assertThat(po.getCzkAvailable()).isEqualTo(BigDecimal.ZERO); softly.assertThat(po.getCzkInvested()).isEqualTo(adj); softly.assertThat(po.getCzkAtRisk()).isEqualTo(adj); final BigDecimal share = divide(po.getCzkAtRisk(), po.getCzkInvested()); softly.assertThat(po.getShareAtRisk()).isEqualTo(share); for (final Rating r : Rating.values()) { final BigDecimal expectedAbsolute = r == Rating.D ? adj : BigDecimal.ZERO; final BigDecimal expectedRelative = r == Rating.D ? BigDecimal.ONE : BigDecimal.ZERO; softly.assertThat(po.getCzkInvested(r)).as(r + " invested").isEqualTo(expectedAbsolute); softly.assertThat(po.getCzkAtRisk(r)).as(r + " at risk").isEqualTo(expectedAbsolute); softly.assertThat(po.getShareOnInvestment(r)) .as(r + " as a share") .isEqualTo(expectedRelative); softly.assertThat(po.getAtRiskShareOnInvestment(r)) .as(r + " at risk as a share") .isEqualTo(expectedRelative); } }); } }