From 5482a8dcfe8d5a0e341204277d0d3a123407b7df Mon Sep 17 00:00:00 2001 From: nyg Date: Sat, 29 Nov 2025 15:06:14 +0100 Subject: [PATCH] chore(examples): add yearly totals in staking rewards summary --- .../example/StakingRewardsSummaryExample.java | 19 ++++++-- .../kraken/example/report/ReportFetcher.java | 2 +- .../kraken/example/reward/AssetRewards.java | 8 ++++ .../kraken/example/reward/StakingRewards.java | 13 ++++++ .../reward/csv/CsvStakingRewardsSummary.java | 45 ++++++++++++------- 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/examples/src/main/java/dev/andstuff/kraken/example/StakingRewardsSummaryExample.java b/examples/src/main/java/dev/andstuff/kraken/example/StakingRewardsSummaryExample.java index 6feb3e4..3bb5618 100644 --- a/examples/src/main/java/dev/andstuff/kraken/example/StakingRewardsSummaryExample.java +++ b/examples/src/main/java/dev/andstuff/kraken/example/StakingRewardsSummaryExample.java @@ -1,7 +1,6 @@ package dev.andstuff.kraken.example; import static dev.andstuff.kraken.example.helper.CredentialsHelper.readFromFile; -import static java.util.function.Predicate.not; import java.time.Instant; import java.util.List; @@ -10,6 +9,7 @@ import dev.andstuff.kraken.api.KrakenAPI; import dev.andstuff.kraken.api.endpoint.KrakenException; import dev.andstuff.kraken.api.endpoint.account.response.LedgerEntry; +import dev.andstuff.kraken.api.endpoint.market.response.AssetPairs; import dev.andstuff.kraken.api.rest.KrakenCredentials; import dev.andstuff.kraken.example.report.ReportFetcher; import dev.andstuff.kraken.example.reward.AssetRates; @@ -52,13 +52,24 @@ public void generate(String rewardsFileName, String rewardSummaryFileName) { private AssetRates fetchRatesFor(Set assets) { try { - return new AssetRates(api.ticker(assets.stream() + AssetPairs allAssetPairs = api.assetPairs(); + List wantedAssetPairs = assets.stream() .map(asset -> asset + AssetRates.REFERENCE_ASSET) - .filter(not(AssetRates.REFERENCE_PAIR::equals)) - .toList())); + .filter(assetPair -> assetPairExists(allAssetPairs, assetPair)) + .toList(); + + return new AssetRates(api.ticker(wantedAssetPairs)); } catch (KrakenException e) { throw new IllegalStateException("Couldn't fetch rates", e); } } + + private boolean assetPairExists(AssetPairs assetPairs, String assetPair) { + boolean assetPairExists = assetPairs.findBy(assetPair).isPresent(); + if (!assetPairExists) { + log.warn("Asset pair {} does not exist, rate will be 0", assetPair); + } + return assetPairExists; + } } diff --git a/examples/src/main/java/dev/andstuff/kraken/example/report/ReportFetcher.java b/examples/src/main/java/dev/andstuff/kraken/example/report/ReportFetcher.java index 87e6428..23b922b 100644 --- a/examples/src/main/java/dev/andstuff/kraken/example/report/ReportFetcher.java +++ b/examples/src/main/java/dev/andstuff/kraken/example/report/ReportFetcher.java @@ -31,7 +31,7 @@ public List fetchReportData(String reportId) { AtomicBoolean processed = new AtomicBoolean(false); while (!processed.get()) { try { - Thread.sleep(1_000); + Thread.sleep(2_000); } catch (InterruptedException e) { log.warn("Thread interrupted while waiting for the report to be processed", e); diff --git a/examples/src/main/java/dev/andstuff/kraken/example/reward/AssetRewards.java b/examples/src/main/java/dev/andstuff/kraken/example/reward/AssetRewards.java index c3d9021..2facef0 100644 --- a/examples/src/main/java/dev/andstuff/kraken/example/reward/AssetRewards.java +++ b/examples/src/main/java/dev/andstuff/kraken/example/reward/AssetRewards.java @@ -29,4 +29,12 @@ public AssetRewards(String asset, List rewards) { this.yearlyRewards = rewards.stream() .collect(toMap(LedgerEntry::year, LedgerEntry::netAmount, BigDecimal::add)); } + + public BigDecimal totalFiatAmount(AssetRates rates) { + return rates.evaluate(totalReward, asset); + } + + public BigDecimal fiatAmountFor(int year, AssetRates rates) { + return rates.evaluate(yearlyRewards.getOrDefault(year, BigDecimal.ZERO), asset); + } } diff --git a/examples/src/main/java/dev/andstuff/kraken/example/reward/StakingRewards.java b/examples/src/main/java/dev/andstuff/kraken/example/reward/StakingRewards.java index b525f62..a87c9ca 100644 --- a/examples/src/main/java/dev/andstuff/kraken/example/reward/StakingRewards.java +++ b/examples/src/main/java/dev/andstuff/kraken/example/reward/StakingRewards.java @@ -3,6 +3,7 @@ import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toSet; +import java.math.BigDecimal; import java.util.List; import java.util.Set; @@ -29,4 +30,16 @@ public StakingRewards(List rewards) { .map(entry -> new AssetRewards(entry.getKey(), entry.getValue())) .collect(toSet()); } + + public BigDecimal totalFiatAmount(AssetRates rates) { + return assetRewards.stream() + .map(reward -> reward.totalFiatAmount(rates)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + public BigDecimal totalFiatAmountFor(int year, AssetRates rates) { + return assetRewards.stream() + .map(reward -> reward.fiatAmountFor(year, rates)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } } diff --git a/examples/src/main/java/dev/andstuff/kraken/example/reward/csv/CsvStakingRewardsSummary.java b/examples/src/main/java/dev/andstuff/kraken/example/reward/csv/CsvStakingRewardsSummary.java index d457605..e3f87c8 100644 --- a/examples/src/main/java/dev/andstuff/kraken/example/reward/csv/CsvStakingRewardsSummary.java +++ b/examples/src/main/java/dev/andstuff/kraken/example/reward/csv/CsvStakingRewardsSummary.java @@ -8,6 +8,7 @@ import java.io.FileWriter; import java.io.IOException; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -48,12 +49,18 @@ public void writeToFile(String fileName) { * @return an array of String: Asset, y1, _, y2, _, …, total, _ */ private static String[] buildHeaderRow(Set years) { - List headerCells = years.stream() + List headerCells = new ArrayList<>(); + headerCells.add("Asset"); + headerCells.addAll(buildYearlyHeaders(years)); + headerCells.add("Total"); + headerCells.add(AssetRates.REFERENCE_ASSET); + return headerCells.toArray(String[]::new); + } + + private static List buildYearlyHeaders(Set years) { + return years.stream() .flatMap(year -> Stream.of(year.toString(), AssetRates.REFERENCE_ASSET)) - .collect(toList()); - headerCells.addFirst("Asset"); - headerCells.addAll(List.of("Total", AssetRates.REFERENCE_ASSET)); - return headerCells.toArray(new String[0]); + .toList(); } /** @@ -79,23 +86,27 @@ private static List buildRewardRows(StakingRewards rewards, AssetRates })) .entrySet().stream() .map(entry -> { - List cells = entry.getValue().stream().map(BigDecimal::toPlainString).collect(toList()); - cells.addFirst(entry.getKey()); - return cells.toArray(new String[0]); + List cells = new ArrayList<>(); + cells.add(entry.getKey()); + cells.addAll(entry.getValue().stream().map(BigDecimal::toPlainString).toList()); + return cells.toArray(String[]::new); }) - .sorted(comparing(e -> new BigDecimal(e[e.length - 1]), reverseOrder())) + .sorted(comparing(row -> new BigDecimal(row[row.length - 1]), reverseOrder())) .toList(); } private String[] buildFooterRow(StakingRewards rewards, AssetRates rates) { + List footerCells = new ArrayList<>(); + footerCells.add("Total"); + footerCells.addAll(buildYearlyTotals(rewards, rates)); + footerCells.add(""); + footerCells.add(rewards.totalFiatAmount(rates).toPlainString()); + return footerCells.toArray(String[]::new); + } - BigDecimal totalFiatAmount = rewards.getAssetRewards().stream() - .map(reward -> rates.evaluate(reward.getTotalReward(), reward.getAsset())) - .reduce(BigDecimal.ZERO, BigDecimal::add); - - List footerCells = rewards.getYears().stream().flatMap(year -> Stream.of("", "")).collect(toList()); - footerCells.addFirst("Total"); - footerCells.addAll(List.of("", totalFiatAmount.toPlainString())); - return footerCells.toArray(new String[0]); + private List buildYearlyTotals(StakingRewards rewards, AssetRates rates) { + return rewards.getYears().stream() + .flatMap(year -> Stream.of("", rewards.totalFiatAmountFor(year, rates).toPlainString())) + .toList(); } }