/*
 * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com.
 * 
 * Created on 15.02.2004
 */
package net.finmath.montecarlo.interestrate.products;

import java.util.Set;

import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.RandomVariable;
import net.finmath.montecarlo.interestrate.LIBORModelMonteCarloSimulationInterface;
import net.finmath.montecarlo.interestrate.products.components.AbstractProductComponent;
import net.finmath.stochastic.RandomVariableInterface;

/**
 * Implements the pricing of a portfolio of AbstractLIBORMonteCarloProduct products
 * under a AbstractLIBORMarketModel. The products can be scaled by weights.
 * 
 * The value of the portfolio is that of
 * \( \sum_{i=0}^{n} weights\[i\] \cdot products\[i\] \text{.} \)
 * 
 * Note: Currently the products have to be of the same currency.
 * 
 * @author Christian Fries
 * @date 08.09.2006
 * @version 1.2
 */
public class Portfolio extends AbstractProductComponent {
	
	private static final long serialVersionUID = -1360506093081238482L;

	private AbstractLIBORMonteCarloProduct[]	products;
	private double[]							weights;

	/**
	 * Creates a portfolio consisting of a single product and a weight.
	 * 
	 * The currency of this portfolio is the currency of the product.
	 * 
	 * @param product A product.
	 * @param weight A weight.
	 */
	public Portfolio(AbstractLIBORMonteCarloProduct product, double weight) {
		super(product.getCurrency());
		this.products = new AbstractLIBORMonteCarloProduct[] { product };
		this.weights = new double[] { weight };
	}

	/**
	 * Creates a portfolio consisting of a set of products and a weights.
	 * 
	 * Note: Currently the products have to be of the same currency.
	 * 
	 * @param products An array of products.
	 * @param weights An array of weights (having the same lengths as the array of products).
	 */
	public Portfolio(AbstractLIBORMonteCarloProduct[] products, double[] weights) {
		super();
		String currency = products[0].getCurrency();
		for(AbstractLIBORMonteCarloProduct product : products) if(!currency.equals(product.getCurrency()))
			throw new IllegalArgumentException("Product currencies do not match. Please use a constructor providing the currency of the result.");

		this.products = products;
		this.weights = weights;
	}

	/**
	 * Creates a portfolio consisting of a set of products and a weights.
	 * 
	 * Note: Currently the products have to be of the same currency, namely the one provided.
	 * 
	 * @param currency The currency of the value of this portfolio when calling getValue.
	 * @param products An array of products.
	 * @param weights An array of weights (having the same lengths as the array of products).
	 */
	public Portfolio(String currency, AbstractLIBORMonteCarloProduct[] products, double[] weights) {
		super(currency);

		for(AbstractLIBORMonteCarloProduct product : products) if(!currency.equals(product.getCurrency()))
			throw new IllegalArgumentException("Product currencies do not match. Currency conversion (via model FX) is not supported yet.");

		this.products = products;
		this.weights = weights;
	}

	@Override
	public String getCurrency() {
		// @TODO: We report only the currency of the first item, because mixed currency portfolios are currently not allowed.
		return (products != null && products.length > 0) ? products[0].getCurrency() : null;
	}

	@Override
	public Set queryUnderlyings() {
		Set underlyingNames = null;
		for(AbstractLIBORMonteCarloProduct product : products) {
			Set productUnderlyingNames;
			if(product instanceof AbstractProductComponent)		productUnderlyingNames = ((AbstractProductComponent)product).queryUnderlyings();
			else												throw new IllegalArgumentException("Underlying cannot be queried for underlyings.");

			if(productUnderlyingNames != null) {
				if(underlyingNames == null)	underlyingNames = productUnderlyingNames;
				else						underlyingNames.addAll(productUnderlyingNames);
			}
		}
		return underlyingNames;
	}

	/**
	 * This method returns the value random variable of the product within the specified model, evaluated at a given evalutationTime.
	 * Note: For a lattice this is often the value conditional to evalutationTime, for a Monte-Carlo simulation this is the (sum of) value discounted to evaluation time.
	 * Cashflows prior evaluationTime are not considered.
	 * 
	 * @TODO The conversion between different currencies is currently not performed.
	 * @param evaluationTime The time on which this products value should be observed.
	 * @param model The model used to price the product.
	 * @return The random variable representing the value of the product discounted to evaluation time
	 * @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method. 
	 */
	@Override
	public RandomVariableInterface getValue(double evaluationTime, LIBORModelMonteCarloSimulationInterface model) throws CalculationException {
		RandomVariableInterface values = new RandomVariable(0.0);

		for(int productIndex = 0; productIndex < products.length; productIndex++) {
			RandomVariableInterface    valueOfProduct = products[productIndex].getValue(evaluationTime, model);
			double   				   weightOfProduct = weights[productIndex];

			values = values.addProduct(valueOfProduct, weightOfProduct);
		}
		return values;
	}

	/**
	 * @return the products
	 */
	public AbstractLIBORMonteCarloProduct[] getProducts() {
		return products.clone();
	}

	/**
	 * @return the weights
	 */
	public double[] getWeights() {
		return weights.clone();
	}
}

 

Ads help maintain this website.