public void DoTestBiNormalCdfWest(double x, double y, double rho) { var A = NormalCdf.NormalCdfGenz(x, y, rho); var B = NormalCdf.NormalBiCdfWest(x, y, rho); Assert.AreEqual(A, B, 1e-8); }
//West on wilmott private double WestBestOfAssetsOrCash(double S1, double S2, double T, double r, double b1, double b2, double sigma1, double sigma2, double rho) { WestModel(S1, S2, T, r, b1, b2, sigma1, sigma2, rho, out double d1, out double d1_, out double d2, out double d2_, out double rho1, out double rho2, out double d21, out double d12, out double q1, out double q2); return(S1 * Math.Exp(-q1 * T) * NormalCdf.NormalCdfGenz(-d21, d1, rho1) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfGenz(-d12, d2, rho2) + _X1 * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-d1_, -d2_, rho)); }
private double CalcPV(double S1, double S2, double T, double r, double b1, double b2, double sigma1, double sigma2, double rho) { //for two asset cash or nothing option var d11 = (Math.Log(S1 / _X1) + (b1 - sigma1 * sigma1 * 0.5) * T) / sigma1 / Math.Sqrt(T); var d22 = (Math.Log(S2 / _X2) + (b2 - sigma2 * sigma2 * 0.5) * T) / sigma2 / Math.Sqrt(T); switch (_rainbowType) { //Haug case RainbowType.TwoAssetsCashOrNothing: return((_optionType == OptionType.Call) ? _K * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(d11, d22, rho) : _K *Math.Exp(-r *T) * NormalCdf.NormalCdfGenz(-d11, -d22, rho)); case RainbowType.TwoAssetsCashOrNothingUpDown: return(_K * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(d11, -d22, -rho)); case RainbowType.TwoAssetsCashOrNothingDownUp: return(_K * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-d11, d22, -rho)); case RainbowType.BestCashOrNothing: case RainbowType.WorstCashOrNothing: return(BestOrWorst(S1, S2, T, r, b1, b2, sigma1, sigma2, rho)); //west case RainbowType.BestOfAssetsOrCash: return(WestBestOfAssetsOrCash(S1, S2, T, r, b1, b2, sigma1, sigma2, rho)); case RainbowType.Min: case RainbowType.Max: if (_optionType == OptionType.Call) { return(WestRainbowCall(S1, S2, T, r, b1, b2, sigma1, sigma2, rho)); } else { //put, use put/call parity to price double q1 = r - b1; double q2 = r - b2; var vol = Math.Sqrt(sigma1 * sigma1 + sigma2 * sigma2 - 2.0 * rho * sigma1 * sigma2); var d21 = (Math.Log(S2 / S1) + (q1 - q2 - 0.5 * vol * vol) * T) / vol / Math.Sqrt(T); var d12 = (Math.Log(S1 / S2) + (q2 - q1 - 0.5 * vol * vol) * T) / vol / Math.Sqrt(T); var VC0max = S1 * Math.Exp(-q1 * T) * NormalCdf.NormalCdfHart(-d21) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfHart(-d12); var VC0min = S1 * Math.Exp(-q1 * T) * NormalCdf.NormalCdfHart(d21) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfHart(d12); return((_rainbowType == RainbowType.Max) ? WestRainbowCall(S1, S2, T, r, b1, b2, sigma1, sigma2, rho) - VC0max + _X1 * Math.Exp(-r * T) : WestRainbowCall(S1, S2, T, r, b1, b2, sigma1, sigma2, rho) - VC0min + _X1 * Math.Exp(-r * T)); } default: throw new PricingLibraryException("Unsupported rainbow option type"); } }
//West on wilmott private double WestRainbowCall(double S1, double S2, double T, double r, double b1, double b2, double sigma1, double sigma2, double rho) { WestModel(S1, S2, T, r, b1, b2, sigma1, sigma2, rho, out double d1, out double d1_, out double d2, out double d2_, out double rho1, out double rho2, out double d21, out double d12, out double q1, out double q2); return((_rainbowType == RainbowType.Max) ? S1 * Math.Exp(-q1 * T) * NormalCdf.NormalCdfGenz(-d21, d1, rho1) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfGenz(-d12, d2, rho2) - _X1 * Math.Exp(-r * T) * (1 - NormalCdf.NormalCdfGenz(-d1_, -d2_, rho)) : S1 *Math.Exp(-q1 *T) * NormalCdf.NormalCdfGenz(d21, d1, -rho1) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfGenz(d12, d2, -rho2) - _X1 * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(d1_, d2_, rho)); }
private double Ksi(double S, double T, double gamma, double h, double i2, double i1, double t1, double r, double b, double sigma) { double e1 = (Math.Log(S / i1) + (b + (gamma - 0.5) * sigma * sigma) * t1) / sigma / Math.Sqrt(t1); double e2 = (Math.Log(i2 * i2 / S / i1) + (b + (gamma - 0.5) * sigma * sigma) * t1) / sigma / Math.Sqrt(t1); double e3 = (Math.Log(S / i1) - (b + (gamma - 0.5) * sigma * sigma) * t1) / sigma / Math.Sqrt(t1); double e4 = (Math.Log(i2 * i2 / S / i1) - (b + (gamma - 0.5) * sigma * sigma) * t1) / sigma / Math.Sqrt(t1); double f1 = (Math.Log(S / h) + (b + (gamma - 0.5) * sigma * sigma) * T) / sigma / Math.Sqrt(T); double f2 = (Math.Log(i2 * i2 / S / h) + (b + (gamma - 0.5) * sigma * sigma) * T) / sigma / Math.Sqrt(T); double f3 = (Math.Log(i1 * i1 / S / h) + (b + (gamma - 0.5) * sigma * sigma) * T) / sigma / Math.Sqrt(T); double f4 = (Math.Log(S * i1 * i1 / i2 / i2 / h) + (b + (gamma - 0.5) * sigma * sigma) * T) / sigma / Math.Sqrt(T); double rho = Math.Sqrt(t1 / T); double lambda = -r + gamma * b + 0.5 * gamma * (gamma - 1) * sigma * sigma; double kappa = 2 * b / sigma / sigma + (2 * gamma - 1); double ksi = Math.Exp(lambda * T) * Math.Pow(S, gamma) * (NormalCdf.NormalCdfGenz(-e1, -f1, rho) - Math.Pow(i2 / S, kappa) * NormalCdf.NormalCdfGenz(-e2, -f2, rho) - Math.Pow(i1 / S, kappa) * NormalCdf.NormalCdfGenz(-e3, -f3, -rho) + Math.Pow(i1 / i2, kappa) * NormalCdf.NormalCdfGenz(-e4, -f4, -rho)); return(ksi); }
//Haug 2007 private double BestOrWorst(double S1, double S2, double T, double r, double b1, double b2, double sigma1, double sigma2, double rho) { double vol = Math.Sqrt(sigma1 * sigma1 + sigma2 * sigma2 - 2.0 * rho * sigma1 * sigma2); double y = 1.0 / vol / Math.Sqrt(T) * (Math.Log(S1 / S2) + T * (b1 - b2 + vol * vol / 2.0)); double z1 = 1.0 / sigma1 / Math.Sqrt(T) * (Math.Log(S1 / _X1) + T * (b1 + sigma1 * sigma1 / 2.0)); double z2 = 1.0 / sigma2 / Math.Sqrt(T) * (Math.Log(S2 / _X1) + T * (b2 + sigma2 * sigma2 / 2.0)); double rho1 = (sigma1 - sigma2 * rho) / vol; double rho2 = (sigma2 - rho * sigma1) / vol; double pv = 0; if (_rainbowType == RainbowType.BestCashOrNothing) { pv = (_optionType == OptionType.Call) ? _K * _notional * Math.Exp(-r * T) * (NormalCdf.NormalCdfGenz(y, z1, -rho1) + NormalCdf.NormalCdfGenz(-y, z2, -rho2)) : _K *_notional *Math.Exp(-r *T) * (1 - NormalCdf.NormalCdfGenz(y, z1, -rho1) - NormalCdf.NormalCdfGenz(-y, z2, -rho2)); } if (_rainbowType == RainbowType.WorstCashOrNothing) { pv = (_optionType == OptionType.Call) ? _K * _notional * Math.Exp(-r * T) * (NormalCdf.NormalCdfGenz(-y, z1, rho1) + NormalCdf.NormalCdfGenz(y, z2, rho2)) : _K *_notional *Math.Exp(-r *T) * (1 - NormalCdf.NormalCdfGenz(-y, z1, rho1) + NormalCdf.NormalCdfGenz(y, z2, rho2)); } return(pv); }
//Haug 2007: Chapter 4.9 & 4.10 //Payoff: max((S-X)/X,0) or max(S-X,0) private double CalcPV(double S, double T, double r, double b, double sigma, double t) { double rho = Math.Sqrt(t / T); double a1 = (Math.Log(S / _X) + (b + sigma * sigma * 0.5) * t) / sigma / Math.Sqrt(t); double a2 = a1 - sigma * Math.Sqrt(t); double z1 = (b + sigma * sigma * 0.5) * (T - t) / sigma / Math.Sqrt(T - t); double z2 = z1 - sigma * Math.Sqrt(T - t); double y1 = (Math.Log(S / _X) + (b + sigma * sigma * 0.5) * T) / sigma / Math.Sqrt(T); double y2 = y1 - sigma * Math.Sqrt(T); double C1 = Math.Exp((b - r) * (T - t)) * NormalCdf.NormalCdfHart(-a2) * NormalCdf.NormalCdfHart(z1) * Math.Exp(-r * t) - Math.Exp(-r * T) * NormalCdf.NormalCdfHart(-a2) * NormalCdf.NormalCdfHart(z2) - Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(a2, y2, rho) + (S / _X) * Math.Exp((b - r) * T) * NormalCdf.NormalCdfGenz(a1, y1, rho); double P1 = -Math.Exp((b - r) * (T - t)) * NormalCdf.NormalCdfHart(a2) * NormalCdf.NormalCdfHart(-z1) * Math.Exp(-r * t) + Math.Exp(-r * T) * NormalCdf.NormalCdfHart(a2) * NormalCdf.NormalCdfHart(-z2) + Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-a2, -y2, rho) - (S / _X) * Math.Exp((b - r) * T) * NormalCdf.NormalCdfGenz(-a1, -y1, rho); double C2 = S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfGenz(a1, y1, rho) - _X * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(a2, y2, rho) - S * Math.Exp((b - r) * t) * NormalCdf.NormalCdfHart(-a1) * NormalCdf.NormalCdfHart(z2) * Math.Exp(-r * (T - t)) + S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(-a1) * NormalCdf.NormalCdfHart(z1); double P2 = -S *Math.Exp((b - r) *T) * NormalCdf.NormalCdfGenz(-a1, -y1, rho) + _X * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-a2, -y2, rho) + S * Math.Exp((b - r) * t) * NormalCdf.NormalCdfHart(a1) * NormalCdf.NormalCdfHart(-z2) * Math.Exp(-r * (T - t)) - S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(a1) * NormalCdf.NormalCdfHart(-z1); switch (_resetstrikeType) { case ResetStrikeType.PercentagePayoff: return((_optionType == OptionType.Call) ? _notional * C1 : _notional *P1); case ResetStrikeType.NormalPayoff: return((_optionType == OptionType.Call) ? _notional * C2 : _notional *P2); default: throw new PricingLibraryException("Unsupported reset strike option type"); } }
public void DoTestNormalCdfGenz(double x, double y, double rho, double actual) { var A = NormalCdf.NormalCdfGenz(x, y, rho); Assert.AreEqual(A, actual, 1e-8); }