FiniteDifferenceDeltaHedgedPortfolio.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.Arrays;
import java.util.HashMap;
import java.util.Map;
import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
import net.finmath.montecarlo.assetderivativevaluation.AssetModelMonteCarloSimulationModel;
import net.finmath.stochastic.RandomVariable;
/**
* This class implements a delta hedged portfolio of a given product (a hedge simulator).
* The hedge is done using a given model to calculate delta via finite difference.
* <br>
* WARNING: If the model used for calculating the delta is "slow" (e.g., a Monte-Carlo simulation)
* then the calculation might take very long.
* <br>
*
* @author Christian Fries
* @version 1.0
*/
public class FiniteDifferenceDeltaHedgedPortfolio extends AbstractAssetMonteCarloProduct {
// Model assumptions for the hedge
private final AbstractAssetMonteCarloProduct productToHedge;
private final AssetModelMonteCarloSimulationModel modelUsedForHedging;
/**
* Construction of a delta hedge portfolio using finite differences on every path and
* in every time-step. Note that this requires many revaluations of the product
* provided.
*
* @param productToHedge The financial product for which the hedge portfolio should be constructed.
* @param modelUsedForHedging The model used for calculating the hedge rations (deltas). This may differ from the model passed to <code>getValue</code>.
*/
public FiniteDifferenceDeltaHedgedPortfolio(final AbstractAssetMonteCarloProduct productToHedge, final AssetModelMonteCarloSimulationModel modelUsedForHedging) {
super();
this.productToHedge = productToHedge;
this.modelUsedForHedging = modelUsedForHedging;
}
@Override
public RandomVariable getValue(final double evaluationTime, final AssetModelMonteCarloSimulationModel model) throws CalculationException {
// Ask the model for its discretization
final int timeIndexEvaluationTime = model.getTimeIndex(evaluationTime);
final int numberOfPath = model.getNumberOfPaths();
/*
* Going forward in time we monitor the hedge portfolio on each path.
*/
// We store the composition of the hedge portfolio (depending on the path)
final double[] amountOfUderlyingAsset = new double[numberOfPath];
final double[] amountOfNumeraireAsset = new double[numberOfPath];
/*
* 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);
final double initialValueAsset = underlyingToday.get(0);
final double initialValueNumeraire = numeraireToday.get(0);
final double valueOfOptionAccordingHedgeModel = productToHedge.getValue(modelUsedForHedging);
Arrays.fill(amountOfNumeraireAsset, valueOfOptionAccordingHedgeModel/initialValueNumeraire);
Arrays.fill(amountOfUderlyingAsset, 0.0);
for(int timeIndex = 0; timeIndex<timeIndexEvaluationTime; timeIndex++) {
final double time = model.getTime(timeIndex);
// Get value of underlying and numeraire assets
final RandomVariable underlyingAtTimeIndex = model.getAssetValue(timeIndex,0);
final RandomVariable numeraireAtTimeIndex = model.getNumeraire(timeIndex);
for(int path=0; path<model.getNumberOfPaths(); path++)
{
final double underlyingValue = underlyingAtTimeIndex.get(path);
final double numeraireValue = numeraireAtTimeIndex.get(path);
// Delta of option to replicate
final double shift = initialValueAsset * 1E-8;
final Map<String, Object> dataUpShift = new HashMap<>();
dataUpShift.put("initialValue", new Double(underlyingValue+shift));
dataUpShift.put("initialTime", new Double(time));
final Map<String, Object> dataDownShift = new HashMap<>();
dataDownShift.put("initialValue", new Double(underlyingValue-shift));
dataDownShift.put("initialTime", new Double(time));
final double delta = (
productToHedge.getValue(time, modelUsedForHedging.getCloneWithModifiedData(dataUpShift)).getAverage()
-
productToHedge.getValue(time, modelUsedForHedging.getCloneWithModifiedData(dataDownShift)).getAverage()
) / (2*shift);
// Determine the delta hedge
final double newNumberOfStocks = delta;
final double stocksToBuy = newNumberOfStocks - amountOfUderlyingAsset[path];
// Ensure self financing
final double numeraireAssetsToBuy = - (stocksToBuy * underlyingValue) / numeraireValue;
final double newNumberOfNumeraireAsset = amountOfNumeraireAsset[path] + numeraireAssetsToBuy;
// Update portfolio
amountOfNumeraireAsset[path] = newNumberOfNumeraireAsset;
amountOfUderlyingAsset[path] = newNumberOfStocks;
}
}
/*
* At maturity, calculate the value of the replication portfolio
*/
final double[] portfolioValue = new double[numberOfPath];
// Get value of underlying and numeraire assets
final RandomVariable underlyingAtEvaluationTime = model.getAssetValue(evaluationTime,0);
final RandomVariable numeraireAtEvaluationTime = model.getNumeraire(evaluationTime);
for(int path=0; path<underlyingAtEvaluationTime.size(); path++)
{
final double underlyingValue = underlyingAtEvaluationTime.get(path);
portfolioValue[path] =
amountOfNumeraireAsset[path] * numeraireAtEvaluationTime.get(path)
+ amountOfUderlyingAsset[path] * underlyingValue;
}
return new RandomVariableFromDoubleArray(evaluationTime, portfolioValue);
}
}