private void RainbowOptionGreekCalc(double ExpectedPv, string rainbowType = "Max", string ValuationDate = "2017-12-18", double vol = 0.28, double spot = 1.0, double volNew = 0.30, double spotNew = 2.0, double strike1 = 1.03, double strike2 = 1.05, Boolean isCall = true) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var asset1 = "asset1"; var asset2 = "asset2"; var option = new RainbowOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: isCall ? OptionType.Call : OptionType.Put, rainbowType: ToRainbowType(rainbowType), strikes: new double[] { strike1, strike2 }, cashAmount: 1.0, underlyingInstrumentType: InstrumentType.EquityIndex, calendar: calendar, dayCount: new Act365(), payoffCcy: CurrencyCode.CNY, settlementCcy: CurrencyCode.CNY, exerciseDates: new[] { maturityDate }, observationDates: new[] { maturityDate }, underlyingTickers: new[] { asset1, asset2 } ) { UnderlyingTickers = new string[] { asset1, asset2 } }; var market = TestMarket(referenceDate: ValuationDate, vol: vol, volNew: volNew, spot: spot, spotNew: spotNew, asset1: asset1, asset2: asset2); var analyticalEngine = new AnalyticalRainbowOptionEngine(); var analyticalResult = analyticalEngine.Calculate(option, market, PricingRequest.All); Assert.AreEqual(ExpectedPv, analyticalResult.Pv, 1e-8); }
private void RainbowOptionGreekTest(double vol = 0.28, double spot = 1.0, double volNew = 0.30, double spotNew = 2.0, double strike1 = 1.03, double strike2 = 1.05, Boolean isCall = true, Boolean isBest = true, string t0 = "2015-03-19", string t1 = "2015-03-20", double volMove = 0.10, double mktMove = 1e-4, double toleranceInPct = 2) { var valuationDate = DateFromStr(t0); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var spot2 = spot + spot * mktMove; var spotNew2 = spotNew + spotNew * mktMove; var vol2 = vol + volMove; var volNew2 = volNew + volMove; var T0 = DateFromStr(t0); var T1 = DateFromStr(t1); var valuationDay = t0; var valuationDayNew = t1; var asset1 = "asset1"; var asset2 = "asset2"; var option = new RainbowOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: isCall ? OptionType.Call : OptionType.Put, rainbowType: isBest ? RainbowType.Max : RainbowType.Min, strikes: new double[] { strike1, strike2 }, cashAmount: 1.0, underlyingInstrumentType: InstrumentType.EquityIndex, calendar: calendar, dayCount: new Act365(), payoffCcy: CurrencyCode.CNY, settlementCcy: CurrencyCode.CNY, exerciseDates: new[] { maturityDate }, observationDates: new[] { maturityDate }, underlyingTickers: new[] { asset1, asset2 } ) { UnderlyingTickers = new string[] { asset1, asset2 } }; var market = TestMarket(referenceDate: t0, vol: vol, volNew: volNew, spot: spot, spotNew: spotNew, asset1: asset1, asset2: asset2); var marketNew = TestMarket(referenceDate: t1, vol: vol2, volNew: volNew2, spot: spot2, spotNew: spotNew2, asset1: asset1, asset2: asset2); var marketPI = TestMarket(referenceDate: t0, vol: vol, volNew: volNew, spot: spot2, spotNew: spotNew2, asset1: asset1, asset2: asset2); var marketVI = TestMarket(referenceDate: t0, vol: vol2, volNew: volNew2, spot: spot, spotNew: spotNew, asset1: asset1, asset2: asset2); var marketPVC = TestMarket(referenceDate: t0, vol: vol2, volNew: volNew2, spot: spot2, spotNew: spotNew2, asset1: asset1, asset2: asset2); var engine = new AnalyticalRainbowOptionEngine(); var result = engine.Calculate(option, market, PricingRequest.All); var resultNew = engine.Calculate(option, marketNew, PricingRequest.All); var resultPI = engine.Calculate(option, marketPI, PricingRequest.All); var resultVI = engine.Calculate(option, marketVI, PricingRequest.All); var resultPVC = engine.Calculate(option, marketPVC, PricingRequest.All); var actualPL = resultNew.Pv - result.Pv; //price Impact //PI = PV(t-1, priceNew) - Pv(t-1) var basePv = result.Pv; var PI = resultPI.Pv - basePv; var thetapl = result.Theta * (T1 - T0); //vol impact //VI = PV(t-1. volNew) - Pv (t-1) var VI = resultVI.Pv - basePv; //price vol cross impact //PVC = PV(t-1. volNew, PriceNew) - Pv (t-1) - (PI+VI) var PVC = resultPVC.Pv - basePv - PI - VI; var newEstimate = PI + VI + PVC + thetapl; var newUnexplained = actualPL - newEstimate; //Time impact //TI = PV(t, all OldInfo) - Pv(t-1) //TODO: //Time/ price cross Impact //TPC = PV(t, priceNew) - pv(t-1) - (TI +PI) //Time/vol cross impact //TVC = PV(t, volNew) - pv(t-1) -(TI+VI) //TODO: //in case of big move ( vol and spot), we need high order risk to explain pnl //var diff = actualPL - esimstatedPL; //Assert.AreEqual(true, Math.Abs(diff / actualPL) * 100.0 < toleranceInPct); //pnl well explained in not too extreme moves Assert.AreEqual(true, Math.Abs(newUnexplained / actualPL) * 100.0 < toleranceInPct); }
private void RainbowOptionParity(string ValuationDate = "2017-12-18", double vol = 0.28, double spot = 1.0, double volNew = 0.30, double spotNew = 2.0, double strike1 = 1.03, double strike2 = 1.05, Boolean isCall = true, Boolean isBest = true) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var asset1 = "asset1"; var asset2 = "asset2"; var option1 = new RainbowOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: isCall ? OptionType.Call : OptionType.Put, rainbowType: isBest ? RainbowType.Max : RainbowType.Min, strikes: new double[] { strike1, strike2 }, cashAmount: 1.0, underlyingInstrumentType: InstrumentType.EquityIndex, calendar: calendar, dayCount: new Act365(), payoffCcy: CurrencyCode.CNY, settlementCcy: CurrencyCode.CNY, exerciseDates: new[] { maturityDate }, observationDates: new[] { maturityDate }, underlyingTickers: new[] { asset1, asset2 } ) { UnderlyingTickers = new string[] { asset1, asset2 } }; var option2 = new RainbowOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: isCall ? OptionType.Put : OptionType.Call, rainbowType: isBest ? RainbowType.Max : RainbowType.Min, strikes: new double[] { strike1, strike2 }, cashAmount: 1.0, underlyingInstrumentType: InstrumentType.EquityIndex, calendar: calendar, dayCount: new Act365(), payoffCcy: CurrencyCode.CNY, settlementCcy: CurrencyCode.CNY, exerciseDates: new[] { maturityDate }, observationDates: new[] { maturityDate }, underlyingTickers: new[] { asset1, asset2 } ) { UnderlyingTickers = new string[] { asset1, asset2 } }; var option = new RainbowOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: isCall ? OptionType.Call : OptionType.Put, rainbowType: isBest ? RainbowType.Max : RainbowType.Min, strikes: new double[] { 1e-8, 0 }, cashAmount: 1.0, underlyingInstrumentType: InstrumentType.EquityIndex, calendar: calendar, dayCount: new Act365(), payoffCcy: CurrencyCode.CNY, settlementCcy: CurrencyCode.CNY, exerciseDates: new[] { maturityDate }, observationDates: new[] { maturityDate }, underlyingTickers: new[] { asset1, asset2 } ) { UnderlyingTickers = new string[] { asset1, asset2 } }; var market = TestMarket(referenceDate: ValuationDate, vol: vol, volNew: volNew, spot: spot, spotNew: spotNew, asset1: asset1, asset2: asset2); var analyticalEngine = new AnalyticalRainbowOptionEngine(); var result1 = analyticalEngine.Calculate(option1, market, PricingRequest.All); var result2 = analyticalEngine.Calculate(option2, market, PricingRequest.All); var result = analyticalEngine.Calculate(option, market, PricingRequest.All); var r = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, maturityDate); var T = option1.DayCount.CalcDayCountFraction(market.ValuationDate, maturityDate); Assert.AreEqual(0.0, (result1.Pv + strike1 * Math.Exp(-r * T) - result2.Pv - result.Pv), 1.0e-6); }