diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java index 632f657..af058a2 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java @@ -19,51 +19,57 @@ /** * Represents a stock exchange where stocks can be traded. * - *

Holds a map of {@link Stock} objects where stock symbol is key and - * stock is value.

+ *

+ * Holds a map of {@link Stock} objects where stock symbol is key and + * stock is value. + *

* - *

Delegates buying and selling to player elements using calculators

+ *

+ * Delegates buying and selling to player elements using calculators + *

* - *

Additionally controls the time in weeks, and therefore has the main - * responsibility for advancing weeks.

+ *

+ * Additionally controls the time in weeks, and therefore has the main + * responsibility for advancing weeks. + *

* * @see Player * @see edu.ntnu.idi.idatt2003.g40.mappe.service.TransactionCalculator * * @version 1.1.0 - * */ + */ public final class Exchange { /** * Exchange name. - * */ + */ private final String name; /** * Current week (set to 1 in constructor). - * */ + */ private final ReadOnlyIntegerWrapper week = new ReadOnlyIntegerWrapper(1); /** * Map of {@link Stock} objects. Key is stock symbol. Value is stock. - * */ + */ private final Map stockMap; /** * Random value determining week changes. - * */ + */ private final Random random; /** * Constructor. * - * @param name name of exchange. - * @param stocks list of {@link Stock} objects. + * @param name name of exchange. + * @param stocks list of {@link Stock} objects. * * @throws IllegalArgumentException if name or stocks are empty/null. - * */ + */ public Exchange(final String name, final List stocks) - throws IllegalArgumentException { + throws IllegalArgumentException { if (!Validator.NOT_EMPTY.isValid(name) || stocks == null || stocks.isEmpty()) { @@ -81,7 +87,7 @@ public Exchange(final String name, final List stocks) * Getter method for name. * * @return name of exchange. - * */ + */ public String getName() { return name; } @@ -90,7 +96,7 @@ public String getName() { * Getter method for current week. * * @return week. - * */ + */ public int getWeek() { return week.get(); } @@ -99,7 +105,7 @@ public int getWeek() { * Getter method for the {@link ReadOnlyIntegerProperty} object of week. * * @return week. - * */ + */ public ReadOnlyIntegerProperty weekProperty() { return week.getReadOnlyProperty(); } @@ -117,7 +123,7 @@ public ReadOnlyIntegerProperty weekProperty() { * @param newWeek the value to set the week to. * * @throws IllegalArgumentException if newWeek is below 1. - * */ + */ public void setWeek(final int newWeek) throws IllegalArgumentException { if (newWeek < 1) { throw new IllegalArgumentException("Week must be at least 1!"); @@ -140,7 +146,7 @@ public void setWeek(final int newWeek) throws IllegalArgumentException { * @param baselinePrices map of symbol to the price to seed with. * Symbols that aren't on this exchange are * skipped. - * */ + */ public void resetStocksTo(final Map baselinePrices) { if (baselinePrices == null) { return; @@ -158,8 +164,8 @@ public void resetStocksTo(final Map baselinePrices) { * * @param symbol the stock symbol. * - * @return true or false. - * */ + * @return true or false. + */ public boolean hasStock(final String symbol) { return stockMap.containsKey(symbol); } @@ -168,7 +174,7 @@ public boolean hasStock(final String symbol) { * Getter method for all stocks in exchange. * * @return List of stocks. - * */ + */ public List getStocks() { return List.copyOf(this.stockMap.values()); } @@ -176,18 +182,18 @@ public List getStocks() { /** * Getter method for stock element. * - * @param symbol the symbol of the stock to get. + * @param symbol the symbol of the stock to get. * - * @return {@link Stock} element gotten. + * @return {@link Stock} element gotten. * * @throws IllegalArgumentException if symbol is invalid or not in exchange. - * */ + */ public Stock getStock(final String symbol) - throws IllegalArgumentException { + throws IllegalArgumentException { if (!Validator.VALID_STOCK_SYMBOL.isValid(symbol) || !stockMap.containsKey(symbol)) { throw new IllegalArgumentException( - Validator.VALID_STOCK_SYMBOL.getErrorMessage()); + Validator.VALID_STOCK_SYMBOL.getErrorMessage()); } return stockMap.get(symbol); } @@ -197,14 +203,14 @@ public Stock getStock(final String symbol) * * @param searchTerm the term to search for. * - * @return a list of {@link Stock} objects. - * */ + * @return a list of {@link Stock} objects. + */ public List findStocks(final String searchTerm) { List result = new ArrayList<>(); for (Stock stock : stockMap.values()) { if (stock.getSymbol().toLowerCase() - .contains(searchTerm.toLowerCase()) - || stock.getCompany().toLowerCase() + .contains(searchTerm.toLowerCase()) + || stock.getCompany().toLowerCase() .contains(searchTerm.toLowerCase())) { result.add(stock); } @@ -215,17 +221,17 @@ public List findStocks(final String searchTerm) { /** * Method called when a player buys a stock. * - * @param symbol the stock this player buys. - * @param quantity the amount of stock to buy. - * @param player the player buying stock. + * @param symbol the stock this player buys. + * @param quantity the amount of stock to buy. + * @param player the player buying stock. * - * @return Transaction representing the transaction. + * @return Transaction representing the transaction. * * @throws IllegalArgumentException if symbol or player is invalid. - * */ + */ public Transaction buy(final String symbol, - final BigDecimal quantity, - final Player player) throws IllegalArgumentException { + final BigDecimal quantity, + final Player player) throws IllegalArgumentException { if (!Validator.VALID_STOCK_SYMBOL.isValid(symbol) || quantity == null || player == null) { @@ -234,8 +240,7 @@ public Transaction buy(final String symbol, Stock stock = getStock(symbol); Share share = new Share(stock, quantity, stock.getSalesPrice()); Transaction purchase = TransactionFactory.createTransaction( - TransactionType.PURCHASE, share, getWeek() - ); + TransactionType.PURCHASE, share, getWeek()); player.handleTransaction(purchase); return purchase; } @@ -243,21 +248,20 @@ TransactionType.PURCHASE, share, getWeek() /** * Method called when a player sells share. * - * @param share the share to sell. - * @param player the player buying stock. + * @param share the share to sell. + * @param player the player buying stock. * - * @return Transaction representing the transaction. + * @return Transaction representing the transaction. * * @throws IllegalArgumentException if share or player is null. - * */ + */ public Transaction sell(final Share share, final Player player) - throws IllegalArgumentException { + throws IllegalArgumentException { if (share == null || player == null) { throw new IllegalArgumentException("Invalid sell!"); } Transaction sale = TransactionFactory.createTransaction( - TransactionType.SALE, share, getWeek() - ); + TransactionType.SALE, share, getWeek()); player.handleTransaction(sale); return sale; } @@ -266,26 +270,28 @@ TransactionType.SALE, share, getWeek() * Method called when a player sells share, * defined by an amount instead of specific {@link Share} object. * - *

{@link edu.ntnu.idi.idatt2003.g40.mappe.model.Portfolio}

+ *

+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.model.Portfolio} + *

* * @param amount the amount of "shares" to sell. * @param stockSymbol the stock to sell shares in. * @param player the player buying stock. * - * @return List of transactions commited to sell the shares. + * @return List of transactions commited to sell the shares. * * @throws IllegalArgumentException if any parameter is null, * or if player does not have enough shares, * or if player does not own any shares * of the given stock. - * */ + */ public Transaction sell(BigDecimal amount, - final String stockSymbol, - final Player player) - throws IllegalArgumentException { + final String stockSymbol, + final Player player) + throws IllegalArgumentException { if (amount == null - || player == null - || !Validator.VALID_STOCK_SYMBOL.isValid(stockSymbol)) { + || player == null + || !Validator.VALID_STOCK_SYMBOL.isValid(stockSymbol)) { throw new IllegalArgumentException("Invalid sell parameters!"); } @@ -310,8 +316,7 @@ public Transaction sell(BigDecimal amount, Share shareToSell = new Share(stock, amount, oldestPurchasePrice); Transaction sale = TransactionFactory.createTransaction( - TransactionType.SALE, shareToSell, getWeek() - ); + TransactionType.SALE, shareToSell, getWeek()); player.handleTransaction(sale); return sale; @@ -320,23 +325,26 @@ TransactionType.SALE, shareToSell, getWeek() /** * Method for advancing time, increasing the amount of weeks. * - *

Applies a random price change from -5% to 5% to every stock, + *

+ * Applies a random price change from -5% to 5% to every stock, * plus a flat percent determined by their fortune, that can range from - * -10% to +10%.

+ * -10% to +10%. + *

* * @see edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameEngineView - * */ + */ public void advance() { for (Stock stock : stockMap.values()) { BigDecimal currentPrice = stock.getSalesPrice(); BigDecimal change = BigDecimal.valueOf(random.nextDouble() * 0.10 - 0.05) - .add(BigDecimal.valueOf(stock.getFortune())); + .add(BigDecimal.valueOf(stock.getFortune())); stock.setFortune(0); BigDecimal factor = BigDecimal.ONE.add(change); + // Keep full simulation precision at 10 decimals. BigDecimal newPrice = currentPrice.multiply(factor) - .setScale(2, java.math.RoundingMode.HALF_UP); + .setScale(10, java.math.RoundingMode.HALF_UP); stock.addNewSalesPrice(newPrice); } week.set(week.get() + 1); @@ -346,31 +354,29 @@ public void advance() { * Method for getting the stocks with the most * amount of increase since last week. * - * @param limit the maximum amount of stocks returned + * @param limit the maximum amount of stocks returned * * @return list of {@link Stock} objects. * * @throws IllegalArgumentException if limit is invalid (negative or zero). - * */ + */ public List getGainers(final int limit) - throws IllegalArgumentException { + throws IllegalArgumentException { if (limit < 1) { throw new IllegalArgumentException("Invalid limit for getting gainers!"); } return stockMap.entrySet().stream() - // We only want the stocks with a positive price change. - .filter(e -> - e.getValue().getLatestPriceChange() - .compareTo(BigDecimal.ZERO) > 0) - // We sort the stocks based on the price change. - .sorted((e1, e2) -> - e2.getValue().getLatestPriceChange() - .compareTo(e1.getValue().getLatestPriceChange())) - // Sets a limit to the stream. - .limit(limit) - .map(Map.Entry::getValue) - // Converts to a list - .toList(); + // We only want the stocks with a positive price change. + .filter(e -> e.getValue().getLatestPriceChange() + .compareTo(BigDecimal.ZERO) > 0) + // We sort the stocks based on the price change. + .sorted((e1, e2) -> e2.getValue().getLatestPriceChange() + .compareTo(e1.getValue().getLatestPriceChange())) + // Sets a limit to the stream. + .limit(limit) + .map(Map.Entry::getValue) + // Converts to a list + .toList(); } /** @@ -382,34 +388,34 @@ public List getGainers(final int limit) * @return list of {@link Stock} objects. * * @throws IllegalArgumentException if limit is invalid (negative or zero). - * */ + */ public List getLosers(final int limit) - throws IllegalArgumentException { + throws IllegalArgumentException { if (limit < 1) { throw new IllegalArgumentException("Invalid limit for getting losers!"); } return stockMap.entrySet().stream() - // Only get entries with negative price change. - .filter(e -> - e.getValue().getLatestPriceChange() - .compareTo(BigDecimal.ZERO) < 0) - // Sort (lowest first) - .sorted((e1, e2) -> - e1.getValue().getLatestPriceChange() - .compareTo(e2.getValue().getLatestPriceChange())) - .limit(limit) - .map(Map.Entry::getValue) - .toList(); + // Only get entries with negative price change. + .filter(e -> e.getValue().getLatestPriceChange() + .compareTo(BigDecimal.ZERO) < 0) + // Sort (lowest first) + .sorted((e1, e2) -> e1.getValue().getLatestPriceChange() + .compareTo(e2.getValue().getLatestPriceChange())) + .limit(limit) + .map(Map.Entry::getValue) + .toList(); } /** * Replaces list of stocks with a new list. * - *

Used when loading a save game that uses a completely different set of - * stocks than the currently active simulation context.

+ *

+ * Used when loading a save game that uses a completely different set of + * stocks than the currently active simulation context. + *

* - * @param newStocks the new list of {@link Stock} - * objects to list on the exchange. + * @param newStocks the new list of {@link Stock} + * objects to list on the exchange. * @throws IllegalArgumentException if the provided list is null or empty. */ public void updateStockPool(final List newStocks) throws IllegalArgumentException { diff --git a/src/main/resources/saves/Halleluja.json b/src/main/resources/saves/Halleluja.json deleted file mode 100644 index 7737bf7..0000000 --- a/src/main/resources/saves/Halleluja.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "Halleluja", - "balance": 1000650901.43, - "startingCapital": 10000.0, - "stockDataPath": null, - "week": 1, - "ownedShares": [], - "transactions": [], - "stocks": [ - { "symbol": "TOTA", "name": "Total badass1", "price": 136.80 }, - { "symbol": "LIBR", "name": "Libra avenger of worlds", "price": 19134.23 } - ] -} diff --git a/src/main/resources/saves/Newbie.json b/src/main/resources/saves/Newbie.json deleted file mode 100644 index 9ce1a99..0000000 --- a/src/main/resources/saves/Newbie.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "name": "Newbie", - "balance": 11.2045, - "startingCapital": 10000.0, - "stockDataPath": null, - "week": 5, - "ownedShares": [ - { "symbol": "NVDA", "quantity": 50.0, "purchasePrice": 191.27 }, - { "symbol": "CARR", "quantity": 5.0, "purchasePrice": 75.12 } - ], - "transactions": [ - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }, - { "type": "PURCHASE", "symbol": "CARR", "quantity": 1.0, "price": 75.12, "week": 5 }, - { "type": "PURCHASE", "symbol": "CARR", "quantity": 4.0, "price": 75.12, "week": 5 } - ], - "stocks": [ - { "symbol": "CARR", "name": "Carrier Global", "price": 75.12 }, - { "symbol": "AAPL", "name": "Apple Inc.", "price": 232.42 }, - { "symbol": "SNDK", "name": "Sandisk Corporation", "price": 861.26 }, - { "symbol": "WYNN", "name": "Wynn Resorts", "price": 97.54 }, - { "symbol": "TSCO", "name": "Tractor Supply", "price": 53.32 }, - { "symbol": "AMGN", "name": "Amgen", "price": 404.61 }, - { "symbol": "TSLA", "name": "Tesla Inc.", "price": 360.17 }, - { "symbol": "GDDY", "name": "GoDaddy", "price": 85.21 }, - { "symbol": "SBUX", "name": "Starbucks", "price": 110.59 }, - { "symbol": "KVUE", "name": "Kenvue", "price": 15.57 }, - { "symbol": "META", "name": "Meta Platforms", "price": 707.00 }, - { "symbol": "DLTR", "name": "Dollar Tree", "price": 175.45 }, - { "symbol": "ABBV", "name": "AbbVie", "price": 258.94 }, - { "symbol": "HUBB", "name": "Hubbell Incorporated", "price": 495.97 }, - { "symbol": "JKHY", "name": "Jack Henry & Associates", "price": 169.66 }, - { "symbol": "FSLR", "name": "First Solar", "price": 229.93 }, - { "symbol": "FTNT", "name": "Fortinet", "price": 95.95 }, - { "symbol": "EPAM", "name": "EPAM Systems", "price": 178.35 }, - { "symbol": "POOL", "name": "Pool Corporation", "price": 318.43 }, - { "symbol": "MCHP", "name": "Microchip Technology", "price": 65.59 }, - { "symbol": "VRSK", "name": "Verisk Analytics", "price": 178.39 }, - { "symbol": "MRNA", "name": "Moderna", "price": 31.43 }, - { "symbol": "HOOD", "name": "Robinhood Markets Inc.", "price": 54.38 }, - { "symbol": "VRSN", "name": "Verisign", "price": 233.77 }, - { "symbol": "AMAT", "name": "Applied Materials", "price": 377.25 }, - { "symbol": "MDLZ", "name": "Mondelez International", "price": 65.31 }, - { "symbol": "PCAR", "name": "Paccar", "price": 115.13 }, - { "symbol": "NDAQ", "name": "Nasdaq Inc.", "price": 83.12 }, - { "symbol": "INTU", "name": "Intuit", "price": 440.63 }, - { "symbol": "HSIC", "name": "Henry Schein", "price": 91.95 }, - { "symbol": "FISV", "name": "Fiserv Inc.", "price": 59.88 }, - { "symbol": "CSGP", "name": "CoStar Group", "price": 42.70 }, - { "symbol": "DDOG", "name": "Datadog", "price": 146.05 }, - { "symbol": "BLDR", "name": "Builders FirstSource", "price": 128.46 }, - { "symbol": "AXON", "name": "Axon Enterprise", "price": 504.02 }, - { "symbol": "ALGN", "name": "Align Technology", "price": 183.45 }, - { "symbol": "FICO", "name": "Fair Isaac", "price": 1520.04 }, - { "symbol": "FITB", "name": "Fifth Third Bancorp", "price": 51.73 }, - { "symbol": "NTAP", "name": "NetApp", "price": 120.48 }, - { "symbol": "FOXA", "name": "Fox Corporation (Class A)", "price": 55.61 }, - { "symbol": "QCOM", "name": "Qualcomm", "price": 141.80 }, - { "symbol": "VTRS", "name": "Viatris", "price": 17.43 }, - { "symbol": "LRCX", "name": "Lam Research", "price": 248.71 }, - { "symbol": "PLTR", "name": "Palantir Technologies", "price": 131.78 }, - { "symbol": "PANW", "name": "Palo Alto Networks", "price": 184.16 }, - { "symbol": "NFLX", "name": "Netflix", "price": 65.49 }, - { "symbol": "KLAC", "name": "KLA Corporation", "price": 1443.99 }, - { "symbol": "NVDA", "name": "Nvidia", "price": 179.79 }, - { "symbol": "IBKR", "name": "Interactive Brokers Group", "price": 71.52 }, - { "symbol": "CRWD", "name": "CrowdStrike", "price": 411.42 }, - { "symbol": "ULTA", "name": "Ulta Beauty", "price": 575.53 }, - { "symbol": "JBHT", "name": "J.B. Hunt", "price": 232.28 }, - { "symbol": "SMCI", "name": "Supermicro", "price": 33.83 }, - { "symbol": "NXPI", "name": "NXP Semiconductors", "price": 219.91 }, - { "symbol": "VRTX", "name": "Vertex Pharmaceuticals", "price": 528.78 }, - { "symbol": "MTCH", "name": "Match Group", "price": 32.55 }, - { "symbol": "CBOE", "name": "Cboe Global Markets", "price": 252.98 }, - { "symbol": "CPRT", "name": "Copart", "price": 42.35 }, - { "symbol": "VICI", "name": "Vici Properties", "price": 30.53 }, - { "symbol": "CHRW", "name": "C.H. Robinson", "price": 194.63 }, - { "symbol": "INTC", "name": "Intel", "price": 39.70 }, - { "symbol": "ROST", "name": "Ross Stores", "price": 204.91 }, - { "symbol": "GEHC", "name": "GE HealthCare", "price": 85.26 }, - { "symbol": "SCHW", "name": "Charles Schwab Corporation", "price": 80.90 }, - { "symbol": "CVNA", "name": "Carvana Co.", "price": 356.72 }, - { "symbol": "IDXX", "name": "Idexx Laboratories", "price": 864.02 }, - { "symbol": "INCY", "name": "Incyte", "price": 116.33 }, - { "symbol": "GNRC", "name": "Generac", "price": 218.82 }, - { "symbol": "CPAY", "name": "Corpay", "price": 416.82 }, - { "symbol": "REGN", "name": "Regeneron Pharmaceuticals", "price": 628.99 }, - { "symbol": "CTAS", "name": "Cintas", "price": 213.98 }, - { "symbol": "FAST", "name": "Fastenal", "price": 39.25 }, - { "symbol": "AMZN", "name": "Amazon", "price": 221.21 }, - { "symbol": "ZBRA", "name": "Zebra Technologies", "price": 289.08 }, - { "symbol": "ODFL", "name": "Old Dominion", "price": 180.38 }, - { "symbol": "TTWO", "name": "Take-Two Interactive", "price": 158.67 }, - { "symbol": "CTRA", "name": "Coterra", "price": 32.93 }, - { "symbol": "LDOS", "name": "Leidos", "price": 166.54 }, - { "symbol": "ARES", "name": "Ares Management Corporation", "price": 120.77 }, - { "symbol": "CINF", "name": "Cincinnati Financial", "price": 154.99 }, - { "symbol": "ANET", "name": "Arista Networks", "price": 139.90 }, - { "symbol": "AMCR", "name": "Amcor", "price": 42.97 }, - { "symbol": "HBAN", "name": "Huntington Bancshares", "price": 21.94 }, - { "symbol": "EVRG", "name": "Evergy", "price": 85.83 }, - { "symbol": "ABNB", "name": "Airbnb", "price": 109.68 }, - { "symbol": "DASH", "name": "DoorDash", "price": 149.25 }, - { "symbol": "COIN", "name": "Coinbase Global", "price": 145.35 }, - { "symbol": "CIEN", "name": "Ciena Corporation", "price": 235.39 }, - { "symbol": "FANG", "name": "Diamondback Energy", "price": 150.66 }, - { "symbol": "PSKY", "name": "Paramount Skydance Corp", "price": 9.44 }, - { "symbol": "ORLY", "name": "O'Reilly Auto Parts", "price": 92.14 }, - { "symbol": "SBAC", "name": "SBA Communications", "price": 220.40 }, - { "symbol": "ACGL", "name": "Arch Capital Group", "price": 87.91 }, - { "symbol": "CTSH", "name": "Cognizant", "price": 60.15 }, - { "symbol": "VLTO", "name": "Veralto", "price": 110.53 }, - { "symbol": "MPWR", "name": "Monolithic Power Systems", "price": 1094.81 }, - { "symbol": "PODD", "name": "Insulet Corporation", "price": 261.32 }, - { "symbol": "MRSH", "name": "Marsh & McLennan Companies Inc.", "price": 156.59 }, - { "symbol": "PAYC", "name": "Paycom", "price": 133.30 }, - { "symbol": "NTRS", "name": "Northern Trust", "price": 140.60 }, - { "symbol": "ADSK", "name": "Autodesk", "price": 229.35 }, - { "symbol": "MSCI", "name": "MSCI", "price": 383.57 }, - { "symbol": "ORCL", "name": "Oracle Corporation", "price": 175.34 }, - { "symbol": "ERIE", "name": "Erie Indemnity", "price": 329.21 }, - { "symbol": "TECH", "name": "Bio-Techne", "price": 51.66 }, - { "symbol": "TRMB", "name": "Trimble Inc.", "price": 71.90 }, - { "symbol": "EBAY", "name": "eBay", "price": 78.21 }, - { "symbol": "INVH", "name": "Invitation Homes", "price": 25.62 }, - { "symbol": "NDSN", "name": "Nordson Corporation", "price": 310.61 }, - { "symbol": "DECK", "name": "Deckers Brands", "price": 108.29 }, - { "symbol": "ADBE", "name": "Adobe Inc.", "price": 275.09 }, - { "symbol": "SNPS", "name": "Synopsys", "price": 424.09 }, - { "symbol": "CHTR", "name": "Charter Communications", "price": 311.42 }, - { "symbol": "STLD", "name": "Steel Dynamics", "price": 180.50 }, - { "symbol": "BIIB", "name": "Biogen", "price": 210.90 }, - { "symbol": "TRGP", "name": "Targa Resources", "price": 243.04 }, - { "symbol": "SOLV", "name": "Solventum", "price": 57.18 }, - { "symbol": "TROW", "name": "T. Rowe Price", "price": 103.71 }, - { "symbol": "AVGO", "name": "Broadcom", "price": 361.04 }, - { "symbol": "CSCO", "name": "Cisco", "price": 78.72 }, - { "symbol": "CTVA", "name": "Corteva", "price": 75.55 }, - { "symbol": "EXPD", "name": "Expeditors International", "price": 164.36 }, - { "symbol": "EXPE", "name": "Expedia Group", "price": 320.19 }, - { "symbol": "AKAM", "name": "Akamai Technologies", "price": 98.72 }, - { "symbol": "CBRE", "name": "CBRE Group", "price": 123.63 }, - { "symbol": "FFIV", "name": "F5 Inc.", "price": 290.99 }, - { "symbol": "MSFT", "name": "Microsoft", "price": 392.30 }, - { "symbol": "COST", "name": "Costco", "price": 904.79 }, - { "symbol": "NCLH", "name": "Norwegian Cruise Line Holdings", "price": 23.90 }, - { "symbol": "KEYS", "name": "Keysight Technologies", "price": 195.34 }, - { "symbol": "SPGI", "name": "S&P Global", "price": 467.26 }, - { "symbol": "UBER", "name": "Uber", "price": 74.73 }, - { "symbol": "BKNG", "name": "Booking Holdings", "price": 4604.23 }, - { "symbol": "DELL", "name": "Dell Technologies", "price": 137.42 }, - { "symbol": "DXCM", "name": "Dexcom", "price": 59.60 }, - { "symbol": "PYPL", "name": "PayPal", "price": 29.98 }, - { "symbol": "GOOG", "name": "Alphabet Inc. (Class C)", "price": 247.04 }, - { "symbol": "BALL", "name": "Ball Corporation", "price": 79.65 }, - { "symbol": "WELL", "name": "Welltower", "price": 205.91 }, - { "symbol": "MNST", "name": "Monster Beverage", "price": 80.26 }, - { "symbol": "OTIS", "name": "Otis Worldwide", "price": 84.99 }, - { "symbol": "SWKS", "name": "Skyworks Solutions", "price": 65.09 }, - { "symbol": "GRMN", "name": "Garmin", "price": 201.12 }, - { "symbol": "WDAY", "name": "Workday Inc.", "price": 99.40 }, - { "symbol": "APTV", "name": "Aptiv", "price": 79.90 }, - { "symbol": "RVTY", "name": "Revvity", "price": 88.91 }, - { "symbol": "TMUS", "name": "T-Mobile US", "price": 188.82 }, - { "symbol": "LULU", "name": "Lululemon Athletica", "price": 150.36 }, - { "symbol": "HOLX", "name": "Hologic", "price": 60.47 }, - { "symbol": "NWSA", "name": "News Corp (Class A)", "price": 19.11 }, - { "symbol": "PAYX", "name": "Paychex", "price": 88.93 }, - { "symbol": "CDNS", "name": "Cadence Design Systems", "price": 269.75 }, - { "symbol": "ALLE", "name": "Allegion", "price": 187.22 }, - { "symbol": "GILD", "name": "Gilead Sciences", "price": 152.35 }, - { "symbol": "EQIX", "name": "Equinix", "price": 898.66 }, - { "symbol": "ISRG", "name": "Intuitive Surgical", "price": 563.46 } - ] -}