diff --git a/src/main/java/millions/controller/fileIO/CSV/CSVStockFileParser.java b/src/main/java/millions/controller/fileIO/CSV/CSVStockFileParser.java index 2a5d1ae..04e80db 100644 --- a/src/main/java/millions/controller/fileIO/CSV/CSVStockFileParser.java +++ b/src/main/java/millions/controller/fileIO/CSV/CSVStockFileParser.java @@ -21,7 +21,7 @@ public CSVStockFileParser() {} public boolean verifyCSV(List lines) { return lines.stream() .filter(l -> !(l.startsWith("#") || l.isBlank())) - .noneMatch(l -> l.split(",").length != 3); + .noneMatch(l -> l.split(",").length != 4); } /** @@ -49,9 +49,14 @@ public List parse(List lines) { String symbol = split[0]; String company = split[1]; BigDecimal price = new BigDecimal(split[2]); - stocks.add(new Stock(symbol, company, price)); + String[] functionValues = split[3].split(";"); + List convertedFunctionValues = new ArrayList<>(); + for (String functionValue : functionValues) { + convertedFunctionValues.add(new BigDecimal(functionValue)); + } + stocks.add(new Stock(symbol, company, price, convertedFunctionValues)); } catch (NumberFormatException e) { - throw new InvalidFormatException("Error with number conversion on line: " + l + "\n" + "Last field must be a number"); + throw new InvalidFormatException("Error with number conversion on line: " + l + "\n" + "ensure all number fields are actually numbers"); } catch (IllegalArgumentException e) { throw new InvalidFormatException("Illegal argument on line: " + l + "\n" + e.getMessage()); } diff --git a/src/main/java/millions/model/Exchange.java b/src/main/java/millions/model/Exchange.java index 55b2ab7..f96d2bb 100644 --- a/src/main/java/millions/model/Exchange.java +++ b/src/main/java/millions/model/Exchange.java @@ -10,6 +10,8 @@ import java.util.Map; import java.util.Random; import java.util.stream.Collectors; + +import millions.model.calculators.PriceChangeCalculator; import millions.model.factories.PurchaseFactory; import millions.model.factories.SaleFactory; import millions.model.factories.TransactionFactory; @@ -143,15 +145,19 @@ public List getLosers(int limit) { * Advances the current game week by performing new price calculations for all stocks. */ public void advance() { + PriceChangeCalculator priceChangeCalculator = new PriceChangeCalculator(); this.weekNumber++; for (Stock stock : this.stocks.values()) { - double change = 0.9 + random.nextDouble() * 0.2; - stock.addNewSalesPrice( - stock - .getSalesPrice() - .multiply(BigDecimal.valueOf(change)) - .setScale(2, RoundingMode.HALF_UP)); - // RoundingMode from AI suggestion + BigDecimal change = priceChangeCalculator.calculateChange(stock); + stock.addNewSalesPrice(stock.getSalesPrice().add(change)); + + // double change = 0.9 + random.nextDouble() * 0.2; + // stock.addNewSalesPrice( + // stock + // .getSalesPrice() + // .multiply(BigDecimal.valueOf(change)) + // .setScale(2, RoundingMode.HALF_UP)); + // // RoundingMode from AI suggestion } notifyWeekAdvanced(); } diff --git a/src/main/java/millions/model/Stock.java b/src/main/java/millions/model/Stock.java index cc1a23f..95954e1 100644 --- a/src/main/java/millions/model/Stock.java +++ b/src/main/java/millions/model/Stock.java @@ -8,19 +8,27 @@ public class Stock { String symbol; String company; + List volatility; List prices; /** * @param symbol Stock ticker symbol * @param company company name * @param prices List of prices + * @param volatilityParameters numbers used for price change calculation functions * @throws IllegalArgumentException */ - public Stock(String symbol, String company, List prices) { + public Stock(String symbol, String company, List prices, List volatilityParameters) { this.symbol = symbol; this.company = company; this.prices = new ArrayList<>(prices); + this.volatility = volatilityParameters; + + if (volatilityParameters.size() != 5) { + throw new IllegalArgumentException("Invalid volatility function count"); + } + if (symbol == null || symbol.isBlank()) { throw new IllegalArgumentException("Symbol cannot be null or blank"); } @@ -31,8 +39,8 @@ public Stock(String symbol, String company, List prices) { } /** Stock() with single price instead of list */ - public Stock(String symbol, String company, BigDecimal initialPrice) { - this(symbol, company, new ArrayList<>(List.of(initialPrice))); + public Stock(String symbol, String company, BigDecimal initialPrice, List volatilityFunctions) { + this(symbol, company, new ArrayList<>(List.of(initialPrice)), volatilityFunctions); } /** @@ -110,6 +118,10 @@ public BigDecimal getLatestPriceChange() { return currentPrice.subtract(lastPrice); } + public List getVolatilityParameters() { + return this.volatility; + } + @Override public String toString() { return "Stock [symbol: " + symbol + ", company: " + company + ", prices: " + prices + "]"; diff --git a/src/main/java/millions/model/calculators/PriceChangeCalculator.java b/src/main/java/millions/model/calculators/PriceChangeCalculator.java new file mode 100644 index 0000000..c9b3074 --- /dev/null +++ b/src/main/java/millions/model/calculators/PriceChangeCalculator.java @@ -0,0 +1,56 @@ +package millions.model.calculators; + +import millions.model.Stock; + +import java.math.BigDecimal; +import java.util.List; + +public class PriceChangeCalculator { + + public PriceChangeCalculator() {} + + public BigDecimal calculateChange(Stock stock) { + BigDecimal change = BigDecimal.ZERO; + List volatilityParameters = stock.getVolatilityParameters(); + change = change.add(upChange(volatilityParameters.get(0))); + change = change.add(downChange(volatilityParameters.get(1))); + change = change.add(randomChange(volatilityParameters.get(2))); + change = change.add(sinChange(volatilityParameters.get(3))); + change = change.add(cosChange(volatilityParameters.get(4))); + return change; + } + + private BigDecimal upChange(BigDecimal input) { + if (input.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; + } + return input; + + } + private BigDecimal downChange(BigDecimal input) { + if (input.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; + } + return input.negate(); + } + + private BigDecimal randomChange(BigDecimal input) { + if (input.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; + } + return new BigDecimal(Math.random()*10).multiply(input); + } + + private BigDecimal sinChange(BigDecimal input) { + if (input.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; + } + return new BigDecimal(Math.sin(input.doubleValue())); + } + private BigDecimal cosChange(BigDecimal input) { + if (input.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; + } + return new BigDecimal(Math.cos(input.doubleValue())); + } +}