public void CommodityBinaryEuropeanOptionTest() { var goldOption = new BinaryOption( new Date(2015, 03, 20), new Date(2015, 06, 16), OptionExercise.European, OptionType.Put, 231.733, InstrumentType.Futures, BinaryOptionPayoffType.CashOrNothing, 10.0, CalendarImpl.Get("chn"), new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { new Date(2015, 06, 16) }, new[] { new Date(2015, 06, 16) }, 5.5 ); var market = GetMarket(); IMarketCondition marketCondition = new MarketCondition( x => x.ValuationDate.Value = market.ReferenceDate, x => x.DiscountCurve.Value = market.GetData <CurveData>("Fr007").YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", market.GetData <CurveData>("Fr007").YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", 240.6 } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", market.GetData <VolSurfMktData>("goldVolSurf").ToImpliedVolSurface(market.ReferenceDate) } } ); var engine = new AnalyticalBinaryEuropeanOptionEngine(); var result = engine.Calculate(goldOption, marketCondition, PricingRequest.All); Assert.AreEqual(0.615985804, result.Pv, 1e-8); Assert.AreEqual(-0.409184000310747, result.Delta, 1e-8); Assert.AreEqual(0.239395655872165, result.Gamma, 1e-8); Assert.AreEqual(0.265082040475919, result.Vega, 1e-8); Assert.AreEqual(-8.43816170E-07, result.Rho, 1e-8); var engine2 = new AnalyticalBinaryEuropeanOptionReplicationEngine(2.0, BinaryOptionReplicationStrategy.Up); result = engine2.Calculate(goldOption, marketCondition, PricingRequest.All); Assert.AreEqual(1.25655313, result.Pv, 1e-8); Assert.AreEqual(-0.745647330608376, result.Delta, 1e-8); Assert.AreEqual(0.377738685022888, result.Gamma, 1e-8); Assert.AreEqual(0.417379971819684, result.Vega, 1e-8); Assert.AreEqual(-1.72130447839702E-06, result.Rho, 1e-8); }
public void CommodityJinTaoBinaryEuropeanOptionTest() { var strike = 3100.0; var spot = 2900; var expiry = new Date(2017, 12, 17); var valuationDay = "2017-12-01"; var option = new BinaryOption( new Date(2017, 12, 1), expiry, OptionExercise.European, OptionType.Call, strike, InstrumentType.CommodityFutures, BinaryOptionPayoffType.CashOrNothing, 2, CalendarImpl.Get("chn"), new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { expiry }, new[] { expiry }, notional: 1 ); var optionInfo = new BinaryOptionInfo( tradeId: "", valuationParameter: new OptionValuationParameters("Fr007", "diviCurve", "volSurf", "000300.SH"), underlyingTicker: "000300.SH", strike: strike, underlyingInstrumentType: "CommodityFutures", optionType: "Call", notional: 1, startDate: "2017-12-01", exerciseDates: "2017-12-17" ) { CashOrNothingAmount = 2, BinaryOptionPayoffType = "CashOrNothing", BinaryOptionReplicationStrategy = "Down", ReplicationShiftSize = 2, }; var curveName = "Fr007"; var volName = "volSurf"; var diviCurveName = "diviCurve"; var market = GetMarketJinTao(valuationDay, rate: 0.04, vol: 0.4, dividendRate: 0, curveName: curveName, volName: volName, diviCurveName: diviCurveName, spot: spot); var volsurf = market.GetData <VolSurfMktData>(volName).ToImpliedVolSurface(market.ReferenceDate); IMarketCondition marketCondition = new MarketCondition( x => x.ValuationDate.Value = market.ReferenceDate, x => x.DiscountCurve.Value = market.GetData <CurveData>(curveName).YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", market.GetData <CurveData>(diviCurveName).YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spot } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", volsurf } } ); var engine = new AnalyticalBinaryEuropeanOptionEngine(); var result = engine.Calculate(option, marketCondition, PricingRequest.All); Assert.AreEqual(0.401208951727572, result.Pv, 1e-8); Assert.AreEqual(0.00230806033816866, result.Delta, 1e-8); Assert.AreEqual(7.16979364767667E-06, result.Gamma, 1e-8); Assert.AreEqual(0.0105751548032081, result.Vega, 1e-8); Assert.AreEqual(-0.0149236357909549, result.Theta, 1e-8); Assert.AreEqual(-1.75872031726865E-06, result.Rho, 1e-8); var engine2 = new AnalyticalBinaryEuropeanOptionReplicationEngine(2.0, BinaryOptionReplicationStrategy.Down); var result2 = engine2.Calculate(option, marketCondition, PricingRequest.All); Assert.AreEqual(0.403373182249897, result2.Pv, 1e-7); Assert.AreEqual(0.00231550673674974, result2.Delta, 1e-7); Assert.AreEqual(7.16340764483903E-06, result2.Gamma, 1e-7); Assert.AreEqual(0.0105550810113932, result2.Vega, 1e-7); Assert.AreEqual(-0.0149004654797067, result2.Theta, 1e-7); Assert.AreEqual(-1.74927811613657E-06, result2.Rho, 1e-7); var vfResult = new BinaryOptionVf(optionInfo).ValueTrade(market, PricingRequest.Pv); Assert.AreEqual(vfResult.Pv, result2.Pv, 1e-7); Assert.AreEqual(result2.Pv > result.Pv, true); }
public void CommodityBinaryOptionGreekTest(double vol, double spot, double strike, Boolean isCall = true, Boolean isCashOrNothing = true, string t0 = "2017-12-01", string t1 = "2017-12-02", double volMove = 0.10, double mktMove = 1e-4, double toleranceInPct = 2) { var T0 = DateFromStr(t0); var T1 = DateFromStr(t1); var spotNew = spot + spot * mktMove; var volNew = vol + volMove; var expiry = new Date(2017, 12, 17); var valuationDay = t0; var valuationDayNew = t1; var option = new BinaryOption( T0, expiry, OptionExercise.European, isCall ? OptionType.Call : OptionType.Put, strike, InstrumentType.CommodityFutures, isCashOrNothing ? BinaryOptionPayoffType.CashOrNothing : BinaryOptionPayoffType.AssetOrNothing, 2, CalendarImpl.Get("chn"), new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { expiry }, new[] { expiry }, notional: 1 ); var curveName = "Fr007"; var volName = "volSurf"; var diviCurveName = "diviCurve"; var market = GetMarketJinTao(valuationDay, rate: 0.04, vol: vol, dividendRate: 0, curveName: curveName, volName: volName, diviCurveName: diviCurveName); IMarketCondition marketCondition = new MarketCondition( x => x.ValuationDate.Value = market.ReferenceDate, x => x.DiscountCurve.Value = market.GetData <CurveData>(curveName).YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", market.GetData <CurveData>(diviCurveName).YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spot } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", market.GetData <VolSurfMktData>(volName).ToImpliedVolSurface(market.ReferenceDate) } } ); var marketNew = GetMarketJinTao(valuationDayNew, rate: 0.04, vol: volNew, dividendRate: 0, curveName: curveName, volName: volName, diviCurveName: diviCurveName); IMarketCondition marketConditionNew = new MarketCondition( x => x.ValuationDate.Value = marketNew.ReferenceDate, x => x.DiscountCurve.Value = marketNew.GetData <CurveData>(curveName).YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", marketNew.GetData <CurveData>(diviCurveName).YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spotNew } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", marketNew.GetData <VolSurfMktData>(volName).ToImpliedVolSurface(market.ReferenceDate) } } ); IMarketCondition marketConditionPI = new MarketCondition( x => x.ValuationDate.Value = market.ReferenceDate, x => x.DiscountCurve.Value = market.GetData <CurveData>(curveName).YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", market.GetData <CurveData>(diviCurveName).YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spotNew } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", market.GetData <VolSurfMktData>(volName).ToImpliedVolSurface(market.ReferenceDate) } } ); var marketVI = GetMarketJinTao(valuationDay, rate: 0.04, vol: volNew, dividendRate: 0, curveName: curveName, volName: volName, diviCurveName: diviCurveName); IMarketCondition marketConditionVI = new MarketCondition( x => x.ValuationDate.Value = marketVI.ReferenceDate, x => x.DiscountCurve.Value = marketVI.GetData <CurveData>(curveName).YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", marketVI.GetData <CurveData>(diviCurveName).YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spot } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", marketVI.GetData <VolSurfMktData>(volName).ToImpliedVolSurface(market.ReferenceDate) } } ); var marketPVC = GetMarketJinTao(valuationDay, rate: 0.04, vol: volNew, dividendRate: 0, curveName: curveName, volName: volName, diviCurveName: diviCurveName); IMarketCondition marketConditionPVC = new MarketCondition( x => x.ValuationDate.Value = marketPVC.ReferenceDate, x => x.DiscountCurve.Value = marketPVC.GetData <CurveData>(curveName).YieldCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", marketPVC.GetData <CurveData>(diviCurveName).YieldCurve } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spotNew } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", marketPVC.GetData <VolSurfMktData>(volName).ToImpliedVolSurface(market.ReferenceDate) } } ); var engine = new AnalyticalBinaryEuropeanOptionEngine(); var result = engine.Calculate(option, marketCondition, PricingRequest.All); var resultNew = engine.Calculate(option, marketConditionNew, PricingRequest.All); var resultPI = engine.Calculate(option, marketConditionPI, PricingRequest.All); var resultVI = engine.Calculate(option, marketConditionVI, PricingRequest.All); var resultPVC = engine.Calculate(option, marketConditionPVC, 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); var engine2 = new AnalyticalBinaryEuropeanOptionReplicationEngine(2.0, BinaryOptionReplicationStrategy.Up); var result2 = engine2.Calculate(option, marketCondition, PricingRequest.All); var resultNew2 = engine2.Calculate(option, marketConditionNew, PricingRequest.All); var resultPI2 = engine2.Calculate(option, marketConditionPI, PricingRequest.All); var resultVI2 = engine2.Calculate(option, marketConditionVI, PricingRequest.All); var resultPVC2 = engine2.Calculate(option, marketConditionPVC, PricingRequest.All); var actualPL2 = resultNew2.Pv - result2.Pv; //price Impact //PI = PV(t-1, priceNew) - Pv(t-1) var basePv2 = result2.Pv; var PI2 = resultPI2.Pv - basePv2; var thetapl2 = result2.Theta * (T1 - T0); //vol impact //VI = PV(t-1. volNew) - Pv (t-1) var VI2 = resultVI2.Pv - basePv2; //price vol cross impact //PVC = PV(t-1. volNew, PriceNew) - Pv (t-1) - (PI+VI) var PVC2 = resultPVC2.Pv - basePv2 - PI2 - VI2; var newEstimate2 = PI2 + VI2 + PVC2 + thetapl2; var newUnexplained2 = actualPL2 - newEstimate2; Assert.AreEqual(true, Math.Abs(newUnexplained2 / actualPL2) * 100.0 < toleranceInPct); }