/*
* (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de.
*
* Created on 11.03.2006
*/
package net.finmath.montecarlo.interestrate.products;
import java.util.ArrayList;
import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.RandomVariable;
import net.finmath.montecarlo.conditionalexpectation.MonteCarloConditionalExpectation;
import net.finmath.montecarlo.conditionalexpectation.MonteCarloConditionalExpectationRegression;
import net.finmath.montecarlo.interestrate.LIBORModelMonteCarloSimulationInterface;
import net.finmath.stochastic.RandomVariableInterface;
/**
* Implements the valuation of a cancelable swap under a LIBORModelMonteCarloSimulationInterface
*
* @author Christian Fries
* @version 1.2
* @date 06.12.2009
*/
public class BermudanSwaption extends AbstractLIBORMonteCarloProduct {
private final boolean[] isPeriodStartDateExerciseDate; // Exercise date
private final double[] fixingDates; // Vector of fixing dates (must be sorted)
private final double[] periodLengths; // Vector of period length;
private final double[] paymentDates; // Vector of payment dates (same length as fixing dates)
private final double[] periodNotionals; // Vector of notionals for each period
private final double[] swaprates; // Vector of strikes
/**
* @param isPeriodStartDateExerciseDate If true, we may exercise at period start
* @param fixingDates Vector of fixing dates
* @param periodLength Period lengths (must have same length as fixing dates)
* @param paymentDates Vector of payment dates (must have same length as fixing dates)
* @param periodNotionals Period notionals (must have same length as fixing dates)
* @param swaprates Vector of strikes (must have same length as fixing dates)
*/
public BermudanSwaption(boolean[] isPeriodStartDateExerciseDate, double[] fixingDates, double[] periodLength, double[] paymentDates, double[] periodNotionals, double[] swaprates) {
super();
this.isPeriodStartDateExerciseDate = isPeriodStartDateExerciseDate;
this.fixingDates = fixingDates;
this.periodLengths = periodLength;
this.paymentDates = paymentDates;
this.periodNotionals = periodNotionals;
this.swaprates = swaprates;
}
/**
* 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.
*
* @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 {
// After the last period the product has value zero: Initialize values to zero.
RandomVariableInterface values = new RandomVariable(fixingDates[fixingDates.length-1], 0.0);
RandomVariableInterface valuesUnderlying = new RandomVariable(fixingDates[fixingDates.length-1], 0.0);
// Loop backward over the swap periods
for(int period=fixingDates.length-1; period>=0; period--)
{
double fixingDate = fixingDates[period];
double periodLength = periodLengths[period];
double paymentDate = paymentDates[period];
double notional = periodNotionals[period];
double swaprate = swaprates[period];
// Get random variables - note that this is the rate at simulation time = exerciseDate
RandomVariableInterface libor = model.getLIBOR(fixingDate, fixingDate, fixingDate+periodLength);
// foreach(path) values[path] += notional * (libor.get(path) - swaprate) * periodLength / numeraire.get(path) * monteCarloProbabilities.get(path);
RandomVariableInterface payoff = libor.sub(swaprate).mult(periodLength).mult(notional);
// Apply discounting and Monte-Carlo probabilities
RandomVariableInterface numeraire = model.getNumeraire(paymentDate);
RandomVariableInterface monteCarloProbabilities = model.getMonteCarloWeights(paymentDate);
payoff = payoff.div(numeraire).mult(monteCarloProbabilities);
// model.discount(paymentDate, values);
valuesUnderlying = valuesUnderlying.add(payoff);
if(isPeriodStartDateExerciseDate[period]) {
RandomVariableInterface triggerValuesDiscounted = values.sub(valuesUnderlying);
// Remove foresight through condition expectation
MonteCarloConditionalExpectation condExpEstimator = getConditionalExpectationEstimator(period, model);
// Calculate conditional expectation. Note that no discounting (numeraire division) is required!
RandomVariableInterface triggerValues = condExpEstimator.getConditionalExpectation(triggerValuesDiscounted);
// Apply the exercise criteria
// foreach(path) if(valueIfExcercided.get(path) < 0.0) values[path] = 0.0;
values = values.barrier(triggerValues, values, valuesUnderlying);
}
}
// model.discount(evaluationTime, values);
// Note that values is a relative price - no numeraire division is required
RandomVariableInterface numeraireAtZero = model.getNumeraire(evaluationTime);
RandomVariableInterface monteCarloProbabilitiesAtZero = model.getMonteCarloWeights(evaluationTime);
values = values.mult(numeraireAtZero).div(monteCarloProbabilitiesAtZero);
return values;
}
/**
* Return the conditional expectation estimator suitable for this product.
*
* @param fixingDateIndex The time index corresponding to the fixing date
* @param model The model
* @return The conditional expectation estimator suitable for this product
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
private MonteCarloConditionalExpectation getConditionalExpectationEstimator(int fixingDateIndex, LIBORModelMonteCarloSimulationInterface model) throws CalculationException {
MonteCarloConditionalExpectationRegression condExpEstimator = new MonteCarloConditionalExpectationRegression(
getRegressionBasisFunctions(fixingDateIndex, model)
);
return condExpEstimator;
}
/**
* Return the basis functions for the regression suitable for this product.
*
* @param fixingDateIndex The time index corresponding to the fixing date
* @param model The model
* @return The basis functions for the regression suitable for this product.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
private RandomVariableInterface[] getRegressionBasisFunctions(int fixingDateIndex, LIBORModelMonteCarloSimulationInterface model) throws CalculationException {
double fixingDate = fixingDates[fixingDateIndex];
ArrayList basisFunctions = new ArrayList();
// Constant
RandomVariableInterface basisFunction = new RandomVariable(fixingDate, 1.0);
basisFunctions.add(basisFunction);
// LIBORs
RandomVariableInterface rate = model.getLIBOR(fixingDate, fixingDates[0], paymentDates[paymentDates.length-1]);
double periodLength = paymentDates[paymentDates.length-1]-fixingDates[0];
basisFunction = basisFunctions.get(0).discount(rate, periodLength);
basisFunctions.add(basisFunction);
basisFunction = basisFunctions.get(1).discount(rate, periodLength);
basisFunctions.add(basisFunction);
return basisFunctions.toArray(new RandomVariableInterface[basisFunctions.size()]);
}
}
Ads help maintain this website.