/// <summary> /// AreaSpread describes areas that should be placed on the map /// </summary> /// <param name="id">Mapped tile id</param> /// <param name="flag">Tile flags</param> /// <param name="percentage">Percentage of map space covered by this flag</param> /// <param name="minSizeInMeter">Minimum size of area in meter</param> /// <param name="maxSizeInMeter">Maximum size of area in meter</param> /// <param name="useEdgeNoise">Can be used to add aliasing to avoid symmetric areas</param> /// <param name="connectEqualFlags">Areas with the same flags will be connected, all free tiles within a give distance will be set to the flag value</param> /// <param name="connectDistance">Maximum distance between two areas with the same flag</param> /// <param name="spreadType">Geometrical form of the area</param> /// <param name="layer">Dicides which generation algorithm will be used</param> public AreaSpread(ushort id, byte flag, float percentage, int minSizeInMeter, int maxSizeInMeter, bool useEdgeNoise, bool connectEqualFlags, int connectDistance, SpreadOption spreadType, LayerType layer) { Id = id; Flag = flag; Percentage = percentage; MinSizeInMeter = minSizeInMeter; MaxSizeInMeter = maxSizeInMeter; UseEdgeNoise = useEdgeNoise; SpreadType = spreadType; Layer = layer; ConnectEqualFlags = connectEqualFlags; ConnectDistance = connectDistance; }
private void SpreadOptionBjerksundCalc(string spreadType = "TwoAssetsSpread", Boolean isCall = true, string ValuationDate = "2017-12-26", double vol1 = 0.28, double spot1 = 1.0, double vol2 = 0.30, double spot2 = 2.0, double vol3 = 0.28, double spot3 = 1.0, double vol4 = 0.28, double spot4 = 1.0, double strike = 1.03, double tol = 1e-8) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var asset1 = "asset1"; var asset2 = "asset2"; var asset3 = "asset3"; var asset4 = "asset4"; var option = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: (isCall) ? OptionType.Call : OptionType.Put, spreadType: ToSpreadType(spreadType), strike: strike, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var market = TestMarket(referenceDate: ValuationDate, vol1: vol1, vol2: vol2, vol3: vol3, vol4: vol4, spot1: spot1, spot2: spot2, spot3: spot3, spot4: spot4, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var analyticalEngine = new AnalyticalSpreadOptionBjerksundEngine(); var analyticalResult = analyticalEngine.Calculate(option, market, PricingRequest.All); var Engine = new AnalyticalSpreadOptionKirkEngine(); var Result = Engine.Calculate(option, market, PricingRequest.All); Assert.AreEqual(analyticalResult.Pv, Result.Pv, tol); }
private void SpreadOptionGreekCalc(double ExpectedPv, string spreadType = "TwoAssetsSpread", string ValuationDate = "2017-12-26") { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var asset1 = "asset1"; var asset2 = "asset2"; var asset3 = "asset3"; var asset4 = "asset4"; var option = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: ToSpreadType(spreadType), strike: 1.03, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var market = TestMarket(referenceDate: ValuationDate, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); //var analyticalEngine = new AnalyticalSpreadOptionEngine(); //var analyticalResult = analyticalEngine.Calculate(option, market, PricingRequest.All); var Engine = new AnalyticalSpreadOptionKirkEngine(); var Result = Engine.Calculate(option, market, PricingRequest.All); //Assert.AreEqual(ExpectedPv, analyticalResult.Pv, 1e-8); Assert.AreEqual(ExpectedPv, Result.Pv, 1e-8); }
private void SpreadOptionGreekTest(double vol1 = 0.28, double vol2 = 0.30, double vol3 = 0.40, double spot1 = 4900, double spot2 = 1500, double spot3 = 1500, string spreadType = "TwoAssetsSpread", string t0 = "2017-12-26", string t1 = "2017-12-27", 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 spot1New = spot1 + spot1 * mktMove; var spot2New = spot2 + spot2 * mktMove; var spot3New = spot3 + spot3 * mktMove; var vol1New = vol1 + volMove; var vol2New = vol2 + volMove; var vol3New = vol3 + volMove; var T0 = DateFromStr(t0); var T1 = DateFromStr(t1); var valuationDay = t0; var valuationDayNew = t1; var asset1 = "asset1"; var asset2 = "asset2"; var asset3 = "asset3"; var asset4 = "asset4"; var option = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: ToSpreadType(spreadType), strike: 1000, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var market = TestMarket(referenceDate: t0, vol1: vol1, vol2: vol2, vol3: vol3, spot1: spot1, spot2: spot2, spot3: spot3, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var marketNew = TestMarket(referenceDate: t1, vol1: vol1New, vol2: vol2New, vol3: vol3New, spot1: spot1New, spot2: spot2New, spot3: spot3New, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var marketPI = TestMarket(referenceDate: t0, vol1: vol1, vol2: vol2, vol3: vol3, spot1: spot1New, spot2: spot2New, spot3: spot3New, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var marketVI = TestMarket(referenceDate: t0, vol1: vol1New, vol2: vol2New, vol3: vol3New, spot1: spot1, spot2: spot2, spot3: spot3, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var marketPVC = TestMarket(referenceDate: t0, vol1: vol1New, vol2: vol2New, vol3: vol3New, spot1: spot1New, spot2: spot2New, spot3: spot3New, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var engine = new AnalyticalSpreadOptionKirkEngine(); 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 SpreadVanillaCalc(string spreadType = "TwoAssetsSpread", string ValuationDate = "2017-12-26", double spot1 = 4500, double spot2 = 2500, double strike = 2000, double vol1 = 0.5, double vol2 = 0.5, double rho12 = 0.5) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var asset1 = "asset1"; var asset2 = "asset2"; var asset3 = "asset3"; var asset4 = "asset4"; var option = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: ToSpreadType(spreadType), strike: strike, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var option1 = new VanillaOption( valuationDate, maturityDate, OptionExercise.European, OptionType.Call, 2.0 * strike, InstrumentType.EquityIndex, calendar, new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, new[] { maturityDate } ); var option2 = new VanillaOption( valuationDate, maturityDate, OptionExercise.European, OptionType.Put, strike, InstrumentType.EquityIndex, calendar, new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, new[] { maturityDate } ); var market = TestMarket(referenceDate: ValuationDate, vol1: vol1, vol2: vol2, vol3: 0.0, spot1: spot1, spot2: spot2, spot3: 0.0, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4, rho12: rho12, rho23: 0.0, rho13: 0.0); var market1 = GetMarket(referenceDate: ValuationDate, vol: vol1, spot: spot1); var market2 = GetMarket(referenceDate: ValuationDate, vol: vol2, spot: spot2); var analyticalEngine = new AnalyticalSpreadOptionKirkEngine(); var analyticalEngine2 = new AnalyticalVanillaEuropeanOptionEngine(); var result = analyticalEngine.Calculate(option, market, PricingRequest.All); var result1 = analyticalEngine2.Calculate(option1, market1, PricingRequest.All); var result2 = analyticalEngine2.Calculate(option2, market2, PricingRequest.All); Assert.AreEqual(true, result1.Pv + result2.Pv - result.Pv > 0); }
private void SpreadOptionParity(string ValuationDate = "2017-12-26", double vol1 = 0.28, double spot1 = 1.0, double vol2 = 0.30, double spot2 = 2.0, double vol3 = 0.30, double spot3 = 2.0, double strike = 1.03) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var asset1 = "asset1"; var asset2 = "asset2"; var asset3 = "asset3"; var asset4 = "asset4"; var option1 = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: SpreadType.ThreeAssetsSpread, strike: strike, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var option2 = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: SpreadType.FourAssetsSpread, strike: strike, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var option3 = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: SpreadType.ThreeAssetsSpreadBasket, strike: strike, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var option4 = new SpreadOption( startDate: valuationDate, maturityDate: maturityDate, exercise: OptionExercise.European, optionType: OptionType.Call, spreadType: SpreadType.FourAssetsSpreadBasketType1, strike: strike, weights: new double[] { 1.0, 1.0, 1.0, 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, asset3, asset4 } ) { UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 } }; var market = TestMarket(referenceDate: ValuationDate, vol1: vol1, vol2: vol2, vol3: vol3, spot1: spot1, spot2: spot2, spot3: spot3, asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4); var analyticalEngine = new AnalyticalSpreadOptionKirkEngine(); var result1 = analyticalEngine.Calculate(option1, market, PricingRequest.All); var result2 = analyticalEngine.Calculate(option2, market, PricingRequest.All); var result3 = analyticalEngine.Calculate(option3, market, PricingRequest.All); var result4 = analyticalEngine.Calculate(option4, market, PricingRequest.All); var Engine = new AnalyticalSpreadOptionBjerksundEngine(); var result5 = Engine.Calculate(option1, market, PricingRequest.All); var result6 = Engine.Calculate(option2, market, PricingRequest.All); var result7 = Engine.Calculate(option3, market, PricingRequest.All); var result8 = Engine.Calculate(option4, market, PricingRequest.All); Assert.AreEqual(result1.Pv, result2.Pv, 1.0e-8); Assert.AreEqual(result3.Pv, result4.Pv, 1.0e-8); //Assert.AreEqual(result5.Pv, result6.Pv, 1.0e-8); Assert.AreEqual(result7.Pv, result8.Pv, 1.0e-8); }
public void testKirkEngine() { // Testing Kirk approximation for spread options /* The example data below are from "complete guide to option * pricing formulas", Espen Gaarder Haug, p 60 * * Expected values of option theta were calculated using automatic * differentiation of the pricing function. The engine uses closed-form * formula */ Case[] cases = { new Case(28.0, 20.0, 7.0, 0.05, 0.29, 0.36, 0.42, 90, 2.1670, 3.0431), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, -0.5, 36, 4.7530, 25.5905), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.0, 36, 3.7970, 20.8841), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.5, 36, 2.5537, 14.7260), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, -0.5, 180, 10.7517, 10.0847), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.0, 180, 8.7020, 8.2619), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.5, 180, 6.0257, 5.8661), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, -0.5, 36, 5.4275, 28.9013), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.0, 36, 4.3712, 23.7133), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.5, 36, 3.0086, 16.9864), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, -0.5, 180, 12.1941, 11.3603), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.0, 180, 9.9340, 9.3589), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.5, 180, 7.0067, 6.7463), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, -0.5, 36, 5.4061, 28.7963), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.0, 36, 4.3451, 23.5848), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.5, 36, 2.9723, 16.8060), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, -0.5, 180, 12.1483, 11.3200), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.0, 180, 9.8780, 9.3091), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.5, 180, 6.9284, 6.6761) }; for (int i = 0; i < cases.Length; ++i) { // First step: preparing the test values // Useful dates DayCounter dc = new Actual360(); Date today = Date.Today; Date exerciseDate = today + cases[i].length; // Futures values SimpleQuote F1 = new SimpleQuote(cases[i].F1); SimpleQuote F2 = new SimpleQuote(cases[i].F2); // Risk-free interest rate double riskFreeRate = cases[i].r; YieldTermStructure forwardRate = Utilities.flatRate(today, riskFreeRate, dc); // Correlation Quote rho = new SimpleQuote(cases[i].rho); // Volatilities double vol1 = cases[i].sigma1; double vol2 = cases[i].sigma2; BlackVolTermStructure volTS1 = Utilities.flatVol(today, vol1, dc); BlackVolTermStructure volTS2 = Utilities.flatVol(today, vol2, dc); // Black-Scholes Processes // The BlackProcess is the relevant class for futures contracts BlackProcess stochProcess1 = new BlackProcess(new Handle <Quote>(F1), new Handle <YieldTermStructure>(forwardRate), new Handle <BlackVolTermStructure>(volTS1)); BlackProcess stochProcess2 = new BlackProcess(new Handle <Quote>(F2), new Handle <YieldTermStructure>(forwardRate), new Handle <BlackVolTermStructure>(volTS2)); // Creating the pricing engine IPricingEngine engine = new KirkSpreadOptionEngine(stochProcess1, stochProcess2, new Handle <Quote>(rho)); // Finally, create the option: Option.Type type = Option.Type.Call; double strike = cases[i].X; PlainVanillaPayoff payoff = new PlainVanillaPayoff(type, strike); Exercise exercise = new EuropeanExercise(exerciseDate); SpreadOption option = new SpreadOption(payoff, exercise); option.setPricingEngine(engine); // And test the data double value = option.NPV(); double theta = option.theta(); double tolerance = 1e-4; if (Math.Abs(value - cases[i].value) > tolerance) { REPORT_FAILURE("value", payoff, exercise, cases[i].value, value, tolerance, today); } if (Math.Abs(theta - cases[i].theta) > tolerance) { REPORT_FAILURE("theta", payoff, exercise, cases[i].theta, theta, tolerance, today); } } }