MoneyWiseXAnalysisSecurity.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.atlas.data.analysis.analyse;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysis;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisPortfolioBucket.MoneyWiseXAnalysisPortfolioBucketList;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisSecurityBucket;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTaxBasisBucket;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTaxBasisBucket.MoneyWiseXAnalysisTaxBasisBucketList;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTransCategoryBucket;
import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTransCategoryBucket.MoneyWiseXAnalysisTransCategoryBucketList;
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.statics.MoneyWiseSecurityClass;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxClass;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransCategoryClass;
import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseLogicException;
/**
* Security analysis.
*/
public class MoneyWiseXAnalysisSecurity {
/**
* Local Report fields.
*/
private static final String ERROR_CATEGORY = "Unexpected Category Type: ";
/**
* The portfolioBuckets.
*/
private final MoneyWiseXAnalysisPortfolioBucketList thePortfolios;
/**
* The analysis state.
*/
private final MoneyWiseXAnalysisState theState;
/**
* The market analysis.
*/
private final MoneyWiseXAnalysisMarket theMarket;
/**
* The transAnalyser.
*/
private final MoneyWiseXAnalysisTransAnalyser theTransAnalyser;
/**
* The xferIn analysis.
*/
private final MoneyWiseXAnalysisXferIn theXferIn;
/**
* The xferOut analysis.
*/
private final MoneyWiseXAnalysisXferOut theXferOut;
/**
* The dividend analysis.
*/
private final MoneyWiseXAnalysisDividend theDividend;
/**
* The deMerger analysis.
*/
private final MoneyWiseXAnalysisDeMerger theDeMerger;
/**
* The takeover analysis.
*/
private final MoneyWiseXAnalysisTakeover theTakeover;
/**
* The transaction.
*/
private MoneyWiseXAnalysisTransaction theTransaction;
/**
* The capitalGains category.
*/
private final MoneyWiseXAnalysisTransCategoryBucket theCapitalCat;
/**
* The taxFreeGains category.
*/
private final MoneyWiseXAnalysisTransCategoryBucket theTaxFreeCat;
/**
* The residentialGains category.
*/
private final MoneyWiseXAnalysisTransCategoryBucket theResidentialCat;
/**
* The chargeableGains category.
*/
private final MoneyWiseXAnalysisTransCategoryBucket theChargeableCat;
/**
* The capitalGains TaxBasis.
*/
private final MoneyWiseXAnalysisTaxBasisBucket theCapitalTax;
/**
* The taxFreeGains TaxBasis.
*/
private final MoneyWiseXAnalysisTaxBasisBucket theTaxFreeTax;
/**
* The residentialGains TaxBasis.
*/
private final MoneyWiseXAnalysisTaxBasisBucket theResidentialTax;
/**
* The chargeableGains TaxBasis.
*/
private final MoneyWiseXAnalysisTaxBasisBucket theChargeableTax;
/**
* Constructor.
*
* @param pAnalyser the event analyser
* @param pTrans the transAnalyser
* @throws OceanusException on error
*/
MoneyWiseXAnalysisSecurity(final MoneyWiseXAnalysisEventAnalyser pAnalyser,
final MoneyWiseXAnalysisTransAnalyser pTrans) throws OceanusException {
/* Record important classes */
final MoneyWiseXAnalysis myAnalysis = pAnalyser.getAnalysis();
thePortfolios = myAnalysis.getPortfolios();
theState = pAnalyser.getState();
theMarket = pAnalyser.getMarket();
theTransAnalyser = pTrans;
/* Create analysers */
theXferIn = new MoneyWiseXAnalysisXferIn(pAnalyser, this);
theXferOut = new MoneyWiseXAnalysisXferOut(pAnalyser, this);
theDividend = new MoneyWiseXAnalysisDividend(pAnalyser, this);
theDeMerger = new MoneyWiseXAnalysisDeMerger(pAnalyser, this);
theTakeover = new MoneyWiseXAnalysisTakeover(pAnalyser, this);
/* Determine important categoryBuckets */
final MoneyWiseXAnalysisTransCategoryBucketList myCategories = myAnalysis.getTransCategories();
theCapitalCat = myCategories.getBucket(MoneyWiseTransCategoryClass.CAPITALGAIN);
theTaxFreeCat = myCategories.getBucket(MoneyWiseTransCategoryClass.TAXFREEGAIN);
theResidentialCat = myCategories.getBucket(MoneyWiseTransCategoryClass.RESIDENTIALGAIN);
theChargeableCat = myCategories.getBucket(MoneyWiseTransCategoryClass.CHARGEABLEGAIN);
/* Determine important taxBuckets */
final MoneyWiseXAnalysisTaxBasisBucketList myTaxBases = myAnalysis.getTaxBasis();
theCapitalTax = myTaxBases.getBucket(MoneyWiseTaxClass.CAPITALGAINS);
theTaxFreeTax = myTaxBases.getBucket(MoneyWiseTaxClass.TAXFREE);
theResidentialTax = myTaxBases.getBucket(MoneyWiseTaxClass.RESIDENTIALGAINS);
theChargeableTax = myTaxBases.getBucket(MoneyWiseTaxClass.CHARGEABLEGAINS);
}
/**
* Obtain the trans analyser.
*
* @return the transAnalyser
*/
MoneyWiseXAnalysisTransAnalyser getTransAnalyser() {
return theTransAnalyser;
}
/**
* Obtain the xferIn analyser.
*
* @return the xferInAnalyser
*/
MoneyWiseXAnalysisXferIn getXferInAnalyser() {
return theXferIn;
}
/**
* Process a debit security transaction.
*
* @param pTrans the transaction
* @throws OceanusException on error
*/
void processDebitSecurity(final MoneyWiseXAnalysisTransaction pTrans) throws OceanusException {
/* Store transaction */
theTransaction = pTrans;
/* If credit account is also SecurityHolding */
if (MoneyWiseXAnalysisTransAnalyser.isSecurityHolding(theTransaction.getCreditAccount())) {
/* Split out working */
processDebitCreditSecurity();
return;
}
/* Switch on the category */
final MoneyWiseTransCategoryClass myCatClass = theTransaction.getCategoryClass();
switch (myCatClass) {
/* Process a dividend */
case DIVIDEND:
theDividend.processDividend(theTransaction);
break;
/* Process standard transfer in/out */
case TRANSFER:
case SECURITYCLOSURE:
case EXPENSE:
case INHERITED:
case OTHERINCOME:
case STOCKRIGHTSISSUE:
theXferOut.processTransferOut(theTransaction);
break;
/* Throw an Exception */
default:
throw new MoneyWiseLogicException(ERROR_CATEGORY
+ myCatClass);
}
}
/**
* Process a credit security transaction.
*
* @param pTrans the transaction
* @throws OceanusException on error
*/
void processCreditSecurity(final MoneyWiseXAnalysisTransaction pTrans) throws OceanusException {
/* Store transaction */
theTransaction = pTrans;
/* Switch on the category */
final MoneyWiseTransCategoryClass myCatClass = theTransaction.getCategoryClass();
switch (myCatClass) {
/* Process standard transfer in/out */
case STOCKRIGHTSISSUE:
case TRANSFER:
case EXPENSE:
case INHERITED:
case OTHERINCOME:
case PENSIONCONTRIB:
theXferIn.processTransferIn(theTransaction);
break;
/* Throw an Exception */
default:
throw new MoneyWiseLogicException(ERROR_CATEGORY
+ myCatClass);
}
}
/**
* Process a debit+credit security transaction.
*
* @throws OceanusException on error
*/
private void processDebitCreditSecurity() throws OceanusException {
/* Switch on the category */
final MoneyWiseTransCategoryClass myCatClass = theTransaction.getCategoryClass();
switch (myCatClass) {
/* Process a stock split */
case STOCKSPLIT:
case UNITSADJUST:
processUnitsAdjust();
break;
/* Process a stock DeMerger */
case STOCKDEMERGER:
theDeMerger.processStockDeMerger(theTransaction);
break;
/* Process a Stock TakeOver */
case SECURITYREPLACE:
case STOCKTAKEOVER:
theTakeover.processStockTakeover(theTransaction);
break;
/* Process a dividend */
case DIVIDEND:
theDividend.processDividend(theTransaction);
break;
/* Process standard transfer in/out */
case TRANSFER:
processStockXchange();
break;
/* Throw an Exception */
default:
throw new MoneyWiseLogicException(ERROR_CATEGORY
+ myCatClass);
}
}
/**
* adjust Asset Valuation.
*
* @param pAsset the asset
*/
void adjustAssetValuation(final MoneyWiseXAnalysisSecurityBucket pAsset) {
/* Value the asset and calculate unrealised gains */
pAsset.valueAsset();
pAsset.adjustValuation();
pAsset.calculateUnrealisedGains();
/* determine the MarketGrowth */
final OceanusMoney myDeltaValue = pAsset.getDeltaUnrealisedGains();
theMarket.adjustTotalsForMarketGrowth(theTransaction.getEvent(), myDeltaValue);
}
/**
* Adjust for Standard Gains.
*
* @param pSource the source security holding
* @param pGains the gains
*/
void adjustStandardGain(final MoneyWiseSecurityHolding pSource,
final OceanusMoney pGains) {
/* Access security and portfolio */
final MoneyWiseSecurity mySecurity = pSource.getSecurity();
final MoneyWisePortfolio myPortfolio = pSource.getPortfolio();
final MoneyWiseSecurityClass myClass = mySecurity.getCategoryClass();
/* Determine the type of gains */
MoneyWiseXAnalysisTransCategoryBucket myCategory = theCapitalCat;
MoneyWiseXAnalysisTaxBasisBucket myTaxBasis = theCapitalTax;
if (myPortfolio.isTaxFree()) {
myCategory = theTaxFreeCat;
myTaxBasis = theTaxFreeTax;
} else if (myClass.isResidentialGains()) {
myCategory = theResidentialCat;
myTaxBasis = theResidentialTax;
} else if (myClass.isChargeableGains()) {
myCategory = theChargeableCat;
myTaxBasis = theChargeableTax;
}
/* Add to Capital Gains income/expense */
if (pGains.isPositive()) {
myCategory.addIncome(pGains);
} else {
myCategory.subtractExpense(pGains);
}
myTaxBasis.adjustGrossAndNett(pGains);
theMarket.adjustForGains(pGains);
/* Register the buckets */
theState.registerBucketInterest(myCategory);
theState.registerBucketInterest(myTaxBasis);
}
/**
* Process a transaction that is a unitsAdjust.
*/
void processUnitsAdjust() {
/* Access the units */
final OceanusUnits myDelta = theTransaction.getDebitUnitsDelta();
/* Adjust the Security Units */
final MoneyWiseSecurityHolding myHolding = (MoneyWiseSecurityHolding) theTransaction.getDebitAccount();
final MoneyWiseXAnalysisSecurityBucket myAsset = thePortfolios.getBucket(myHolding);
myAsset.adjustUnits(myDelta);
/* Record the price of the asset if we have a price */
final OceanusPrice myPrice = theTransaction.getTransaction().getPrice();
if (myPrice != null) {
/* Record the new price and update the bucket */
theState.setNewPriceViaTransaction(myHolding.getSecurity(), myPrice);
/* update the price and determine the value delta */
myAsset.recordSecurityPrice();
}
/* Adjust the valuation */
adjustAssetValuation(myAsset);
/* Register the transaction */
theState.registerBucketInterest(myAsset);
}
/**
* Process a transaction that is a stockXchange.
*/
void processStockXchange() {
/* Adjust the debit transfer details */
theXferOut.processDebitXferOut(theTransaction);
/* Adjust the credit transfer details */
theXferIn.processCreditXferIn(theTransaction);
}
}