package hirondelle.stocks.quotes;
import java.math.BigDecimal;
import hirondelle.stocks.util.HashCodeUtil;
import hirondelle.stocks.util.EqualsUtil;
import hirondelle.stocks.util.Util;
import hirondelle.stocks.util.Consts;
public final class Quote {
public Quote(Stock aStock, BigDecimal aCurrentPrice, BigDecimal aChange) {
fStock = aStock;
fCurrentPrice = aCurrentPrice;
fChange = aChange;
validateState();
}
public BigDecimal getPercentChange(){
BigDecimal result = new BigDecimal("0.00");
if( ! Util.isZeroMoney(getPrice()) ){
result = getChange().divide(getOpeningPrice(), EXTRA_DECIMALS, ROUNDING_MODE);
result = rounded(result.multiply(HUNDRED));
}
return result;
}
public BigDecimal getCurrentValue(){
BigDecimal numShares = new BigDecimal( getStock().getNumShares().toString() );
return numShares.multiply( getPrice() );
}
public BigDecimal getProfit(){
return getCurrentValue().subtract( getStock().getBookValue() );
}
public BigDecimal getPercentProfit(){
BigDecimal result = new BigDecimal("0.00");
BigDecimal bookValue = getStock().getBookValue();
if ( ! Util.isZeroMoney(bookValue) && ! Util.isZeroMoney(getPrice()) ) {
result = getProfit().divide(bookValue, EXTRA_DECIMALS, ROUNDING_MODE);
result = rounded(result.multiply(HUNDRED));
}
return result;
}
public Stock getStock() {
return fStock;
}
public BigDecimal getPrice() {
return fCurrentPrice;
}
public BigDecimal getChange() {
return fChange;
}
@Override public String toString() {
StringBuilder result = new StringBuilder();
String newLine = System.getProperty("line.separator");
result.append( this.getClass().getName() );
result.append(" {");
result.append(newLine);
result.append("Stock: ").append(fStock).append(newLine);
result.append("Opening Price: ").append(getOpeningPrice()).append(newLine);
result.append("Current Price: ").append(fCurrentPrice).append(newLine);
result.append("Change: ").append(fChange).append(newLine);
result.append("%Change: ").append(getPercentChange()).append(newLine);
result.append("%Profit: ").append(getPercentProfit()).append(newLine);
result.append("}");
result.append(newLine);
return result.toString();
}
@Override public boolean equals(Object aThat) {
if ( this == aThat ) return true;
if ( !(aThat instanceof Quote) ) return false;
Quote that = (Quote)aThat;
return
EqualsUtil.areEqual(this.fStock, that.fStock) &&
EqualsUtil.areEqual(this.fCurrentPrice, that.fCurrentPrice) &&
EqualsUtil.areEqual(this.fChange, that.fChange)
;
}
@Override public int hashCode() {
int result = HashCodeUtil.SEED;
result = HashCodeUtil.hash(result, fStock);
result = HashCodeUtil.hash(result, fCurrentPrice);
result = HashCodeUtil.hash(result, fChange);
return result;
}
private final Stock fStock;
private final BigDecimal fCurrentPrice;
private final BigDecimal fChange;
private static final int DECIMALS = 2;
private static int EXTRA_DECIMALS = 4;
private static final int ROUNDING_MODE = BigDecimal.ROUND_HALF_EVEN;
private static BigDecimal HUNDRED = new BigDecimal("100");
private static final BigDecimal ZERO = Consts.ZERO_MONEY_WITH_DECIMAL;
private void validateState() {
boolean hasValidState =
(fStock!=null) &&
(fCurrentPrice!=null && fCurrentPrice.compareTo(ZERO) >= 0) &&
(fChange!=null)
;
if ( !hasValidState ) throw new IllegalArgumentException(this.toString());
}
private BigDecimal getOpeningPrice(){
return getPrice().subtract( getChange() );
}
private BigDecimal rounded(BigDecimal aNumber){
return aNumber.setScale(DECIMALS, ROUNDING_MODE);
}
private static void main(String... aArgs){
Exchange NYSE = Exchange.valueFrom("NYSE Stock Exchanges");
Stock stock = new Stock("Blah", "BLA", NYSE, 122, new BigDecimal("88"));
Quote quote = new Quote(stock, new BigDecimal("118.53"), new BigDecimal("-0.17"));
System.out.println(quote);
}
}