private OneTouchCalculator ConfigureCalculator(IOption option, IMarketCondition market, double timeIncrement = 0.0) { var trade = (BinaryOption)option; var exerciseDate = trade.ExerciseDates.Last(); var maturityDate = trade.UnderlyingMaturityDate; var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var riskfreeDfAtExercise = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var spot = market.SpotPrices.Value.Values.First(); double sigma = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: exerciseDate, option: option, spot: spot); var dividendCurveInput = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var dividendInput = AnalyticalOptionPricerUtil.dividendYieldOutput(dividendCurveInput, riskFreeRate, option.Dividends, spot, market.ValuationDate, trade.ExerciseDates.Last(), option.DayCount); var dividendRate = AnalyticalOptionPricerUtil.dividenRate(trade.UnderlyingProductType, dividendInput, riskfreeDfAtExercise); var exerciseInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade) + timeIncrement; var calculator = new OneTouchCalculator( trade.BinaryRebateType, strike: option.IsMoneynessOption ? trade.Strike * trade.InitialSpotPrice : trade.Strike, spotPrice: spot, sigma: sigma, dividendRate: dividendRate, riskFreeRate: riskfreeDfAtExercise, cashOrNothingAmount: trade.CashOrNothingAmount, exerciseInYears: exerciseInYears, underlyingInstrumentType: trade.UnderlyingProductType, notional: trade.Notional); this._calculator = calculator; return(calculator); }
public BarrierOptionFourierPvPricer(BarrierOption barrierOption, IMarketCondition market, double timeIncrement = 0.0) { var exerciseDate = barrierOption.ExerciseDates.Last(); var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var spotPrice = market.SpotPrices.Value.Values.First(); var vol = market.VolSurfaces.Value.Values.First().GetValue(market.ValuationDate, barrierOption.Strike, spotPrice); var exerciseInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, barrierOption) + timeIncrement; _optionType = barrierOption.OptionType; _rebate = barrierOption.Rebate; _coupon = barrierOption.Coupon; _K = barrierOption.Strike; _S = spotPrice; _T = exerciseInYears; _v = vol; _r = riskFreeRate; _B = barrierOption.UpperBarrier; _A = barrierOption.Barrier; b = Math.Log(_B); a = Math.Log(_A); x0 = Math.Log(_S); v2 = Math.Pow(_v, 2); u = _r - v2 / 2; u2 = Math.Pow(u, 2); }
private BarrierOptionCalculator configureCalculator(IOption option, IMarketCondition market, double expiryDayRemainingLife = double.NaN, double timeIncrement = 0.0) { var trade = (BarrierOption)option; var exerciseDate = trade.ExerciseDates.Last(); var maturityDate = trade.UnderlyingMaturityDate; var spot = market.SpotPrices.Value.Values.First(); double exerciseInYears; if (!double.IsNaN(expiryDayRemainingLife)) { exerciseInYears = expiryDayRemainingLife; } else { exerciseInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade) + timeIncrement; } //barrier adjust var dt = trade.DayCount.CalcDayCountFraction(trade.ObservationDates.First(), trade.ObservationDates.Last()) / trade.ObservationDates.Length; var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var riskfreeRateAtMaturity = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, maturityDate); var dividendCurveInput = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var dividendInput = AnalyticalOptionPricerUtil.dividendYieldOutput(dividendCurveInput, riskFreeRate, option.Dividends, spot, market.ValuationDate, trade.ExerciseDates.Last(), option.DayCount); var dividendRate = AnalyticalOptionPricerUtil.dividenRate(trade.UnderlyingProductType, dividendInput, riskFreeRate); var vol = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: exerciseDate, option: option, spot: spot); var barrierCalculator = new BarrierOptionCalculator( trade.OptionType, trade.BarrierType, trade.Rebate, trade.IsDiscreteMonitored ? DiscreteAdjustedBarrier(trade.BarrierType, trade.Position, trade.Barrier, vol, dt, trade.BarrierShift) : trade.Barrier, trade.IsDiscreteMonitored ? DiscreteAdjustedBarrier(trade.BarrierType, trade.Position, trade.UpperBarrier, vol, dt, trade.BarrierShift) : trade.UpperBarrier, option.IsMoneynessOption ? trade.Strike * trade.InitialSpotPrice : trade.Strike, spot, exerciseInYears, vol, riskFreeRate, dividendRate, valuationDate: market.ValuationDate, exerciseDate: exerciseDate, underlyingMaturityDate: trade.UnderlyingMaturityDate, dayCount: trade.DayCount, underlyingInstrumentType: trade.UnderlyingProductType, notional: trade.Notional ); this._calculator = barrierCalculator; return(barrierCalculator); }
private AsianOptionCalculator ConfigureCalculator(IOption option, IMarketCondition market, double expiryDayRemainingLife = double.NaN, double timeIncrement = 0.0) { var trade = (AsianOption)option; var exerciseDate = trade.ExerciseDates.Last(); var remainingObsDates = trade.ObservationDates.Where(x => x >= market.ValuationDate).ToArray(); var numOfObsDates = trade.ObservationDates.Count(); var numOfObservedDates = numOfObsDates - remainingObsDates.Count(); var observedAverage = trade.Fixings.Any() ? trade.Fixings.Average(x => x.Value) : market.SpotPrices.Value.Values.First(); //if (trade.Fixings.Count != numOfObservedDates) //{ // throw new PricingLibraryException("AsianOption: number of fixings does not match!"); //} var spot = market.SpotPrices.Value.Values.First(); double sigma = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: exerciseDate, option: option, spot: spot); double t; if (!double.IsNaN(expiryDayRemainingLife)) { t = expiryDayRemainingLife; } else { t = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade) + timeIncrement; } var t2 = AnalyticalOptionPricerUtil.timeToMaturityFraction(trade.ObservationDates[0], remainingObsDates.Last(), trade); var t1 = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, remainingObsDates[0], trade) + timeIncrement; var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var dividendCurveInput = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var dividendInput = AnalyticalOptionPricerUtil.dividendYieldOutput(dividendCurveInput, riskFreeRate, option.Dividends, spot, market.ValuationDate, trade.ExerciseDates.Last(), option.DayCount); var dividendRate = AnalyticalOptionPricerUtil.dividenRate(trade.UnderlyingProductType, dividendInput, riskFreeRate); var calculator = new AsianOptionCalculator(trade.OptionType, trade.AsianType, trade.UnderlyingProductType, trade.StrikeStyle, strike: option.IsMoneynessOption ? trade.Strike * trade.InitialSpotPrice : trade.Strike, spotPrice: spot, realizedAveragePrice: observedAverage, exerciseInYears: t, originalAveragePeriod: t2, timetoNextAveragePoint: t1, sigma: sigma, riskFreeRate: riskFreeRate, dividendRate: dividendRate, notional: trade.Notional, numOfObsDates: numOfObsDates, numOfObservedDates: numOfObservedDates); this._calculator = calculator; return(calculator); }
private BlackScholeCalculator ConfigureCalculator(IOption option, IMarketCondition market, double expiryDayRemainingLife = double.NaN, double timeIncrement = 0.0) { var trade = (BinaryOption)option; var exerciseDate = trade.ExerciseDates.Last(); var maturityDate = trade.UnderlyingMaturityDate; var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var riskfreeDfAtMaturity = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, maturityDate); var riskfreeDfAtExercise = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var spot = market.SpotPrices.Value.Values.First(); double sigma = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: exerciseDate, option: option, spot: spot); var dividendCurveInput = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var dividendInput = AnalyticalOptionPricerUtil.dividendYieldOutput(dividendCurveInput, riskFreeRate, option.Dividends, spot, market.ValuationDate, trade.ExerciseDates.Last(), option.DayCount); var dividendRate = AnalyticalOptionPricerUtil.dividenRate(trade.UnderlyingProductType, dividendInput, riskfreeDfAtExercise); var exerciseInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade) + timeIncrement; var maturityInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, maturityDate, trade) + timeIncrement; var _isDelayedPay = exerciseInYears.AlmostEqual(maturityInYears); var calculator = new BlackScholeCalculator(trade.OptionType, trade.BinaryOptionPayoffType, strike: option.IsMoneynessOption ? trade.Strike * trade.InitialSpotPrice : trade.Strike, spotPrice: spot, sigma: sigma, dividendRate: dividendRate, riskfreeRateAtExercise: riskfreeDfAtExercise, riskfreeRateAtMaturity: riskfreeDfAtMaturity, curveDayCount: market.DiscountCurve.Value.DayCount, cashOrNothingAmount: trade.CashOrNothingAmount, exerciseDate: exerciseDate, maturityDate: maturityDate, valuationDate: market.ValuationDate, trade: trade, underlyingInstrumentType: trade.UnderlyingProductType, notional: trade.Notional, isDelayedPay: _isDelayedPay, expiryDayRemainingLife: expiryDayRemainingLife, timeIncrement: timeIncrement); this._calculator = calculator; return(calculator); }
public override IPricingResult Calculate(ResetStrikeOption trade, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); var exerciseDate = trade.ExerciseDates.Last(); var strikefixingDate = trade.StrikeFixingDate; var spot = market.SpotPrices.Value.Values.First(); var sigma = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: exerciseDate, option: trade, spot: spot); var T = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade); var t = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, strikefixingDate, trade); var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var dividendRateInput = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var dividendRate = AnalyticalOptionPricerUtil.dividenRate(trade.UnderlyingProductType, dividendRateInput, riskFreeRate); var calculator = new ResetStrikeOptionCalculator(trade.OptionType, trade.ResetStrikeType, trade.UnderlyingProductType, trade.Strike, market.SpotPrices.Value.Values.First(), T, t, sigma, riskFreeRate, dividendRate, trade.Notional); result.Pv = calculator.Pv; result.Delta = calculator.Delta; result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First(); result.Gamma = calculator.Gamma; result.GammaCash = result.Gamma * market.SpotPrices.Value.Values.First() * market.SpotPrices.Value.Values.First() / 100; result.Vega = calculator.Vega; result.Rho = calculator.Rho; result.Theta = calculator.Theta; result.DDeltaDt = calculator.DDeltaDt; result.DDeltaDvol = calculator.DDeltaDvol; result.DVegaDvol = calculator.DDeltaDvol; result.DVegaDt = calculator.DVegaDt; return(result); }
public override IPricingResult Calculate(RainbowOption trade, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); var exerciseDate = trade.ExerciseDates.Last(); var maturityDate = trade.UnderlyingMaturityDate; //TODO: support timeIncrement var exerciseInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade); var maturityInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, maturityDate, trade); var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var ticker1 = trade.UnderlyingTickers[0]; var ticker2 = trade.UnderlyingTickers[1]; double dividendRate1, dividendRate2; if (AnalyticalOptionPricerUtil.isForwardFuturesOption(trade.UnderlyingProductType)) { dividendRate1 = riskFreeRate; dividendRate2 = riskFreeRate; } else { dividendRate1 = market.DividendCurves.Value[ticker1].ZeroRate(market.ValuationDate, exerciseDate); dividendRate2 = market.DividendCurves.Value[ticker2].ZeroRate(market.ValuationDate, exerciseDate); } var spot1 = market.SpotPrices.Value[ticker1]; var spot2 = market.SpotPrices.Value[ticker2]; var sigma1 = market.VolSurfaces.Value[ticker1].GetValue(exerciseDate, trade.Strikes[0], spot1); var sigma2 = market.VolSurfaces.Value[ticker2].GetValue(exerciseDate, trade.Strikes[0], spot2); var strike1 = trade.Strikes[0]; var strike2 = 0.0; if (trade.Strikes.Length > 1) { strike2 = trade.Strikes[1]; } //Note: correlation here is a scala number. can be a grid for multi-asset option var rho = market.Correlations.Value[ticker1].GetValue(exerciseDate, strike1); var calculator = new RainbowOptionCalculator(trade.OptionType, trade.RainbowType, strike1, strike2, trade.CashAmount, spot1, spot2, rho, sigma1, sigma2, exerciseInYears, riskFreeRate, dividendRate1, dividendRate2, trade.Notional); bool isExpired = trade.ExerciseDates.Last() < market.ValuationDate; bool isExpiredforTheta = trade.ExerciseDates.Last() <= market.ValuationDate; if (isExpired) { result.Pv = 0.0; result.Theta = 0.0; result.asset1Delta = 0.0; result.asset1DeltaCash = 0.0; result.asset2Delta = 0.0; result.asset2DeltaCash = 0.0; result.asset1PartialDelta = 0.0; result.asset2PartialDelta = 0.0; result.asset1Gamma = 0.0; result.asset1GammaCash = 0.0; result.asset2Gamma = 0.0; result.asset2GammaCash = 0.0; result.asset1Vega = 0.0; result.asset2Vega = 0.0; result.Rho = 0.0; result.Theta = 0.0; result.asset1DDeltaDt = 0.0; result.asset2DDeltaDt = 0.0; result.asset1DVegaDvol = 0.0; result.asset2DVegaDvol = 0.0; result.asset1DDeltaDvol = 0.0; result.asset2DDeltaDvol = 0.0; result.asset1DVegaDt = 0.0; result.asset2DVegaDt = 0.0; result.crossGamma = 0.0; result.crossVomma = 0.0; result.crossVanna1 = 0.0; result.crossVanna2 = 0.0; result.correlationVega = 0.0; } else { if (result.IsRequested(PricingRequest.Pv)) { result.Pv = calculator.Pv; } if (AnalyticalOptionPricerUtil.isBasicPricing(result)) { result.asset1Delta = calculator.asset1Delta; result.asset2Delta = calculator.asset2Delta; result.asset1DeltaCash = calculator.asset1Delta * spot1; result.asset2DeltaCash = calculator.asset2Delta * spot2; result.asset1PartialDelta = calculator.asset1PartialDelta; result.asset2PartialDelta = calculator.asset2PartialDelta; result.asset1Gamma = calculator.asset1Gamma; result.asset2Gamma = calculator.asset2Gamma; result.asset1GammaCash = calculator.asset1Gamma * spot1 * spot1 / 100; result.asset2GammaCash = calculator.asset2Gamma * spot2 * spot2 / 100; result.asset1Vega = calculator.asset1Vega; result.asset2Vega = calculator.asset2Vega; result.Rho = calculator.Rho; result.Theta = (isExpiredforTheta) ? 0.0 : calculator.Theta; } if (AnalyticalOptionPricerUtil.isHighOrderPricing(result)) { result.asset1DVegaDvol = calculator.asset1DVegaDvol; result.asset2DVegaDvol = calculator.asset2DVegaDvol; result.asset1DDeltaDvol = calculator.asset1DDeltaDvol; result.asset2DDeltaDvol = calculator.asset2DDeltaDvol; result.crossGamma = calculator.crossGamma; result.crossVomma = calculator.crossVomma; result.crossVanna1 = calculator.crossVanna1; result.crossVanna2 = calculator.crossVanna2; result.correlationVega = calculator.correlationVega; } if (isExpiredforTheta) { result.asset1DDeltaDt = result.asset2DDeltaDt = 0.0; result.asset1DVegaDt = result.asset2DVegaDt = 0.0; } else { result.asset1DDeltaDt = calculator.asset1DDeltaDt; result.asset2DDeltaDt = calculator.asset2DDeltaDt; result.asset1DVegaDt = calculator.asset1DVegaDt; result.asset2DVegaDt = calculator.asset2DVegaDt; } } return(result); }
public override IPricingResult Calculate(AsianOption trade, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); var exerciseDate = trade.ExerciseDates.Last(); var remainingObsDates = trade.ObservationDates.Where(x => x > market.ValuationDate).ToArray(); var n = trade.ObservationDates.Count(); var n2 = remainingObsDates.Count(); var m = n - n2; if (trade.Fixings.Count != m) { throw new PricingLibraryException("AsianOption: number of fixings does not match!"); } var fixingAverage = trade.Fixings.Any() ? trade.Fixings.Average(x => x.Value) : 0.0; if (!remainingObsDates.Any()) { //already fix on all observation days var cfs = trade.GetPayoff(new[] { fixingAverage }); result.Pv = cfs.Sum(x => x.PaymentAmount * market.DiscountCurve.Value.GetDf(market.ValuationDate, x.PaymentDate)); result.Delta = 0.0; result.DeltaCash = 0.0; result.Gamma = 0.0; result.GammaCash = 0.0; result.Vega = 0.0; result.Theta = 0.0; result.Rho = 0.0; return(result); } //TODO: do it properly var newSpot = market.SpotPrices.Value.Values.First(); var sigma = market.VolSurfaces.Value.Values.First().GetValue(exerciseDate, trade.Strike, newSpot); var newSigma = market.VolSurfaces.Value.Values.First().GetValue(exerciseDate, trade.Strike, newSpot); double newStrike; var factor = 1.0; if (remainingObsDates.Count() == 1) { newStrike = trade.ObservationDates.Count() * trade.Strike - (n - 1) * trade.Fixings.Average(x => x.Value); factor = 1.0 / n; } else { var T = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade); var T2 = AnalyticalOptionPricerUtil.timeToMaturityFraction(remainingObsDates[0], remainingObsDates.Last(), trade); var t1 = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, remainingObsDates[0], trade); var h = T2 / (n2 - 1); var S = market.SpotPrices.Value.Values.First(); var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var dividendRate = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var b = riskFreeRate - dividendRate; var sigma2 = sigma * sigma; double eat, eat2; if (riskFreeRate.AlmostEqual(dividendRate)) { eat = market.SpotPrices.Value.Values.First(); eat2 = S * S * Math.Exp(sigma2 * t1) / n / n * ( (1 - Math.Exp(sigma2 * h * n)) / (1 - Math.Exp(sigma2 * h)) + 2.0 / (1 - Math.Exp(sigma2 * h)) * (n - (1 - Math.Exp(sigma2 * h * n)) / (1 - Math.Exp(sigma2 * h))) ); } else { var o = 2 * b + sigma2; eat = S / n2 * Math.Exp(b * t1) * (1 - Math.Exp(b * h * n2)) / (1 - Math.Exp(b * h)); eat2 = S * S * Math.Exp(o * t1) / n / n * ( (1 - Math.Exp(o * h * n)) / (1 - Math.Exp(o * h)) + 2.0 / (1 - Math.Exp((b + sigma2) * h)) * ((1 - Math.Exp(b * h * n)) / (1 - Math.Exp(b * h)) - (1 - Math.Exp(o * h * n)) / (1 - Math.Exp(o * h))) ); } newSpot = eat; newSigma = Math.Sqrt(Math.Log(eat2 / eat / eat) / T); newStrike = (n * trade.Strike - m * fixingAverage) / (n - m) - m / (n - m); factor = 1.0 * (n - m) / n; } var newTrade = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, newStrike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional, trade.SettlmentGap, trade.OptionPremiumPaymentDate, trade.OptionPremium); var newVol = market.VolSurfaces.Value.Values.First().BumpVolSurf(newSigma - sigma); var newMarket = market.UpdateCondition( new UpdateMktConditionPack <Dictionary <string, double> >(x => x.SpotPrices, new Dictionary <string, double> { { "", newSpot } }), new UpdateMktConditionPack <Dictionary <string, IVolSurface> >(x => x.VolSurfaces, new Dictionary <string, IVolSurface> { { "", newVol } }) ); var bsEngine = new AnalyticalVanillaEuropeanOptionEngine(); result = (PricingResult)bsEngine.Calculate(newTrade, newMarket, request); result.Pv *= factor; result.Delta *= factor; result.Gamma *= factor; result.Vega *= factor; result.Theta *= factor; result.Rho *= factor; return(result); }