DeltaHedgedPortfolioWithAAD.java
/*
* (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
*
* Created on 27.04.2012
*/
package net.finmath.montecarlo.assetderivativevaluation.products;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel;
import net.finmath.montecarlo.automaticdifferentiation.RandomVariableDifferentiable;
import net.finmath.montecarlo.conditionalexpectation.MonteCarloConditionalExpectationRegression;
import net.finmath.stochastic.ConditionalExpectationEstimator;
import net.finmath.stochastic.RandomVariable;
/**
* This class implements a delta hedged portfolio (a hedge simulator).
* The delta hedge uses numerical calculation of
* the delta and - in theory - works for any model implementing <code>AssetModelMonteCarloSimulationModel</code>
* and any product implementing <code>AbstractAssetMonteCarloProduct</code>.
* The results however somewhat depend on the choice of the internal regression basis functions.
*
* The <code>getValue</code>-method returns the random variable \( \Pi(t) \) representing the value
* of the replication portfolio \( \Pi(t) = \phi_0(t) N(t) + \phi_1(t) S(t) \).
*
* @author Christian Fries
* @version 1.1
*/
public class DeltaHedgedPortfolioWithAAD extends AbstractAssetMonteCarloProduct {
// The financial product we like to replicate
private final AssetMonteCarloProduct productToReplicate;
private int numberOfRegressionFunctions = 20;
private double lastOperationTimingValuation = Double.NaN;
private double lastOperationTimingDerivative = Double.NaN;
/**
* Construction of a delta hedge portfolio. The delta hedge uses numerical calculation of
* the delta and - in theory - works for any model implementing <code>AssetModelMonteCarloSimulationModel</code>
* and any product implementing <code>AbstractAssetMonteCarloProduct</code>.
* The results however somewhat depend on the choice of the internal regression basis functions.
*
* @param productToReplicate The product for which the replication portfolio should be build. May be any product implementing the <code>AbstractAssetMonteCarloProduct</code> interface.
* @param numberOfBins The number of bins used to aggregate the conditional expectation of the delta.
*/
public DeltaHedgedPortfolioWithAAD(final AssetMonteCarloProduct productToReplicate, final int numberOfBins) {
super();
this.productToReplicate = productToReplicate;
this.numberOfRegressionFunctions = numberOfBins;
}
/**
* Construction of a delta hedge portfolio. The delta hedge uses numerical calculation of
* the delta and - in theory - works for any model implementing <code>AssetModelMonteCarloSimulationModel</code>
* and any product implementing <code>AbstractAssetMonteCarloProduct</code>.
* The results however somewhat depend on the choice of the internal regression basis functions.
*
* @param productToReplicate The product for which the replication portfolio should be build. May be any product implementing the <code>AbstractAssetMonteCarloProduct</code> interface.
*/
public DeltaHedgedPortfolioWithAAD(final AssetMonteCarloProduct productToReplicate) {
super();
this.productToReplicate = productToReplicate;
}
@Override
public RandomVariable getValue(final double evaluationTime, final AssetModelMonteCarloSimulationModel model) throws CalculationException {
// Ask the model for its discretization
final int timeIndexEvaluationTime = model.getTimeIndex(evaluationTime);
/*
* Going forward in time we monitor the hedge portfolio on each path.
*/
final long timingValuationStart = System.currentTimeMillis();
final RandomVariable value = productToReplicate.getValue(model.getTime(0), model);
if(!(value instanceof RandomVariableDifferentiable)) {
throw new IllegalArgumentException("The product's getValue method, when used with the specified model, does not return a RandomVariableDifferentiable. Please check, if the model uses an appropriate RandomVariableFactory.");
}
RandomVariable exerciseTime = null;
if(productToReplicate instanceof BermudanOption) {
exerciseTime = ((BermudanOption) productToReplicate).getLastValuationExerciseTime();
}
final long timingValuationEnd = System.currentTimeMillis();
final RandomVariable valueOfOption = model.getRandomVariableForConstant(value.getAverage());
// Initialize the portfolio to zero stocks and as much cash as the Black-Scholes Model predicts we need.
final RandomVariable underlyingToday = model.getAssetValue(0.0,0);
final RandomVariable numeraireToday = model.getNumeraire(0.0);
// We store the composition of the hedge portfolio (depending on the path)
RandomVariable amountOfNumeraireAsset = valueOfOption.div(numeraireToday);
RandomVariable amountOfUderlyingAsset = model.getRandomVariableForConstant(0.0);
// Delta of option to replicate
final long timingDerivativeStart = System.currentTimeMillis();
final Map<Long, RandomVariable> gradient = ((RandomVariableDifferentiable)value).getGradient();
final long timingDerivativeEnd = System.currentTimeMillis();
lastOperationTimingValuation = (timingValuationEnd-timingValuationStart) / 1000.0;
lastOperationTimingDerivative = (timingDerivativeEnd-timingDerivativeStart) / 1000.0;
for(int timeIndex = 0; timeIndex<timeIndexEvaluationTime; timeIndex++) {
// Get value of underlying and numeraire assets
final RandomVariable underlyingAtTimeIndex = model.getAssetValue(timeIndex,0);
final RandomVariable numeraireAtTimeIndex = model.getNumeraire(timeIndex);
// Get delta
RandomVariable delta = gradient.get(((RandomVariableDifferentiable)underlyingAtTimeIndex).getID());
if(delta == null) {
delta = underlyingAtTimeIndex.mult(0.0);
}
delta = delta.mult(numeraireAtTimeIndex);
RandomVariable indicator = new RandomVariableFromDoubleArray(1.0);
if(exerciseTime != null) {
indicator = exerciseTime.sub(model.getTime(timeIndex)+0.001).choose(new RandomVariableFromDoubleArray(1.0), new RandomVariableFromDoubleArray(0.0));
}
// Create a conditional expectation estimator with some basis functions (predictor variables) for conditional expectation estimation.
final ArrayList<RandomVariable> basisFunctions = getRegressionBasisFunctionsBinning(underlyingAtTimeIndex, indicator);
// ArrayList<RandomVariable> basisFunctions = getRegressionBasisFunctions(underlyingAtTimeIndex, indicator);
final ConditionalExpectationEstimator conditionalExpectationOperator = new MonteCarloConditionalExpectationRegression(basisFunctions.toArray(new RandomVariable[0]));
delta = delta.getConditionalExpectation(conditionalExpectationOperator);
/*
* Change the portfolio according to the trading strategy
*/
// Determine the delta hedge
final RandomVariable newNumberOfStocks = delta;
final RandomVariable stocksToBuy = newNumberOfStocks.sub(amountOfUderlyingAsset);
// Ensure self financing
final RandomVariable numeraireAssetsToSell = stocksToBuy.mult(underlyingAtTimeIndex).div(numeraireAtTimeIndex);
final RandomVariable newNumberOfNumeraireAsset = amountOfNumeraireAsset.sub(numeraireAssetsToSell);
// Update portfolio
amountOfNumeraireAsset = newNumberOfNumeraireAsset;
amountOfUderlyingAsset = newNumberOfStocks;
}
/*
* At maturity, calculate the value of the replication portfolio
*/
// Get value of underlying and numeraire assets
final RandomVariable underlyingAtEvaluationTime = model.getAssetValue(evaluationTime,0);
final RandomVariable numeraireAtEvaluationTime = model.getNumeraire(evaluationTime);
final RandomVariable portfolioValue = amountOfNumeraireAsset.mult(numeraireAtEvaluationTime)
.add(amountOfUderlyingAsset.mult(underlyingAtEvaluationTime));
return portfolioValue;
}
public double getLastOperationTimingValuation() {
return lastOperationTimingValuation;
}
public double getLastOperationTimingDerivative() {
return lastOperationTimingDerivative;
}
private ArrayList<RandomVariable> getRegressionBasisFunctions(final RandomVariable underlying, final RandomVariable indicator) {
final ArrayList<RandomVariable> basisFunctions = new ArrayList<>();
// Create basis functions - here: 1, S, S^2, S^3, S^4
for(int powerOfRegressionMonomial=0; powerOfRegressionMonomial<numberOfRegressionFunctions; powerOfRegressionMonomial++) {
basisFunctions.add(underlying.pow(powerOfRegressionMonomial).mult(indicator));
}
return basisFunctions;
}
private ArrayList<RandomVariable> getRegressionBasisFunctionsBinning(final RandomVariable underlying, final RandomVariable indicator) {
final ArrayList<RandomVariable> basisFunctions = new ArrayList<>();
if(underlying.isDeterministic()) {
basisFunctions.add(underlying);
}
else {
final double[] values = underlying.getRealizations();
Arrays.sort(values);
for(int i = 0; i<numberOfRegressionFunctions; i++) {
final double binLeft = values[(int)((double)i/(double)numberOfRegressionFunctions*values.length)];
final RandomVariable basisFunction = underlying.sub(binLeft).choose(new RandomVariableFromDoubleArray(1.0), new RandomVariableFromDoubleArray(0.0)).mult(indicator);
basisFunctions.add(basisFunction);
}
}
return basisFunctions;
}
}