ForwardSensitivityDeltaHedgedPortfolio.java
/*
* (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
*
* Created on 14.05.2026
*/
package net.finmath.montecarlo.interestrate.products;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.automaticdifferentiation.RandomVariableDifferentiable;
import net.finmath.montecarlo.automaticdifferentiation.forwardsensitivities.ForwardSensitivities;
import net.finmath.montecarlo.automaticdifferentiation.forwardsensitivities.ForwardSensitivities.ProjectedHedgeRatioResult;
import net.finmath.montecarlo.automaticdifferentiation.forwardsensitivities.ForwardSensitivities.ReductionMethod;
import net.finmath.montecarlo.conditionalexpectation.MonteCarloConditionalExpectationRegression;
import net.finmath.montecarlo.interestrate.TermStructureMonteCarloSimulationModel;
import net.finmath.stochastic.ConditionalExpectationEstimator;
import net.finmath.stochastic.RandomVariable;
import net.finmath.stochastic.Scalar;
import net.finmath.time.TimeDiscretization;
/**
* A self-financing hedge simulator for term-structure products using stochastic
* hedge ratios obtained from {@link ForwardSensitivities}.
*
* <p>
* This class is the term-structure analogue of a delta-hedged portfolio. At each
* rebalancing time {@code t} it
* </p>
* <ol>
* <li>selects the differentiable process state at {@code t} as the set of
* model primitives,</li>
* <li>values the product to replicate and the hedge instruments as
* pathwise/proto-values,</li>
* <li>calls {@link ForwardSensitivities} to obtain stochastic hedge ratios,
* and</li>
* <li>changes hedge-instrument positions in a self-financing way using
* adapted trade values, i.e. conditional expectations of the proto-values
* given the information at {@code t}.</li>
* </ol>
*
* <p>
* The distinction between proto-values and trade values is important for
* products such as {@link Bond}: {@code Bond.getValue(t, model)} returns the
* discounted pathwise unit payoff converted to evaluation time {@code t}. For a
* Monte-Carlo simulation this is generally not yet the tradable bond price
* {@code P(t,T)}; the tradable price is its conditional expectation given
* {@code F_t}. The proto-values are used for the sensitivity identities, while
* the adapted trade values are used for the cash-account update.
* </p>
*
* <p>
* The default primitive ID provider uses the process values
* {@code model.getProcess().getProcessValue(timeIndex(t))}. Thus the
* sensitivities are with respect to the state at the current rebalancing time,
* not with respect to initial model parameters. This is the appropriate local
* hedge object for a dynamic delta hedge.
* </p>
*
* <p>
* The simulator does not independently book hedge-instrument cashflows paid
* between rebalancing and final evaluation. Hedge instruments must therefore
* have no payment strictly before {@code evaluationTime}, unless a custom hedge
* product represents a total-return value that carries paid cashflows. Known
* built-in cashflow products are checked at runtime. For custom products,
* ensuring this convention is the caller's responsibility.
* </p>
*
* @author Christian Fries
*/
public class ForwardSensitivityDeltaHedgedPortfolio extends AbstractTermStructureMonteCarloProduct {
/**
* Provides basis functions used to represent stochastic hedge ratios.
*/
@FunctionalInterface
public interface BasisFunctionProvider {
/**
* Returns basis functions evaluated at the given time on the paths of the model.
*
* @param evaluationTime The time t at which the hedge ratio is calculated.
* @param model The term-structure Monte-Carlo model.
* @return The basis functions X_q(t, omega).
* @throws CalculationException Thrown if a model quantity cannot be obtained.
*/
RandomVariable[] getBasisFunctions(
double evaluationTime,
TermStructureMonteCarloSimulationModel model) throws CalculationException;
}
/**
* Provides the AAD IDs of the primitives with respect to which the hedge
* equations are formed.
*/
@FunctionalInterface
public interface ParameterIDProvider {
/**
* Returns the AAD IDs of the model primitives at the given rebalancing time.
*
* @param evaluationTime The rebalancing time t.
* @param model The term-structure Monte-Carlo model.
* @return Map from primitive names to AAD IDs.
* @throws CalculationException Thrown if the process state cannot be obtained.
*/
Map<String, Long> getParameterIDs(
double evaluationTime,
TermStructureMonteCarloSimulationModel model) throws CalculationException;
}
/**
* Provides the hedge-instrument values used in the forward-sensitivity
* equation. The default implementation calls product.getValue(t, model).
* For diagnostic purposes, bonds may instead be valued analytically from the
* current forward rates.
*/
@FunctionalInterface
public interface HedgeInstrumentValueProvider {
/**
* Returns the hedge-instrument values used by ForwardSensitivities.
*
* @param evaluationTime The rebalancing time t.
* @param model The term-structure Monte-Carlo model.
* @param hedgeInstruments The hedge instruments.
* @return The hedge-instrument values P_j(t).
* @throws CalculationException Thrown if a value cannot be obtained.
*/
RandomVariable[] getValues(
double evaluationTime,
TermStructureMonteCarloSimulationModel model,
List<TermStructureMonteCarloProduct> hedgeInstruments) throws CalculationException;
}
/**
* Provides adapted trade values used in the self-financing cash-account update.
*/
@FunctionalInterface
public interface HedgeInstrumentTradeValueProvider {
/**
* Returns adapted trade values of the hedge instruments at evaluationTime.
*
* @param evaluationTime The rebalancing time t.
* @param model The term-structure Monte-Carlo model.
* @param hedgeInstruments The hedge instruments.
* @param hedgeInstrumentProtoValues The current-time raw product values returned by getValue(t, model).
* @param conditioningBasisFunctions Basis functions used for conditional-expectation projection.
* May be null if the provider supports a fallback conditioning rule.
* @return The adapted trade values used to finance the hedge trades.
* @throws CalculationException Thrown if a value cannot be obtained.
*/
RandomVariable[] getTradeValues(
double evaluationTime,
TermStructureMonteCarloSimulationModel model,
List<TermStructureMonteCarloProduct> hedgeInstruments,
RandomVariable[] hedgeInstrumentProtoValues,
RandomVariable[] conditioningBasisFunctions) throws CalculationException;
}
/**
* Provides the hedge-ratio estimator used at a rebalancing time.
*
* <p>
* The default provider delegates to {@link ForwardSensitivities#getHedgeRatios(Map, double, Map, List, RandomVariable[], RandomVariable[], double, ReductionMethod, int)}.
* A custom provider may persist the raw pathwise gradients or replace them by
* externally projected gradients before delegating to {@link ForwardSensitivities}.
* </p>
*/
@FunctionalInterface
public interface HedgeRatioProvider {
ProjectedHedgeRatioResult getHedgeRatios(
Map<String, Long> parameterIDsByName,
double evaluationTime,
Map<Long, RandomVariable> derivativeGradient,
List<Map<Long, RandomVariable>> hedgePortfolioGradients,
RandomVariable[] solutionBasisFunctions,
RandomVariable[] testBasisFunctions,
double regularizationLambda,
ReductionMethod reductionMethod,
int numberOfPaths) throws CalculationException;
}
private final TermStructureMonteCarloProduct productToReplicate;
private final List<TermStructureMonteCarloProduct> hedgeInstruments;
private final TimeDiscretization rebalancingTimes;
private final BasisFunctionProvider solutionBasisFunctionProvider;
private final BasisFunctionProvider testBasisFunctionProvider;
private final ParameterIDProvider parameterIDProvider;
private final HedgeInstrumentValueProvider hedgeInstrumentValueProvider;
private final HedgeInstrumentTradeValueProvider hedgeInstrumentTradeValueProvider;
private final HedgeInstrumentValueProvider finalHedgeInstrumentValueProvider;
private final HedgeRatioProvider hedgeRatioProvider;
private final double regularizationLambda;
private final ReductionMethod reductionMethod;
private double lastOperationTimingTotal = Double.NaN;
private double lastOperationTimingValuation = Double.NaN;
private double lastOperationTimingHedgeRatios = Double.NaN;
private double lastOperationTimingHedgeRatioProject = Double.NaN;
private double lastOperationTimingHedgeRatioSolve = Double.NaN;
private double lastOperationTimingTradeValues = Double.NaN;
private List<Double> lastRebalancingTimes = Collections.emptyList();
private List<Map<String, Long>> lastParameterIDsByName = Collections.emptyList();
private List<ProjectedHedgeRatioResult> lastHedgeRatioResults = Collections.emptyList();
private RandomVariable[] lastHedgeInstrumentPositions = new RandomVariable[0];
private RandomVariable lastNumerairePosition;
/**
* Creates a self-financing hedge using the same basis for solution and test
* functions, the process-state primitive provider, and regression trade values.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param productToReplicate The product to replicate.
* @param hedgeInstruments The hedge instruments P_j.
* @param rebalancingTimes The times at which the hedge is rebalanced.
* @param basisFunctionProvider The basis functions X_q used for the hedge ratios.
* May be null for an unreduced PATHWISE hedge.
* @param regularizationLambda Finite, non-negative Tikhonov parameter.
* Must be 0.0 for PATHWISE.
* @param reductionMethod The reduction method, e.g. PROJECTED_GALERKIN or L2.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final List<TermStructureMonteCarloProduct> hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider basisFunctionProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod) {
this(
productToReplicate,
hedgeInstruments,
rebalancingTimes,
basisFunctionProvider,
null,
getProcessStateParameterIDProvider(),
getRegressionTradeValueProvider(),
regularizationLambda,
reductionMethod);
}
/**
* Creates a self-financing hedge using possibly different solution and test bases,
* the process-state primitive provider, and regression trade values.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param productToReplicate The product to replicate.
* @param hedgeInstruments The hedge instruments P_j.
* @param rebalancingTimes The times at which the hedge is rebalanced.
* @param solutionBasisFunctionProvider The basis functions X_q used for hedge ratios.
* @param testBasisFunctionProvider The basis functions Y_s used for PROJECTED_GALERKIN moments. May be null.
* @param regularizationLambda Finite, non-negative Tikhonov parameter.
* Must be 0.0 for PATHWISE.
* @param reductionMethod The reduction method, e.g. PROJECTED_GALERKIN or L2.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final List<TermStructureMonteCarloProduct> hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider solutionBasisFunctionProvider,
final BasisFunctionProvider testBasisFunctionProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod) {
this(
productToReplicate,
hedgeInstruments,
rebalancingTimes,
solutionBasisFunctionProvider,
testBasisFunctionProvider,
getProcessStateParameterIDProvider(),
getRegressionTradeValueProvider(),
regularizationLambda,
reductionMethod);
}
/**
* Full constructor allowing custom primitive and trade-value providers. The
* hedge-instrument values used in ForwardSensitivities are the product values
* returned by {@code product.getValue(t, model)}.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param productToReplicate The product to replicate.
* @param hedgeInstruments The hedge instruments P_j.
* @param rebalancingTimes The times at which the hedge is rebalanced.
* @param solutionBasisFunctionProvider The basis functions X_q used for hedge ratios.
* @param testBasisFunctionProvider The basis functions Y_s used for PROJECTED_GALERKIN moments. May be null.
* @param parameterIDProvider Provides the primitive AAD IDs used by ForwardSensitivities.
* @param hedgeInstrumentTradeValueProvider Provides adapted trade values for the self-financing update.
* @param regularizationLambda Finite, non-negative Tikhonov parameter.
* Must be 0.0 for PATHWISE.
* @param reductionMethod The reduction method, e.g. PROJECTED_GALERKIN or L2.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final List<TermStructureMonteCarloProduct> hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider solutionBasisFunctionProvider,
final BasisFunctionProvider testBasisFunctionProvider,
final ParameterIDProvider parameterIDProvider,
final HedgeInstrumentTradeValueProvider hedgeInstrumentTradeValueProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod) {
this(
productToReplicate,
hedgeInstruments,
rebalancingTimes,
solutionBasisFunctionProvider,
testBasisFunctionProvider,
parameterIDProvider,
getProductValueProvider(),
hedgeInstrumentTradeValueProvider,
regularizationLambda,
reductionMethod);
}
/**
* Full constructor allowing custom primitive, hedge-instrument value and
* trade-value providers. The final portfolio is marked using the product
* value convention. This preserves the previous behavior and is appropriate
* when the evaluation time is the payment time and the hedge instruments are
* interpreted as their cashflow products.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param productToReplicate The product to replicate.
* @param hedgeInstruments The hedge instruments P_j.
* @param rebalancingTimes The times at which the hedge is rebalanced.
* @param solutionBasisFunctionProvider The basis functions X_q used for hedge ratios.
* @param testBasisFunctionProvider The basis functions Y_s used for PROJECTED_GALERKIN moments. May be null.
* @param parameterIDProvider Provides the primitive AAD IDs used by ForwardSensitivities.
* @param hedgeInstrumentValueProvider Provides the hedge-instrument values used in ForwardSensitivities.
* @param hedgeInstrumentTradeValueProvider Provides adapted trade values for the self-financing update.
* @param regularizationLambda Finite, non-negative Tikhonov parameter.
* Must be 0.0 for PATHWISE.
* @param reductionMethod The reduction method, e.g. PROJECTED_GALERKIN or L2.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final List<TermStructureMonteCarloProduct> hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider solutionBasisFunctionProvider,
final BasisFunctionProvider testBasisFunctionProvider,
final ParameterIDProvider parameterIDProvider,
final HedgeInstrumentValueProvider hedgeInstrumentValueProvider,
final HedgeInstrumentTradeValueProvider hedgeInstrumentTradeValueProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod) {
this(
productToReplicate,
hedgeInstruments,
rebalancingTimes,
solutionBasisFunctionProvider,
testBasisFunctionProvider,
parameterIDProvider,
hedgeInstrumentValueProvider,
hedgeInstrumentTradeValueProvider,
getProductValueProvider(),
regularizationLambda,
reductionMethod);
}
/**
* Full constructor allowing custom primitive, hedge-instrument value, trade-value
* and final marking providers. The final marking provider is useful for
* diagnostics where the hedge is stopped at the fixing time and should be
* marked with adapted tradable prices instead of product proto-values.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param productToReplicate The product to replicate.
* @param hedgeInstruments The hedge instruments \( P_{j} \).
* @param rebalancingTimes The times at which the hedge is rebalanced.
* @param solutionBasisFunctionProvider The basis functions X_q used for hedge ratios.
* @param testBasisFunctionProvider The basis functions Y_s used for PROJECTED_GALERKIN moments. May be null.
* @param parameterIDProvider Provides the primitive AAD IDs used by ForwardSensitivities.
* @param hedgeInstrumentValueProvider Provides the hedge-instrument values used in ForwardSensitivities.
* @param hedgeInstrumentTradeValueProvider Provides adapted trade values for the self-financing update.
* @param finalHedgeInstrumentValueProvider Provides hedge-instrument values used for final portfolio marking.
* @param regularizationLambda Finite, non-negative Tikhonov parameter.
* Must be 0.0 for PATHWISE.
* @param reductionMethod The reduction method, e.g. PROJECTED_GALERKIN or L2.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final List<TermStructureMonteCarloProduct> hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider solutionBasisFunctionProvider,
final BasisFunctionProvider testBasisFunctionProvider,
final ParameterIDProvider parameterIDProvider,
final HedgeInstrumentValueProvider hedgeInstrumentValueProvider,
final HedgeInstrumentTradeValueProvider hedgeInstrumentTradeValueProvider,
final HedgeInstrumentValueProvider finalHedgeInstrumentValueProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod) {
this(
productToReplicate,
hedgeInstruments,
rebalancingTimes,
solutionBasisFunctionProvider,
testBasisFunctionProvider,
parameterIDProvider,
hedgeInstrumentValueProvider,
hedgeInstrumentTradeValueProvider,
finalHedgeInstrumentValueProvider,
regularizationLambda,
reductionMethod,
getDefaultHedgeRatioProvider());
}
/**
* Full constructor with a custom hedge-ratio estimator.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param hedgeRatioProvider Provider that estimates hedge ratios from the raw
* pathwise product and hedge-instrument gradients.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final List<TermStructureMonteCarloProduct> hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider solutionBasisFunctionProvider,
final BasisFunctionProvider testBasisFunctionProvider,
final ParameterIDProvider parameterIDProvider,
final HedgeInstrumentValueProvider hedgeInstrumentValueProvider,
final HedgeInstrumentTradeValueProvider hedgeInstrumentTradeValueProvider,
final HedgeInstrumentValueProvider finalHedgeInstrumentValueProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod,
final HedgeRatioProvider hedgeRatioProvider) {
super();
this.productToReplicate = Objects.requireNonNull(productToReplicate, "productToReplicate must not be null.");
Objects.requireNonNull(hedgeInstruments, "hedgeInstruments must not be null.");
if(hedgeInstruments.isEmpty()) {
throw new IllegalArgumentException("hedgeInstruments must contain at least one hedge instrument.");
}
this.hedgeInstruments = Collections.unmodifiableList(new ArrayList<>(hedgeInstruments));
Objects.requireNonNull(rebalancingTimes, "rebalancingTimes must not be null.");
if(rebalancingTimes.size() == 0) {
throw new IllegalArgumentException("rebalancingTimes must contain at least one time.");
}
this.rebalancingTimes = rebalancingTimes;
this.solutionBasisFunctionProvider = solutionBasisFunctionProvider;
this.testBasisFunctionProvider = testBasisFunctionProvider;
this.parameterIDProvider = Objects.requireNonNull(parameterIDProvider, "parameterIDProvider must not be null.");
this.hedgeInstrumentValueProvider = Objects.requireNonNull(
hedgeInstrumentValueProvider,
"hedgeInstrumentValueProvider must not be null.");
this.hedgeInstrumentTradeValueProvider = Objects.requireNonNull(
hedgeInstrumentTradeValueProvider,
"hedgeInstrumentTradeValueProvider must not be null.");
this.finalHedgeInstrumentValueProvider = Objects.requireNonNull(
finalHedgeInstrumentValueProvider,
"finalHedgeInstrumentValueProvider must not be null.");
this.hedgeRatioProvider = Objects.requireNonNull(
hedgeRatioProvider,
"hedgeRatioProvider must not be null.");
if(!Double.isFinite(regularizationLambda) || regularizationLambda < 0.0) {
throw new IllegalArgumentException("regularizationLambda must be finite and non-negative.");
}
this.regularizationLambda = regularizationLambda;
this.reductionMethod = Objects.requireNonNull(reductionMethod, "reductionMethod must not be null.");
if(reductionMethod == ReductionMethod.PATHWISE && regularizationLambda != 0.0) {
throw new IllegalArgumentException("PATHWISE requires regularizationLambda to be 0.0.");
}
}
/**
* Convenience constructor accepting an array of hedge instruments.
* Hedge instruments are subject to the intermediate-cashflow restriction in
* the class documentation.
*
* @param productToReplicate The product to replicate.
* @param hedgeInstruments The hedge instruments P_j.
* @param rebalancingTimes The times at which the hedge is rebalanced.
* @param basisFunctionProvider The basis functions X_q used for hedge ratios.
* @param regularizationLambda Finite, non-negative Tikhonov parameter.
* Must be 0.0 for PATHWISE.
* @param reductionMethod The reduction method, e.g. PROJECTED_GALERKIN or L2.
*/
public ForwardSensitivityDeltaHedgedPortfolio(
final TermStructureMonteCarloProduct productToReplicate,
final TermStructureMonteCarloProduct[] hedgeInstruments,
final TimeDiscretization rebalancingTimes,
final BasisFunctionProvider basisFunctionProvider,
final double regularizationLambda,
final ReductionMethod reductionMethod) {
this(
productToReplicate,
Arrays.asList(hedgeInstruments),
rebalancingTimes,
basisFunctionProvider,
regularizationLambda,
reductionMethod);
}
/**
* Values the self-financing hedge at {@code evaluationTime}.
*
* <p>
* Intermediate hedge cashflows are not booked separately. Known built-in
* hedge products with a payment strictly before {@code evaluationTime} are
* rejected; callers using custom products must ensure that their values carry
* any earlier cashflows as a total-return value.
* </p>
*
* @param evaluationTime The final portfolio evaluation time.
* @param model The term-structure Monte-Carlo model.
* @return The value of the hedge portfolio.
* @throws CalculationException Thrown if model quantities cannot be calculated.
*/
@Override
public RandomVariable getValue(
final double evaluationTime,
final TermStructureMonteCarloSimulationModel model) throws CalculationException {
final long timingStart = System.currentTimeMillis();
validateNoIntermediateHedgeCashflows(evaluationTime, model);
long timingValuationMillis = 0L;
long timingHedgeRatioMillis = 0L;
long timingTradeValueMillis = 0L;
long timingHedgeRatioProjectMillis = 0L;
long timingHedgeRatioSolveMillis = 0L;
/*
* Initial funding: start with the time-0 price of the product in the
* numeraire account and zero positions in all hedge instruments.
*/
final long timingInitialValuationStart = System.currentTimeMillis();
final RandomVariable initialProductValue = productToReplicate.getValue(0.0, model);
RandomVariable amountOfNumeraireAsset = model.getRandomVariableForConstant(initialProductValue.getAverage()).div(model.getNumeraire(0.0));
timingValuationMillis += System.currentTimeMillis() - timingInitialValuationStart;
RandomVariable[] hedgeInstrumentPositions = new RandomVariable[hedgeInstruments.size()];
for(int hedgeIndex = 0; hedgeIndex < hedgeInstrumentPositions.length; hedgeIndex++) {
hedgeInstrumentPositions[hedgeIndex] = model.getRandomVariableForConstant(0.0);
}
final List<Double> rebalancedTimes = new ArrayList<>();
final List<Map<String, Long>> parameterIDsByNameHistory = new ArrayList<>();
final List<ProjectedHedgeRatioResult> hedgeRatioResults = new ArrayList<>();
/*
* Note: There are two possible ways of doing this here:
* 1) we can use the proto values V(0) and P(0) to calculate dV(0)/dM(t) and dP(0)/dM(t) and infer dV(t)/dP(t), or,
* 2) we can use the proto values V(t) and P(t) to calculate dV(t)/dM(t) and dP(t)/dM(t) and infer dV(t)/dP(t).
* The second option is much slower. The first works for sensitivities because
* V(t) w(t) / N(t) - V(0) w(0) / N(0) does not depend on M(t).
* Trade values are nevertheless recomputed from current-time proto values below,
* preserving their units and ex-dividend cash-flow semantics.
*/
final RandomVariable derivativeProtoValue = productToReplicate.getValue(0.0, model);
final RandomVariable[] hedgeInstrumentSensitivityProtoValues = hedgeInstrumentValueProvider.getValues(0.0, model, hedgeInstruments);
if(hedgeInstrumentSensitivityProtoValues.length != hedgeInstrumentPositions.length) {
throw new IllegalStateException(
"Hedge-instrument sensitivity-value provider returned "
+ hedgeInstrumentSensitivityProtoValues.length + " values for "
+ hedgeInstrumentPositions.length + " hedge instruments.");
}
final Map<Long, RandomVariable> derivativeGradient = ((RandomVariableDifferentiable)derivativeProtoValue).getGradient();
final List<Map<Long, RandomVariable>> hedgePortfolioGradients = Arrays.stream(hedgeInstrumentSensitivityProtoValues).map(hedgeInstrumentProtoValue ->
hedgeInstrumentProtoValue instanceof RandomVariableDifferentiable ? ((RandomVariableDifferentiable)hedgeInstrumentProtoValue).getGradient() : Map.<Long, RandomVariable>of())
.collect(Collectors.toList());
for(final double rebalancingTime : rebalancingTimes) {
if(rebalancingTime < 0.0 || rebalancingTime >= evaluationTime) {
continue;
}
/*
* Materialize the process state at the rebalancing time first. The
* product values calculated below should then be linked to the same
* cached AAD nodes of the process state.
*/
final long timingParameterStart = System.currentTimeMillis();
final Map<String, Long> parameterIDsByName = parameterIDProvider.getParameterIDs(rebalancingTime, model);
timingValuationMillis += System.currentTimeMillis() - timingParameterStart;
final long timingValuationStart = System.currentTimeMillis();
final RandomVariable[] solutionBasisFunctions = solutionBasisFunctionProvider != null ? solutionBasisFunctionProvider.getBasisFunctions(rebalancingTime, model) : null;
final RandomVariable[] testBasisFunctions = testBasisFunctionProvider != null ? testBasisFunctionProvider.getBasisFunctions(rebalancingTime, model) : null;
final RandomVariable[] hedgeInstrumentTradeProtoValues = getHedgeInstrumentProductValues(
rebalancingTime,
model);
final RandomVariable numeraireAtRebalancingTime = model.getNumeraire(rebalancingTime).getValues();
timingValuationMillis += System.currentTimeMillis() - timingValuationStart;
if(hedgeInstrumentTradeProtoValues.length != hedgeInstrumentPositions.length) {
throw new IllegalStateException(
"Current-time product valuation returned " + hedgeInstrumentTradeProtoValues.length
+ " values for " + hedgeInstrumentPositions.length + " hedge instruments.");
}
final long timingTradeValueStart = System.currentTimeMillis();
final RandomVariable[] hedgeInstrumentTradeValues = hedgeInstrumentTradeValueProvider.getTradeValues(
rebalancingTime,
model,
hedgeInstruments,
hedgeInstrumentTradeProtoValues,
solutionBasisFunctions);
timingTradeValueMillis += System.currentTimeMillis() - timingTradeValueStart;
final long timingHedgeRatioStart = System.currentTimeMillis();
final ProjectedHedgeRatioResult hedgeRatioResult = hedgeRatioProvider.getHedgeRatios(
parameterIDsByName,
rebalancingTime,
derivativeGradient,
hedgePortfolioGradients,
solutionBasisFunctions,
testBasisFunctions,
regularizationLambda,
reductionMethod, derivativeProtoValue.size());
timingHedgeRatioMillis += System.currentTimeMillis() - timingHedgeRatioStart;
timingHedgeRatioProjectMillis += hedgeRatioResult.getTimings().getTimingProjectSystem();
timingHedgeRatioSolveMillis += hedgeRatioResult.getTimings().getTimingSolveSystem();
final RandomVariable[] newHedgeInstrumentPositions = hedgeRatioResult.getHedgeRatios();
if(newHedgeInstrumentPositions.length != hedgeInstrumentPositions.length) {
throw new IllegalStateException(
"ForwardSensitivities returned " + newHedgeInstrumentPositions.length
+ " hedge ratios for " + hedgeInstrumentPositions.length + " hedge instruments.");
}
if(hedgeInstrumentTradeValues.length != hedgeInstrumentPositions.length) {
throw new IllegalStateException(
"Trade-value provider returned " + hedgeInstrumentTradeValues.length
+ " trade values for " + hedgeInstrumentPositions.length + " hedge instruments.");
}
/*
* Self-financing rebalancing: buy/sell hedge instruments at adapted
* trade values and finance the trade via the numeraire account.
*/
RandomVariable valueOfHedgeInstrumentsToBuy = model.getRandomVariableForConstant(0.0);
for(int hedgeIndex = 0; hedgeIndex < hedgeInstrumentPositions.length; hedgeIndex++) {
final RandomVariable hedgeInstrumentPositionChange = newHedgeInstrumentPositions[hedgeIndex]
.sub(hedgeInstrumentPositions[hedgeIndex]);
valueOfHedgeInstrumentsToBuy = valueOfHedgeInstrumentsToBuy
.add(hedgeInstrumentPositionChange.mult(hedgeInstrumentTradeValues[hedgeIndex]));
}
amountOfNumeraireAsset = amountOfNumeraireAsset
.sub(valueOfHedgeInstrumentsToBuy.div(numeraireAtRebalancingTime));
hedgeInstrumentPositions = newHedgeInstrumentPositions;
rebalancedTimes.add(rebalancingTime);
parameterIDsByNameHistory.add(Collections.unmodifiableMap(new LinkedHashMap<>(parameterIDsByName)));
hedgeRatioResults.add(hedgeRatioResult);
}
/*
* No rebalance occurs exactly at evaluationTime. Mark the remaining positions
* with the configured final provider, whose product/analytic convention
* determines the final ex-dividend or total-return semantics.
*/
final long timingFinalValuationStart = System.currentTimeMillis();
RandomVariable portfolioValue = amountOfNumeraireAsset.mult(model.getNumeraire(evaluationTime));
final RandomVariable[] hedgeInstrumentValuesAtEvaluationTime = finalHedgeInstrumentValueProvider.getValues(
evaluationTime,
model,
hedgeInstruments);
for(int hedgeIndex = 0; hedgeIndex < hedgeInstrumentPositions.length; hedgeIndex++) {
portfolioValue = portfolioValue.add(
hedgeInstrumentPositions[hedgeIndex].mult(hedgeInstrumentValuesAtEvaluationTime[hedgeIndex]));
}
timingValuationMillis += System.currentTimeMillis() - timingFinalValuationStart;
lastOperationTimingTotal = (System.currentTimeMillis() - timingStart) / 1000.0;
lastOperationTimingValuation = timingValuationMillis / 1000.0;
lastOperationTimingHedgeRatios = timingHedgeRatioMillis / 1000.0;
lastOperationTimingHedgeRatioProject = timingHedgeRatioProjectMillis / 1000.0;
lastOperationTimingHedgeRatioSolve = timingHedgeRatioSolveMillis / 1000.0;
lastOperationTimingTradeValues = timingTradeValueMillis / 1000.0;
lastRebalancingTimes = Collections.unmodifiableList(new ArrayList<>(rebalancedTimes));
lastParameterIDsByName = Collections.unmodifiableList(new ArrayList<>(parameterIDsByNameHistory));
lastHedgeRatioResults = Collections.unmodifiableList(new ArrayList<>(hedgeRatioResults));
lastHedgeInstrumentPositions = hedgeInstrumentPositions.clone();
lastNumerairePosition = amountOfNumeraireAsset;
return portfolioValue;
}
private void validateNoIntermediateHedgeCashflows(
final double evaluationTime,
final TermStructureMonteCarloSimulationModel model) {
for(final TermStructureMonteCarloProduct hedgeInstrument : hedgeInstruments) {
if(hedgeInstrument instanceof Bond) {
final Bond bond = (Bond)hedgeInstrument;
validatePaymentTime(
"Bond",
bond.getProductToModelTimeOffset(model) + bond.getMaturity(),
evaluationTime);
}
else if(hedgeInstrument instanceof SwapAnnuity) {
final SwapAnnuity swapAnnuity = (SwapAnnuity)hedgeInstrument;
final double offset = swapAnnuity.getProductToModelTimeOffset(model);
final double[] maturities = swapAnnuity.getMaturities();
final double[] periodLengths = swapAnnuity.getPeriodLengths();
for(int periodIndex = 0; periodIndex < maturities.length; periodIndex++) {
if(periodLengths[periodIndex] != 0.0) {
validatePaymentTime(
"SwapAnnuity payment " + periodIndex,
offset + maturities[periodIndex],
evaluationTime);
}
}
}
else if(hedgeInstrument instanceof DiscreteTenorRollOver) {
validatePaymentTime(
"DiscreteTenorRollOver",
((DiscreteTenorRollOver)hedgeInstrument).getPaymentTime(),
evaluationTime);
}
}
}
private static void validatePaymentTime(
final String hedgeInstrumentDescription,
final double paymentTime,
final double evaluationTime) {
if(paymentTime < evaluationTime - Bond.PAYMENT_TIME_TOLERANCE) {
throw new IllegalArgumentException(
hedgeInstrumentDescription + " pays at " + paymentTime
+ ", strictly before portfolio evaluationTime " + evaluationTime
+ ". ForwardSensitivityDeltaHedgedPortfolio does not book intermediate hedge cashflows; "
+ "use a custom total-return hedge product instead.");
}
}
/**
* Returns the standard in-process hedge-ratio estimator.
*
* @return A provider delegating to {@link ForwardSensitivities}.
*/
public static HedgeRatioProvider getDefaultHedgeRatioProvider() {
return ForwardSensitivities::getHedgeRatios;
}
private RandomVariable[] getHedgeInstrumentProductValues(
final double evaluationTime,
final TermStructureMonteCarloSimulationModel model) throws CalculationException {
final RandomVariable[] values = new RandomVariable[hedgeInstruments.size()];
for(int hedgeIndex = 0; hedgeIndex < hedgeInstruments.size(); hedgeIndex++) {
values[hedgeIndex] = hedgeInstruments.get(hedgeIndex).getValue(evaluationTime, model);
}
return values;
}
/**
* Hedge-instrument value provider using each product's getValue method.
*
* @return A provider returning product.getValue(t, model).
*/
public static HedgeInstrumentValueProvider getProductValueProvider() {
return (evaluationTime, model, hedgeInstruments) -> {
final RandomVariable[] values = new RandomVariable[hedgeInstruments.size()];
for(int hedgeIndex = 0; hedgeIndex < hedgeInstruments.size(); hedgeIndex++) {
values[hedgeIndex] = hedgeInstruments.get(hedgeIndex).getValue(evaluationTime, model);
}
return values;
};
}
/**
* Hedge-instrument value provider valuing {@link Bond}s, the bond components
* of {@link SwapAnnuity}s, and {@link DiscreteTenorRollOver}s by the model's
* forward-discount-bond implementation.
*
* <p>
* For a bond with maturity T greater than t, the provider returns the
* model-implied adapted bond price
*
* \[
* P(t,T) = E\left(\frac{N(t)}{N(T)} \mid \mathcal F_t\right),
* \]
*
* using {@code model.getModel().getForwardDiscountBond(model.getProcess(), t, T)}.
* This keeps the hedge-instrument value consistent with the model's numeraire,
* measure, interpolation and any deterministic discount-curve adjustment.
* Differentiable values returned by the model are preserved so this provider
* can safely be used as the AAD sensitivity-value provider.
* </p>
*
* @param tenorPeriodLength Kept for backward compatibility. It is not used by
* the model-implied bond valuation.
* @return A hedge-instrument value provider with model-implied analytic bond values.
*/
public static HedgeInstrumentValueProvider getAnalyticBondValueProvider(final double tenorPeriodLength) {
return (evaluationTime, model, hedgeInstruments) -> {
final RandomVariable[] values = new RandomVariable[hedgeInstruments.size()];
for(int hedgeIndex = 0; hedgeIndex < hedgeInstruments.size(); hedgeIndex++) {
final TermStructureMonteCarloProduct hedgeInstrument = hedgeInstruments.get(hedgeIndex);
if(hedgeInstrument instanceof Bond) {
final Bond bond = (Bond)hedgeInstrument;
final double maturity = bond.getProductToModelTimeOffset(model) + bond.getMaturity();
values[hedgeIndex] = getAnalyticBondValue(
evaluationTime,
maturity,
tenorPeriodLength,
model);
}
else if(hedgeInstrument instanceof SwapAnnuity) {
values[hedgeIndex] = Scalar.of(0.0);
final SwapAnnuity swapAnnuity = (SwapAnnuity)hedgeInstrument;
final double[] maturities = swapAnnuity.getMaturities();
final double[] periodLengths = swapAnnuity.getPeriodLengths();
final double productToModelTimeOffset = swapAnnuity.getProductToModelTimeOffset(model);
for(int timeIndex = 0; timeIndex<maturities.length; timeIndex++) {
final double paymentTime = productToModelTimeOffset + maturities[timeIndex];
if(paymentTime < evaluationTime - Bond.PAYMENT_TIME_TOLERANCE) {
continue;
}
values[hedgeIndex] = values[hedgeIndex].add(getAnalyticBondValue(
evaluationTime,
paymentTime,
tenorPeriodLength,
model).mult(periodLengths[timeIndex]));
}
}
else if(hedgeInstrument instanceof DiscreteTenorRollOver) {
/*
* The product owns the piecewise fixing/payment semantics and already
* uses adapted forward-discount bonds in each pre-payment phase.
*/
values[hedgeIndex] = hedgeInstrument.getValue(evaluationTime, model);
}
else {
// Using the proto value will generate biases, due to correlation (need cond. exp. first).
// Option: Add numerical cond. expectation.
throw new UnsupportedOperationException("The hedge instrument does not have an analytic proxy. We need an analytic proxy here for benchmarking.");
}
}
return values;
};
}
/**
* Trade-value provider using the analytic hedge-instrument values supplied by
* {@link #getAnalyticBondValueProvider(double)}. Differentiation wrappers are
* removed from the returned trade values since they are not sensitivity inputs.
*
* @param tenorPeriodLength The tenor period length used to form analytic bond prices.
* @return A trade-value provider with analytic bond values.
*/
public static HedgeInstrumentTradeValueProvider getAnalyticBondTradeValueProvider(final double tenorPeriodLength) {
final HedgeInstrumentValueProvider valueProvider = getAnalyticBondValueProvider(tenorPeriodLength);
return (evaluationTime, model, hedgeInstruments, hedgeInstrumentProtoValues, conditioningBasisFunctions) -> {
final RandomVariable[] values = valueProvider.getValues(evaluationTime, model, hedgeInstruments);
for(int hedgeIndex = 0; hedgeIndex < values.length; hedgeIndex++) {
values[hedgeIndex] = values[hedgeIndex].getValues();
}
return values;
};
}
/**
* Model-implied analytic bond value.
*
* <p>
* This method intentionally does not rebuild the discount bond as a raw product
* over the model's current forward rates. Instead, it delegates to the
* term-structure model's forward-discount-bond implementation, which is the
* adapted conditional expectation of the numeraire ratio and is therefore
* consistent with the model's numeraire, interpolation and optional
* discount-curve adjustment.
* </p>
*
* @param evaluationTime The valuation time t.
* @param maturity The bond maturity T.
* @param tenorPeriodLength Kept for backward compatibility. It is not used by
* the model-implied bond valuation.
* @param model The term-structure Monte-Carlo model.
* @return The model-implied adapted bond value P(t,T), or zero after the
* bond has paid.
* @throws CalculationException Thrown if the model cannot calculate the bond value.
*/
public static RandomVariable getAnalyticBondValue(
final double evaluationTime,
final double maturity,
final double tenorPeriodLength,
final TermStructureMonteCarloSimulationModel model) throws CalculationException {
final double tolerance = Bond.PAYMENT_TIME_TOLERANCE;
if(maturity <= evaluationTime + tolerance) {
if(maturity >= evaluationTime - tolerance) {
return model.getRandomVariableForConstant(1.0);
}
return model.getRandomVariableForConstant(0.0);
}
return model.getModel().getForwardDiscountBond(
model.getProcess(),
evaluationTime,
maturity);
}
/**
* Single-curve product-of-forwards diagnostic value.
*
* <p>
* This is useful for diagnostics, but it is not used by the analytic bond
* hedge-value provider. It can differ from the model-implied bond value if
* the model uses a deterministic discounting adjustment, a different
* interpolation convention, or if {@code getForwardRate(t,S,T)} for a long
* period is not equivalent to chaining all short-tenor forward rates.
* </p>
*
* @param evaluationTime The valuation time t.
* @param maturity The bond maturity T.
* @param tenorPeriodLength The tenor period length used to form the product.
* @param model The term-structure Monte-Carlo model.
* @return The product-of-forwards value.
* @throws CalculationException Thrown if a forward rate cannot be obtained.
*/
public static RandomVariable getForwardProductBondValue(
final double evaluationTime,
final double maturity,
final double tenorPeriodLength,
final TermStructureMonteCarloSimulationModel model) throws CalculationException {
if(tenorPeriodLength <= 0.0) {
throw new IllegalArgumentException("tenorPeriodLength must be positive.");
}
final double tolerance = 1E-12;
if(maturity <= evaluationTime + tolerance) {
if(maturity >= evaluationTime - tolerance) {
return model.getRandomVariableForConstant(1.0);
}
return model.getRandomVariableForConstant(1.0)
.div(model.getNumeraire(maturity))
.mult(model.getMonteCarloWeights(maturity))
.mult(model.getNumeraire(evaluationTime))
.div(model.getMonteCarloWeights(evaluationTime));
}
RandomVariable bondValue = model.getRandomVariableForConstant(1.0);
double periodStart = evaluationTime;
while(periodStart < maturity - tolerance) {
final double nextTenorTime = getNextTenorTimeStrictlyAfter(periodStart, tenorPeriodLength, tolerance);
final double periodEnd = Math.min(maturity, nextTenorTime);
final double periodLength = periodEnd - periodStart;
if(periodLength <= tolerance) {
break;
}
final RandomVariable forwardRate = model.getForwardRate(evaluationTime, periodStart, periodEnd);
final RandomVariable onePlusForwardRateTimesPeriodLength = model.getRandomVariableForConstant(1.0)
.add(forwardRate.mult(periodLength));
bondValue = bondValue.div(onePlusForwardRateTimesPeriodLength);
periodStart = periodEnd;
}
return bondValue;
}
private static double getNextTenorTimeStrictlyAfter(
final double time,
final double tenorPeriodLength,
final double tolerance) {
final double scaledTime = time / tenorPeriodLength;
double nextTenorTime = Math.floor(scaledTime + tolerance) * tenorPeriodLength + tenorPeriodLength;
if(nextTenorTime <= time + tolerance) {
nextTenorTime += tenorPeriodLength;
}
return nextTenorTime;
}
/**
* Default primitive provider: use the differentiable process state at the
* rebalancing time.
*
* @return A primitive provider based on model.getProcess().getProcessValue(timeIndex).
*/
public static ParameterIDProvider getProcessStateParameterIDProvider() {
return getProcessStateParameterIDProvider(0);
}
public static ParameterIDProvider getProcessStateParameterIDProvider(int lag) {
return (evaluationTime, model) -> {
int processTimeIndex = model.getTimeIndex(evaluationTime);
if(processTimeIndex < 0) {
processTimeIndex = model.getProcess().getTimeDiscretization().getTimeIndexNearestLessOrEqual(evaluationTime);
}
if(processTimeIndex < 0) {
throw new IllegalArgumentException("Could not find process time index for evaluationTime " + evaluationTime + ".");
}
final List<RandomVariable> modelPrimitivesList = new ArrayList<>();
for(int processTimeIndexLagged = Math.max(processTimeIndex-lag, 0); processTimeIndexLagged<=processTimeIndex; processTimeIndexLagged++) {
final RandomVariable[] modelPrimitivesLagged = model.getProcess().getProcessValue(processTimeIndexLagged);
modelPrimitivesList.addAll(Arrays.asList(modelPrimitivesLagged));
}
final RandomVariable[] modelPrimitives = modelPrimitivesList.toArray(RandomVariable[]::new);
final Map<String, Long> parameterIDsByName = new LinkedHashMap<>();
for(int componentIndex = 0; componentIndex < modelPrimitives.length; componentIndex++) {
final RandomVariable primitive = modelPrimitives[componentIndex];
if(!(primitive instanceof RandomVariableDifferentiable)) {
throw new IllegalArgumentException(
"Process primitive (" + evaluationTime + "," + componentIndex + ") is not differentiable. "
+ "Check that the model was created with RandomVariableDifferentiableAADFactory.");
}
parameterIDsByName.put(
"(" + evaluationTime + "," + componentIndex + ")",
((RandomVariableDifferentiable)primitive).getID());
}
if(parameterIDsByName.isEmpty()) {
throw new IllegalArgumentException("No differentiable process primitives found at time " + evaluationTime + ".");
}
return parameterIDsByName;
};
}
/**
* Default primitive provider: use the differentiable process state at the
* rebalancing time.
*
* @return A primitive provider based on model.getProcess().getProcessValue(timeIndex).
*/
public static ParameterIDProvider getForwardRateIDProvider(TimeDiscretization tenorDiscretization) {
return (evaluationTime, model) -> {
int processTimeIndex = model.getTimeIndex(evaluationTime);
if(processTimeIndex < 0) {
processTimeIndex = model.getProcess().getTimeDiscretization().getTimeIndexNearestLessOrEqual(evaluationTime);
}
if(processTimeIndex < 0) {
throw new IllegalArgumentException("Could not find process time index for evaluationTime " + evaluationTime + ".");
}
final List<RandomVariable> forwardRates = new ArrayList<>();
final int indexRateStart = tenorDiscretization.getTimeIndexNearestGreaterOrEqual(evaluationTime);
final int indexRateEnd = tenorDiscretization.getNumberOfTimes()-1;
for(int indexPeriodStart = indexRateStart; indexPeriodStart<indexRateEnd; indexPeriodStart++) {
final RandomVariable forwardRate = model.getForwardRate(evaluationTime, tenorDiscretization.getTime(indexPeriodStart), tenorDiscretization.getTime(indexPeriodStart+1));
forwardRates.add(forwardRate);
}
final RandomVariable[] modelPrimitives = forwardRates.toArray(RandomVariable[]::new);
final Map<String, Long> parameterIDsByName = new LinkedHashMap<>();
for(int componentIndex = 0; componentIndex < modelPrimitives.length; componentIndex++) {
final RandomVariable primitive = modelPrimitives[componentIndex];
if(!(primitive instanceof RandomVariableDifferentiable)) {
throw new IllegalArgumentException(
"Process primitive (" + evaluationTime + "," + componentIndex + ") is not differentiable. "
+ "Check that the model was created with RandomVariableDifferentiableAADFactory.");
}
else {
parameterIDsByName.put(
"(" + evaluationTime + "," + componentIndex + ")",
((RandomVariableDifferentiable)primitive).getID());
}
}
if(parameterIDsByName.isEmpty()) {
throw new IllegalArgumentException("No differentiable process primitives found at time " + evaluationTime + ".");
}
return parameterIDsByName;
};
}
/**
* Default trade-value provider: regress proto-values on the supplied
* conditioning basis. At time zero it returns constants equal to the Monte-Carlo
* averages, which is the correct static trade price. If no conditioning basis
* is supplied, it uses a constant basis. This keeps a raw PATHWISE hedge usable
* without conflating its absent solution basis with the basis required to adapt
* trade values; the resulting trade values are unconditional adapted prices.
*
* @return A trade-value provider based on conditional-expectation regression.
*/
public static HedgeInstrumentTradeValueProvider getRegressionTradeValueProvider() {
return (evaluationTime, model, hedgeInstruments, hedgeInstrumentProtoValues, conditioningBasisFunctions) -> {
Objects.requireNonNull(hedgeInstrumentProtoValues, "hedgeInstrumentProtoValues must not be null.");
final RandomVariable[] tradeValues = new RandomVariable[hedgeInstrumentProtoValues.length];
if(evaluationTime == 0.0) {
for(int hedgeIndex = 0; hedgeIndex < tradeValues.length; hedgeIndex++) {
tradeValues[hedgeIndex] = model.getRandomVariableForConstant(hedgeInstrumentProtoValues[hedgeIndex].getAverage());
}
return tradeValues;
}
final RandomVariable[] effectiveConditioningBasisFunctions =
conditioningBasisFunctions == null || conditioningBasisFunctions.length == 0
? new RandomVariable[] { model.getRandomVariableForConstant(1.0) }
: conditioningBasisFunctions;
final ConditionalExpectationEstimator conditionalExpectationOperator =
new MonteCarloConditionalExpectationRegression(effectiveConditioningBasisFunctions);
for(int hedgeIndex = 0; hedgeIndex < tradeValues.length; hedgeIndex++) {
tradeValues[hedgeIndex] = hedgeInstrumentProtoValues[hedgeIndex]
.getConditionalExpectation(conditionalExpectationOperator);
}
return tradeValues;
};
}
public TermStructureMonteCarloProduct getProductToReplicate() {
return productToReplicate;
}
public List<TermStructureMonteCarloProduct> getHedgeInstruments() {
return hedgeInstruments;
}
public TimeDiscretization getRebalancingTimes() {
return rebalancingTimes;
}
public double getRegularizationLambda() {
return regularizationLambda;
}
public ReductionMethod getReductionMethod() {
return reductionMethod;
}
public double getLastOperationTimingTotal() {
return lastOperationTimingTotal;
}
public double getLastOperationTimingValuation() {
return lastOperationTimingValuation;
}
public double getLastOperationTimingHedgeRatios() {
return lastOperationTimingHedgeRatios;
}
public double getLastOperationTimingHedgeRatioProject() {
return lastOperationTimingHedgeRatioProject;
}
public double getLastOperationTimingHedgeRatioSolve() {
return lastOperationTimingHedgeRatioSolve;
}
public double getLastOperationTimingTradeValues() {
return lastOperationTimingTradeValues;
}
public List<Double> getLastRebalancingTimes() {
return lastRebalancingTimes;
}
public List<Map<String, Long>> getLastParameterIDsByName() {
return lastParameterIDsByName;
}
public List<ProjectedHedgeRatioResult> getLastHedgeRatioResults() {
return lastHedgeRatioResults;
}
public RandomVariable[] getLastHedgeInstrumentPositions() {
return lastHedgeInstrumentPositions.clone();
}
public RandomVariable getLastNumerairePosition() {
return lastNumerairePosition;
}
public HedgeInstrumentValueProvider getFinalHedgeInstrumentValueProvider() {
return finalHedgeInstrumentValueProvider;
}
}