From f5879c17a1ada785b3df67d9796a4a275b7673da Mon Sep 17 00:00:00 2001 From: Thomas Quintana Date: Thu, 29 Jan 2015 21:15:10 -0500 Subject: [PATCH 1/4] Replaced doubles for BigDecimal when handling money. --- src/yahoofinance/Utils.java | 35 +++++++ .../histquotes/HistQuotesRequest.java | 10 +- .../histquotes/HistoricalQuote.java | 33 ++++--- src/yahoofinance/quotes/fx/FxQuote.java | 17 ++-- .../quotes/fx/FxQuotesRequest.java | 2 +- .../quotes/stock/StockDividend.java | 15 +-- src/yahoofinance/quotes/stock/StockQuote.java | 98 ++++++++++--------- .../quotes/stock/StockQuotesData.java | 52 +++++----- src/yahoofinance/quotes/stock/StockStats.java | 82 ++++++++-------- 9 files changed, 194 insertions(+), 150 deletions(-) diff --git a/src/yahoofinance/Utils.java b/src/yahoofinance/Utils.java index 2bac074..3067a67 100644 --- a/src/yahoofinance/Utils.java +++ b/src/yahoofinance/Utils.java @@ -1,6 +1,7 @@ package yahoofinance; import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; import java.net.URLEncoder; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -37,6 +38,32 @@ private static boolean isParseable(String data) { return !(data == null || data.equals("N/A") || data.equals("-") || data.equals("")); } + public static BigDecimal getBigDecimal(String data) { + BigDecimal result = new BigDecimal("0.00"); + if (!Utils.isParseable(data)) { + return result; + } + try { + data = Utils.cleanNumberString(data); + char lastChar = data.charAt(data.length() - 1); + BigDecimal multiplier = new BigDecimal(1); + switch (lastChar) { + case 'B': + data = data.substring(0, data.length() - 1); + multiplier = new BigDecimal(1000000000); + break; + case 'M': + data = data.substring(0, data.length() - 1); + multiplier = new BigDecimal(1000000); + break; + } + result = new BigDecimal(data).multiply(multiplier); + } catch (NumberFormatException e) { + YahooFinance.logger.log(Level.INFO, "Failed to parse: " + data, e); + } + return result; + } + public static double getDouble(String data) { double result = 0.00; if (!Utils.isParseable(data)) { @@ -91,6 +118,14 @@ public static long getLong(String data) { return result; } + public static BigDecimal getPercent(BigDecimal numerator, BigDecimal denominator) { + final BigDecimal zero = new BigDecimal(0); + if(denominator.equals(zero)) { + return zero; + } + return numerator.divide(denominator, 2, BigDecimal.ROUND_DOWN); + } + public static double getPercent(double numerator, double denominator) { if(denominator == 0) { return 0; diff --git a/src/yahoofinance/histquotes/HistQuotesRequest.java b/src/yahoofinance/histquotes/HistQuotesRequest.java index 55354fb..e74786d 100644 --- a/src/yahoofinance/histquotes/HistQuotesRequest.java +++ b/src/yahoofinance/histquotes/HistQuotesRequest.java @@ -116,11 +116,11 @@ private HistoricalQuote parseCSVLine(String line) { String[] data = line.split(YahooFinance.QUOTES_CSV_DELIMITER); return new HistoricalQuote(this.symbol, Utils.parseHistDate(data[0]), - Utils.getDouble(data[1]), - Utils.getDouble(data[3]), - Utils.getDouble(data[2]), - Utils.getDouble(data[4]), - Utils.getDouble(data[6]), + Utils.getBigDecimal(data[1]), + Utils.getBigDecimal(data[3]), + Utils.getBigDecimal(data[2]), + Utils.getBigDecimal(data[4]), + Utils.getBigDecimal(data[6]), Utils.getLong(data[5]) ); } diff --git a/src/yahoofinance/histquotes/HistoricalQuote.java b/src/yahoofinance/histquotes/HistoricalQuote.java index f004767..6048a41 100644 --- a/src/yahoofinance/histquotes/HistoricalQuote.java +++ b/src/yahoofinance/histquotes/HistoricalQuote.java @@ -1,6 +1,7 @@ package yahoofinance.histquotes; +import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -14,18 +15,18 @@ public class HistoricalQuote { private Calendar date; - private double open; - private double low; - private double high; - private double close; + private BigDecimal open; + private BigDecimal low; + private BigDecimal high; + private BigDecimal close; - private double adjClose; + private BigDecimal adjClose; private long volume; public HistoricalQuote() {} - public HistoricalQuote(String symbol, Calendar date, double open, double low, double high, double close, double adjClose, long volume) { + public HistoricalQuote(String symbol, Calendar date, BigDecimal open, BigDecimal low, BigDecimal high, BigDecimal close, BigDecimal adjClose, long volume) { this.symbol = symbol; this.date = date; this.open = open; @@ -52,11 +53,11 @@ public void setDate(Calendar date) { this.date = date; } - public double getOpen() { + public BigDecimal getOpen() { return open; } - public void setOpen(double open) { + public void setOpen(BigDecimal open) { this.open = open; } @@ -64,11 +65,11 @@ public void setOpen(double open) { * * @return the intra-day low */ - public double getLow() { + public BigDecimal getLow() { return low; } - public void setLow(double low) { + public void setLow(BigDecimal low) { this.low = low; } @@ -76,19 +77,19 @@ public void setLow(double low) { * * @return the intra-day high */ - public double getHigh() { + public BigDecimal getHigh() { return high; } - public void setHigh(double high) { + public void setHigh(BigDecimal high) { this.high = high; } - public double getClose() { + public BigDecimal getClose() { return close; } - public void setClose(double close) { + public void setClose(BigDecimal close) { this.close = close; } @@ -100,11 +101,11 @@ public void setClose(double close) { * that an investor earned if shares were purchased on that date. * @return the adjusted close price */ - public double getAdjClose() { + public BigDecimal getAdjClose() { return adjClose; } - public void setAdjClose(double adjClose) { + public void setAdjClose(BigDecimal adjClose) { this.adjClose = adjClose; } diff --git a/src/yahoofinance/quotes/fx/FxQuote.java b/src/yahoofinance/quotes/fx/FxQuote.java index de39d45..4974854 100644 --- a/src/yahoofinance/quotes/fx/FxQuote.java +++ b/src/yahoofinance/quotes/fx/FxQuote.java @@ -1,6 +1,8 @@ package yahoofinance.quotes.fx; +import java.math.BigDecimal; + /** * * @author Stijn Strickx @@ -8,14 +10,14 @@ public class FxQuote { private String symbol; - private double price; + private BigDecimal price; public FxQuote(String symbol) { this.symbol = symbol; - this.price = 0; + this.price = new BigDecimal(0); } - public FxQuote(String symbol, double price) { + public FxQuote(String symbol, BigDecimal price) { this.symbol = symbol; this.price = price; } @@ -34,8 +36,9 @@ public void setSymbol(String symbol) { * * @return the requested FX rate */ - public double getPrice() { - if(price == 0) { + public BigDecimal getPrice() { + final BigDecimal zero = new BigDecimal(0); + if(price.equals(zero)) { return this.getPrice(true); } return price; @@ -54,7 +57,7 @@ public double getPrice() { * @param refresh indicates whether the data should be requested again to Yahoo Finance * @return the requested FX rate */ - public double getPrice(boolean refresh) { + public BigDecimal getPrice(boolean refresh) { if(refresh) { FxQuotesRequest request = new FxQuotesRequest(this.symbol); this.price = request.getSingleResult().getPrice(); @@ -62,7 +65,7 @@ public double getPrice(boolean refresh) { return price; } - public void setPrice(double price) { + public void setPrice(BigDecimal price) { this.price = price; } diff --git a/src/yahoofinance/quotes/fx/FxQuotesRequest.java b/src/yahoofinance/quotes/fx/FxQuotesRequest.java index 885407f..4f093ae 100644 --- a/src/yahoofinance/quotes/fx/FxQuotesRequest.java +++ b/src/yahoofinance/quotes/fx/FxQuotesRequest.java @@ -28,7 +28,7 @@ public FxQuotesRequest(String query) { protected FxQuote parseCSVLine(String line) { String[] split = Utils.stripOverhead(line).split(YahooFinance.QUOTES_CSV_DELIMITER); if(split.length >= 2) { - return new FxQuote(split[0], Utils.getDouble(split[1])); + return new FxQuote(split[0], Utils.getBigDecimal(split[1])); } return null; } diff --git a/src/yahoofinance/quotes/stock/StockDividend.java b/src/yahoofinance/quotes/stock/StockDividend.java index a113a1c..1902862 100644 --- a/src/yahoofinance/quotes/stock/StockDividend.java +++ b/src/yahoofinance/quotes/stock/StockDividend.java @@ -1,6 +1,7 @@ package yahoofinance.quotes.stock; +import java.math.BigDecimal; import java.util.Calendar; /** @@ -13,14 +14,14 @@ public class StockDividend { private Calendar payDate; private Calendar exDate; - private double annualYield; - private double annualYieldPercent; + private BigDecimal annualYield; + private BigDecimal annualYieldPercent; public StockDividend(String symbol) { this.symbol = symbol; } - public StockDividend(String symbol, Calendar payDate, Calendar exDate, double annualYield, double annualYieldPercent) { + public StockDividend(String symbol, Calendar payDate, Calendar exDate, BigDecimal annualYield, BigDecimal annualYieldPercent) { this(symbol); this.payDate = payDate; this.exDate = exDate; @@ -48,19 +49,19 @@ public void setExDate(Calendar exDate) { this.exDate = exDate; } - public double getAnnualYield() { + public BigDecimal getAnnualYield() { return annualYield; } - public void setAnnualYield(double annualYield) { + public void setAnnualYield(BigDecimal annualYield) { this.annualYield = annualYield; } - public double getAnnualYieldPercent() { + public BigDecimal getAnnualYieldPercent() { return annualYieldPercent; } - public void setAnnualYieldPercent(double annualYieldPercent) { + public void setAnnualYieldPercent(BigDecimal annualYieldPercent) { this.annualYieldPercent = annualYieldPercent; } diff --git a/src/yahoofinance/quotes/stock/StockQuote.java b/src/yahoofinance/quotes/stock/StockQuote.java index 5e8a854..7215faa 100644 --- a/src/yahoofinance/quotes/stock/StockQuote.java +++ b/src/yahoofinance/quotes/stock/StockQuote.java @@ -1,7 +1,9 @@ package yahoofinance.quotes.stock; +import java.math.BigDecimal; import java.util.Calendar; + import yahoofinance.Utils; /** @@ -12,22 +14,22 @@ public class StockQuote { private final String symbol; - private double ask; + private BigDecimal ask; private int askSize; - private double bid; + private BigDecimal bid; private int bidSize; - private double price; + private BigDecimal price; private int lastTradeSize; private Calendar lastTradeTime; - private double open; - private double previousClose; - private double dayLow; - private double dayHigh; + private BigDecimal open; + private BigDecimal previousClose; + private BigDecimal dayLow; + private BigDecimal dayHigh; - private double yearLow; - private double yearHigh; - private double priceAvg50; - private double priceAvg200; + private BigDecimal yearLow; + private BigDecimal yearHigh; + private BigDecimal priceAvg50; + private BigDecimal priceAvg200; private long volume; private long avgVolume; @@ -40,15 +42,15 @@ public StockQuote(String symbol) { * * @return difference between current price and previous close */ - public double getChange() { - return this.price - this.previousClose; + public BigDecimal getChange() { + return this.price.subtract(this.previousClose); } /** * * @return change relative to previous close */ - public double getChangeInPercent() { + public BigDecimal getChangeInPercent() { return Utils.getPercent(this.getChange(), this.previousClose); } @@ -56,15 +58,15 @@ public double getChangeInPercent() { * * @return difference between current price and year low */ - public double getChangeFromYearLow() { - return this.price - this.yearLow; + public BigDecimal getChangeFromYearLow() { + return this.price.subtract(this.yearLow); } /** * * @return change from year low relative to year low */ - public double getChangeFromYearLowInPercent() { + public BigDecimal getChangeFromYearLowInPercent() { return Utils.getPercent(this.getChangeFromYearLow(), this.yearLow); } @@ -72,15 +74,15 @@ public double getChangeFromYearLowInPercent() { * * @return difference between current price and year high */ - public double getChangeFromYearHigh() { - return this.price - this.yearHigh; + public BigDecimal getChangeFromYearHigh() { + return this.price.subtract(this.yearHigh); } /** * * @return change from year high relative to year high */ - public double getChangeFromYearHighInPercent() { + public BigDecimal getChangeFromYearHighInPercent() { return Utils.getPercent(this.getChangeFromYearHigh(), this.yearHigh); } @@ -88,15 +90,15 @@ public double getChangeFromYearHighInPercent() { * * @return difference between current price and 50 day moving average */ - public double getChangeFromAvg50() { - return this.price - this.priceAvg50; + public BigDecimal getChangeFromAvg50() { + return this.price.subtract(this.priceAvg50); } /** * * @return change from 50 day moving average relative to 50 day moving average */ - public double getChangeFromAvg50InPercent() { + public BigDecimal getChangeFromAvg50InPercent() { return Utils.getPercent(this.getChangeFromAvg50(), this.priceAvg50); } @@ -104,15 +106,15 @@ public double getChangeFromAvg50InPercent() { * * @return difference between current price and 200 day moving average */ - public double getChangeFromAvg200() { - return this.price - this.priceAvg200; + public BigDecimal getChangeFromAvg200() { + return this.price.subtract(this.priceAvg200); } /** * * @return change from 200 day moving average relative to 200 day moving average */ - public double getChangeFromAvg200InPercent() { + public BigDecimal getChangeFromAvg200InPercent() { return Utils.getPercent(this.getChangeFromAvg200(), this.priceAvg200); } @@ -120,11 +122,11 @@ public String getSymbol() { return symbol; } - public double getAsk() { + public BigDecimal getAsk() { return ask; } - public void setAsk(double ask) { + public void setAsk(BigDecimal ask) { this.ask = ask; } @@ -136,11 +138,11 @@ public void setAskSize(int askSize) { this.askSize = askSize; } - public double getBid() { + public BigDecimal getBid() { return bid; } - public void setBid(double bid) { + public void setBid(BigDecimal bid) { this.bid = bid; } @@ -152,11 +154,11 @@ public void setBidSize(int bidSize) { this.bidSize = bidSize; } - public double getPrice() { + public BigDecimal getPrice() { return price; } - public void setPrice(double price) { + public void setPrice(BigDecimal price) { this.price = price; } @@ -176,51 +178,51 @@ public void setLastTradeTime(Calendar lastTradeTime) { this.lastTradeTime = lastTradeTime; } - public double getOpen() { + public BigDecimal getOpen() { return open; } - public void setOpen(double open) { + public void setOpen(BigDecimal open) { this.open = open; } - public double getPreviousClose() { + public BigDecimal getPreviousClose() { return previousClose; } - public void setPreviousClose(double previousClose) { + public void setPreviousClose(BigDecimal previousClose) { this.previousClose = previousClose; } - public double getDayLow() { + public BigDecimal getDayLow() { return dayLow; } - public void setDayLow(double dayLow) { + public void setDayLow(BigDecimal dayLow) { this.dayLow = dayLow; } - public double getDayHigh() { + public BigDecimal getDayHigh() { return dayHigh; } - public void setDayHigh(double dayHigh) { + public void setDayHigh(BigDecimal dayHigh) { this.dayHigh = dayHigh; } - public double getYearLow() { + public BigDecimal getYearLow() { return yearLow; } - public void setYearLow(double yearLow) { + public void setYearLow(BigDecimal yearLow) { this.yearLow = yearLow; } - public double getYearHigh() { + public BigDecimal getYearHigh() { return yearHigh; } - public void setYearHigh(double yearHigh) { + public void setYearHigh(BigDecimal yearHigh) { this.yearHigh = yearHigh; } @@ -228,11 +230,11 @@ public void setYearHigh(double yearHigh) { * * @return 50 day moving average */ - public double getPriceAvg50() { + public BigDecimal getPriceAvg50() { return priceAvg50; } - public void setPriceAvg50(double priceAvg50) { + public void setPriceAvg50(BigDecimal priceAvg50) { this.priceAvg50 = priceAvg50; } @@ -240,11 +242,11 @@ public void setPriceAvg50(double priceAvg50) { * * @return 200 day moving average */ - public double getPriceAvg200() { + public BigDecimal getPriceAvg200() { return priceAvg200; } - public void setPriceAvg200(double priceAvg200) { + public void setPriceAvg200(BigDecimal priceAvg200) { this.priceAvg200 = priceAvg200; } diff --git a/src/yahoofinance/quotes/stock/StockQuotesData.java b/src/yahoofinance/quotes/stock/StockQuotesData.java index 7b99511..a723e98 100644 --- a/src/yahoofinance/quotes/stock/StockQuotesData.java +++ b/src/yahoofinance/quotes/stock/StockQuotesData.java @@ -28,23 +28,23 @@ public StockQuote getQuote() { String symbol = this.getValue(QuotesProperty.Symbol); StockQuote quote = new StockQuote(symbol); - quote.setPrice(Utils.getDouble(this.getValue(QuotesProperty.LastTradePriceOnly))); + quote.setPrice(Utils.getBigDecimal(this.getValue(QuotesProperty.LastTradePriceOnly))); quote.setLastTradeSize(Utils.getInt(this.getValue(QuotesProperty.LastTradeSize))); - quote.setAsk(Utils.getDouble(this.getValue(QuotesProperty.AskRealtime))); + quote.setAsk(Utils.getBigDecimal(this.getValue(QuotesProperty.AskRealtime))); quote.setAskSize(Utils.getInt(this.getValue(QuotesProperty.AskSize))); - quote.setBid(Utils.getDouble(this.getValue(QuotesProperty.BidRealtime))); + quote.setBid(Utils.getBigDecimal(this.getValue(QuotesProperty.BidRealtime))); quote.setBidSize(Utils.getInt(this.getValue(QuotesProperty.BidSize))); - quote.setOpen(Utils.getDouble(this.getValue(QuotesProperty.Open))); - quote.setPreviousClose(Utils.getDouble(this.getValue(QuotesProperty.PreviousClose))); - quote.setDayHigh(Utils.getDouble(this.getValue(QuotesProperty.DaysHigh))); - quote.setDayLow(Utils.getDouble(this.getValue(QuotesProperty.DaysLow))); + quote.setOpen(Utils.getBigDecimal(this.getValue(QuotesProperty.Open))); + quote.setPreviousClose(Utils.getBigDecimal(this.getValue(QuotesProperty.PreviousClose))); + quote.setDayHigh(Utils.getBigDecimal(this.getValue(QuotesProperty.DaysHigh))); + quote.setDayLow(Utils.getBigDecimal(this.getValue(QuotesProperty.DaysLow))); quote.setLastTradeTime(Utils.parseDateTime(this.getValue(QuotesProperty.LastTradeDate), this.getValue(QuotesProperty.LastTradeTime))); - quote.setYearHigh(Utils.getDouble(this.getValue(QuotesProperty.YearHigh))); - quote.setYearLow(Utils.getDouble(this.getValue(QuotesProperty.YearLow))); - quote.setPriceAvg50(Utils.getDouble(this.getValue(QuotesProperty.FiftydayMovingAverage))); - quote.setPriceAvg200(Utils.getDouble(this.getValue(QuotesProperty.TwoHundreddayMovingAverage))); + quote.setYearHigh(Utils.getBigDecimal(this.getValue(QuotesProperty.YearHigh))); + quote.setYearLow(Utils.getBigDecimal(this.getValue(QuotesProperty.YearLow))); + quote.setPriceAvg50(Utils.getBigDecimal(this.getValue(QuotesProperty.FiftydayMovingAverage))); + quote.setPriceAvg200(Utils.getBigDecimal(this.getValue(QuotesProperty.TwoHundreddayMovingAverage))); quote.setVolume(Utils.getLong(this.getValue(QuotesProperty.Volume))); quote.setAvgVolume(Utils.getLong(this.getValue(QuotesProperty.AverageDailyVolume))); @@ -56,26 +56,26 @@ public StockStats getStats() { String symbol = this.getValue(QuotesProperty.Symbol); StockStats stats = new StockStats(symbol); - stats.setMarketCap(Utils.getDouble(this.getValue(QuotesProperty.MarketCapitalization))); + stats.setMarketCap(Utils.getBigDecimal(this.getValue(QuotesProperty.MarketCapitalization))); stats.setSharesFloat(Utils.getLong(this.getValue(QuotesProperty.SharesFloat))); stats.setSharesOutstanding(Utils.getLong(this.getValue(QuotesProperty.SharesOutstanding))); stats.setSharesOwned(Utils.getLong(this.getValue(QuotesProperty.SharesOwned))); - stats.setEps(Utils.getDouble(this.getValue(QuotesProperty.DilutedEPS))); - stats.setPe(Utils.getDouble(this.getValue(QuotesProperty.PERatio))); - stats.setPeg(Utils.getDouble(this.getValue(QuotesProperty.PEGRatio))); + stats.setEps(Utils.getBigDecimal(this.getValue(QuotesProperty.DilutedEPS))); + stats.setPe(Utils.getBigDecimal(this.getValue(QuotesProperty.PERatio))); + stats.setPeg(Utils.getBigDecimal(this.getValue(QuotesProperty.PEGRatio))); - stats.setEpsEstimateCurrentYear(Utils.getDouble(this.getValue(QuotesProperty.EPSEstimateCurrentYear))); - stats.setEpsEstimateNextQuarter(Utils.getDouble(this.getValue(QuotesProperty.EPSEstimateNextQuarter))); - stats.setEpsEstimateNextYear(Utils.getDouble(this.getValue(QuotesProperty.EPSEstimateNextYear))); + stats.setEpsEstimateCurrentYear(Utils.getBigDecimal(this.getValue(QuotesProperty.EPSEstimateCurrentYear))); + stats.setEpsEstimateNextQuarter(Utils.getBigDecimal(this.getValue(QuotesProperty.EPSEstimateNextQuarter))); + stats.setEpsEstimateNextYear(Utils.getBigDecimal(this.getValue(QuotesProperty.EPSEstimateNextYear))); - stats.setPriceBook(Utils.getDouble(this.getValue(QuotesProperty.PriceBook))); - stats.setPriceSales(Utils.getDouble(this.getValue(QuotesProperty.PriceSales))); - stats.setBookValuePerShare(Utils.getDouble(this.getValue(QuotesProperty.BookValuePerShare))); + stats.setPriceBook(Utils.getBigDecimal(this.getValue(QuotesProperty.PriceBook))); + stats.setPriceSales(Utils.getBigDecimal(this.getValue(QuotesProperty.PriceSales))); + stats.setBookValuePerShare(Utils.getBigDecimal(this.getValue(QuotesProperty.BookValuePerShare))); - stats.setOneYearTargetPrice(Utils.getDouble(this.getValue(QuotesProperty.OneyrTargetPrice))); - stats.setEBITDA(Utils.getDouble(this.getValue(QuotesProperty.EBITDA))); - stats.setRevenue(Utils.getDouble(this.getValue(QuotesProperty.Revenue))); + stats.setOneYearTargetPrice(Utils.getBigDecimal(this.getValue(QuotesProperty.OneyrTargetPrice))); + stats.setEBITDA(Utils.getBigDecimal(this.getValue(QuotesProperty.EBITDA))); + stats.setRevenue(Utils.getBigDecimal(this.getValue(QuotesProperty.Revenue))); return stats; } @@ -86,8 +86,8 @@ public StockDividend getDividend() { dividend.setPayDate(Utils.parseDividendDate(this.getValue(QuotesProperty.DividendPayDate))); dividend.setExDate(Utils.parseDividendDate(this.getValue(QuotesProperty.ExDividendDate))); - dividend.setAnnualYield(Utils.getDouble(this.getValue(QuotesProperty.TrailingAnnualDividendYield))); - dividend.setAnnualYieldPercent(Utils.getDouble(this.getValue(QuotesProperty.TrailingAnnualDividendYieldInPercent))); + dividend.setAnnualYield(Utils.getBigDecimal(this.getValue(QuotesProperty.TrailingAnnualDividendYield))); + dividend.setAnnualYieldPercent(Utils.getBigDecimal(this.getValue(QuotesProperty.TrailingAnnualDividendYieldInPercent))); return dividend; } diff --git a/src/yahoofinance/quotes/stock/StockStats.java b/src/yahoofinance/quotes/stock/StockStats.java index de75dd7..0fd6c76 100644 --- a/src/yahoofinance/quotes/stock/StockStats.java +++ b/src/yahoofinance/quotes/stock/StockStats.java @@ -1,6 +1,8 @@ package yahoofinance.quotes.stock; +import java.math.BigDecimal; + import yahoofinance.Utils; /** @@ -11,32 +13,32 @@ public class StockStats { private final String symbol; - private double marketCap; + private BigDecimal marketCap; private long sharesFloat; private long sharesOutstanding; private long sharesOwned; - private double eps; - private double pe; - private double peg; + private BigDecimal eps; + private BigDecimal pe; + private BigDecimal peg; - private double epsEstimateCurrentYear; - private double epsEstimateNextQuarter; - private double epsEstimateNextYear; + private BigDecimal epsEstimateCurrentYear; + private BigDecimal epsEstimateNextQuarter; + private BigDecimal epsEstimateNextYear; - private double priceBook; - private double priceSales; - private double bookValuePerShare; + private BigDecimal priceBook; + private BigDecimal priceSales; + private BigDecimal bookValuePerShare; - private double revenue; // ttm - private double EBITDA; // ttm - private double oneYearTargetPrice; + private BigDecimal revenue; // ttm + private BigDecimal EBITDA; // ttm + private BigDecimal oneYearTargetPrice; public StockStats(String symbol) { this.symbol = symbol; } - public double getROE() { + public BigDecimal getROE() { return Utils.getPercent(this.EBITDA, this.marketCap); } @@ -44,11 +46,11 @@ public String getSymbol() { return symbol; } - public double getMarketCap() { + public BigDecimal getMarketCap() { return marketCap; } - public void setMarketCap(double marketCap) { + public void setMarketCap(BigDecimal marketCap) { this.marketCap = marketCap; } @@ -76,99 +78,99 @@ public void setSharesOwned(long sharesOwned) { this.sharesOwned = sharesOwned; } - public double getEps() { + public BigDecimal getEps() { return eps; } - public void setEps(double eps) { + public void setEps(BigDecimal eps) { this.eps = eps; } - public double getPe() { + public BigDecimal getPe() { return pe; } - public void setPe(double pe) { + public void setPe(BigDecimal pe) { this.pe = pe; } - public double getPeg() { + public BigDecimal getPeg() { return peg; } - public void setPeg(double peg) { + public void setPeg(BigDecimal peg) { this.peg = peg; } - public double getEpsEstimateCurrentYear() { + public BigDecimal getEpsEstimateCurrentYear() { return epsEstimateCurrentYear; } - public void setEpsEstimateCurrentYear(double epsEstimateCurrentYear) { + public void setEpsEstimateCurrentYear(BigDecimal epsEstimateCurrentYear) { this.epsEstimateCurrentYear = epsEstimateCurrentYear; } - public double getEpsEstimateNextQuarter() { + public BigDecimal getEpsEstimateNextQuarter() { return epsEstimateNextQuarter; } - public void setEpsEstimateNextQuarter(double epsEstimateNextQuarter) { + public void setEpsEstimateNextQuarter(BigDecimal epsEstimateNextQuarter) { this.epsEstimateNextQuarter = epsEstimateNextQuarter; } - public double getEpsEstimateNextYear() { + public BigDecimal getEpsEstimateNextYear() { return epsEstimateNextYear; } - public void setEpsEstimateNextYear(double epsEstimateNextYear) { + public void setEpsEstimateNextYear(BigDecimal epsEstimateNextYear) { this.epsEstimateNextYear = epsEstimateNextYear; } - public double getPriceBook() { + public BigDecimal getPriceBook() { return priceBook; } - public void setPriceBook(double priceBook) { + public void setPriceBook(BigDecimal priceBook) { this.priceBook = priceBook; } - public double getPriceSales() { + public BigDecimal getPriceSales() { return priceSales; } - public void setPriceSales(double priceSales) { + public void setPriceSales(BigDecimal priceSales) { this.priceSales = priceSales; } - public double getBookValuePerShare() { + public BigDecimal getBookValuePerShare() { return bookValuePerShare; } - public void setBookValuePerShare(double bookValuePerShare) { + public void setBookValuePerShare(BigDecimal bookValuePerShare) { this.bookValuePerShare = bookValuePerShare; } - public double getRevenue() { + public BigDecimal getRevenue() { return revenue; } - public void setRevenue(double revenue) { + public void setRevenue(BigDecimal revenue) { this.revenue = revenue; } - public double getEBITDA() { + public BigDecimal getEBITDA() { return EBITDA; } - public void setEBITDA(double EBITDA) { + public void setEBITDA(BigDecimal EBITDA) { this.EBITDA = EBITDA; } - public double getOneYearTargetPrice() { + public BigDecimal getOneYearTargetPrice() { return oneYearTargetPrice; } - public void setOneYearTargetPrice(double oneYearTargetPrice) { + public void setOneYearTargetPrice(BigDecimal oneYearTargetPrice) { this.oneYearTargetPrice = oneYearTargetPrice; } From 455c1591511d1c5f6a8b74d23ecf98c62156f3a1 Mon Sep 17 00:00:00 2001 From: Thomas Quintana Date: Thu, 29 Jan 2015 21:45:40 -0500 Subject: [PATCH 2/4] Updated README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4498b20..bfbb6ef 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,10 @@ Please check the javadoc (available in dist directory) to get a complete overvie ```java Stock stock = YahooFinance.get("INTC"); -double price = stock.getQuote().getPrice(); -double change = stock.getQuote().getChangeInPercent(); -double peg = stock.getStats().getPeg(); -double dividend = stock.getDividend().getAnnualYieldPercent(); +BigDecimal price = stock.getQuote().getPrice(); +BigDecimal change = stock.getQuote().getChangeInPercent(); +BigDecimal peg = stock.getStats().getPeg(); +BigDecimal dividend = stock.getDividend().getAnnualYieldPercent(); stock.print(); ``` From bd8c188e1dd52d1cc94b24403e8e26dbbf4db80d Mon Sep 17 00:00:00 2001 From: Stijn Strickx Date: Sun, 15 Feb 2015 17:33:14 +0100 Subject: [PATCH 3/4] Minor changes to BigDecimal use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Used the available BigDecimal.ZERO and BigDecimal.ONE where possible - Changed the rounding method from ROUND_DOWN to ROUND_HALF_UP - the getBigDecimal method didn’t include a fix yet that was made on the getDouble method --- src/yahoofinance/Utils.java | 106 ++++++++++++------------ src/yahoofinance/quotes/fx/FxQuote.java | 5 +- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/yahoofinance/Utils.java b/src/yahoofinance/Utils.java index 4cccf82..f2184d0 100644 --- a/src/yahoofinance/Utils.java +++ b/src/yahoofinance/Utils.java @@ -29,24 +29,24 @@ public static String join(String[] data, String d) { } return sb.append(data[i]).toString(); } - + private static String cleanNumberString(String data) { return Utils.join(data.trim().split(","), ""); } - + private static boolean isParseable(String data) { return !(data == null || data.equals("N/A") || data.equals("-") || data.equals("")); } - + public static BigDecimal getBigDecimal(String data) { - BigDecimal result = new BigDecimal("0.00"); - if (!Utils.isParseable(data)) { + BigDecimal result = BigDecimal.ZERO; + if (!Utils.isParseable(data)) { return result; } - try { + try { data = Utils.cleanNumberString(data); char lastChar = data.charAt(data.length() - 1); - BigDecimal multiplier = new BigDecimal(1); + BigDecimal multiplier = BigDecimal.ONE; switch (lastChar) { case 'B': data = data.substring(0, data.length() - 1); @@ -56,14 +56,18 @@ public static BigDecimal getBigDecimal(String data) { data = data.substring(0, data.length() - 1); multiplier = new BigDecimal(1000000); break; + case 'K': + data = data.substring(0, data.length() - 1); + multiplier = new BigDecimal(1000); + break; } result = new BigDecimal(data).multiply(multiplier); } catch (NumberFormatException e) { YahooFinance.logger.log(Level.INFO, "Failed to parse: " + data, e); } - return result; + return result; } - + public static double getDouble(String data) { double result = 0.00; if (!Utils.isParseable(data)) { @@ -107,51 +111,51 @@ public static int getInt(String data) { } return result; } - + public static long getLong(String data) { long result = 0; if (!Utils.isParseable(data)) { return result; } try { - data = Utils.cleanNumberString(data); + data = Utils.cleanNumberString(data); result = Long.parseLong(data); } catch (NumberFormatException e) { YahooFinance.logger.log(Level.INFO, "Failed to parse: " + data, e); } return result; } - + public static BigDecimal getPercent(BigDecimal numerator, BigDecimal denominator) { - final BigDecimal zero = new BigDecimal(0); - if(denominator.equals(zero)) { - return zero; + if (denominator.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; } - return numerator.divide(denominator, 2, BigDecimal.ROUND_DOWN); + return numerator.divide(denominator, 2, BigDecimal.ROUND_HALF_UP); } - + public static double getPercent(double numerator, double denominator) { - if(denominator == 0) { + if (denominator == 0) { return 0; } return numerator / denominator; } private static String getDividendDateFormat(String date) { - if(date.matches("[0-9][0-9]-...-[0-9][0-9]")) { + if (date.matches("[0-9][0-9]-...-[0-9][0-9]")) { return "dd-MMM-yy"; - } else if(date.matches("[0-9]-...-[0-9][0-9]")) { + } else if (date.matches("[0-9]-...-[0-9][0-9]")) { return "d-MMM-yy"; } else { return "MMM d"; } } + /** - * Used to parse the dividend dates. - * Returns null if the date cannot be parsed. - * - * @param date String received that represents the date - * @return Calendar object representing the parsed date + * Used to parse the dividend dates. Returns null if the date cannot be + * parsed. + * + * @param date String received that represents the date + * @return Calendar object representing the parsed date */ public static Calendar parseDividendDate(String date) { if (!Utils.isParseable(date)) { @@ -164,40 +168,40 @@ public static Calendar parseDividendDate(String date) { Calendar today = Calendar.getInstance(TimeZone.getTimeZone(YahooFinance.TIMEZONE)); Calendar parsedDate = Calendar.getInstance(TimeZone.getTimeZone(YahooFinance.TIMEZONE)); parsedDate.setTime(format.parse(date)); - - if(parsedDate.get(Calendar.YEAR) == 1970) { + + if (parsedDate.get(Calendar.YEAR) == 1970) { // Not really clear which year the dividend date is... making a reasonable guess. int monthDiff = parsedDate.get(Calendar.MONTH) - today.get(Calendar.MONTH); int year = today.get(Calendar.YEAR); - if(monthDiff > 6) { + if (monthDiff > 6) { year -= 1; - } else if(monthDiff < -6) { + } else if (monthDiff < -6) { year += 1; } parsedDate.set(Calendar.YEAR, year); } - + return parsedDate; - } catch(ParseException ex) { + } catch (ParseException ex) { YahooFinance.logger.log(Level.SEVERE, ex.getMessage(), ex); return null; } } - + /** - * Used to parse the last trade date / time. - * Returns null if the date / time cannot be parsed. - * - * @param date String received that represents the date - * @param time String received that represents the time - * @return Calendar object with the parsed datetime + * Used to parse the last trade date / time. Returns null if the date / time + * cannot be parsed. + * + * @param date String received that represents the date + * @param time String received that represents the time + * @return Calendar object with the parsed datetime */ public static Calendar parseDateTime(String date, String time) { String datetime = date + " " + time; SimpleDateFormat format = new SimpleDateFormat("M/d/yyyy h:mma"); format.setTimeZone(TimeZone.getTimeZone(YahooFinance.TIMEZONE)); try { - if(Utils.isParseable(date) && Utils.isParseable(time)) { + if (Utils.isParseable(date) && Utils.isParseable(time)) { Calendar c = Calendar.getInstance(); c.setTime(format.parse(datetime)); return c; @@ -207,12 +211,12 @@ public static Calendar parseDateTime(String date, String time) { } return null; } - + public static Calendar parseHistDate(String date) { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); format.setTimeZone(TimeZone.getTimeZone(YahooFinance.TIMEZONE)); try { - if(Utils.isParseable(date)) { + if (Utils.isParseable(date)) { Calendar c = Calendar.getInstance(); c.setTime(format.parse(date)); return c; @@ -222,11 +226,11 @@ public static Calendar parseHistDate(String date) { } return null; } - + public static String getURLParameters(Map params) { StringBuilder sb = new StringBuilder(); - - for(Entry entry : params.entrySet()) { + + for (Entry entry : params.entrySet()) { if (sb.length() > 0) { sb.append("&"); } @@ -241,20 +245,20 @@ public static String getURLParameters(Map params) { } sb.append(String.format("%s=%s", key, value)); } - return sb.toString(); + return sb.toString(); } - + /** - * Strips the unwanted chars from a line returned in the CSV + * Strips the unwanted chars from a line returned in the CSV * Used for parsing the FX CSV lines - * - * @param line the original CSV line - * @return the stripped line + * + * @param line the original CSV line + * @return the stripped line */ public static String stripOverhead(String line) { return line.replaceAll("\"", ""); } - + public static String unescape(String data) { StringBuilder buffer = new StringBuilder(data.length()); for (int i = 0; i < data.length(); i++) { diff --git a/src/yahoofinance/quotes/fx/FxQuote.java b/src/yahoofinance/quotes/fx/FxQuote.java index 4974854..54c5157 100644 --- a/src/yahoofinance/quotes/fx/FxQuote.java +++ b/src/yahoofinance/quotes/fx/FxQuote.java @@ -14,7 +14,7 @@ public class FxQuote { public FxQuote(String symbol) { this.symbol = symbol; - this.price = new BigDecimal(0); + this.price = BigDecimal.ZERO; } public FxQuote(String symbol, BigDecimal price) { @@ -37,8 +37,7 @@ public void setSymbol(String symbol) { * @return the requested FX rate */ public BigDecimal getPrice() { - final BigDecimal zero = new BigDecimal(0); - if(price.equals(zero)) { + if(price.equals(BigDecimal.ZERO)) { return this.getPrice(true); } return price; From c72cfc1d71d1ab4fdffe7e836b2a9f1630efd467 Mon Sep 17 00:00:00 2001 From: Stijn Strickx Date: Sun, 15 Feb 2015 18:07:49 +0100 Subject: [PATCH 4/4] Fixed issue with percentage getPercent was just returning the fraction, instead of the value in percentage (x 100) --- src/yahoofinance/Utils.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/yahoofinance/Utils.java b/src/yahoofinance/Utils.java index f2184d0..cb9913b 100644 --- a/src/yahoofinance/Utils.java +++ b/src/yahoofinance/Utils.java @@ -17,6 +17,11 @@ */ public class Utils { + public static final BigDecimal HUNDRED = new BigDecimal(100); + public static final BigDecimal THOUSAND = new BigDecimal(1000); + public static final BigDecimal MILLION = new BigDecimal(1000000); + public static final BigDecimal BILLION = new BigDecimal(1000000000); + public static String join(String[] data, String d) { if (data.length == 0) { return ""; @@ -50,15 +55,15 @@ public static BigDecimal getBigDecimal(String data) { switch (lastChar) { case 'B': data = data.substring(0, data.length() - 1); - multiplier = new BigDecimal(1000000000); + multiplier = BILLION; break; case 'M': data = data.substring(0, data.length() - 1); - multiplier = new BigDecimal(1000000); + multiplier = MILLION; break; case 'K': data = data.substring(0, data.length() - 1); - multiplier = new BigDecimal(1000); + multiplier = THOUSAND; break; } result = new BigDecimal(data).multiply(multiplier); @@ -130,14 +135,15 @@ public static BigDecimal getPercent(BigDecimal numerator, BigDecimal denominator if (denominator.equals(BigDecimal.ZERO)) { return BigDecimal.ZERO; } - return numerator.divide(denominator, 2, BigDecimal.ROUND_HALF_UP); + return numerator.divide(denominator, 4, BigDecimal.ROUND_HALF_EVEN) + .multiply(HUNDRED).setScale(2, BigDecimal.ROUND_HALF_EVEN); } - + public static double getPercent(double numerator, double denominator) { if (denominator == 0) { return 0; } - return numerator / denominator; + return (numerator / denominator) * 100; } private static String getDividendDateFormat(String date) {