/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.equity.variance.pricing; import java.util.Arrays; import com.opengamma.util.ArgumentChecker; /** * Dividend payment (per share) at time $\tau_i$ of the form $\alpha_i + \beta_iS_{\tau_{i^-}}$ where $S_{\tau_{i^-}}$ is the stock price immediately before the * dividend payment. */ public class AffineDividends { /** The times */ private final double[] _tau; /** The cash dividends */ private final double[] _alpha; /** The proportional dividends */ private final double[] _beta; /** The number of times */ private final int _n; /** * @return An object representing no dividends */ public static AffineDividends noDividends() { final double[] z = new double[0]; return new AffineDividends(z, z, z); } /** * @param tau The dividend payment times, not null. The values must be greater than zero and strictly increasing. * @param alpha The cash dividends, not null. Must be the same length as the times with all values positive. * @param beta The proportional dividends, not null. Must be the same length as the times with all values between 0 (inclusive) and 1 (exclusive). */ public AffineDividends(final double[] tau, final double[] alpha, final double[] beta) { ArgumentChecker.notNull(tau, "null tau"); ArgumentChecker.notNull(alpha, "null alpha"); ArgumentChecker.notNull(beta, "null beta"); _n = tau.length; ArgumentChecker.isTrue(_n == alpha.length, "alpha wrong length"); ArgumentChecker.isTrue(_n == beta.length, "beta wrong length"); if (_n > 0) { ArgumentChecker.isTrue(tau[0] >= 0.0, "first dividend at negative time. Please remove from list"); ArgumentChecker.isTrue(alpha[0] >= 0.0, "first cash dividend is negative."); ArgumentChecker.isTrue(beta[0] >= 0.0 && beta[0] < 1.0, "Proportional dividend must be between 0.0 (inclusive) and 1.0 (exclusive). Value is {}", beta[0]); for (int i = 1; i < _n; i++) { ArgumentChecker.isTrue(tau[i] > tau[i - 1], "Dividends not increasing. {}th dividend is {}, and {}th is {}", i, tau[i], i - 1, tau[i - 1]); ArgumentChecker.isTrue(alpha[i] >= 0.0, "Cash dividend is negative. alpha[{}] = {}", i, alpha[i]); ArgumentChecker.isTrue(beta[i] >= 0.0 && beta[i] < 1.0, "Proportional dividend must be between 0.0 (inclusive) and 1.0 (exclusive). beta[{}] = {}", i, beta[i]); } } _tau = tau; _alpha = alpha; _beta = beta; } /** * Gets the dividend times * @return the tau */ public double[] getTau() { final double[] tau = Arrays.copyOf(_tau, _n); return tau; } /** * Gets the cash dividends. * @return the alpha */ public double[] getAlpha() { final double[] alpha = Arrays.copyOf(_alpha, _n); return alpha; } /** * Gets the proportional dividends. * @return the beta */ public double[] getBeta() { final double[] beta = Arrays.copyOf(_beta, _n); return beta; } /** * Gets the dividend times * @param index the index of the dividend * @return the tau */ public double getTau(final int index) { return _tau[index]; } /** * Gets the cash dividends. * @param index the index of the dividend * @return the alpha */ public double getAlpha(final int index) { return _alpha[index]; } /** * Gets the proportional dividends. * @param index the index of the dividend * @return the beta */ public double getBeta(final int index) { return _beta[index]; } /** * Gets the number of dividends. * @return the number of dividends */ public int getNumberOfDividends() { return _n; } /** * Change one of the dividend times * @param value The new value of the dividend time, tau * @param index The index of the new dividend time * @return A new AffineDividends with the changed tau */ public AffineDividends withTau(final double value, final int index) { ArgumentChecker.isTrue(value >= 0.0, "negative tau"); ArgumentChecker.isTrue(index >= 0 && index < _n, "index out of range"); final double[] tau = Arrays.copyOf(_tau, _n); tau[index] = value; return new AffineDividends(tau, _alpha, _beta); } /** * Change one of the alpha values * @param value The new value of alpha * @param index The index of the new alpha * @return A new AffineDividends with the changed alpha */ public AffineDividends withAlpha(final double value, final int index) { ArgumentChecker.isTrue(value >= 0.0, "negative alpha"); ArgumentChecker.isTrue(index >= 0 && index < _n, "index out of range"); final double[] alpha = Arrays.copyOf(_alpha, _n); alpha[index] = value; return new AffineDividends(_tau, alpha, _beta); } /** * Change one of the beta values * @param value The new value of beta * @param index The index of the new beta * @return A new AffineDividends with the changed beta */ public AffineDividends withBeta(final double value, final int index) { ArgumentChecker.isTrue(value >= 0.0, "negative beta"); ArgumentChecker.isTrue(index >= 0 && index < _n, "index out of range"); final double[] beta = Arrays.copyOf(_beta, _n); beta[index] = value; return new AffineDividends(_tau, _alpha, beta); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(_alpha); result = prime * result + Arrays.hashCode(_beta); result = prime * result + Arrays.hashCode(_tau); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (!(obj instanceof AffineDividends)) { return false; } final AffineDividends other = (AffineDividends) obj; if (!Arrays.equals(_alpha, other._alpha)) { return false; } if (!Arrays.equals(_beta, other._beta)) { return false; } if (!Arrays.equals(_tau, other._tau)) { return false; } return true; } }