public override double value(double x) { if (x.IsNotEqual(vol_.value())) { vol_.setValue(x); engine_.calculate(); } return(results_.value.Value - targetValue_); }
public void testFSpreaded() { //("Testing consistency of forward-spreaded term structure..."); CommonVars vars = new CommonVars(); double tolerance = 1.0e-10; Quote me = new SimpleQuote(0.01); Handle<Quote> mh = new Handle<Quote>(me); YieldTermStructure spreaded = new ForwardSpreadedTermStructure(new Handle<YieldTermStructure>(vars.termStructure), mh); Date testDate = vars.termStructure.referenceDate() + new Period(5, TimeUnit.Years); DayCounter tsdc = vars.termStructure.dayCounter(); DayCounter sprdc = spreaded.dayCounter(); double forward = vars.termStructure.forwardRate(testDate, testDate, tsdc, Compounding.Continuous, Frequency.NoFrequency).rate(); double spreadedForward = spreaded.forwardRate(testDate, testDate, sprdc, Compounding.Continuous, Frequency.NoFrequency).rate(); if (Math.Abs(forward - (spreadedForward - me.value())) > tolerance) Console.WriteLine("unable to reproduce forward from spreaded curve\n" + " calculated: " + (spreadedForward - me.value()) + "\n" + " expected: " + forward); }
public void testDerived() { // Testing derived quotes Func<double, double>[] f = {add10,mul10,sub10}; Quote me = new SimpleQuote(17.0); Handle<Quote> h = new Handle<Quote>(me); for (int i=0; i<3; i++) { DerivedQuote derived = new DerivedQuote(h,f[i]); double x = derived.value(), y = f[i](me.value()); if (Math.Abs(x-y) > 1.0e-10) Assert.Fail("derived quote yields " + x + "function result is " + y); } }
public void testComposite() { // Testing composite quotes Func<double, double,double >[] f = { add, mul, sub }; Quote me1 = new SimpleQuote(12.0), me2 = new SimpleQuote(13.0); Handle<Quote> h1 = new Handle<Quote>(me1), h2 = new Handle<Quote>(me2); for (int i=0; i<3; i++) { CompositeQuote composite = new CompositeQuote(h1,h2,f[i]); double x = composite.value(), y = f[i](me1.value(),me2.value()); if (Math.Abs(x-y) > 1.0e-10) Assert.Fail("composite quote yields " + x + "function result is " + y); } }
public void testBackwardFlatInterpolation() { // Testing backward flat interpolation between two dates... CommonVars vars = new CommonVars(); List<Handle<Quote>> spreads = new List<Handle<Quote>>(); SimpleQuote spread1 = new SimpleQuote(0.02); SimpleQuote spread2 = new SimpleQuote(0.03); SimpleQuote spread3 = new SimpleQuote(0.04); spreads.Add(new Handle<Quote>(spread1)); spreads.Add(new Handle<Quote>(spread2)); spreads.Add(new Handle<Quote>(spread3)); List<Date> spreadDates = new List<Date>(); spreadDates.Add(vars.calendar.advance(vars.today, 100, TimeUnit.Days)); spreadDates.Add(vars.calendar.advance(vars.today, 200, TimeUnit.Days)); spreadDates.Add(vars.calendar.advance(vars.today, 300, TimeUnit.Days)); Date interpolationDate = vars.calendar.advance(vars.today, 110, TimeUnit.Days); ZeroYieldStructure spreadedTermStructure = new InterpolatedPiecewiseZeroSpreadedTermStructure<BackwardFlat>( new Handle<YieldTermStructure>(vars.termStructure), spreads, spreadDates); double t = vars.dayCount.yearFraction(vars.today, interpolationDate); double interpolatedZeroRate = spreadedTermStructure.zeroRate(t, vars.compounding).value(); double tolerance = 1e-9; double expectedRate = vars.termStructure.zeroRate(t, vars.compounding).value() + spread2.value(); if (Math.Abs(interpolatedZeroRate - expectedRate) > tolerance) Assert.Fail( "unable to reproduce interpolated rate\n" + " calculated: " + interpolatedZeroRate + "\n" + " expected: " + expectedRate); }
static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(22, Month.September, 2004); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 2; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); todaysDate = Settings.evaluationDate(); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // deposits double d1wQuote = 0.0382; double d1mQuote = 0.0372; double d3mQuote = 0.0363; double d6mQuote = 0.0353; double d9mQuote = 0.0348; double d1yQuote = 0.0345; // FRAs double fra3x6Quote = 0.037125; double fra6x9Quote = 0.037125; double fra6x12Quote = 0.037125; // futures double fut1Quote = 96.2875; double fut2Quote = 96.7875; double fut3Quote = 96.9875; double fut4Quote = 96.6875; double fut5Quote = 96.4875; double fut6Quote = 96.3875; double fut7Quote = 96.2875; double fut8Quote = 96.0875; // swaps double s2yQuote = 0.037125; double s3yQuote = 0.0398; double s5yQuote = 0.0443; double s10yQuote = 0.05165; double s15yQuote = 0.055175; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits Quote d1wRate = new SimpleQuote(d1wQuote); Quote d1mRate = new SimpleQuote(d1mQuote); Quote d3mRate = new SimpleQuote(d3mQuote); Quote d6mRate = new SimpleQuote(d6mQuote); Quote d9mRate = new SimpleQuote(d9mQuote); Quote d1yRate = new SimpleQuote(d1yQuote); // FRAs Quote fra3x6Rate = new SimpleQuote(fra3x6Quote); Quote fra6x9Rate = new SimpleQuote(fra6x9Quote); Quote fra6x12Rate = new SimpleQuote(fra6x12Quote); // futures Quote fut1Price = new SimpleQuote(fut1Quote); Quote fut2Price = new SimpleQuote(fut2Quote); Quote fut3Price = new SimpleQuote(fut3Quote); Quote fut4Price = new SimpleQuote(fut4Quote); Quote fut5Price = new SimpleQuote(fut5Quote); Quote fut6Price = new SimpleQuote(fut6Quote); Quote fut7Price = new SimpleQuote(fut7Quote); Quote fut8Price = new SimpleQuote(fut8Quote); // swaps Quote s2yRate = new SimpleQuote(s2yQuote); Quote s3yRate = new SimpleQuote(s3yQuote); Quote s5yRate = new SimpleQuote(s5yQuote); Quote s10yRate = new SimpleQuote(s10yQuote); Quote s15yRate = new SimpleQuote(s15yQuote); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // deposits DayCounter depositDayCounter = new Actual360(); RateHelper d1w = new DepositRateHelper(new Handle<Quote>(d1wRate), new Period(1, TimeUnit.Weeks), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1m = new DepositRateHelper(new Handle<Quote>(d1mRate), new Period(1, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d3m = new DepositRateHelper(new Handle<Quote>(d3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d6m = new DepositRateHelper(new Handle<Quote>(d6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d9m = new DepositRateHelper(new Handle<Quote>(d9mRate), new Period(9, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1y = new DepositRateHelper(new Handle<Quote>(d1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup FRAs RateHelper fra3x6 = new FraRateHelper(new Handle<Quote>(fra3x6Rate), 3, 6, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper fra6x9 = new FraRateHelper(new Handle<Quote>(fra6x9Rate), 6, 9, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper fra6x12 = new FraRateHelper(new Handle<Quote>(fra6x12Rate), 6, 12, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup futures // Handle<Quote> convexityAdjustment = new Handle<Quote>(new SimpleQuote(0.0)); int futMonths = 3; Date imm = IMM.nextDate(settlementDate); RateHelper fut1 = new FuturesRateHelper(new Handle<Quote>(fut1Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut2 = new FuturesRateHelper(new Handle<Quote>(fut2Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut3 = new FuturesRateHelper(new Handle<Quote>(fut3Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut4 = new FuturesRateHelper(new Handle<Quote>(fut4Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut5 = new FuturesRateHelper(new Handle<Quote>(fut5Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut6 = new FuturesRateHelper(new Handle<Quote>(fut6Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut7 = new FuturesRateHelper(new Handle<Quote>(fut7Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut8 = new FuturesRateHelper(new Handle<Quote>(fut8Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps Frequency swFixedLegFrequency = Frequency.Annual; BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted; DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); IborIndex swFloatingLegIndex = new Euribor6M(); RateHelper s2y = new SwapRateHelper(new Handle<Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s3y = new SwapRateHelper(new Handle<Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s5y = new SwapRateHelper(new Handle<Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s10y = new SwapRateHelper(new Handle<Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s15y = new SwapRateHelper(new Handle<Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); double tolerance = 1.0e-15; // A depo-swap curve List<RateHelper> depoSwapInstruments = new List<RateHelper>(); depoSwapInstruments.Add(d1w); depoSwapInstruments.Add(d1m); depoSwapInstruments.Add(d3m); depoSwapInstruments.Add(d6m); depoSwapInstruments.Add(d9m); depoSwapInstruments.Add(d1y); depoSwapInstruments.Add(s2y); depoSwapInstruments.Add(s3y); depoSwapInstruments.Add(s5y); depoSwapInstruments.Add(s10y); depoSwapInstruments.Add(s15y); YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // A depo-futures-swap curve List<RateHelper> depoFutSwapInstruments = new List<RateHelper>(); depoFutSwapInstruments.Add(d1w); depoFutSwapInstruments.Add(d1m); depoFutSwapInstruments.Add(fut1); depoFutSwapInstruments.Add(fut2); depoFutSwapInstruments.Add(fut3); depoFutSwapInstruments.Add(fut4); depoFutSwapInstruments.Add(fut5); depoFutSwapInstruments.Add(fut6); depoFutSwapInstruments.Add(fut7); depoFutSwapInstruments.Add(fut8); depoFutSwapInstruments.Add(s3y); depoFutSwapInstruments.Add(s5y); depoFutSwapInstruments.Add(s10y); depoFutSwapInstruments.Add(s15y); YieldTermStructure depoFutSwapTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFutSwapInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // A depo-FRA-swap curve List<RateHelper> depoFRASwapInstruments = new List<RateHelper>(); depoFRASwapInstruments.Add(d1w); depoFRASwapInstruments.Add(d1m); depoFRASwapInstruments.Add(d3m); depoFRASwapInstruments.Add(fra3x6); depoFRASwapInstruments.Add(fra6x9); depoFRASwapInstruments.Add(fra6x12); depoFRASwapInstruments.Add(s2y); depoFRASwapInstruments.Add(s3y); depoFRASwapInstruments.Add(s5y); depoFRASwapInstruments.Add(s10y); depoFRASwapInstruments.Add(s15y); YieldTermStructure depoFRASwapTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFRASwapInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure = new RelinkableHandle<YieldTermStructure>(); // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure = new RelinkableHandle<YieldTermStructure>(); /********************* * SWAPS TO BE PRICED * **********************/ // constant nominal 1,000,000 Euro double nominal = 1000000.0; // fixed leg Frequency fixedLegFrequency = Frequency.Annual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); double fixedRate = 0.04; DayCounter floatingLegDayCounter = new Actual360(); // floating leg Frequency floatingLegFrequency = Frequency.Semiannual; IborIndex euriborIndex = new Euribor6M(forecastingTermStructure); double spread = 0.0; int lenghtInYears = 5; VanillaSwap.Type swapType = VanillaSwap.Type.Payer; Date maturity = settlementDate + new Period(lenghtInYears, TimeUnit.Years); Schedule fixedSchedule = new Schedule(settlementDate, maturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(settlementDate, maturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap spot5YearSwap = new VanillaSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, TimeUnit.Years); Date fwdMaturity = fwdStart + new Period(lenghtInYears, TimeUnit.Years); Schedule fwdFixedSchedule = new Schedule(fwdStart, fwdMaturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule fwdFloatSchedule = new Schedule(fwdStart, fwdMaturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap oneYearForward5YearSwap = new VanillaSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); /*************** * SWAP PRICING * ****************/ // utilities for reporting List<string> headers = new List<string>(); headers.Add("term structure"); headers.Add("net present value"); headers.Add("fair spread"); headers.Add("fair fixed rate"); string separator = " | "; int width = headers[0].Length + separator.Length + headers[1].Length + separator.Length + headers[2].Length + separator.Length + headers[3].Length + separator.Length - 1; string rule = string.Format("").PadLeft(width, '-'), dblrule = string.Format("").PadLeft(width, '='); string tab = string.Format("").PadLeft(8, ' '); // calculations Console.WriteLine(dblrule); Console.WriteLine("5-year market swap-rate = {0:0.00%}", s5yRate.value()); Console.WriteLine(dblrule); Console.WriteLine(tab + "5-years swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); double NPV; double fairRate; double fairSpread; IPricingEngine swapEngine = new DiscountingSwapEngine(discountingTermStructure); spot5YearSwap.setPricingEngine(swapEngine); oneYearForward5YearSwap.setPricingEngine(swapEngine); // Of course, you're not forced to really use different curves forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); // let's check that the 5 years swap has been correctly re-priced if (!(Math.Abs(fairRate-s5yQuote)<1e-8)) throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate-s5yQuote)); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate-s5yQuote)<1e-8)) throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate-s5yQuote)); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate-s5yQuote)<1e-8)) throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate-s5yQuote)); Console.WriteLine(rule); // now let's price the 1Y forward 5Y swap Console.WriteLine(tab + "5-years, 1-year forward swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); // now let's say that the 5-years swap rate goes up to 4.60%. // A smarter market element--say, connected to a data source-- would // notice the change itself. Since we're using SimpleQuotes, // we'll have to change the value manually--which forces us to // downcast the handle and use the SimpleQuote // interface. In any case, the point here is that a change in the // value contained in the Quote triggers a new bootstrapping // of the curve and a repricing of the swap. SimpleQuote fiveYearsRate = s5yRate as SimpleQuote; fiveYearsRate.setValue(0.0460); Console.WriteLine(dblrule); Console.WriteLine("5-year market swap-rate = {0:0.00%}", s5yRate.value()); Console.WriteLine(dblrule); Console.WriteLine(tab + "5-years swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); // now get the updated results forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate-s5yRate.value())<1e-8)) throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate-s5yRate.value())); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate-s5yRate.value())<1e-8)) throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate-s5yRate.value())); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate-s5yRate.value())<1e-8)) throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate-s5yRate.value())); Console.WriteLine(rule); // the 1Y forward 5Y swap changes as well Console.WriteLine(tab + "5-years, 1-year forward swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public void testZSpreaded() { // ("Testing consistency of zero-spreaded term structure..."); CommonVars vars = new CommonVars(); double tolerance = 1.0e-10; Quote me = new SimpleQuote(0.01); Handle<Quote> mh = new Handle<Quote>(me); YieldTermStructure spreaded = new ZeroSpreadedTermStructure(new Handle<YieldTermStructure>(vars.termStructure), mh); Date testDate = vars.termStructure.referenceDate() + new Period(5, TimeUnit.Years); DayCounter rfdc = vars.termStructure.dayCounter(); double zero = vars.termStructure.zeroRate(testDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).rate(); double spreadedZero = spreaded.zeroRate(testDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).rate(); if (Math.Abs(zero - (spreadedZero - me.value())) > tolerance) Console.WriteLine("unable to reproduce zero yield from spreaded curve\n" + " calculated: " + (spreadedZero - me.value()) + "\n" + " expected: " + zero); }
//void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary<string,double> tolerance, // bool testGreeks = false) { void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary<string, double> tolerance, bool testGreeks) { //QL_TEST_START_TIMING Dictionary<string, double> calculated = new Dictionary<string, double>(), expected = new Dictionary<string, double>(); // test options Option.Type[] types = { Option.Type.Call, Option.Type.Put }; double[] strikes = { 75.0, 100.0, 125.0 }; int[] lengths = { 1 }; // test data double[] underlyings = { 100.0 }; double[] qRates = { 0.00, 0.05 }; double[] rRates = { 0.01, 0.05, 0.15 }; double[] vols = { 0.11, 0.50, 1.20 }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote vol = new SimpleQuote(0.0); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); SimpleQuote qRate = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); for (int i = 0; i < types.Length; i++) { for (int j = 0; j < strikes.Length; j++) { for (int k = 0; k < lengths.Length; k++) { Date exDate = today + lengths[k] * 360; Exercise exercise = new EuropeanExercise(exDate); StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); // reference option VanillaOption refOption = makeOption(payoff, exercise, spot, qTS, rTS, volTS, EngineType.Analytic, 0, 0); // option to check VanillaOption option = makeOption(payoff, exercise, spot, qTS, rTS, volTS, engine, binomialSteps, samples); for (int l = 0; l < underlyings.Length; l++) { for (int m = 0; m < qRates.Length; m++) { for (int n = 0; n < rRates.Length; n++) { for (int p = 0; p < vols.Length; p++) { double u = underlyings[l]; double q = qRates[m], r = rRates[n]; double v = vols[p]; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); expected.Clear(); calculated.Clear(); // FLOATING_POINT_EXCEPTION expected.Add("value", refOption.NPV()); calculated.Add("value", option.NPV()); if (testGreeks && option.NPV() > spot.value() * 1.0e-5) { expected.Add("delta", refOption.delta()); expected.Add("gamma", refOption.gamma()); expected.Add("theta", refOption.theta()); calculated.Add("delta", option.delta()); calculated.Add("gamma", option.gamma()); calculated.Add("theta", option.theta()); } foreach (string greek in calculated.Keys) { double expct = expected[greek], calcl = calculated[greek], tol = tolerance[greek]; double error = Utilities.relativeError(expct, calcl, u); if (error > tol) { REPORT_FAILURE(greek, payoff, exercise, u, q, r, today, v, expct, calcl, error, tol); } } } } } } } } } }
public void testLinearInterpolationMultipleSpreads() { // Testing linear interpolation with more than two spreaded dates... CommonVars vars = new CommonVars(); List<Handle<Quote>> spreads = new List<Handle<Quote>>(); SimpleQuote spread1 = new SimpleQuote(0.02); SimpleQuote spread2 = new SimpleQuote(0.02); SimpleQuote spread3 = new SimpleQuote(0.035); SimpleQuote spread4 = new SimpleQuote(0.04); spreads.Add(new Handle<Quote>(spread1)); spreads.Add(new Handle<Quote>(spread2)); spreads.Add(new Handle<Quote>(spread3)); spreads.Add(new Handle<Quote>(spread4)); List<Date> spreadDates = new List<Date>(); spreadDates.Add(vars.calendar.advance(vars.today, 90, TimeUnit.Days)); spreadDates.Add(vars.calendar.advance(vars.today, 150, TimeUnit.Days)); spreadDates.Add(vars.calendar.advance(vars.today, 30, TimeUnit.Months)); spreadDates.Add(vars.calendar.advance(vars.today, 40, TimeUnit.Months)); Date interpolationDate = vars.calendar.advance(vars.today, 120, TimeUnit.Days); ZeroYieldStructure spreadedTermStructure = new PiecewiseZeroSpreadedTermStructure( new Handle<YieldTermStructure>(vars.termStructure), spreads, spreadDates); double t = vars.dayCount.yearFraction(vars.today, interpolationDate); double interpolatedZeroRate = spreadedTermStructure.zeroRate(t, vars.compounding).value(); double tolerance = 1e-9; double expectedRate = vars.termStructure.zeroRate(t, vars.compounding).value() + spread1.value(); if (Math.Abs(interpolatedZeroRate - expectedRate) > tolerance) Assert.Fail( "unable to reproduce interpolated rate\n" + " calculated: " + interpolatedZeroRate + "\n" + " expected: " + expectedRate); }
public void testAnalyticContinuousGeometricAveragePrice() { //("Testing analytic continuous geometric average-price Asians..."); // data from "Option Pricing Formulas", Haug, pag.96-97 DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(80.0); SimpleQuote qRate = new SimpleQuote(-0.03); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.05); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.20); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticContinuousGeometricAveragePriceAsianEngine(stochProcess); Average.Type averageType = Average.Type.Geometric; Option.Type type = Option.Type.Put; double strike = 85.0; Date exerciseDate = today + 90; int pastFixings = 0; //Null<int>(); double runningAccumulator = 0.0; //Null<Real>(); StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike); Exercise exercise = new EuropeanExercise(exerciseDate); ContinuousAveragingAsianOption option = new ContinuousAveragingAsianOption(averageType, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = 4.6922; double tolerance = 1.0e-4; if (Math.Abs(calculated - expected) > tolerance) { REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings, new List<Date>(), payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); } // trying to approximate the continuous version with the discrete version runningAccumulator = 1.0; pastFixings = 0; List<Date> fixingDates = new InitializedList<Date>(exerciseDate - today + 1); for (int i = 0; i < fixingDates.Count; i++) { fixingDates[i] = today + i; } IPricingEngine engine2 = new AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess); DiscreteAveragingAsianOption option2 = new DiscreteAveragingAsianOption(averageType, runningAccumulator, pastFixings, fixingDates, payoff, exercise); option2.setPricingEngine(engine2); calculated = option2.NPV(); tolerance = 3.0e-3; /*if (Math.Abs(calculated - expected) > tolerance) { REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings, fixingDates, payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); }*/ }
public void testFlatInterpolationRight() { // Testing flat interpolation after the last spreaded date... CommonVars vars = new CommonVars(); List<Handle<Quote>> spreads = new List<Handle<Quote>>(); SimpleQuote spread1 = new SimpleQuote(0.02); SimpleQuote spread2 = new SimpleQuote(0.03); spreads.Add(new Handle<Quote>(spread1)); spreads.Add(new Handle<Quote>(spread2)); List<Date> spreadDates = new List<Date>(); spreadDates.Add(vars.calendar.advance(vars.today, 8, TimeUnit.Months)); spreadDates.Add(vars.calendar.advance(vars.today, 15, TimeUnit.Months)); Date interpolationDate = vars.calendar.advance(vars.today, 20, TimeUnit.Months); ZeroYieldStructure spreadedTermStructure = new PiecewiseZeroSpreadedTermStructure( new Handle<YieldTermStructure>(vars.termStructure), spreads, spreadDates); spreadedTermStructure.enableExtrapolation(); double t = vars.dayCount.yearFraction(vars.today, interpolationDate); double interpolatedZeroRate = spreadedTermStructure.zeroRate(t, vars.compounding).value(); double tolerance = 1e-9; double expectedRate = vars.termStructure.zeroRate(t, vars.compounding).value() + spread2.value(); if (Math.Abs(interpolatedZeroRate - expectedRate) > tolerance) Assert.Fail("unable to reproduce interpolated rate\n" + " calculated: " + interpolatedZeroRate + "\n" + " expected: " + expectedRate); }
public void testPastFixings() { //BOOST_MESSAGE("Testing use of past fixings in Asian options..."); DayCounter dc = new Actual360(); Date today = Date.Today ; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.03); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.06); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.20); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Put, 100.0); Exercise exercise = new EuropeanExercise(today + new Period(1,TimeUnit.Years)); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); // MC arithmetic average-price double runningSum = 0.0; int pastFixings = 0; List<Date> fixingDates1 = new InitializedList<Date>(); for (int i=0; i<=12; ++i) fixingDates1.Add(today + new Period(i,TimeUnit.Months)); DiscreteAveragingAsianOption option1 = new DiscreteAveragingAsianOption(Average.Type.Arithmetic, runningSum, pastFixings, fixingDates1, payoff, exercise); pastFixings = 2; runningSum = pastFixings * spot.value() * 0.8; List<Date> fixingDates2 = new InitializedList<Date>(); for (int i=-2; i<=12; ++i) fixingDates2.Add(today + new Period(i,TimeUnit.Months)); DiscreteAveragingAsianOption option2 = new DiscreteAveragingAsianOption(Average.Type.Arithmetic, runningSum, pastFixings, fixingDates2, payoff, exercise); IPricingEngine engine = new MakeMCDiscreteArithmeticAPEngine<LowDiscrepancy,Statistics>(stochProcess) .withStepsPerYear(1) .withSamples(2047) .value() ; option1.setPricingEngine(engine); option2.setPricingEngine(engine); double price1 = option1.NPV(); double price2 = option2.NPV(); if (Utils.close(price1, price2)) { Assert.Fail( "past fixings had no effect on arithmetic average-price option" + "\n without fixings: " + price1 + "\n with fixings: " + price2); } // MC arithmetic average-strike engine = new MakeMCDiscreteArithmeticASEngine<LowDiscrepancy,Statistics>(stochProcess) .withSamples(2047) .value(); option1.setPricingEngine(engine); option2.setPricingEngine(engine); price1 = option1.NPV(); price2 = option2.NPV(); if (Utils.close(price1, price2)) { Assert.Fail( "past fixings had no effect on arithmetic average-strike option" + "\n without fixings: " + price1 + "\n with fixings: " + price2); } // analytic geometric average-price double runningProduct = 1.0; pastFixings = 0; DiscreteAveragingAsianOption option3 = new DiscreteAveragingAsianOption(Average.Type.Geometric, runningProduct, pastFixings, fixingDates1, payoff, exercise); pastFixings = 2; runningProduct = spot.value() * spot.value(); DiscreteAveragingAsianOption option4 = new DiscreteAveragingAsianOption(Average.Type.Geometric, runningProduct, pastFixings, fixingDates2, payoff, exercise); engine = new AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess); option3.setPricingEngine(engine); option4.setPricingEngine(engine); double price3 = option3.NPV(); double price4 = option4.NPV(); if (Utils.close(price3, price4)) { Assert.Fail( "past fixings had no effect on geometric average-price option" + "\n without fixings: " + price3 + "\n with fixings: " + price4); } // MC geometric average-price engine = new MakeMCDiscreteGeometricAPEngine<LowDiscrepancy,Statistics>(stochProcess) .withStepsPerYear(1) .withSamples(2047) .value(); option3.setPricingEngine(engine); option4.setPricingEngine(engine); price3 = option3.NPV(); price4 = option4.NPV(); if (Utils.close(price3, price4)) { Assert.Fail( "past fixings had no effect on geometric average-price option" + "\n without fixings: " + price3 + "\n with fixings: " + price4); } }
public void testMCDiscreteGeometricAveragePrice() { //BOOST_MESSAGE("Testing Monte Carlo discrete geometric average-price Asians..."); // data from "Implementing Derivatives Model", // Clewlow, Strickland, p.118-123 DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.03); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.06); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.20); BlackVolTermStructure volTS =Utilities.flatVol(today, vol, dc); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); double tolerance = 4.0e-3; IPricingEngine engine = new MakeMCDiscreteGeometricAPEngine <LowDiscrepancy,Statistics>(stochProcess) .withStepsPerYear(1) .withSamples(8191) .value(); Average.Type averageType = Average.Type.Geometric; double runningAccumulator = 1.0; int pastFixings = 0; int futureFixings = 10; Option.Type type = Option.Type.Call; double strike = 100.0; StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike); Date exerciseDate = today + 360; Exercise exercise = new EuropeanExercise(exerciseDate); List<Date> fixingDates = new InitializedList<Date>(futureFixings); int dt = (int)(360/futureFixings+0.5); fixingDates[0] = today + dt; for (int j=1; j<futureFixings; j++) fixingDates[j] = fixingDates[j-1] + dt; DiscreteAveragingAsianOption option = new DiscreteAveragingAsianOption(averageType, runningAccumulator, pastFixings, fixingDates, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); IPricingEngine engine2 = new AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess); option.setPricingEngine(engine2); double expected = option.NPV(); if (Math.Abs(calculated-expected) > tolerance) { REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings, fixingDates, payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); } }
public void testMCDiscreteArithmeticAverageStrike() { //BOOST_MESSAGE("Testing Monte Carlo discrete arithmetic average-strike Asians..."); //QL_TEST_START_TIMING // data from "Asian Option", Levy, 1997 // in "Exotic Options: The State of the Art", // edited by Clewlow, Strickland DiscreteAverageData[] cases5 = { new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 2, 0.13, true, 1.51917595129 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 4, 0.13, true, 1.67940165674 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 8, 0.13, true, 1.75371215251 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 12, 0.13, true, 1.77595318693 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 26, 0.13, true, 1.81430536630 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 52, 0.13, true, 1.82269246898 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 100, 0.13, true, 1.83822402464 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 250, 0.13, true, 1.83875059026 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 500, 0.13, true, 1.83750703638 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0/12.0, 1000, 0.13, true, 1.83887181884 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 2, 0.13, true, 1.51154400089 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 4, 0.13, true, 1.67103508506 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 8, 0.13, true, 1.74529684070 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 12, 0.13, true, 1.76667074564 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 26, 0.13, true, 1.80528400613 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 52, 0.13, true, 1.81400883891 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 100, 0.13, true, 1.82922901451 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 250, 0.13, true, 1.82937111773 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 500, 0.13, true, 1.82826193186 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 1.0/12.0, 11.0/12.0, 1000, 0.13, true, 1.82967846654 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 2, 0.13, true, 1.49648170891 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 4, 0.13, true, 1.65443100462 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 8, 0.13, true, 1.72817806731 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 12, 0.13, true, 1.74877367895 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 26, 0.13, true, 1.78733801988 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 52, 0.13, true, 1.79624826757 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 100, 0.13, true, 1.81114186876 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 250, 0.13, true, 1.81101152587 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 500, 0.13, true, 1.81002311939 ), new DiscreteAverageData(Option.Type.Call, 90.0, 87.0, 0.06, 0.025, 3.0/12.0, 11.0/12.0, 1000, 0.13, true, 1.81145760308 ) }; DayCounter dc = new Actual360(); Date today = Date.Today ; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.03); YieldTermStructure qTS =Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.06); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.20); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); Average.Type averageType = QLNet.Average.Type.Arithmetic; double runningSum = 0.0; int pastFixings = 0; for (int l=0; l<cases5.Length; l++) { StrikedTypePayoff payoff = new PlainVanillaPayoff(cases5[l].type, cases5[l].strike); double dt = cases5[l].length/(cases5[l].fixings-1); List<double> timeIncrements = new InitializedList<double>(cases5[l].fixings); List<Date> fixingDates = new InitializedList<Date>(cases5[l].fixings); timeIncrements[0] = cases5[l].first; fixingDates[0] = today + (int)(timeIncrements[0]*360+0.5); for (int i=1; i<cases5[l].fixings; i++) { timeIncrements[i] = i*dt + cases5[l].first; fixingDates[i] = today + (int)(timeIncrements[i]*360+0.5); } Exercise exercise = new EuropeanExercise(fixingDates[cases5[l].fixings-1]); spot.setValue(cases5[l].underlying); qRate.setValue(cases5[l].dividendYield); rRate.setValue(cases5[l].riskFreeRate); vol.setValue(cases5[l].volatility); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); IPricingEngine engine = new MakeMCDiscreteArithmeticASEngine<LowDiscrepancy,Statistics>(stochProcess) .withSeed(3456789) .withSamples(1023) .value() ; DiscreteAveragingAsianOption option = new DiscreteAveragingAsianOption(averageType, runningSum, pastFixings, fixingDates, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = cases5[l].result; double tolerance = 2.0e-2; if (Math.Abs(calculated-expected) > tolerance) { REPORT_FAILURE("value", averageType, runningSum, pastFixings, fixingDates, payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); } } }
public void testMCDiscreteArithmeticAveragePrice() { //BOOST_MESSAGE("Testing Monte Carlo discrete arithmetic average-price Asians..."); //QL_TEST_START_TIMING // data from "Asian Option", Levy, 1997 // in "Exotic Options: The State of the Art", // edited by Clewlow, Strickland DiscreteAverageData[] cases4 = { new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 2,0.13, true, 1.3942835683), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 4,0.13, true, 1.5852442983), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 8,0.13, true, 1.66970673), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 12,0.13, true, 1.6980019214), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 26,0.13, true, 1.7255070456), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 52,0.13, true, 1.7401553533), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 100,0.13, true, 1.7478303712), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 250,0.13, true, 1.7490291943), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 500,0.13, true, 1.7515113291), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 0.0,11.0/12.0, 1000,0.13, true, 1.7537344885), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 2,0.13, true, 1.8496053697), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 4,0.13, true, 2.0111495205), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 8,0.13, true, 2.0852138818), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 12,0.13, true, 2.1105094397), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 26,0.13, true, 2.1346526695), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 52,0.13, true, 2.147489651), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 100,0.13, true, 2.154728109), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 250,0.13, true, 2.1564276565), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 500,0.13, true, 2.1594238588), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 1.0/12.0,11.0/12.0, 1000,0.13, true, 2.1595367326), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 2,0.13, true, 2.63315092584), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 4,0.13, true, 2.76723962361), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 8,0.13, true, 2.83124836881), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 12,0.13, true, 2.84290301412), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 26,0.13, true, 2.88179560417), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 52,0.13, true, 2.88447044543), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 100,0.13, true, 2.89985329603), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 250,0.13, true, 2.90047296063), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 500,0.13, true, 2.89813412160), new DiscreteAverageData(Option.Type.Put, 90.0, 87.0, 0.06, 0.025, 3.0/12.0,11.0/12.0, 1000,0.13, true, 2.89703362437) }; DayCounter dc = new Actual360(); Date today = Date.Today ; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.03); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.06); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.20); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); Average.Type averageType = Average.Type.Arithmetic; double runningSum = 0.0; int pastFixings = 0; for (int l=0; l<cases4.Length ; l++) { StrikedTypePayoff payoff = new PlainVanillaPayoff(cases4[l].type, cases4[l].strike); double dt = cases4[l].length/(cases4[l].fixings-1); List<double> timeIncrements = new QLNet.InitializedList<double>(cases4[l].fixings); List<Date> fixingDates = new QLNet.InitializedList<Date>(cases4[l].fixings); timeIncrements[0] = cases4[l].first; fixingDates[0] = today + (int)(timeIncrements[0]*360+0.5); for (int i=1; i<cases4[l].fixings; i++) { timeIncrements[i] = i*dt + cases4[l].first; fixingDates[i] = today + (int)(timeIncrements[i]*360+0.5); } Exercise exercise = new EuropeanExercise(fixingDates[cases4[l].fixings-1]); spot.setValue(cases4[l].underlying); qRate.setValue(cases4[l].dividendYield); rRate.setValue(cases4[l].riskFreeRate); vol.setValue(cases4[l].volatility); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); ulong seed=42; const int nrTrails = 5000; LowDiscrepancy.icInstance = new InverseCumulativeNormal(); IRNG rsg = (IRNG)new LowDiscrepancy().make_sequence_generator(nrTrails,seed); new PseudoRandom().make_sequence_generator(nrTrails,seed); IPricingEngine engine = new MakeMCDiscreteArithmeticAPEngine<LowDiscrepancy, Statistics>(stochProcess) .withStepsPerYear(1) .withSamples(2047) .withControlVariate() .value(); DiscreteAveragingAsianOption option= new DiscreteAveragingAsianOption(averageType, runningSum, pastFixings, fixingDates, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = cases4[l].result; double tolerance = 2.0e-2; if (Math.Abs(calculated-expected) > tolerance) { REPORT_FAILURE("value", averageType, runningSum, pastFixings, fixingDates, payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); } } }
public void testAnalyticDiscreteGeometricAveragePriceGreeks() { //BOOST_MESSAGE("Testing discrete-averaging geometric Asian greeks..."); //SavedSettings backup; Dictionary<string,double> calculated, expected, tolerance; calculated = new Dictionary<string, double>(6); expected = new Dictionary<string, double>(6); tolerance = new Dictionary<string, double>(6); tolerance["delta"] = 1.0e-5; tolerance["gamma"] = 1.0e-5; tolerance["theta"] = 1.0e-5; tolerance["rho"] = 1.0e-5; tolerance["divRho"] = 1.0e-5; tolerance["vega"] = 1.0e-5; Option.Type[] types = { Option.Type.Call, Option.Type.Put }; double[] underlyings = { 100.0 }; double[] strikes = { 90.0, 100.0, 110.0 }; double[] qRates = { 0.04, 0.05, 0.06 }; double[] rRates = { 0.01, 0.05, 0.15 }; int[] lengths = { 1, 2 }; double[] vols = { 0.11, 0.50, 1.20 }; DayCounter dc = new Actual360(); Date today = Date.Today; Settings.setEvaluationDate(today); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); Handle<YieldTermStructure> qTS = new Handle<YieldTermStructure> (Utilities.flatRate(qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.0); Handle<YieldTermStructure> rTS = new Handle<YieldTermStructure> (Utilities.flatRate(rRate, dc)); SimpleQuote vol = new SimpleQuote(0.0); Handle<BlackVolTermStructure> volTS = new Handle<BlackVolTermStructure> (Utilities.flatVol(vol, dc)); BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle<Quote>(spot), qTS, rTS, volTS); for (int i=0; i<types.Length ; i++) { for (int j=0; j<strikes.Length ; j++) { for (int k=0; k<lengths.Length ; k++) { EuropeanExercise maturity = new EuropeanExercise( today + new Period(lengths[k],TimeUnit.Years)); PlainVanillaPayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); double runningAverage = 120; int pastFixings = 1; List<Date> fixingDates = new List<Date>(); for (Date d = today + new Period(3, TimeUnit.Months); d <= maturity.lastDate(); d += new Period(3, TimeUnit.Months)) fixingDates.Add(d); IPricingEngine engine = new AnalyticDiscreteGeometricAveragePriceAsianEngine(process); DiscreteAveragingAsianOption option = new DiscreteAveragingAsianOption(Average.Type.Geometric, runningAverage, pastFixings, fixingDates, payoff, maturity); option.setPricingEngine(engine); for (int l=0; l<underlyings.Length ; l++) { for (int m=0; m<qRates.Length ; m++) { for (int n=0; n<rRates.Length ; n++) { for (int p=0; p<vols.Length ; p++) { double u = underlyings[l]; double q = qRates[m], r = rRates[n]; double v = vols[p]; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); double value = option.NPV(); calculated["delta"] = option.delta(); calculated["gamma"] = option.gamma(); calculated["theta"] = option.theta(); calculated["rho"] = option.rho(); calculated["divRho"] = option.dividendRho(); calculated["vega"] = option.vega(); if (value > spot.value()*1.0e-5) { // perturb spot and get delta and gamma double du = u*1.0e-4; spot.setValue(u+du); double value_p = option.NPV(), delta_p = option.delta(); spot.setValue(u-du); double value_m = option.NPV(), delta_m = option.delta(); spot.setValue(u); expected["delta"] = (value_p - value_m)/(2*du); expected["gamma"] = (delta_p - delta_m)/(2*du); // perturb rates and get rho and dividend rho double dr = r*1.0e-4; rRate.setValue(r+dr); value_p = option.NPV(); rRate.setValue(r-dr); value_m = option.NPV(); rRate.setValue(r); expected["rho"] = (value_p - value_m)/(2*dr); double dq = q*1.0e-4; qRate.setValue(q+dq); value_p = option.NPV(); qRate.setValue(q-dq); value_m = option.NPV(); qRate.setValue(q); expected["divRho"] = (value_p - value_m)/(2*dq); // perturb volatility and get vega double dv = v*1.0e-4; vol.setValue(v+dv); value_p = option.NPV(); vol.setValue(v-dv); value_m = option.NPV(); vol.setValue(v); expected["vega"] = (value_p - value_m)/(2*dv); // perturb date and get theta double dT = dc.yearFraction(today-1, today+1); Settings.setEvaluationDate(today-1); value_m = option.NPV(); Settings.setEvaluationDate(today+1); value_p = option.NPV(); Settings.setEvaluationDate(today); expected["theta"] = (value_p - value_m)/dT; // compare foreach (KeyValuePair<string, double> kvp in calculated){ string greek = kvp.Key; double expct = expected[greek], calcl = calculated[greek], tol = tolerance [greek]; double error =Utilities.relativeError(expct,calcl,u); if (error>tol) { REPORT_FAILURE(greek, Average.Type.Geometric, runningAverage, pastFixings, new List<Date>(), payoff, maturity, u, q, r, today, v, expct, calcl, tol); } } } } } } } } } } }