org.pau.assetmanager.viewmodel.stocks.StocksUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.pau.assetmanager.viewmodel.stocks.StocksUtils.java

Source

/**
 * This file is part of Pau's Asset Manager Project.
 *
 * Pau's Asset Manager Project is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Pau's Asset Manager Project is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Pau's Asset Manager Project.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.pau.assetmanager.viewmodel.stocks;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.pau.assetmanager.entities.Annotation;
import org.pau.assetmanager.entities.Book;
import org.pau.assetmanager.entities.StockExpensesAnnotation;
import org.pau.assetmanager.entities.StockIncomeAnnotation;

/**
 * @author Pau Carr Cardona
 */

public class StocksUtils {

    public static List<StockIncomeDescription> getStockIncomeDescriptionList(List<Annotation> annotations) {
        StocksHistory stocksHistoryMap = getStocksHistory(annotations);
        List<StockIncomeDescription> stockIncomeDescriptions = new LinkedList<StockIncomeDescription>();
        for (Set<StockIncomeDescription> currentDescriptions : stocksHistoryMap.getStocksHistoryMap().values()) {
            stockIncomeDescriptions.addAll(currentDescriptions);
        }
        return stockIncomeDescriptions;
    }

    public static StocksHistory getStocksHistory(List<Annotation> annotations) {
        Map<String, StocksIncomeError> stocksErrorsHistoryMap = new HashMap<String, StocksIncomeError>();
        Map<String, List<Annotation>> conceptToListOfAnnotationsForStocksBooks = getConceptToListOfAnnotationsForStocksBooks(
                annotations);
        Map<String, Set<StockIncomeDescription>> conceptToStockHistoryMap = new HashMap<String, Set<StockIncomeDescription>>();
        for (String concept : conceptToListOfAnnotationsForStocksBooks.keySet()) {
            Set<StockIncomeDescription> stockHistory = new HashSet<StockIncomeDescription>();
            List<StocksBuySubtransaction> stocksBuySubtransactionList = new LinkedList<StocksBuySubtransaction>();
            List<Annotation> currentListOfAnnotations = conceptToListOfAnnotationsForStocksBooks.get(concept);
            Collections.sort(currentListOfAnnotations, new Comparator<Annotation>() {
                @Override
                public int compare(Annotation o1, Annotation o2) {
                    return o1.getDate().compareTo(o2.getDate());
                }
            });
            boolean errorInConcept = false;
            for (Iterator<Annotation> annotationIterator = currentListOfAnnotations.iterator(); annotationIterator
                    .hasNext() && !errorInConcept;) {
                Annotation annotation = annotationIterator.next();
                // if there a purchase stock transaction then we create its subtransaction
                // For a purchase stock the subtransaction is the same as the transaction initially
                // but it can then be splited depending on the sold stocks.
                if (annotation instanceof StockExpensesAnnotation) {
                    StockExpensesAnnotation stockExpensesAnnotation = (StockExpensesAnnotation) annotation;
                    stocksBuySubtransactionList.add(new StocksBuySubtransaction(stockExpensesAnnotation));
                } else if (annotation instanceof StockIncomeAnnotation) {
                    // if there a sell stock transaction then we compute the previous purchase
                    // stock transactions related in order to fulfill the amount of
                    // stocks sold
                    StockIncomeAnnotation stockIncomeAnnotation = (StockIncomeAnnotation) annotation;
                    // iterate through all the previously buy subtransactions and divide them 
                    // or take their totality of stocks in order to fill the amount of sold stocks
                    Map<StocksBuySubtransaction, Long> stocksBuySubtransactionToStocksNeededMap = splitBuyStockTransaction(
                            stockIncomeAnnotation, stocksBuySubtransactionList);
                    Long numberOfStoksUsed = sum(stocksBuySubtransactionToStocksNeededMap.values());
                    Long additionalNecessaryStocks = stockIncomeAnnotation.getNumberOfStocks() - numberOfStoksUsed;
                    // if there are no longer stocks necessary to buy in order to 
                    // sell the stock then the transaction is consistent and we can create it
                    if (additionalNecessaryStocks == 0L) {
                        Set<StocksBuySubtransaction> stocksBuySubtransactions = getStocksBuySubtransactions(
                                stocksBuySubtransactionToStocksNeededMap, stocksBuySubtransactionList);
                        stockHistory
                                .add(new StockIncomeDescription(stockIncomeAnnotation, stocksBuySubtransactions));
                    } else {
                        // if there are not enough stocks bought to make the sell operation
                        // there is an inconsistency in the sequences of transactions
                        errorInConcept = true;
                        StocksIncomeError stocksIncomeError = new StocksIncomeError(stockIncomeAnnotation,
                                stocksBuySubtransactionToStocksNeededMap, additionalNecessaryStocks);
                        stocksErrorsHistoryMap.put(concept, stocksIncomeError);
                    }
                }
            }
            if (!errorInConcept) {
                conceptToStockHistoryMap.put(concept, stockHistory);
            }
        }

        return new StocksHistory(conceptToStockHistoryMap, stocksErrorsHistoryMap);
    }

    private static Long sum(Collection<Long> values) {
        Long sum = 0L;
        for (Long currentValue : values) {
            sum += currentValue;
        }
        return sum;
    }

    private static Map<StocksBuySubtransaction, Long> splitBuyStockTransaction(
            StockIncomeAnnotation stockIncomeAnnotation,
            List<StocksBuySubtransaction> stocksBuySubtransactionList) {
        Long stocksNeeded = stockIncomeAnnotation.getNumberOfStocks();
        Map<StocksBuySubtransaction, Long> stocksBuySubtransactionToStocksNeededMap = new HashMap<StocksBuySubtransaction, Long>();
        for (Iterator<StocksBuySubtransaction> stocksBuySubtransactionIterator = stocksBuySubtransactionList
                .iterator(); stocksBuySubtransactionIterator.hasNext() && stocksNeeded > 0;) {
            StocksBuySubtransaction stocksBuySubtransaction = stocksBuySubtransactionIterator.next();
            if (stocksBuySubtransaction.getNumberOfStocks() >= stocksNeeded) {
                stocksBuySubtransactionToStocksNeededMap.put(stocksBuySubtransaction, stocksNeeded);
                stocksNeeded = 0L;
            } else {
                stocksBuySubtransactionToStocksNeededMap.put(stocksBuySubtransaction,
                        stocksBuySubtransaction.getNumberOfStocks());
                stocksNeeded -= stocksBuySubtransaction.getNumberOfStocks();
            }
        }
        return stocksBuySubtransactionToStocksNeededMap;
    }

    private static Set<StocksBuySubtransaction> getStocksBuySubtransactions(
            Map<StocksBuySubtransaction, Long> stocksBuySubtransactionToStocksNeededMap,
            List<StocksBuySubtransaction> stocksBuySubtransactionList) {
        Set<StocksBuySubtransaction> stocksBuySubtransactions = new HashSet<StocksBuySubtransaction>();
        for (StocksBuySubtransaction currentBuyTransaction : stocksBuySubtransactionToStocksNeededMap.keySet()) {
            Long stocksTaken = stocksBuySubtransactionToStocksNeededMap.get(currentBuyTransaction);
            stocksBuySubtransactions.add(
                    new StocksBuySubtransaction(currentBuyTransaction.getStockExpensesAnnotation(), stocksTaken));
            stocksBuySubtransactionList.remove(currentBuyTransaction);
            stocksBuySubtransactionList
                    .add(new StocksBuySubtransaction(currentBuyTransaction.getStockExpensesAnnotation(),
                            currentBuyTransaction.getNumberOfStocks() - stocksTaken));
        }
        return stocksBuySubtransactions;
    }

    public static Map<String, StockConceptPerformance> getStocksConceptToProfitLimitedToNumberOfSoldSlocks(
            List<Annotation> annotations) {
        Map<String, StockConceptPerformance> conceptToStockConceptPerformanceMap = new HashMap<String, StockConceptPerformance>();
        Map<String, Set<StockIncomeDescription>> stocksHistoryMap = getStocksHistory(annotations)
                .getStocksHistoryMap();
        for (String concept : stocksHistoryMap.keySet()) {
            Set<StockIncomeDescription> stockIncomeDescriptions = stocksHistoryMap.get(concept);
            if (stockIncomeDescriptions.size() > 0) {
                StockConceptPerformance stockConceptPerformance = getStockConceptPerformance(
                        stockIncomeDescriptions);
                conceptToStockConceptPerformanceMap.put(concept, stockConceptPerformance);
            }
        }
        return conceptToStockConceptPerformanceMap;
    }

    public static StockConceptPerformance getStockConceptPerformance(
            Collection<StockIncomeDescription> stockIncomeDescriptionList) {
        Double profits = 0.0;
        Date lastSoldDate = null;
        Book book = null;
        Long numberOfStocks = 0L;
        String concept = null;
        Validate.notEmpty(stockIncomeDescriptionList, "The StockIncomeDescriptionList cannot be empty");
        Set<StockExpensesAnnotation> stocksBoughtSet = new HashSet<StockExpensesAnnotation>();
        for (StockIncomeDescription stockIncomeDescription : stockIncomeDescriptionList) {
            StockIncomeAnnotation stockIncomeAnnotation = stockIncomeDescription.getStockIncomeAnnotation();
            numberOfStocks += stockIncomeAnnotation.getNumberOfStocks();
            profits += stockIncomeAnnotation.getAmount();
            for (StocksBuySubtransaction stocksBuySubtransaction : stockIncomeDescription
                    .getStocksBuySubtransactionSet()) {
                profits -= (stocksBuySubtransaction.getNumberOfStocks()
                        * stocksBuySubtransaction.getPricePerStock());
                stocksBoughtSet.add(stocksBuySubtransaction.getStockExpensesAnnotation());
            }
            if (lastSoldDate == null) {
                lastSoldDate = stockIncomeAnnotation.getDate();
            } else if (lastSoldDate.before(stockIncomeAnnotation.getDate())) {
                lastSoldDate = stockIncomeAnnotation.getDate();
            }
            book = stockIncomeAnnotation.getBook();
            concept = stockIncomeAnnotation.getConcept();
        }
        Long numberOfStocksBought = 0L;
        for (StockExpensesAnnotation stockExpensesAnnotation : stocksBoughtSet) {
            numberOfStocksBought += stockExpensesAnnotation.getNumberOfStocks();
        }
        StockConceptPerformance stockConceptPerformance = new StockConceptPerformance(profits,
                (numberOfStocks.doubleValue() / numberOfStocksBought.doubleValue()) * 100.0, concept,
                numberOfStocks, lastSoldDate, book);
        return stockConceptPerformance;
    }

    private static Map<String, List<Annotation>> getConceptToListOfAnnotationsForStocksBooks(
            List<Annotation> annotations) {

        Map<String, List<Annotation>> conceptToAnnotationMap = new HashMap<String, List<Annotation>>();
        for (Annotation annotation : annotations) {
            List<Annotation> annotationsForMap = conceptToAnnotationMap.get(annotation.getConcept());
            if (annotationsForMap == null) {
                annotationsForMap = new LinkedList<Annotation>();
                Boolean hasStocks = false;
                if (annotation instanceof StockIncomeAnnotation) {
                    StockIncomeAnnotation stockIncomeAnnotation = (StockIncomeAnnotation) annotation;
                    hasStocks = stockIncomeAnnotation.getNumberOfStocks() > 0;
                } else if (annotation instanceof StockExpensesAnnotation) {
                    StockExpensesAnnotation stockExpensesAnnotation = (StockExpensesAnnotation) annotation;
                    hasStocks = stockExpensesAnnotation.getNumberOfStocks() > 0;
                }
                if (hasStocks) {
                    conceptToAnnotationMap.put(annotation.getConcept(), annotationsForMap);
                }
            }
            annotationsForMap.add(annotation);
        }
        return conceptToAnnotationMap;
    }
}