Skip to content

Commit

Permalink
Feat: Fix portfolio and summary controller
Browse files Browse the repository at this point in the history
Fixed portfolio (revert to arraylist of shares), and fixed visual bug in financial summary graph
  • Loading branch information
tommyah committed May 26, 2026
1 parent 3d8e11c commit f7ef95b
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,14 @@ public Transaction sell(BigDecimal amount,

Share ownedPosition = matchingShares.getFirst();
BigDecimal totalOwned = ownedPosition.getQuantity();
BigDecimal ownedPurchasePrice = ownedPosition.getPurchasePrice();

if (amount.compareTo(totalOwned) > 0) {
amount = totalOwned;
}

Stock stock = ownedPosition.getStock();
Share shareToSell = new Share(stock, amount, stock.getSalesPrice());
Share shareToSell = new Share(stock, amount, ownedPurchasePrice);

Transaction sale = TransactionFactory.createTransaction(
TransactionType.SALE, shareToSell, getWeek()
Expand Down
107 changes: 52 additions & 55 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Portfolio.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -17,9 +18,9 @@
public final class Portfolio {

/**
* Map used to handle internal shares.
* List of shares in portfolio.
* */
private final Map<String, Share> shares = new HashMap<>();
private final List<Share> shares = new ArrayList<>();

/**
* Creates an empty portfolio.
Expand All @@ -39,30 +40,13 @@ public void addShare(final Share share) throws IllegalArgumentException {
if (share == null) {
throw new IllegalArgumentException("Invalid share!");
}
String symbol = share.getStock().getSymbol().toUpperCase();

if (shares.containsKey(symbol)) {
Share existingShare = shares.get(symbol);
BigDecimal totalQuantity =
existingShare.getQuantity().add(share.getQuantity());

shares.put(symbol,
new Share(
share.getStock(),
totalQuantity, existingShare.getPurchasePrice()
)
);
} else {
shares.put(symbol, share);
}
shares.add(share);
}

/**
* Removes a share from the portfolio.
*
* <p>Uses the quantity value to deduct share amount from the map.
* If quantity to remove is equal to amount held, removes share entirely.
* If not, splits the share.</p>
* <p>Removes based on FIFO (First In First Out)</p>
*
* @param share the share to remove
*
Expand All @@ -72,35 +56,42 @@ public void addShare(final Share share) throws IllegalArgumentException {
* @throws IllegalArgumentException if share is null.
*
*/
public boolean removeShare(final Share share)
throws IllegalArgumentException {
public boolean removeShare(final Share share) throws IllegalArgumentException {
if (share == null) {
throw new IllegalArgumentException("Invalid share!");
}
String symbol = share.getStock().getSymbol().toUpperCase();
if (!shares.containsKey(symbol)) {
return false;
}

Share ownedShare = shares.get(symbol);
int comparison = ownedShare.getQuantity().compareTo(share.getQuantity());
String symbol = share.getStock().getSymbol();

if (comparison < 0) {
throw new IllegalArgumentException(
"Cannot remove more shares than are currently owned!");
} else if (comparison == 0) {

shares.remove(symbol);
} else {
BigDecimal remainingQuantity =
ownedShare.getQuantity().subtract(share.getQuantity());
shares.put(symbol,
new Share(
share.getStock(),
remainingQuantity,
ownedShare.getPurchasePrice()
)
);
List<Share> matchingShares = shares.stream()
.filter(s -> s.getStock().getSymbol().equalsIgnoreCase(symbol))
.toList();

BigDecimal quantityToRemove = share.getQuantity();

BigDecimal totalOwned = matchingShares.stream()
.map(Share::getQuantity)
.reduce(BigDecimal.ZERO, BigDecimal::add);

if (quantityToRemove.compareTo(totalOwned) > 0) {
throw new IllegalArgumentException("Cannot remove more shares than are currently owned!");
}

for (Share s : matchingShares) {
if (quantityToRemove.signum() <= 0) {
break;
}

int comparison = s.getQuantity().compareTo(quantityToRemove);
shares.remove(s);

if (comparison > 0) {
BigDecimal remainingQuantity = s.getQuantity().subtract(quantityToRemove);
shares.add(new Share(s.getStock(), remainingQuantity, s.getPurchasePrice()));
quantityToRemove = BigDecimal.ZERO;
} else {
quantityToRemove = quantityToRemove.subtract(s.getQuantity());
}
}
return true;
}
Expand All @@ -111,7 +102,7 @@ public boolean removeShare(final Share share)
* @return a list of shares
*/
public List<Share> getShares() {
return List.copyOf(shares.values());
return shares;
}

/**
Expand Down Expand Up @@ -141,8 +132,9 @@ public List<Share> getShares(final String symbol)
throw new IllegalArgumentException(
Validator.VALID_STOCK_SYMBOL.getErrorMessage());
}
Share share = shares.get(symbol.toUpperCase());
return share != null ? List.of(share) : List.of();
return shares.stream()
.filter(s -> s.getStock().getSymbol().equalsIgnoreCase(symbol))
.toList();
}

/**
Expand All @@ -160,10 +152,13 @@ public boolean contains(final Share share)
if (share == null) {
throw new IllegalArgumentException("Invalid share!");
}
String symbol = share.getStock().getSymbol().toUpperCase();
Share owned = shares.get(symbol);
return owned != null
&& owned.getQuantity().compareTo(share.getQuantity()) >= 0;

BigDecimal totalOwned = shares.stream()
.filter(s -> s.getStock().getSymbol().equalsIgnoreCase(share.getStock().getSymbol()))
.map(Share::getQuantity)
.reduce(BigDecimal.ZERO, BigDecimal::add);

return totalOwned.compareTo(share.getQuantity()) >= 0;
}

/**
Expand All @@ -174,7 +169,7 @@ public boolean contains(final Share share)
* */
public BigDecimal getNetWorth() {
BigDecimal netWorth = BigDecimal.ZERO;
for (Share s : shares.values()) {
for (Share s : shares) {
netWorth = netWorth.add(
s.getQuantity().multiply(s.getStock().getSalesPrice())
);
Expand All @@ -194,7 +189,9 @@ public BigDecimal getTotalShareQuantityBySymbol(final String symbol) {
if (symbol == null) {
return BigDecimal.ZERO;
}
Share share = shares.get(symbol.toUpperCase());
return share != null ? share.getQuantity() : BigDecimal.ZERO;
return shares.stream()
.filter(s -> s.getStock().getSymbol().equalsIgnoreCase(symbol))
.map(Share::getQuantity)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ public void handleContextUpdate(final Exchange criticalExchange, final Player ac
this.playerNetWorthHistory.addAll(this.player.getNetWorthHistory());
} else {
this.playerNetWorthHistory.add(this.player.getStartingMoney());
this.playerNetWorthHistory.add(this.player.getNetWorth());
}

getViewElement().setWeek(this.exchange.getWeek());
Expand Down

0 comments on commit f7ef95b

Please sign in to comment.