MoneyWiseAnalysisSecurityBucket.java
/*
* MoneyWise: Finance Application
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
import io.github.tonywasher.joceanus.metis.data.MetisDataFieldValue;
import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldTableItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.metis.list.MetisListIndexed;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataSet;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseExchangeRate.MoneyWiseExchangeRateDataMap;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityHolding;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityPrice.MoneyWiseSecurityPriceDataMap;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityType;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.base.MoneyWiseAnalysisHistory;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisSecurityAttr;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisSecurityValues;
import java.util.Currency;
import java.util.Iterator;
import java.util.List;
/**
* The Security Bucket class.
*/
public final class MoneyWiseAnalysisSecurityBucket
implements MetisFieldTableItem {
/**
* Local Report fields.
*/
private static final MetisFieldSet<MoneyWiseAnalysisSecurityBucket> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseAnalysisSecurityBucket.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.ANALYSIS_NAME, MoneyWiseAnalysisSecurityBucket::getAnalysis);
FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.ASSETTYPE_SECURITYHOLDING, MoneyWiseAnalysisSecurityBucket::getSecurityHolding);
FIELD_DEFS.declareLocalField(MoneyWiseStaticDataType.SECURITYTYPE, MoneyWiseAnalysisSecurityBucket::getSecurityType);
FIELD_DEFS.declareLocalField(MoneyWiseStaticDataType.CURRENCY, MoneyWiseAnalysisSecurityBucket::getCurrency);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.BUCKET_BASEVALUES, MoneyWiseAnalysisSecurityBucket::getBaseValues);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.BUCKET_HISTORY, MoneyWiseAnalysisSecurityBucket::getHistoryMap);
FIELD_DEFS.declareLocalFieldsForEnum(MoneyWiseAnalysisSecurityAttr.class, MoneyWiseAnalysisSecurityBucket::getAttributeValue);
}
/**
* The analysis.
*/
private final MoneyWiseAnalysis theAnalysis;
/**
* The security holding.
*/
private final MoneyWiseSecurityHolding theHolding;
/**
* The security.
*/
private final MoneyWiseSecurity theSecurity;
/**
* The portfolio.
*/
private final MoneyWisePortfolio thePortfolio;
/**
* The currency.
*/
private final MoneyWiseCurrency theCurrency;
/**
* Is this a foreign currency?
*/
private final Boolean isForeignCurrency;
/**
* The security type.
*/
private final MoneyWiseSecurityType theCategory;
/**
* Values.
*/
private final MoneyWiseAnalysisSecurityValues theValues;
/**
* The base values.
*/
private final MoneyWiseAnalysisSecurityValues theBaseValues;
/**
* History Map.
*/
private final MoneyWiseAnalysisHistory<MoneyWiseAnalysisSecurityValues, MoneyWiseAnalysisSecurityAttr> theHistory;
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pHolding the security holding
*/
MoneyWiseAnalysisSecurityBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseSecurityHolding pHolding) {
/* Store the details */
theHolding = pHolding;
theCurrency = pHolding.getAssetCurrency();
theSecurity = pHolding.getSecurity();
thePortfolio = pHolding.getPortfolio();
theAnalysis = pAnalysis;
/* Obtain category */
theCategory = theSecurity.getCategory();
/* Determine currency */
final MoneyWiseCurrency myReportingCurrency = pAnalysis.getCurrency();
final MoneyWiseCurrency myHoldingCurrency = pHolding.getAssetCurrency();
/* Determine whether we are a foreign currency */
isForeignCurrency = !MetisDataDifference.isEqual(myReportingCurrency, myHoldingCurrency);
final Currency myCurrency = MoneyWiseAnalysisAccountBucket.deriveCurrency(myHoldingCurrency);
final Currency myRepCurrency = MoneyWiseAnalysisAccountBucket.deriveCurrency(myReportingCurrency);
/* Create the history map */
final MoneyWiseAnalysisSecurityValues myValues = Boolean.TRUE.equals(isForeignCurrency)
? new MoneyWiseAnalysisSecurityValues(myCurrency, myRepCurrency)
: new MoneyWiseAnalysisSecurityValues(myCurrency);
theHistory = new MoneyWiseAnalysisHistory<>(myValues);
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pBase the underlying bucket
*/
private MoneyWiseAnalysisSecurityBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisSecurityBucket pBase) {
/* Copy details from base */
theHolding = pBase.getSecurityHolding();
theCurrency = pBase.getCurrency();
theSecurity = pBase.getSecurity();
thePortfolio = pBase.getPortfolio();
theCategory = pBase.getSecurityType();
theAnalysis = pAnalysis;
isForeignCurrency = pBase.isForeignCurrency();
/* Access the relevant history */
theHistory = new MoneyWiseAnalysisHistory<>(pBase.getHistoryMap());
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pBase the underlying bucket
* @param pDate the date for the bucket
*/
private MoneyWiseAnalysisSecurityBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisSecurityBucket pBase,
final OceanusDate pDate) {
/* Copy details from base */
theHolding = pBase.getSecurityHolding();
theCurrency = pBase.getCurrency();
theSecurity = pBase.getSecurity();
thePortfolio = pBase.getPortfolio();
theCategory = pBase.getSecurityType();
theAnalysis = pAnalysis;
isForeignCurrency = pBase.isForeignCurrency();
/* Access the relevant history */
theHistory = new MoneyWiseAnalysisHistory<>(pBase.getHistoryMap(), pDate);
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pBase the underlying bucket
* @param pRange the range for the bucket
*/
private MoneyWiseAnalysisSecurityBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisSecurityBucket pBase,
final OceanusDateRange pRange) {
/* Copy details from base */
theHolding = pBase.getSecurityHolding();
theCurrency = pBase.getCurrency();
theSecurity = pBase.getSecurity();
thePortfolio = pBase.getPortfolio();
theCategory = pBase.getSecurityType();
theAnalysis = pAnalysis;
isForeignCurrency = pBase.isForeignCurrency();
/* Access the relevant history */
theHistory = new MoneyWiseAnalysisHistory<>(pBase.getHistoryMap(), pRange);
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
@Override
public MetisFieldSet<MoneyWiseAnalysisSecurityBucket> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return toString();
}
@Override
public String toString() {
return getDecoratedName();
}
/**
* Obtain the name.
*
* @return the name
*/
public String getSecurityName() {
return theSecurity.getName();
}
/**
* Obtain the decorated name.
*
* @return the decorated name
*/
public String getDecoratedName() {
return theHolding.getName();
}
/**
* Obtain the holding.
*
* @return the holding
*/
public MoneyWiseSecurityHolding getSecurityHolding() {
return theHolding;
}
/**
* Obtain the security.
*
* @return the security
*/
public MoneyWiseSecurity getSecurity() {
return theSecurity;
}
/**
* Obtain the portfolio.
*
* @return the portfolio
*/
public MoneyWisePortfolio getPortfolio() {
return thePortfolio;
}
/**
* Obtain the currency.
*
* @return the currency
*/
public MoneyWiseCurrency getCurrency() {
return theCurrency;
}
/**
* Is this a foreign currency?
*
* @return true/false
*/
public Boolean isForeignCurrency() {
return isForeignCurrency;
}
@Override
public Integer getIndexedId() {
return theSecurity.getIndexedId();
}
/**
* Obtain the security type.
*
* @return the security type
*/
public MoneyWiseSecurityType getSecurityType() {
return theCategory;
}
/**
* Is this bucket idle?
*
* @return true/false
*/
public Boolean isIdle() {
return theHistory.isIdle();
}
/**
* Obtain the analysis.
*
* @return the analysis
*/
MoneyWiseAnalysis getAnalysis() {
return theAnalysis;
}
/**
* Obtain date range.
*
* @return the range
*/
public OceanusDateRange getDateRange() {
return theAnalysis.getDateRange();
}
/**
* Obtain the value map.
*
* @return the value map
*/
public MoneyWiseAnalysisSecurityValues getValues() {
return theValues;
}
/**
* Obtain the base value map.
*
* @return the base value map
*/
public MoneyWiseAnalysisSecurityValues getBaseValues() {
return theBaseValues;
}
/**
* Obtain values for transaction.
*
* @param pTrans the transaction
* @return the values (or null)
*/
public MoneyWiseAnalysisSecurityValues getValuesForTransaction(final MoneyWiseTransaction pTrans) {
return theHistory.getValuesForTransaction(pTrans);
}
/**
* Obtain previous values for transaction.
*
* @param pTrans the transaction
* @return the values (or null)
*/
public MoneyWiseAnalysisSecurityValues getPreviousValuesForTransaction(final MoneyWiseTransaction pTrans) {
return theHistory.getPreviousValuesForTransaction(pTrans);
}
/**
* Obtain delta for transaction.
*
* @param pTrans the transaction
* @param pAttr the attribute
* @return the delta (or null)
*/
public OceanusDecimal getDeltaForTransaction(final MoneyWiseTransaction pTrans,
final MoneyWiseAnalysisSecurityAttr pAttr) {
/* Obtain delta for transaction */
return theHistory.getDeltaValue(pTrans, pAttr);
}
/**
* Obtain money delta for transaction.
*
* @param pTrans the transaction
* @param pAttr the attribute
* @return the delta (or null)
*/
public OceanusMoney getMoneyDeltaForTransaction(final MoneyWiseTransaction pTrans,
final MoneyWiseAnalysisSecurityAttr pAttr) {
/* Obtain delta for transaction */
return theHistory.getDeltaMoneyValue(pTrans, pAttr);
}
/**
* Obtain units delta for transaction.
*
* @param pTrans the transaction
* @param pAttr the attribute
* @return the delta (or null)
*/
public OceanusUnits getUnitsDeltaForTransaction(final MoneyWiseTransaction pTrans,
final MoneyWiseAnalysisSecurityAttr pAttr) {
/* Obtain delta for transaction */
return theHistory.getDeltaUnitsValue(pTrans, pAttr);
}
/**
* Obtain the history map.
*
* @return the history map
*/
private MoneyWiseAnalysisHistory<MoneyWiseAnalysisSecurityValues, MoneyWiseAnalysisSecurityAttr> getHistoryMap() {
return theHistory;
}
/**
* Set Attribute.
*
* @param pAttr the attribute
* @param pValue the value of the attribute
*/
public void setValue(final MoneyWiseAnalysisSecurityAttr pAttr,
final Object pValue) {
/* Set the value into the list */
theValues.setValue(pAttr, pValue);
}
/**
* Get an attribute value.
*
* @param pAttr the attribute
* @return the value to set
*/
private Object getAttributeValue(final MoneyWiseAnalysisSecurityAttr pAttr) {
/* Access value of object */
final Object myValue = getAttribute(pAttr);
/* Return the value */
return myValue != null
? myValue
: MetisDataFieldValue.SKIP;
}
/**
* Obtain an attribute value.
*
* @param pAttr the attribute
* @return the value of the attribute or null
*/
private Object getAttribute(final MoneyWiseAnalysisSecurityAttr pAttr) {
/* Obtain the value */
return theValues.getValue(pAttr);
}
/**
* Adjust counter.
*
* @param pAttr the attribute
* @param pDelta the delta
*/
public void adjustCounter(final MoneyWiseAnalysisSecurityAttr pAttr,
final OceanusMoney pDelta) {
OceanusMoney myValue = theValues.getMoneyValue(pAttr);
myValue = new OceanusMoney(myValue);
myValue.addAmount(pDelta);
setValue(pAttr, myValue);
}
/**
* Adjust counter.
*
* @param pAttr the attribute
* @param pDelta the delta
*/
public void adjustCounter(final MoneyWiseAnalysisSecurityAttr pAttr,
final OceanusUnits pDelta) {
OceanusUnits myValue = theValues.getUnitsValue(pAttr);
myValue = new OceanusUnits(myValue);
myValue.addUnits(pDelta);
setValue(pAttr, myValue);
}
/**
* Register the transaction.
*
* @param pHelper the helper
* @return the registered values
*/
public MoneyWiseAnalysisSecurityValues registerTransaction(final MoneyWiseAnalysisTransactionHelper pHelper) {
/* Register the event in the history */
return theHistory.registerTransaction(pHelper.getTransaction(), theValues);
}
/**
* value the asset for a particular range.
*
* @param pRange the range of valuation
*/
private void valueAsset(final OceanusDateRange pRange) {
/* Obtain the appropriate price */
final MoneyWiseDataSet myData = theAnalysis.getData();
final MoneyWiseSecurityPriceDataMap myPriceMap = myData.getSecurityPriceDataMap();
final OceanusPrice[] myPrices = myPriceMap.getPricesForRange(theSecurity, pRange);
/* Access base units */
OceanusUnits myUnits = theBaseValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
OceanusPrice myPrice = myPrices[0];
/* Calculate the value */
theBaseValues.setValue(MoneyWiseAnalysisSecurityAttr.PRICE, myPrice);
theBaseValues.setValue(MoneyWiseAnalysisSecurityAttr.VALUATION, myUnits.valueAtPrice(myPrice));
/* Access units */
myUnits = theValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
myPrice = myPrices[1];
/* Calculate the value */
setValue(MoneyWiseAnalysisSecurityAttr.PRICE, myPrice);
setValue(MoneyWiseAnalysisSecurityAttr.VALUATION, myUnits.valueAtPrice(myPrice));
}
/**
* value the foreign asset for a particular range.
*
* @param pRange the range of valuation
*/
private void valueForeignAsset(final OceanusDateRange pRange) {
/* Obtain the appropriate price */
final MoneyWiseDataSet myData = theAnalysis.getData();
final MoneyWiseSecurityPriceDataMap myPriceMap = myData.getSecurityPriceDataMap();
final OceanusPrice[] myPrices = myPriceMap.getPricesForRange(theSecurity, pRange);
final MoneyWiseExchangeRateDataMap myRateMap = myData.getExchangeRateDataMap();
final OceanusRatio[] myRates = myRateMap.getRatesForRange(theSecurity.getAssetCurrency(), pRange);
final Currency myCurrency = theAnalysis.getCurrency().getCurrency();
/* Access base units */
OceanusUnits myUnits = theBaseValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
OceanusPrice myPrice = myPrices[0];
OceanusRatio myRate = myRates[0];
/* Calculate the value */
OceanusMoney myValue = myUnits.valueAtPrice(myPrice);
OceanusMoney myLocalValue = myValue.convertCurrency(myCurrency, myRate);
/* Record it */
theBaseValues.setValue(MoneyWiseAnalysisSecurityAttr.PRICE, myPrice);
theBaseValues.setValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUE, myValue);
theBaseValues.setValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE, myRate);
theBaseValues.setValue(MoneyWiseAnalysisSecurityAttr.VALUATION, myLocalValue);
/* Access units */
myUnits = theValues.getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
myPrice = myPrices[1];
myRate = myRates[1];
/* Calculate the value */
myValue = myUnits.valueAtPrice(myPrice);
myLocalValue = myValue.convertCurrency(myCurrency, myRate);
/* Record it */
setValue(MoneyWiseAnalysisSecurityAttr.PRICE, myPrice);
setValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE, myRate);
setValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUE, myValue);
setValue(MoneyWiseAnalysisSecurityAttr.VALUATION, myLocalValue);
}
/**
* calculate the profit for a priced asset.
*/
private void calculateProfit() {
/* Calculate the profit */
final OceanusMoney myValuation = theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA);
final OceanusMoney myProfit = new OceanusMoney(myValuation);
myProfit.subtractAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.INVESTED));
myProfit.addAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.DIVIDEND));
myProfit.addAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.GROWTHADJUST));
/* Set the attribute */
setValue(MoneyWiseAnalysisSecurityAttr.PROFIT, myProfit);
/* Calculate the profit minus the dividend */
final OceanusMoney myMarketProfit = new OceanusMoney(myProfit);
myMarketProfit.subtractAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.DIVIDEND));
setValue(MoneyWiseAnalysisSecurityAttr.MARKETPROFIT, myMarketProfit);
}
/**
* calculate the deltas for a priced asset.
*/
private void calculateDeltas() {
/* Obtain a copy of the value */
OceanusMoney myValue = theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION);
myValue = new OceanusMoney(myValue);
/* Subtract any base value */
myValue.subtractAmount(theBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUATION));
/* Set the delta */
setValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA, myValue);
if (Boolean.TRUE.equals(isForeignCurrency)) {
/* Obtain a copy of the value */
myValue = theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUE);
myValue = new OceanusMoney(myValue);
/* Subtract any base value */
myValue.subtractAmount(theBaseValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUE));
/* Set the delta */
setValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUEDELTA, myValue);
}
}
/**
* Analyse the bucket.
*
* @param pRange the range of valuation
*/
void analyseBucket(final OceanusDateRange pRange) {
/* Value the asset over the range */
if (Boolean.TRUE.equals(isForeignCurrency)) {
valueForeignAsset(pRange);
} else {
valueAsset(pRange);
}
/* Calculate the deltas */
calculateDeltas();
/* Calculate the profit */
calculateProfit();
/* Calculate the market movement */
if (Boolean.TRUE.equals(isForeignCurrency)) {
calculateForeignMarket();
} else {
calculateMarket();
}
}
/**
* Adjust to base.
*/
void adjustToBase() {
/* Adjust to base values */
theValues.adjustToBaseValues(theBaseValues);
theBaseValues.resetBaseValues();
}
/**
* Calculate market movement.
*/
private void calculateMarket() {
/* Obtain the delta value */
OceanusMoney myValue = theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA);
myValue = new OceanusMoney(myValue);
/* Subtract the investment */
myValue.subtractAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.INVESTED));
/* Set the delta */
setValue(MoneyWiseAnalysisSecurityAttr.MARKETGROWTH, myValue);
}
/**
* Calculate foreign market movement.
*/
private void calculateForeignMarket() {
/* Obtain the local market growth */
OceanusMoney myBaseValue = theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.VALUEDELTA);
myBaseValue = new OceanusMoney(myBaseValue);
/* Subtract the investment */
myBaseValue.subtractAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.INVESTED));
/* Set the basic growth */
setValue(MoneyWiseAnalysisSecurityAttr.LOCALMARKETGROWTH, myBaseValue);
/* Obtain the foreign growth */
OceanusMoney myValue = theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.FOREIGNVALUEDELTA);
myValue = new OceanusMoney(myValue);
/* Subtract the investment */
myValue.subtractAmount(theValues.getMoneyValue(MoneyWiseAnalysisSecurityAttr.FOREIGNINVESTED));
/* Set the foreign growth */
setValue(MoneyWiseAnalysisSecurityAttr.FOREIGNMARKETGROWTH, myValue);
/* Calculate the local equivalent */
final Currency myCurrency = theAnalysis.getCurrency().getCurrency();
final OceanusRatio myRate = theValues.getRatioValue(MoneyWiseAnalysisSecurityAttr.EXCHANGERATE);
myValue = myValue.convertCurrency(myCurrency, myRate);
/* Set the market growth */
setValue(MoneyWiseAnalysisSecurityAttr.MARKETGROWTH, myValue);
/* Calculate the fluctuation */
final OceanusMoney myFluct = new OceanusMoney(myBaseValue);
myFluct.subtractAmount(myValue);
setValue(MoneyWiseAnalysisSecurityAttr.CURRENCYFLUCT, myFluct);
}
/**
* Adjust security for natInsurance payments.
*
* @param pTrans the transaction causing the payments
*/
public void adjustForNIPayments(final MoneyWiseAnalysisTransactionHelper pTrans) {
/* Assume no NatInsurance */
OceanusMoney myAmount = null;
/* Access Employer NatInsurance */
OceanusMoney myNatIns = pTrans.getEmployerNatIns();
if (myNatIns != null
&& myNatIns.isNonZero()) {
myAmount = new OceanusMoney(myNatIns);
}
/* Access Employee natInsurance */
myNatIns = pTrans.getEmployeeNatIns();
if (myNatIns != null
&& myNatIns.isNonZero()) {
if (myAmount == null) {
myAmount = new OceanusMoney(myNatIns);
} else {
myAmount.addAmount(myNatIns);
}
}
/* If we have natInsurance */
if (myAmount != null) {
/* Handle autoUnits */
OceanusUnits myUnits = getValues().getUnitsValue(MoneyWiseAnalysisSecurityAttr.UNITS);
if (myUnits.isZero()) {
myUnits = OceanusUnits.getWholeUnits(theSecurity.getCategoryClass().getAutoUnits());
setValue(MoneyWiseAnalysisSecurityAttr.UNITS, myUnits);
}
/* Adjust invested */
adjustCounter(MoneyWiseAnalysisSecurityAttr.INVESTED, myAmount);
adjustCounter(MoneyWiseAnalysisSecurityAttr.RESIDUALCOST, myAmount);
/* Register the transaction in the history */
registerTransaction(pTrans);
}
}
/**
* Is the bucket active?
*
* @return true/false
*/
public boolean isActive() {
return theValues.isActive();
}
/**
* SecurityBucket list class.
*/
public static final class MoneyWiseAnalysisSecurityBucketList
implements MetisFieldItem, MetisDataList<MoneyWiseAnalysisSecurityBucket> {
/**
* Local Report fields.
*/
private static final MetisFieldSet<MoneyWiseAnalysisSecurityBucketList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseAnalysisSecurityBucketList.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.ANALYSIS_NAME, MoneyWiseAnalysisSecurityBucketList::getAnalysis);
}
/**
* The analysis.
*/
private final MoneyWiseAnalysis theAnalysis;
/**
* The list.
*/
private final MetisListIndexed<MoneyWiseAnalysisSecurityBucket> theList;
/**
* Construct a top-level List.
*
* @param pAnalysis the analysis
*/
MoneyWiseAnalysisSecurityBucketList(final MoneyWiseAnalysis pAnalysis) {
theAnalysis = pAnalysis;
theList = new MetisListIndexed<>();
theList.setComparator((l, r) -> l.getSecurity().compareTo(r.getSecurity()));
}
/**
* Construct a view List.
*
* @param pAnalysis the analysis
* @param pBase the base list
*/
MoneyWiseAnalysisSecurityBucketList(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisSecurityBucketList pBase) {
/* Initialise class */
this(pAnalysis);
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisSecurityBucket> myIterator = pBase.iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisSecurityBucket myCurr = myIterator.next();
/* Access the bucket */
final MoneyWiseAnalysisSecurityBucket myBucket = new MoneyWiseAnalysisSecurityBucket(pAnalysis, myCurr);
/*
* Ignore idle securities. Note that we must include securities that have been
* closed in order to adjust Market Growth.
*/
if (Boolean.FALSE.equals(myBucket.isIdle())) {
/* Add to the list */
theList.add(myBucket);
}
}
}
/**
* Construct a dated List.
*
* @param pAnalysis the analysis
* @param pBase the base list
* @param pDate the Date
*/
MoneyWiseAnalysisSecurityBucketList(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisSecurityBucketList pBase,
final OceanusDate pDate) {
/* Initialise class */
this(pAnalysis);
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisSecurityBucket> myIterator = pBase.iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisSecurityBucket myCurr = myIterator.next();
/* Access the bucket for this date */
final MoneyWiseAnalysisSecurityBucket myBucket = new MoneyWiseAnalysisSecurityBucket(pAnalysis, myCurr, pDate);
/*
* Ignore idle securities. Note that we must include securities that have been
* closed in order to adjust Market Growth.
*/
if (Boolean.FALSE.equals(myBucket.isIdle())) {
/* Add to the list */
theList.add(myBucket);
}
}
}
/**
* Construct a ranged List.
*
* @param pAnalysis the analysis
* @param pBase the base list
* @param pRange the Date Range
*/
MoneyWiseAnalysisSecurityBucketList(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisSecurityBucketList pBase,
final OceanusDateRange pRange) {
/* Initialise class */
this(pAnalysis);
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisSecurityBucket> myIterator = pBase.iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisSecurityBucket myCurr = myIterator.next();
/* Access the bucket for this range */
final MoneyWiseAnalysisSecurityBucket myBucket = new MoneyWiseAnalysisSecurityBucket(pAnalysis, myCurr, pRange);
/* If the bucket is non-idle or active */
if (myBucket.isActive() || Boolean.TRUE.equals(!myBucket.isIdle())) {
/* Adjust to base and add to the list */
myBucket.adjustToBase();
theList.add(myBucket);
}
}
}
@Override
public MetisFieldSet<MoneyWiseAnalysisSecurityBucketList> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public List<MoneyWiseAnalysisSecurityBucket> getUnderlyingList() {
return theList.getUnderlyingList();
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return getDataFieldSet().getName();
}
/**
* Obtain the analysis.
*
* @return the analysis
*/
MoneyWiseAnalysis getAnalysis() {
return theAnalysis;
}
/**
* Obtain item by id.
*
* @param pId the id to lookup
* @return the item (or null if not present)
*/
public MoneyWiseAnalysisSecurityBucket findItemById(final Integer pId) {
/* Return results */
return theList.getItemById(pId);
}
/**
* SortBuckets.
*/
void sortBuckets() {
theList.sortList();
}
/**
* Obtain the SecurityBucket for a given security holding.
*
* @param pHolding the security holding
* @return the bucket
*/
public MoneyWiseAnalysisSecurityBucket getBucket(final MoneyWiseSecurityHolding pHolding) {
/* Locate the bucket in the list */
final MoneyWiseSecurity mySecurity = pHolding.getSecurity();
MoneyWiseAnalysisSecurityBucket myItem = findItemById(mySecurity.getIndexedId());
/* If the item does not yet exist */
if (myItem == null) {
/* Create the new bucket */
myItem = new MoneyWiseAnalysisSecurityBucket(theAnalysis, pHolding);
/* Add to the list */
theList.add(myItem);
}
/* Return the bucket */
return myItem;
}
/**
* Mark active securities.
*
* @return true/false are there active securities?
* @throws OceanusException on error
*/
boolean markActiveSecurities() throws OceanusException {
/* Loop through the buckets */
boolean areActive = false;
final Iterator<MoneyWiseAnalysisSecurityBucket> myIterator = iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisSecurityBucket myCurr = myIterator.next();
final MoneyWiseSecurity mySecurity = myCurr.getSecurity();
/* If we are active */
if (myCurr.isActive()) {
/* Set the security as relevant */
mySecurity.setRelevant();
areActive = true;
}
/* If we are closed */
if (Boolean.TRUE.equals(mySecurity.isClosed())) {
/* Ensure that we have correct closed dates */
mySecurity.adjustClosed();
/* If we are Relevant */
if (mySecurity.isRelevant()
&& theAnalysis.getData().checkClosedAccounts()) {
/* throw exception */
throw new MoneyWiseDataException(myCurr, "Illegally closed security");
}
}
}
/* Return active indication */
return areActive;
}
}
}