All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.finmath.singleswaprate.data.ErrorEstimation Maven / Gradle / Ivy

package net.finmath.singleswaprate.data;

import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;

import net.finmath.functions.AnalyticFormulas;
import net.finmath.marketdata.model.volatilities.SwaptionDataLattice;
import net.finmath.marketdata.model.volatilities.VolatilitySurface.QuotingConvention;
import net.finmath.marketdata.products.Swap;
import net.finmath.marketdata.products.SwapAnnuity;
import net.finmath.singleswaprate.annuitymapping.AnnuityMapping.AnnuityMappingType;
import net.finmath.singleswaprate.model.VolatilityCubeModel;
import net.finmath.singleswaprate.products.CashSettledPayerSwaption;
import net.finmath.singleswaprate.products.CashSettledReceiverSwaption;
import net.finmath.time.Schedule;
import net.finmath.time.SchedulePrototype;

/**
 * Provides several error estimates between values taken from market data and values taken from a model.
 * The estimates first have to be generated, after which each estimate can be requested.
 *
 * @author Christian Fries
 * @author Roland Bachl
 *
 */
public class ErrorEstimation {

	private final LocalDate referenceDate;
	private final SchedulePrototype fixMetaSchedule;
	private final SchedulePrototype floatMetaSchedule;
	private final AnnuityMappingType annuityMappingType;
	private final String discountCurveName;
	private final String forwardCurveName;
	private final String volatilityCubeName;

	private final double replicationLowerBound;
	private final double replicationUpperBound;
	private final int replicationNumberOfEvaluationPoints;

	private final SwaptionDataLattice physicalPremiumsATM;
	private final SwaptionDataLattice cashPayerPremiums;
	private final SwaptionDataLattice cashReceiverPremiums;

	private double[] marketCash;
	private double[] marketPhysical;

	private double[] modelCash;
	private double[] modelPhysical;

	private double[] marketCashTenor;
	private double[] modelCashTenor;
	private int evaluatedMaturity;
	private int evaluatedTermination;


	/**
	 * Create the class.
	 *
	 * @param referenceDate The reference date.
	 * @param fixMetaSchedule The meta data with which to create schedules from the tenor grid for the fixed leg.
	 * @param floatMetaSchedule The meta data with which to create schedules from the tenor grid for the float leg.
	 * @param annuityMappingType The type of annuity mapping to use for cash settled swaptions.
	 * @param physicalPremiumsATM The lattice containing atm physically settled swaption premiums.
	 * @param cashPayerPremiums The lattice containing cash payer premiums.
	 * @param cashReceiverPremiums The lattice containing cash receiver premiums.
	 * @param discountCurveName The name of the discount curve in the model.
	 * @param forwardCurveName The name of the forward curve in the model.
	 * @param volatilityCubeName The name of the volatility cube in the model.
	 * @param replicationLowerBound The lowest strike to use during replication.
	 * @param replicationUpperBound The highest strike to use during replication.
	 * @param replicationNumberOfEvaluationPoints The number of strikes to evaluate during replication.
	 *
	 * @throws IOException Thrown when there is a problem fetching data from the MarketDataHandler.
	 */
	public ErrorEstimation(LocalDate referenceDate, SchedulePrototype fixMetaSchedule, SchedulePrototype floatMetaSchedule, AnnuityMappingType annuityMappingType,
			SwaptionDataLattice physicalPremiumsATM, SwaptionDataLattice cashPayerPremiums, SwaptionDataLattice cashReceiverPremiums, String discountCurveName, String forwardCurveName,
			String volatilityCubeName, double replicationLowerBound, double replicationUpperBound, int replicationNumberOfEvaluationPoints) throws IOException {
		super();
		this.referenceDate = referenceDate;
		this.fixMetaSchedule = fixMetaSchedule;
		this.floatMetaSchedule = floatMetaSchedule;
		this.annuityMappingType = annuityMappingType;
		this.discountCurveName = discountCurveName;
		this.forwardCurveName = forwardCurveName;
		this.volatilityCubeName = volatilityCubeName;

		this.replicationLowerBound = replicationLowerBound;
		this.replicationUpperBound = replicationUpperBound;
		this.replicationNumberOfEvaluationPoints = replicationNumberOfEvaluationPoints;

		this.physicalPremiumsATM = physicalPremiumsATM;
		this.cashPayerPremiums = cashPayerPremiums;
		this.cashReceiverPremiums = cashReceiverPremiums;

	}

	/**
	 * Evaluate the market data against the model. The nodes to be evaluated on are given by a lattice.
	 * The values of the lattice are not taken into account, only their position. If no lattice (null) is provided, all available data is evaluated.
	 *
	 * @param nodes A lattice indicating on which points errors should be evaluated. Optional.
	 * @param model The model against which to evaluate.
	 */
	public void evaluate(SwaptionDataLattice nodes, VolatilityCubeModel model) {

		if(nodes == null) {
			nodes = physicalPremiumsATM.append(cashPayerPremiums, model).append(cashReceiverPremiums, model);
		}

		ArrayList marketPhysicalList = new ArrayList<>();
		ArrayList modelPhysicalList = new ArrayList<>();

		ArrayList marketCashPayer = new ArrayList<>();
		ArrayList marketCashReceiver = new ArrayList<>();
		ArrayList modelCashPayer = new ArrayList<>();
		ArrayList modelCashReceiver = new ArrayList<>();


		for(int maturity : nodes.getMaturities()) {
			for(int termination : nodes.getTenors()) {
				Schedule fixSchedule = fixMetaSchedule.generateSchedule(referenceDate, maturity, termination);
				Schedule floatSchedule = floatMetaSchedule.generateSchedule(referenceDate, maturity, termination);

				double optionMaturity 	= fixSchedule.getFixing(0);
				double swapMaturity		= fixSchedule.getPayment(fixSchedule.getNumberOfPeriods()-1);
				double annuity = SwapAnnuity.getSwapAnnuity(optionMaturity, fixSchedule, model.getDiscountCurve(discountCurveName), model);
				double swapRate = Swap.getForwardSwapRate(fixSchedule, floatSchedule, model.getForwardCurve(forwardCurveName), model);
				double volatility = model.getVolatilityCube(volatilityCubeName).getValue(model, swapMaturity, optionMaturity, swapRate,
						QuotingConvention.VOLATILITYNORMAL);

				marketPhysicalList.add(physicalPremiumsATM.getValue(0, maturity, termination));
				modelPhysicalList.add(AnalyticFormulas.bachelierOptionValue(swapRate, volatility, optionMaturity, swapRate, annuity));

				for(int moneyness : cashPayerPremiums.getMoneyness()) {

					if(cashPayerPremiums.containsEntryFor(maturity, termination, moneyness)) {
						double payerStrike = swapRate + moneyness / 10000.0;

						CashSettledPayerSwaption payer = new CashSettledPayerSwaption(fixSchedule, floatSchedule, payerStrike, discountCurveName,
								forwardCurveName, volatilityCubeName, annuityMappingType, replicationLowerBound, replicationUpperBound,
								replicationNumberOfEvaluationPoints);

						marketCashPayer.add(cashPayerPremiums.getValue(maturity, termination, moneyness));
						modelCashPayer.add(payer.getValue(optionMaturity, model));
					}

					if(cashReceiverPremiums.containsEntryFor(maturity, termination, moneyness)) {
						double receiverStrike = swapRate - moneyness / 10000.0;

						CashSettledReceiverSwaption receiver = new CashSettledReceiverSwaption(fixSchedule, floatSchedule, receiverStrike, discountCurveName,
								forwardCurveName, volatilityCubeName, annuityMappingType, replicationLowerBound, replicationUpperBound,
								replicationNumberOfEvaluationPoints);

						marketCashReceiver.add(cashReceiverPremiums.getValue(maturity, termination, moneyness));
						modelCashReceiver.add(receiver.getValue(optionMaturity, model));
					}
				}
			}
		}

		marketPhysical = marketPhysicalList.stream().mapToDouble(Double::doubleValue).toArray();
		modelPhysical = modelPhysicalList.stream().mapToDouble(Double::doubleValue).toArray();

		marketCashPayer.addAll(marketCashReceiver);
		modelCashPayer.addAll(modelCashReceiver);

		marketCash = marketCashPayer.stream().mapToDouble(Double::doubleValue).toArray();
		modelCash = modelCashPayer.stream().mapToDouble(Double::doubleValue).toArray();

	}

	/**
	 * Evaluate the market data against the model at a specific node of the tenor grid.
	 *
	 * @param maturity The maturity at which to evaluate.
	 * @param termination The termination at which to evaluate.
	 * @param model The model against which to evaluate.
	 */
	private void evaluateTenor(int maturity, int termination, VolatilityCubeModel model) {

		ArrayList marketCashPayer = new ArrayList<>();
		ArrayList marketCashReceiver = new ArrayList<>();
		ArrayList modelCashPayer = new ArrayList<>();
		ArrayList modelCashReceiver = new ArrayList<>();

		Schedule fixSchedule = fixMetaSchedule.generateSchedule(referenceDate, maturity, termination);
		Schedule floatSchedule = floatMetaSchedule.generateSchedule(referenceDate, maturity, termination);

		double optionMaturity 	= fixSchedule.getFixing(0);
		double swapRate = Swap.getForwardSwapRate(fixSchedule, floatSchedule, model.getForwardCurve(forwardCurveName), model);

		for(int moneyness : cashPayerPremiums.getMoneyness()) {
			if(cashPayerPremiums.containsEntryFor(maturity, termination, moneyness)) {
				double payerStrike = swapRate + moneyness / 10000.0;

				CashSettledPayerSwaption payer = new CashSettledPayerSwaption(fixSchedule, floatSchedule, payerStrike, discountCurveName,
						forwardCurveName, volatilityCubeName, annuityMappingType, replicationLowerBound, replicationUpperBound,
						replicationNumberOfEvaluationPoints);

				marketCashPayer.add(cashPayerPremiums.getValue(maturity, termination, moneyness));
				modelCashPayer.add(payer.getValue(optionMaturity, model));
			}
		}

		for(int moneyness : cashReceiverPremiums.getMoneyness()) {
			if(cashReceiverPremiums.containsEntryFor(maturity, termination, moneyness)) {
				double receiverStrike = swapRate - moneyness / 10000.0;

				CashSettledReceiverSwaption receiver = new CashSettledReceiverSwaption(fixSchedule, floatSchedule, receiverStrike, discountCurveName,
						forwardCurveName, volatilityCubeName, annuityMappingType, replicationLowerBound, replicationUpperBound,
						replicationNumberOfEvaluationPoints);

				marketCashReceiver.add(cashReceiverPremiums.getValue(maturity, termination, moneyness));
				modelCashReceiver.add(receiver.getValue(optionMaturity, model));
			}
		}

		marketCashPayer.addAll(marketCashReceiver);
		modelCashPayer.addAll(modelCashReceiver);

		marketCashTenor = marketCashPayer.stream().mapToDouble(Double::doubleValue).toArray();
		modelCashTenor = modelCashPayer.stream().mapToDouble(Double::doubleValue).toArray();

		evaluatedMaturity = maturity;
		evaluatedTermination = termination;
	}

	/**
	 * Get the average error in cash settled swaption premiums.
	 *
	 * @return The average error in cash settled swaption premiums.
	 */
	public double getCashAverageError() {
		double sum = 0;
		double c = 0;
		for(int i = 0; i < marketCash.length; i++) {
			double y = Math.abs(marketCash[i] - modelCash[i]) - c;
			double t = sum + y;
			c = (t - sum) -y;
			sum = t;
		}
		return sum / marketCash.length;
	}

	/**
	 * Get the maximal error in cash settled swaption premiums.
	 *
	 * @return The maximal error in cash settled swaption premiums.
	 */
	public double getCashMaxError() {
		double max = 0;
		for(int i = 0; i < marketCash.length; i++) {
			max = Math.max(max, Math.abs(marketCash[i] - modelCash[i]));
		}
		return max;
	}

	/**
	 * Get the average error in cash settled swaption premiums, in percent difference from the market data.
	 *
	 * @return The average error in cash settled swaption premiums, in percent difference from the market data.
	 */
	public double getCashAverageErrorPercent() {
		double sum = 0;
		double c = 0;
		for(int i = 0; i < marketCash.length; i++) {
			double y = Math.abs(modelCash[i] / marketCash[i] - 1) - c;
			double t = sum + y;
			c = (t - sum) - y;
			sum = t;
		}
		return sum / marketCash.length;
	}

	/**
	 * Get the maximal error in cash settled swaption premiums, in percent difference from the market data.
	 *
	 * @return The maximal error in cash settled swaption premiums, in percent difference from the market data.
	 */
	public double getCashMaxErrorPercent() {
		double max = 0;
		for(int i = 0; i < marketCash.length; i++) {
			max = Math.max(max, Math.abs(modelCash[i] / marketCash[i] - 1));
		}
		return max;
	}

	/**
	 * Get the average error in physically settled swaption premiums.
	 *
	 * @return The average error in physically settled swaption premiums.
	 */
	public double getPhysicalAverageError() {
		double sum = 0;
		double c = 0;
		for(int i = 0; i < marketPhysical.length; i++) {
			double y = Math.abs(marketPhysical[i] - modelPhysical[i]) - c;
			double t = sum + y;
			c = (t - sum) -y;
			sum = t;
		}
		return sum / marketPhysical.length;
	}

	/**
	 * Get the maximal error in physically settled swaption premiums.
	 *
	 * @return The maximal error in physically settled swaption premiums.
	 */
	public double getPhysicalMaxError() {
		double max = 0;
		for(int i = 0; i < marketPhysical.length; i++) {
			max = Math.max(max, Math.abs(marketPhysical[i] - modelPhysical[i]));
		}
		return max;
	}

	/**
	 * Get the average error in physically settled swaption premiums, in percent difference from the market data.
	 *
	 * @return The average error in physically settled swaption premiums, in percent difference from the market data.
	 */
	public double getPhysicalAverageErrorPercent() {
		double sum = 0;
		double c = 0;
		for(int i = 0; i < marketPhysical.length; i++) {
			double y = Math.abs(modelPhysical[i] / marketPhysical[i] - 1) - c;
			double t = sum + y;
			c = (t - sum) - y;
			sum = t;
		}
		return sum / marketPhysical.length;
	}

	/**
	 * Get the maximal error in physically settled swaption premiums, in percent difference from the market data.
	 *
	 * @return The maximal error in physically settled swaption premiums, in percent difference from the market data.
	 */
	public double getPhysicalMaxErrorPercent() {
		double max = 0;
		for(int i = 0; i < marketPhysical.length; i++) {
			max = Math.max(max, Math.abs(modelPhysical[i] / marketPhysical[i] - 1));
		}
		return max;
	}

	/**
	 * Get the average error in cash settled swaption premiums at a specific node on the tenor grid.
	 *
	 * @param maturity The maturity at which to evaluate.
	 * @param termination The termination at which to evaluate.
	 * @param model The model against which to evaluate.
	 * @return The average error in cash settled swaption premiums.
	 */
	public double getCashAverageError(int maturity, int termination, VolatilityCubeModel model) {

		if( (maturity != evaluatedMaturity) || (termination != evaluatedTermination) ) {
			evaluateTenor(maturity, termination, model);
		}

		double sum = 0;
		double c = 0;
		for(int i = 0; i < marketCashTenor.length; i++) {
			double y = Math.abs(marketCashTenor[i] - modelCashTenor[i]) - c;
			double t = sum + y;
			c = (t - sum) -y;
			sum = t;
		}
		return sum / marketCashTenor.length;
	}

	/**
	 * Get the maximal error in cash settled swaption premiums at a specific node on the tenor grid.
	 *
	 * @param maturity The maturity at which to evaluate.
	 * @param termination The termination at which to evaluate.
	 * @param model The model against which to evaluate.
	 * @return The maximal error in cash settled swaption premiums.
	 */
	public double getCashMaxError(int maturity, int termination, VolatilityCubeModel model) {

		if( (maturity != evaluatedMaturity) || (termination != evaluatedTermination) ) {
			evaluateTenor(maturity, termination, model);
		}

		double max = 0;
		for(int i = 0; i < marketCashTenor.length; i++) {
			max = Math.max(max, Math.abs(marketCashTenor[i] - modelCashTenor[i]));
		}
		return max;
	}

	/**
	 * Get the average error in cash settled swaption premiums, in percent difference from the market data at a specific node on the tenor grid.
	 *
	 * @param maturity The maturity at which to evaluate.
	 * @param termination The termination at which to evaluate.
	 * @param model The model against which to evaluate.
	 * @return The average error in cash settled swaption premiums, in percent difference from the market data.
	 */
	public double getCashAverageErrorPercent(int maturity, int termination, VolatilityCubeModel model) {

		if( (maturity != evaluatedMaturity) || (termination != evaluatedTermination) ) {
			evaluateTenor(maturity, termination, model);
		}

		double sum = 0;
		double c = 0;
		for(int i = 0; i < marketCashTenor.length; i++) {
			double y = Math.abs(modelCashTenor[i] / marketCashTenor[i] - 1) - c;
			double t = sum + y;
			c = (t - sum) - y;
			sum = t;
		}
		return sum / marketCashTenor.length;
	}

	/**
	 * Get the maximal error in cash settled swaption premiums, in percent difference from the market data at a specific node on the tenor grid.
	 *
	 * @param maturity The maturity at which to evaluate.
	 * @param termination The termination at which to evaluate.
	 * @param model The model against which to evaluate.
	 * @return The maximal error in cash settled swaption premiums, in percent difference from the market data.
	 */
	public double getCashMaxErrorPercent(int maturity, int termination, VolatilityCubeModel model) {

		if( (maturity != evaluatedMaturity) || (termination != evaluatedTermination) ) {
			evaluateTenor(maturity, termination, model);
		}

		double max = 0;
		for(int i = 0; i < marketCashTenor.length; i++) {
			max = Math.max(max, Math.abs(modelCashTenor[i] / marketCashTenor[i] - 1));
		}
		return max;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy