public static double bachelierBlackFormula( Option.Type optionType, double strike, double forward, double stdDev, double discount) { if ( stdDev < 0.0 ) throw new ArgumentException( "stdDev (" + stdDev + ") must be non-negative" ); if ( discount <= 0.0 ) throw new ArgumentException( "discount (" + discount + ") must be positive" ); double d = ( forward - strike ) * (int)optionType; double h = d / stdDev; if ( stdDev == 0.0 ) return discount * Math.Max( d, 0.0 ); CumulativeNormalDistribution phi = new CumulativeNormalDistribution(); double result = discount * ( stdDev * phi.derivative( h ) + d * phi.value( h ) ); if ( !( result >= 0.0 ) ) throw new ApplicationException( "negative value (" + result + ") for " + stdDev + " stdDev, " + optionType + " option, " + strike + " strike , " + forward + " forward" ); return result; }
public static double blackFormula( Option.Type optionType, double strike, double forward, double stdDev, double discount, double displacement ) { checkParameters( strike, forward, displacement ); if ( !( stdDev >= 0.0 ) ) throw new ApplicationException( "stdDev (" + stdDev + ") must be non-negative" ); if ( !( discount > 0.0 ) ) throw new ApplicationException( "discount (" + discount + ") must be positive" ); if ( stdDev == 0.0 ) return Math.Max( ( forward - strike ) * (int)optionType, 0.0 ) * discount; forward = forward + displacement; strike = strike + displacement; // since displacement is non-negative strike==0 iff displacement==0 // so returning forward*discount is OK if ( strike == 0.0 ) return ( optionType == Option.Type.Call ? forward * discount : 0.0 ); double d1 = Math.Log( forward / strike ) / stdDev + 0.5 * stdDev; double d2 = d1 - stdDev; CumulativeNormalDistribution phi = new CumulativeNormalDistribution(); double nd1 = phi.value( (int)optionType * d1 ); double nd2 = phi.value( (int)optionType * d2 ); double result = discount * (int)optionType * ( forward * nd1 - strike * nd2 ); if ( !( result >= 0.0 ) ) throw new ApplicationException( "negative value (" + result + ") for " + stdDev + " stdDev, " + optionType + " option, " + strike + " strike , " + forward + " forward" ); return result; }
/*! Black style formula when forward is normal rather than log-normal. This is essentially the model of Bachelier. \warning Bachelier model needs absolute volatility, not percentage volatility. Standard deviation is absoluteVolatility*sqrt(timeToMaturity) */ public static double bachelierBlackFormula( Option.Type optionType, double strike, double forward, double stdDev ) { return bachelierBlackFormula( optionType, strike, forward, stdDev, 1 ); }
protected override double optionletPriceImp(Option.Type optionType, double effStrike, double forward, double stdDev) { return Utils.blackFormula(optionType, effStrike, forward, stdDev); }
public override double discountBondOption(Option.Type type, double strike, double maturity, double bondMaturity) { if (!(strike > 0.0)) throw new ApplicationException("strike must be positive"); double discountT = discountBond(0.0, maturity, x0()); double discountS = discountBond(0.0, bondMaturity, x0()); if (maturity < Const.QL_EPSILON) { switch (type){ case Option.Type.Call: return Math.Max(discountS - strike, 0.0); case Option.Type.Put: return Math.Max(strike - discountS, 0.0); default: throw new ApplicationException("unsupported option type"); } } double sigma2 = sigma()*sigma(); double h = Math.Sqrt(k()*k() + 2.0*sigma2); double b = B(maturity,bondMaturity); double rho = 2.0*h/(sigma2*(Math.Exp(h*maturity) - 1.0)); double psi = (k() + h)/sigma2; double df = 4.0*k()*theta()/sigma2; double ncps = 2.0*rho*rho*x0()*Math.Exp(h*maturity)/(rho+psi+b); double ncpt = 2.0*rho*rho*x0()*Math.Exp(h*maturity)/(rho+psi); NonCentralChiSquareDistribution chis = new NonCentralChiSquareDistribution(df, ncps); NonCentralChiSquareDistribution chit = new NonCentralChiSquareDistribution(df, ncpt); double z = Math.Log(A(maturity,bondMaturity)/strike)/b; double call = discountS*chis.value(2.0*z*(rho+psi+b)) - strike*discountT*chit.value(2.0*z*(rho+psi)); if (type == Option.Type.Call) return call; else return call - discountS + strike*discountT; }
public override double discountBondOption(Option.Type type, double strike, double maturity, double bondMaturity) { double v; double _a = a(); if (Math.Abs(maturity) < Const.QL_EPSILON){ v = 0.0; } else if (_a < Math.Sqrt(Const.QL_EPSILON)){ v = sigma()*B(maturity, bondMaturity)* Math.Sqrt(maturity); } else { v = sigma()*B(maturity, bondMaturity)* Math.Sqrt(0.5*(1.0 - Math.Exp(-2.0*_a*maturity))/_a); } double f = discountBond(0.0, bondMaturity, r0_); double k = discountBond(0.0, maturity, r0_)*strike; return Utils.blackFormula(type, k, f, v); }
//Hagan, 3.5b, 3.5c protected override double optionletPrice(Option.Type optionType, double strike) { double variance = swaptionVolatility().link.blackVariance(fixingDate_, swapTenor_, swapRateValue_); double firstDerivativeOfGAtForwardValue = gFunction_.firstDerivative(swapRateValue_); double price = 0; double CK = vanillaOptionPricer_.value(strike, optionType, annuity_); price += (discount_ / annuity_) * CK; double sqrtSigma2T = Math.Sqrt(variance); double lnRoverK = Math.Log(swapRateValue_ / strike); double d32 = (lnRoverK + 1.5 * variance) / sqrtSigma2T; double d12 = (lnRoverK + .5 * variance) / sqrtSigma2T; double dminus12 = (lnRoverK - .5 * variance) / sqrtSigma2T; CumulativeNormalDistribution cumulativeOfNormal = new CumulativeNormalDistribution(); double N32 = cumulativeOfNormal.value(((int)optionType) * d32); double N12 = cumulativeOfNormal.value(((int)optionType) * d12); double Nminus12 = cumulativeOfNormal.value(((int)optionType) * dminus12); price += ((int)optionType) * firstDerivativeOfGAtForwardValue * annuity_ * swapRateValue_ * (swapRateValue_ * Math.Exp(variance) * N32 - (swapRateValue_ + strike) * N12 + strike * Nminus12); price *= coupon_.accrualPeriod(); return price; }
public DiscreteAverageData(Option.Type Type, double Underlying, double Strike, double DividendYield, double RiskFreeRate, double First, double Length, int Fixings, double Volatility, bool ControlVariate, double Result) { type = Type; underlying = Underlying; strike = Strike; dividendYield = DividendYield; riskFreeRate = RiskFreeRate; first = First; length = Length; fixings = Fixings; volatility = Volatility; controlVariate = ControlVariate; result = Result; }
public abstract double discountBondOption(Option.Type type, double strike, double maturity, double bondMaturity);
public CashOrNothingPayoff(Option.Type type, double strike, double cashPayoff) : base(type, strike) { _cashPayoff = cashPayoff; }
//! usually only need implement this (of course they may need //! to re-implement initialize too ...) protected virtual double optionletPriceImp(Option.Type optionType, double strike, double forward, double stdDev) { Utils.QL_FAIL("you must implement this to get a vol-dependent price"); return strike * forward * stdDev * (int)optionType; }
//@} //! can replace this if really required protected virtual double optionletPrice(Option.Type optionType, double effStrike) { Date fixingDate = coupon_.fixingDate(); if (fixingDate <= Settings.evaluationDate()) { // the amount is determined double a, b; if (optionType==Option.Type.Call) { a = coupon_.indexFixing(); b = effStrike; } else { a = effStrike; b = coupon_.indexFixing(); } return Math.Max(a - b, 0.0)* coupon_.accrualPeriod()*discount_; } else { // not yet determined, use Black/DD1/Bachelier/whatever from Impl Utils.QL_REQUIRE( !capletVolatility().empty(), () => "missing optionlet volatility" ); double stdDev = Math.Sqrt(capletVolatility().link.totalVariance(fixingDate, effStrike)); double fixing = optionletPriceImp(optionType, effStrike, adjustedFixing(), stdDev); return fixing * coupon_.accrualPeriod() * discount_; } }
public PercentageStrikePayoff(Option.Type type, double moneyness) : base(type, moneyness) { }
public PlainVanillaPayoff(Option.Type type, double strike) : base(type, strike) {}
protected override double optionletPrice(Option.Type optionType, double effStrike) { Date fixingDate = coupon_.fixingDate(); if (fixingDate <= Settings.evaluationDate()) { // the amount is determined double a; double b; if (optionType == Option.Type.Call) { a = coupon_.indexFixing(); b = effStrike; } else { a = effStrike; b = coupon_.indexFixing(); } return Math.Max(a - b, 0.0) * coupon_.accrualPeriod() * discount_; } else { // not yet determined, use Black model if (!(!capletVolatility().empty())) throw new ApplicationException("missing optionlet volatility"); double stdDev = Math.Sqrt(capletVolatility().link.blackVariance(fixingDate, effStrike)); double fixing = Utils.blackFormula(optionType, effStrike, adjustedFixing(), stdDev); return fixing * coupon_.accrualPeriod() * discount_; } }
public ConundrumIntegrand(VanillaOptionPricer o, YieldTermStructure curve, GFunction gFunction, Date fixingDate, Date paymentDate, double annuity, double forwardValue, double strike, Option.Type optionType) { vanillaOptionPricer_ = o; forwardValue_ = forwardValue; annuity_ = annuity; fixingDate_ = fixingDate; paymentDate_ = paymentDate; strike_ = strike; optionType_ = optionType; gFunction_ = gFunction; }
public abstract double value(double strike, Option.Type optionType, double deflator);
// a.k.a. payoff strike public GapPayoff(Option.Type type, double strike, double secondStrike) : base(type, strike) { _secondStrike = secondStrike; }
protected override double optionletPrice(Option.Type t, double d) { throw new ApplicationException("optionletPrice not available"); }
protected override double optionletImpl( Option.Type type, double strike, double forward, double stdDev, double d ) { // could use displacement parameter in blackFormula but this is clearer return Utils.blackFormula( type, strike + 1.0, forward + 1.0, stdDev, d ); }
public virtual double discountBondOption(Option.Type type, double strike, double maturity, double bondMaturity) { double v = sigmaP(maturity, bondMaturity); double f = termStructure().link.discount(bondMaturity); double k = termStructure().link.discount(maturity) * strike; return Utils.blackFormula(type, k, f, v); }
protected override double optionletImpl( Option.Type type, double strike, double forward, double stdDev, double d ) { return Utils.bachelierBlackFormula( type, strike, forward, stdDev, d ); }
public AssetOrNothingPayoff(Option.Type type, double strike) : base(type, strike) { }
public GapPayoff(Option.Type type, double strike, double secondStrike) // a.k.a. payoff strike : base(type, strike) { secondStrike_ = secondStrike; }
protected override double optionletPrice(Option.Type optionType, double strike) { ConundrumIntegrand integrand = new ConundrumIntegrand(vanillaOptionPricer_, rateCurve_, gFunction_, fixingDate_, paymentDate_, annuity_, swapRateValue_, strike, optionType); stdDeviationsForUpperLimit_ = requiredStdDeviations_; double a; double b; double integralValue; if (optionType == Option.Type.Call) { upperLimit_ = resetUpperLimit(stdDeviationsForUpperLimit_); // while(upperLimit_ <= strike){ // stdDeviationsForUpperLimit_ += 1.; // upperLimit_ = resetUpperLimit(stdDeviationsForUpperLimit_); // } integralValue = integrate(strike, upperLimit_, integrand); //refineIntegration(integralValue, *integrand); } else { a = Math.Min(strike, lowerLimit_); b = strike; integralValue = integrate(a, b, integrand); } double dFdK = integrand.firstDerivativeOfF(strike); double swaptionPrice = vanillaOptionPricer_.value(strike, optionType, annuity_); // v. HAGAN, Conundrums..., formule 2.17a, 2.18a return coupon_.accrualPeriod() * (discount_ / annuity_) * ((1 + dFdK) * swaptionPrice + ((int)optionType) * integralValue); }
public TypePayoff(Option.Type type) { type_ = type; }
public override double value(double strike, Option.Type optionType, double deflator) { double variance = _smile.variance(strike); return deflator * Utils.blackFormula(optionType, strike, _forwardValue, Math.Sqrt(variance)); }
public FloatingTypePayoff(Option.Type type) : base(type) {}
protected abstract double optionletPrice(Option.Type optionType, double effStrike);
public StrikedTypePayoff(Option.Type type, double strike) : base(type) { strike_ = strike; }