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 }
- ]
-}