BuehlerDividendForwardStructure.java

package net.finmath.equities.models;

import java.time.LocalDate;
import java.util.HashMap;

import net.finmath.equities.marketdata.AffineDividendStream;
import net.finmath.equities.marketdata.YieldCurve;
import net.finmath.time.daycount.DayCountConvention;

/**
 * This class implements the forward structure for a stock with affine dividends
 * according to Buehler's 2007 paper.
 *
 * @author Andreas Grotz
 */
public class BuehlerDividendForwardStructure implements EquityForwardStructure {

	private final LocalDate valuationDate;
	private final double spot;
	private final YieldCurve repoCurve;
	private final AffineDividendStream dividendStream;
	private final DayCountConvention dayCounter;
	private final HashMap<LocalDate, Double> dividendTimes;

	public BuehlerDividendForwardStructure(
			final LocalDate valuationDate,
			final double spot,
			final YieldCurve repoCurve,
			final AffineDividendStream dividendStream,
			final DayCountConvention dayCounter) {

		this.valuationDate = valuationDate;
		this.spot = spot;
		this.repoCurve = repoCurve;
		this.dividendStream = dividendStream;
		this.dayCounter = dayCounter;

		dividendTimes = new HashMap<LocalDate, Double>();
		for(final LocalDate date : dividendStream.getDividendDates()) {
			dividendTimes.put(date, dayCounter.getDaycountFraction(valuationDate, date));
		}

		validate();
	}

	public void validate() {
		assert getFutureDividendFactor(valuationDate) <= spot : "PV of future dividends is larger than spot.";
	}

	@Override
	public BuehlerDividendForwardStructure cloneWithNewSpot(double newSpot) {
		return new BuehlerDividendForwardStructure(
				this.valuationDate,
				newSpot,
				this.repoCurve,
				this.dividendStream,
				this.dayCounter);
	}

	@Override
	public BuehlerDividendForwardStructure cloneWithNewDate(LocalDate newDate) {
		return new BuehlerDividendForwardStructure(
				newDate,
				this.spot,
				this.repoCurve.rollToDate(newDate),
				this.dividendStream,
				this.dayCounter);
	}

	@Override
	public DividendModelType getDividendModel() {
		return DividendModelType.Buehler;
	}

	@Override
	public LocalDate getValuationDate() {
		return valuationDate;
	}

	@Override
	public double getSpot() {
		return spot;
	}

	@Override
	public YieldCurve getRepoCurve() {
		return repoCurve;
	}

	@Override
	public AffineDividendStream getDividendStream() {
		return dividendStream;
	}

	@Override
	public double getGrowthDiscountFactor(double startTime, double endTime) {
		double df = 1.0;
		for(final LocalDate date : dividendStream.getDividendDates()) {
			final double dividendTime = dividendTimes.get(date);
			if(dividendTime > startTime && dividendTime <= endTime) {
				df *= (1.0 - dividendStream.getProportionalDividendFactor(date));
			}
		}

		return df / repoCurve.getForwardDiscountFactor(startTime, endTime);
	}

	@Override
	public double getGrowthDiscountFactor(LocalDate startDate, LocalDate endDate) {
		final double startTime = dayCounter.getDaycountFraction(valuationDate, startDate);
		final double endTime = dayCounter.getDaycountFraction(valuationDate, endDate);
		return getGrowthDiscountFactor(startTime, endTime);
	}

	@Override
	public double getFutureDividendFactor(double valTime) {
		double df = 0.0;
		for(final LocalDate date : dividendStream.getDividendDates()) {
			final double dividendTime = dividendTimes.get(date);
			if(dividendTime > valTime) {
				df += dividendStream.getCashDividend(date) / getGrowthDiscountFactor(valTime, dividendTime);
			}
		}
		return df;
	}

	@Override
	public double getFutureDividendFactor(LocalDate valDate) {
		final double valTime = dayCounter.getDaycountFraction(valuationDate, valDate);
		return getFutureDividendFactor(valTime);
	}

	@Override
	public double getForward(double expiryTime) {
		double forward = spot * getGrowthDiscountFactor(0.0, expiryTime);
		for(final LocalDate date : dividendStream.getDividendDates()) {
			final double dividendTime = dividendTimes.get(date);
			if(dividendTime <= expiryTime) {
				forward -= dividendStream.getCashDividend(date) * getGrowthDiscountFactor(dividendTime, expiryTime);
			}
		}
		return forward;
	}

	@Override
	public double getForward(LocalDate expiryDate) {
		final double expiryTime = dayCounter.getDaycountFraction(valuationDate, expiryDate);
		return getForward(expiryTime);
	}

	@Override
	public double getDividendAdjustedStrike(double strike, double expiryTime) {
		return strike - getFutureDividendFactor(expiryTime);
	}

	@Override
	public double getDividendAdjustedStrike(double strike, LocalDate expiryDate) {
		return strike - getFutureDividendFactor(expiryDate);
	}

	@Override
	public double getLogMoneyness(double strike, double expiryTime) {
		return Math.log(
				getDividendAdjustedStrike(strike, expiryTime)
				/ getDividendAdjustedStrike(getForward(expiryTime), expiryTime));
	}

	@Override
	public double getLogMoneyness(double strike, LocalDate expiryDate) {
		return Math.log(
				getDividendAdjustedStrike(strike, expiryDate)
				/ getDividendAdjustedStrike(getForward(expiryDate), expiryDate));
	}
}