public void testDefaultProbability()
        {
            // Testing default-probability structure...

             double hazardRate = 0.0100;
             Handle<Quote> hazardRateQuote = new Handle<Quote>(new SimpleQuote(hazardRate));
             DayCounter dayCounter = new Actual360();
             Calendar calendar = new TARGET();
             int n = 20;

             double tolerance = 1.0e-10;
             Date today = Settings.evaluationDate();
             Date startDate = today;
             Date endDate = startDate;

             FlatHazardRate flatHazardRate = new FlatHazardRate(startDate, hazardRateQuote, dayCounter);

             for(int i=0; i<n; i++)
             {
            startDate = endDate;
            endDate = calendar.advance(endDate, 1, TimeUnit.Years);

            double pStart = flatHazardRate.defaultProbability(startDate);
            double pEnd = flatHazardRate.defaultProbability(endDate);

            double pBetweenComputed =
               flatHazardRate.defaultProbability(startDate, endDate);

            double pBetween = pEnd - pStart;

            if (Math.Abs(pBetween - pBetweenComputed) > tolerance)
               Assert.Fail( "Failed to reproduce probability(d1, d2) "
                            + "for default probability structure\n"
                            + "    calculated probability: " + pBetweenComputed + "\n"
                            + "    expected probability:   " + pBetween);

            double t2 = dayCounter.yearFraction(today, endDate);
            double timeProbability = flatHazardRate.defaultProbability(t2);
            double dateProbability =
               flatHazardRate.defaultProbability(endDate);

            if (Math.Abs(timeProbability - dateProbability) > tolerance)
               Assert.Fail( "single-time probability and single-date probability do not match\n"
                           + "    time probability: " + timeProbability + "\n"
                           + "    date probability: " + dateProbability);

            double t1 = dayCounter.yearFraction(today, startDate);
            timeProbability = flatHazardRate.defaultProbability(t1, t2);
            dateProbability = flatHazardRate.defaultProbability(startDate, endDate);

            if (Math.Abs(timeProbability - dateProbability) > tolerance)
               Assert.Fail( "double-time probability and double-date probability do not match\n"
                            + "    time probability: " + timeProbability + "\n"
                            + "    date probability: " + dateProbability);

             }
        }
        public void testInitialisation()
        {
            //"Testing caplet LMM process initialisation..."

            //SavedSettings backup;

            DayCounter dayCounter = new Actual360();
            RelinkableHandle<YieldTermStructure> termStructure= new RelinkableHandle<YieldTermStructure>();;
            termStructure.linkTo(Utilities.flatRate(Date.Today, 0.04, dayCounter));

            IborIndex index=new Euribor6M(termStructure);
            OptionletVolatilityStructure capletVol = new ConstantOptionletVolatility(
                                                        termStructure.currentLink().referenceDate(),
                                                        termStructure.currentLink().calendar(),
                                                        BusinessDayConvention.Following,
                                                        0.2,
                                                        termStructure.currentLink().dayCounter());

            Calendar calendar = index.fixingCalendar();

            for (int daysOffset=0; daysOffset < 1825 /* 5 year*/; daysOffset+=8) {
                Date todaysDate = calendar.adjust(Date.Today+daysOffset);
                Settings.setEvaluationDate(todaysDate);
                Date settlementDate =
                    calendar.advance(todaysDate, index.fixingDays(), TimeUnit.Days);

                termStructure.linkTo(Utilities.flatRate(settlementDate, 0.04, dayCounter));

                LiborForwardModelProcess process=new LiborForwardModelProcess(60, index);

                List<double> fixings = process.fixingTimes();
                for (int i=1; i < fixings.Count-1; ++i) {
                    int ileft  = process.nextIndexReset(fixings[i]-0.000001);
                    int iright = process.nextIndexReset(fixings[i]+0.000001);
                    int ii     = process.nextIndexReset(fixings[i]);

                    if ((ileft != i) || (iright != i+1) || (ii != i+1)) {
                        Assert.Fail("Failed to next index resets");
                    }
                }

            }
        }
Exemple #3
0
        IborIndex makeIndex(List<Date> dates,
                            List<double> rates)
        {
            DayCounter dayCounter = new Actual360();

            RelinkableHandle<YieldTermStructure> termStructure = new RelinkableHandle<YieldTermStructure>(); ;
            IborIndex index = new Euribor6M(termStructure);

            Date todaysDate =
            index.fixingCalendar().adjust(new Date(4, 9, 2005));
            Settings.setEvaluationDate(todaysDate);

            dates[0] = index.fixingCalendar().advance(todaysDate,
                                                   index.fixingDays(), TimeUnit.Days);
            Linear Interpolator = new Linear();
            termStructure.linkTo(new InterpolatedZeroCurve<Linear>(dates, rates, dayCounter, Interpolator));

            return index;
        }
Exemple #4
0
 public MakeCms(Period swapTenor,
                SwapIndex swapIndex,
                IborIndex iborIndex,
                double iborSpread   = 0.0,
                Period forwardStart = null,
                Date maturityDate   = null)
 {
     swapTenor_     = swapTenor;
     swapIndex_     = swapIndex;
     iborIndex_     = iborIndex;
     iborSpread_    = iborSpread;
     iborCap_       = null;
     iborFloor_     = null;
     useAtmSpread_  = false;
     forwardStart_  = forwardStart ?? new Period(0, TimeUnit.Days);
     cmsSpread_     = 0.0;
     cmsGearing_    = 1.0;
     cmsCap_        = null;
     cmsFloor_      = null;
     effectiveDate_ = null;
     cmsCalendar_   = swapIndex.fixingCalendar();
     floatCalendar_ = iborIndex.fixingCalendar();
     payCms_        = true;
     nominal_       = 1.0;
     maturityDate_  = maturityDate;
     cmsTenor_      = new Period(3, TimeUnit.Months);
     floatTenor_    = iborIndex.tenor();
     cmsConvention_ = BusinessDayConvention.ModifiedFollowing;
     cmsTerminationDateConvention_ = BusinessDayConvention.ModifiedFollowing;
     floatConvention_ = iborIndex.businessDayConvention();
     floatTerminationDateConvention_ = iborIndex.businessDayConvention();
     cmsRule_             = DateGeneration.Rule.Backward;
     floatRule_           = DateGeneration.Rule.Backward;
     cmsEndOfMonth_       = false;
     floatEndOfMonth_     = false;
     cmsFirstDate_        = null;
     cmsNextToLastDate_   = null;
     floatFirstDate_      = null;
     floatNextToLastDate_ = null;
     cmsDayCount_         = new Actual360();
     floatDayCount_       = iborIndex.dayCounter();
     engine_ = new DiscountingSwapEngine(swapIndex.forwardingTermStructure());
 }
Exemple #5
0
        public void testImpliedHazardRate()
        {
            // Testing implied hazard-rate for credit-default swaps...

            SavedSettings backup = new SavedSettings();

            // Initialize curves
            Calendar calendar = new TARGET();
            Date today = calendar.adjust(Date.Today);
            Settings.setEvaluationDate(today);

            double h1 = 0.30, h2 = 0.40;
            DayCounter dayCounter = new Actual365Fixed();

            List<Date> dates = new List<Date>(3);
            List<double> hazardRates = new List<double>(3);
            dates.Add(today);
            hazardRates.Add(h1);

            dates.Add(today + new Period(5,TimeUnit.Years));
            hazardRates.Add(h1);

            dates.Add(today + new Period(10,TimeUnit.Years));
            hazardRates.Add(h2);

            RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve =
                new RelinkableHandle<DefaultProbabilityTermStructure>();
            probabilityCurve.linkTo(new InterpolatedHazardRateCurve<BackwardFlat>(dates,
                                                                                            hazardRates,
                                                                                            dayCounter));

            RelinkableHandle<YieldTermStructure> discountCurve = new RelinkableHandle<YieldTermStructure>();
            discountCurve.linkTo(new FlatForward(today,0.03,new Actual360()));

            Frequency frequency = Frequency.Semiannual;
            BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing;

            Date issueDate = calendar.advance(today, -6, TimeUnit.Months);
            double fixedRate = 0.0120;
            DayCounter cdsDayCount = new Actual360();
            double notional = 10000.0;
            double recoveryRate = 0.4;

            double? latestRate = null;
            for (int n=6; n<=10; ++n)
            {
                Date maturity = calendar.advance(issueDate, n, TimeUnit.Years);
                Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar,
                                        convention, convention,
                                        DateGeneration.Rule.Forward, false);

                CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate,
                                            schedule, convention, cdsDayCount,true, true);
                cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve));

                double NPV = cds.NPV();
                double flatRate = cds.impliedHazardRate(NPV, discountCurve,
                                                                    dayCounter,
                                                                    recoveryRate);

                if (flatRate < h1 || flatRate > h2) {
                    Assert.Fail("implied hazard rate outside expected range\n"
                                    + "    maturity: " + n + " years\n"
                                    + "    expected minimum: " + h1 + "\n"
                                    + "    expected maximum: " + h2 + "\n"
                                    + "    implied rate:     " + flatRate);
                }

                if (n > 6 && flatRate < latestRate) {
                    Assert.Fail("implied hazard rate decreasing with swap maturity\n"
                                    + "    maturity: " + n + " years\n"
                                    + "    previous rate: " + latestRate + "\n"
                                    + "    implied rate:  " + flatRate);
                }

                latestRate = flatRate;

                RelinkableHandle<DefaultProbabilityTermStructure> probability = new RelinkableHandle<DefaultProbabilityTermStructure>();
                probability.linkTo(new FlatHazardRate(	today,new Handle<Quote>(new SimpleQuote(flatRate)),dayCounter));

                CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate,
                                                schedule, convention, cdsDayCount,true, true);
                cds2.setPricingEngine(new MidPointCdsEngine(probability,recoveryRate,discountCurve));

                double NPV2 = cds2.NPV();
                double tolerance = 1.0;
                if (Math.Abs(NPV-NPV2) > tolerance) {
                    Assert.Fail("failed to reproduce NPV with implied rate\n"
                                    + "    expected:   " + NPV + "\n"
                                    + "    calculated: " + NPV2);
                }
            }
        }
Exemple #6
0
        public void testCachedMarketValue()
        {
            // Testing credit-default swap against cached market values...

            SavedSettings backup = new SavedSettings();

            Settings.setEvaluationDate(new Date(9,Month.June,2006));
            Date evalDate = Settings.evaluationDate();
            Calendar calendar = new UnitedStates();

            List<Date> discountDates = new List<Date>();
            discountDates.Add(evalDate);
            discountDates.Add(calendar.advance(evalDate, 1, TimeUnit.Weeks,  BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 1, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 2, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 3, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 6, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate,12, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 2, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 3, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 4, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 5, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 6, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 7, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 8, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate, 9, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate,10, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            discountDates.Add(calendar.advance(evalDate,15, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));

            List<double> dfs = new List<double>();
            dfs.Add(1.0);
            dfs.Add(0.9990151375768731);
            dfs.Add(0.99570502636871183);
            dfs.Add(0.99118260474528685);
            dfs.Add(0.98661167950906203);
            dfs.Add(0.9732592953359388 );
            dfs.Add(0.94724424481038083);
            dfs.Add(0.89844996737120875 );
            dfs.Add(0.85216647839921411 );
            dfs.Add(0.80775477692556874 );
            dfs.Add(0.76517289234200347 );
            dfs.Add(0.72401019553182933 );
            dfs.Add(0.68503909569219212 );
            dfs.Add(0.64797499814013748 );
            dfs.Add(0.61263171936255534 );
            dfs.Add(0.5791942350748791  );
            dfs.Add(0.43518868769953606 );

            DayCounter curveDayCounter = new Actual360();

            RelinkableHandle<YieldTermStructure> discountCurve = new RelinkableHandle<YieldTermStructure>();
            discountCurve.linkTo( new InterpolatedDiscountCurve<LogLinear>( discountDates, dfs, curveDayCounter,null,null,null,new LogLinear() ) );

            DayCounter dayCounter = new Thirty360();
            List<Date> dates = new List<Date>();
            dates.Add(evalDate);
            dates.Add(calendar.advance(evalDate, 6, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate, 1, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate, 2, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate, 3, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate, 4, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate, 5, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate, 7, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
            dates.Add(calendar.advance(evalDate,10, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));

            List<double> defaultProbabilities = new List<double>();
            defaultProbabilities.Add(0.0000);
            defaultProbabilities.Add(0.0047);
            defaultProbabilities.Add(0.0093);
            defaultProbabilities.Add(0.0286);
            defaultProbabilities.Add(0.0619);
            defaultProbabilities.Add(0.0953);
            defaultProbabilities.Add(0.1508);
            defaultProbabilities.Add(0.2288);
            defaultProbabilities.Add(0.3666);

            List<double> hazardRates = new List<double>();
            hazardRates.Add(0.0);
            for (int i=1; i<dates.Count; ++i)
            {
                double t1 = dayCounter.yearFraction(dates[0], dates[i-1]);
                double t2 = dayCounter.yearFraction(dates[0], dates[i]);
                double S1 = 1.0 - defaultProbabilities[i-1];
                double S2 = 1.0 - defaultProbabilities[i];
                hazardRates.Add(Math.Log(S1/S2)/(t2-t1));
            }

            RelinkableHandle<DefaultProbabilityTermStructure> piecewiseFlatHazardRate = new RelinkableHandle<DefaultProbabilityTermStructure>();
            piecewiseFlatHazardRate.linkTo(new InterpolatedHazardRateCurve<BackwardFlat>(dates,hazardRates,new Thirty360()));

            // Testing credit default swap

            // Build the schedule
            Date issueDate = new Date(20, Month.March, 2006);
            Date maturity = new Date(20, Month.June, 2013);
            Frequency cdsFrequency = Frequency.Semiannual;
            BusinessDayConvention cdsConvention = BusinessDayConvention.ModifiedFollowing;

            Schedule schedule = new Schedule(issueDate, maturity, new Period(cdsFrequency), calendar,
                                                   cdsConvention, cdsConvention,
                                                   DateGeneration.Rule.Forward, false);

            // Build the CDS
            double recoveryRate = 0.25;
            double fixedRate=0.0224;
            DayCounter dayCount= new Actual360();
            double cdsNotional=100.0;

            CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, cdsNotional, fixedRate,
                                        schedule, cdsConvention, dayCount, true, true);
            cds.setPricingEngine(new MidPointCdsEngine(piecewiseFlatHazardRate, recoveryRate,discountCurve));

            double calculatedNpv = cds.NPV();
            double calculatedFairRate = cds.fairSpread();

            double npv = -1.364048777;        // from Bloomberg we have 98.15598868 - 100.00;
            double fairRate =  0.0248429452; // from Bloomberg we have 0.0258378;

            double tolerance = 1e-9;

            if (Math.Abs(npv - calculatedNpv) > tolerance)
                Assert.Fail(
                    "Failed to reproduce the npv for the given credit-default swap\n"
                    + "    computed NPV:  " + calculatedNpv + "\n"
                    + "    Given NPV:     " + npv);

            if ( Math.Abs( fairRate - calculatedFairRate ) > tolerance )
                Assert.Fail( "Failed to reproduce the fair rate for the given credit-default swap\n"
                    + "    computed fair rate:  " + calculatedFairRate + "\n"
                    + "    Given fair rate:     " + fairRate );
        }
Exemple #7
0
        public void testFairUpfront()
        {
            // Testing fair-upfront calculation for credit-default swaps...

            SavedSettings backup = new SavedSettings();

            // Initialize curves
            Calendar calendar = new TARGET();
            Date today = calendar.adjust(Date.Today);
            Settings.setEvaluationDate(today);

            Handle<Quote> hazardRate = new Handle<Quote>(new SimpleQuote(0.01234));
            RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve =
                new RelinkableHandle<DefaultProbabilityTermStructure>();
            probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360()));

            RelinkableHandle<YieldTermStructure> discountCurve =
                new RelinkableHandle<YieldTermStructure>();
            discountCurve.linkTo(new FlatForward(today,0.06,new Actual360()));

            // Build the schedule
            Date issueDate = today;
            Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years);
            BusinessDayConvention convention = BusinessDayConvention.Following;

            Schedule schedule =
                new MakeSchedule().from(issueDate)
                                       .to(maturity)
                                       .withFrequency(Frequency.Quarterly)
                                       .withCalendar(calendar)
                                       .withTerminationDateConvention(convention)
                                       .withRule(DateGeneration.Rule.TwentiethIMM).value();

            // Build the CDS
            double fixedRate = 0.05;
            double upfront = 0.001;
            DayCounter dayCount = new Actual360();
            double notional = 10000.0;
            double recoveryRate = 0.4;

            IPricingEngine engine = new MidPointCdsEngine(probabilityCurve, recoveryRate,	discountCurve, true);

            CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate,
                                        schedule, convention, dayCount, true, true);
            cds.setPricingEngine(engine);

            double fairUpfront = cds.fairUpfront();

            CreditDefaultSwap fairCds = new CreditDefaultSwap(Protection.Side.Seller, notional,
                                            fairUpfront, fixedRate,	schedule, convention, dayCount, true, true);
            fairCds.setPricingEngine(engine);

            double fairNPV = fairCds.NPV();
            double tolerance = 1e-10;

            if (Math.Abs(fairNPV) > tolerance)
                Assert.Fail(
                    "Failed to reproduce null NPV with calculated fair upfront\n"
                    + "    calculated upfront: " + fairUpfront + "\n"
                    + "    calculated NPV:     " + fairNPV);

            // same with null upfront to begin with
            upfront = 0.0;
            CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate,
                                        schedule, convention, dayCount, true, true);
            cds2.setPricingEngine(engine);

            fairUpfront = cds2.fairUpfront();

            CreditDefaultSwap fairCds2 = new CreditDefaultSwap(Protection.Side.Seller, notional,
                                                fairUpfront, fixedRate,	schedule, convention, dayCount, true, true);
            fairCds2.setPricingEngine(engine);

            fairNPV = fairCds2.NPV();

            if (Math.Abs(fairNPV) > tolerance)
                Assert.Fail(
                    "Failed to reproduce null NPV with calculated fair upfront\n"
                    + "    calculated upfront: " + fairUpfront + "\n"
                    + "    calculated NPV:     " + fairNPV);
        }
Exemple #8
0
        public void testCachedValue()
        {
            // Testing credit-default swap against cached values...

            SavedSettings backup = new SavedSettings();

            // Initialize curves
            Settings.setEvaluationDate(new Date(9,Month.June,2006));
            Date today = Settings.evaluationDate();
            Calendar calendar = new TARGET();

            Handle<Quote> hazardRate = new Handle<Quote>(new SimpleQuote(0.01234));
            RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle<DefaultProbabilityTermStructure>();
            probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360()));

            RelinkableHandle<YieldTermStructure> discountCurve = new RelinkableHandle<YieldTermStructure>();

            discountCurve.linkTo(new FlatForward(today,0.06,new Actual360()));

            // Build the schedule
            Date issueDate = calendar.advance(today, -1, TimeUnit.Years);
            Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years);
            Frequency frequency = Frequency.Semiannual;
            BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing;

            Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar,
                                    convention, convention, DateGeneration.Rule.Forward, false);

            // Build the CDS
            double fixedRate = 0.0120;
            DayCounter dayCount = new Actual360();
            double notional = 10000.0;
            double recoveryRate = 0.4;

            CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate,
                                        schedule, convention, dayCount, true, true);
            cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve,recoveryRate,discountCurve));

            double npv = 295.0153398;
            double fairRate = 0.007517539081;

            double calculatedNpv = cds.NPV();
            double calculatedFairRate = cds.fairSpread();
            double tolerance = 1.0e-7;

            if (Math.Abs(calculatedNpv - npv) > tolerance)
                Assert.Fail(
                    "Failed to reproduce NPV with mid-point engine\n"
                    + "    calculated NPV: " + calculatedNpv + "\n"
                    + "    expected NPV:   " + npv);

            if (Math.Abs(calculatedFairRate - fairRate) > tolerance)
                Assert.Fail(
                    "Failed to reproduce fair rate with mid-point engine\n"
                    + "    calculated fair rate: " + calculatedFairRate + "\n"
                    + "    expected fair rate:   " + fairRate);

            cds.setPricingEngine(new IntegralCdsEngine(new Period(1,TimeUnit.Days),probabilityCurve,
                                                                    recoveryRate,discountCurve));

            calculatedNpv = cds.NPV();
            calculatedFairRate = cds.fairSpread();
            tolerance = 1.0e-5;

            if (Math.Abs(calculatedNpv - npv) > notional*tolerance*10)
                Assert.Fail(
                    "Failed to reproduce NPV with integral engine "
                    + "(step = 1 day)\n"
                    + "    calculated NPV: " + calculatedNpv + "\n"
                    + "    expected NPV:   " + npv);

            if (Math.Abs(calculatedFairRate - fairRate) > tolerance)
                Assert.Fail(
                    "Failed to reproduce fair rate with integral engine "
                    + "(step = 1 day)\n"
                    + "    calculated fair rate: " + calculatedFairRate + "\n"
                    + "    expected fair rate:   " + fairRate);

            cds.setPricingEngine(new IntegralCdsEngine(new Period(1,TimeUnit.Weeks),probabilityCurve,recoveryRate,discountCurve));

            calculatedNpv = cds.NPV();
            calculatedFairRate = cds.fairSpread();
            tolerance = 1.0e-5;

            if (Math.Abs(calculatedNpv - npv) > notional*tolerance*10)
                Assert.Fail(
                    "Failed to reproduce NPV with integral engine "
                    +"(step = 1 week)\n"
                    + "    calculated NPV: " + calculatedNpv + "\n"
                    + "    expected NPV:   " + npv);

            if (Math.Abs(calculatedFairRate - fairRate) > tolerance)
                Assert.Fail(
                    "Failed to reproduce fair rate with integral engine "
                    +"(step = 1 week)\n"
                    + "    calculated fair rate: " + calculatedFairRate + "\n"
                    + "    expected fair rate:   " + fairRate);
        }
        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 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 testFlatHazardRate()
        {
            // Testing flat hazard rate...

             double hazardRate = 0.0100;
             Handle<Quote> hazardRateQuote = new Handle<Quote>(new SimpleQuote(hazardRate));
             DayCounter dayCounter = new Actual360();
             Calendar calendar = new TARGET();
             int n = 20;

             double tolerance = 1.0e-10;
             Date today = Settings.evaluationDate();
             Date startDate = today;
             Date endDate = startDate;

             FlatHazardRate flatHazardRate = new FlatHazardRate(today, hazardRateQuote, dayCounter);

             for(int i=0; i<n; i++)
             {
            endDate = calendar.advance(endDate, 1, TimeUnit.Years);
            double t = dayCounter.yearFraction(startDate, endDate);
            double probability = 1.0 - Math.Exp(-hazardRate * t);
            double computedProbability = flatHazardRate.defaultProbability(t);

            if (Math.Abs(probability - computedProbability) > tolerance)
               Assert.Fail( "Failed to reproduce probability for flat hazard rate\n"
                            + "    calculated probability: " + computedProbability + "\n"
                            + "    expected probability:   " + probability);
             }
        }
Exemple #12
0
        //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 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 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);
                                       }
                                   }
                               }
                           }
                         }
                       }
                     }
                 }
               }
             }
         }
        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);
                }
            }
        }
Exemple #16
0
        public void testTheoretical()
        {
            // "Testing theoretical bond price/yield calculation...");

             CommonVars vars = new CommonVars();

             double tolerance = 1.0e-7;
             int maxEvaluations = 100;

             int[] lengths = new int[] { 3, 5, 10, 15, 20 };
             int settlementDays = 3;
             double[] coupons = new double[] { 0.02, 0.05, 0.08 };
             Frequency[] frequencies = new Frequency[] { Frequency.Semiannual, Frequency.Annual };
             DayCounter bondDayCount = new Actual360();
             BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted;
             BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing;
             double redemption = 100.0;

             double[] yields = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 };

             for (int j = 0; j < lengths.Length; j++)
             {
            for (int k = 0; k < coupons.Length; k++)
            {
               for (int l = 0; l < frequencies.Length; l++)
               {

                  Date dated = vars.today;
                  Date issue = dated;
                  Date maturity = vars.calendar.advance(issue, lengths[j], TimeUnit.Years);

                  SimpleQuote rate = new SimpleQuote(0.0);
                  var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(vars.today, rate, bondDayCount));

                  Schedule sch = new Schedule(dated, maturity, new Period(frequencies[l]), vars.calendar,
                                              accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false);

                  FixedRateBond bond = new FixedRateBond(settlementDays, vars.faceAmount, sch, new List<double>() { coupons[k] },
                                                         bondDayCount, paymentConvention, redemption, issue);

                  IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve);
                  bond.setPricingEngine(bondEngine);

                  for (int m = 0; m < yields.Length; m++)
                  {

                     rate.setValue(yields[m]);

                     double price = bond.cleanPrice(yields[m], bondDayCount, Compounding.Continuous, frequencies[l]);
                     double calculatedPrice = bond.cleanPrice();

                     if (Math.Abs(price - calculatedPrice) > tolerance)
                     {
                        Assert.Fail("price calculation failed:"
                            + "\n    issue:     " + issue
                            + "\n    maturity:  " + maturity
                            + "\n    coupon:    " + coupons[k]
                            + "\n    frequency: " + frequencies[l] + "\n"
                            + "\n    yield:     " + yields[m]
                            + "\n    expected:    " + price
                            + "\n    calculated': " + calculatedPrice
                            + "\n    error':      " + (price - calculatedPrice));
                     }

                     double calculatedYield = bond.yield(bondDayCount, Compounding.Continuous, frequencies[l],
                                              tolerance, maxEvaluations);
                     if (Math.Abs(yields[m] - calculatedYield) > tolerance)
                     {
                        Assert.Fail("yield calculation failed:"
                            + "\n    issue:     " + issue
                            + "\n    maturity:  " + maturity
                            + "\n    coupon:    " + coupons[k]
                            + "\n    frequency: " + frequencies[l] + "\n"
                            + "\n    yield:  " + yields[m]
                            + "\n    price:  " + price
                            + "\n    yield': " + calculatedYield);
                     }
                  }
               }
            }
             }
        }
        static void Main(string[] args) {

            DateTime timer = DateTime.Now;

            /*********************
             ***  MARKET DATA  ***
             *********************/

            Calendar calendar = new TARGET();

            Date settlementDate = new Date(18, Month.September, 2008);
            // must be a business day
            settlementDate = calendar.adjust(settlementDate);

            int fixingDays = 3;
            int settlementDays = 3;

            Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days);
            // nothing to do with Date::todaysDate
            Settings.setEvaluationDate(todaysDate);

            Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate);
            Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate);


            // Building of the bonds discounting yield curve

            /*********************
             ***  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.

            // Common data

            // ZC rates for the short end
             double zc3mQuote=0.0096;
             double zc6mQuote=0.0145;
             double zc1yQuote=0.0194;

             Quote zc3mRate = new SimpleQuote(zc3mQuote);
             Quote zc6mRate = new SimpleQuote(zc6mQuote);
             Quote zc1yRate = new SimpleQuote(zc1yQuote);

             DayCounter zcBondsDayCounter = new Actual365Fixed();

             RateHelper zc3m = new DepositRateHelper(new Handle<Quote>(zc3mRate),
                                                          new Period(3, TimeUnit.Months), fixingDays,
                                                          calendar, BusinessDayConvention.ModifiedFollowing,
                                                          true, zcBondsDayCounter);
             RateHelper zc6m = new DepositRateHelper(new Handle<Quote>(zc6mRate),
                                                          new Period(6, TimeUnit.Months), fixingDays,
                                                          calendar, BusinessDayConvention.ModifiedFollowing,
                                                          true, zcBondsDayCounter);
             RateHelper zc1y = new DepositRateHelper(new Handle<Quote>(zc1yRate),
                                                          new Period(1, TimeUnit.Years), fixingDays,
                                                          calendar, BusinessDayConvention.ModifiedFollowing,
                                                          true, zcBondsDayCounter);

            // setup bonds
            double redemption = 100.0;

            const int numberOfBonds = 5;

            Date[] issueDates = {
                    new Date (15, Month.March, 2005),
                    new Date (15, Month.June, 2005),
                    new Date (30, Month.June, 2006),
                    new Date (15, Month.November, 2002),
                    new Date (15, Month.May, 1987)
            };

            Date[] maturities = {
                    new Date (31, Month.August, 2010),
                    new Date (31, Month.August, 2011),
                    new Date (31, Month.August, 2013),
                    new Date (15, Month.August, 2018),
                    new Date (15, Month.May, 2038)
            };

            double[] couponRates = {
                    0.02375,
                    0.04625,
                    0.03125,
                    0.04000,
                    0.04500
            };

            double[] marketQuotes = {
                    100.390625,
                    106.21875,
                    100.59375,
                    101.6875,
                    102.140625
            };

            List<SimpleQuote> quote = new List<SimpleQuote>();
            for (int i=0; i<numberOfBonds; i++) {
                SimpleQuote cp = new SimpleQuote(marketQuotes[i]);
                quote.Add(cp);
            }

            List<RelinkableHandle<Quote>> quoteHandle = new InitializedList<RelinkableHandle<Quote>>(numberOfBonds);
            for (int i=0; i<numberOfBonds; i++) {
                quoteHandle[i].linkTo(quote[i]);
            }

            // Definition of the rate helpers
            List<FixedRateBondHelper> bondsHelpers = new List<FixedRateBondHelper>();
            for (int i=0; i<numberOfBonds; i++) {

                Schedule schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual), 
                                                 new UnitedStates(UnitedStates.Market.GovernmentBond),
                                                 BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, 
                                                 DateGeneration.Rule.Backward, false);

                FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle[i],
                                                                         settlementDays,
                                                                         100.0,
                                                                         schedule,
                                                                         new List<double>() { couponRates[i] },
                                                                         new ActualActual(ActualActual.Convention.Bond),
                                                                         BusinessDayConvention.Unadjusted,
                                                                         redemption,
                                                                         issueDates[i]);

                bondsHelpers.Add(bondHelper);
            }

            /*********************
             **  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-bond curve
             List<RateHelper> bondInstruments = new List<RateHelper>();

             // Adding the ZC bonds to the curve for the short end
             bondInstruments.Add(zc3m);
             bondInstruments.Add(zc6m);
             bondInstruments.Add(zc1y);

             // Adding the Fixed rate bonds to the curve for the long end
             for (int i=0; i<numberOfBonds; i++) {
                 bondInstruments.Add(bondsHelpers[i]);
             }

             YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>(
                                                                     settlementDate, bondInstruments,
                                                                     termStructureDayCounter,
                                                                     new List<Handle<Quote>>(),
                                                                     new List<Date>(),
                                                                     tolerance);

             // Building of the Libor forecasting curve
             // deposits
             double d1wQuote=0.043375;
             double d1mQuote=0.031875;
             double d3mQuote=0.0320375;
             double d6mQuote=0.03385;
             double d9mQuote=0.0338125;
             double d1yQuote=0.0335125;
             // swaps
             double s2yQuote=0.0295;
             double s3yQuote=0.0323;
             double s5yQuote=0.0359;
             double s10yQuote=0.0412;
             double s15yQuote=0.0433;


             /********************
              ***    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);
             // 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 swaps
             Frequency swFixedLegFrequency =Frequency.Annual;
             BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted;
             DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European);
             IborIndex swFloatingLegIndex = new Euribor6M();

             Period forwardStart = new Period(1, TimeUnit.Days);

             RateHelper s2y = new SwapRateHelper(
                     new Handle<Quote>(s2yRate), new Period(2, TimeUnit.Years),
                     calendar, swFixedLegFrequency,
                     swFixedLegConvention, swFixedLegDayCounter,
                     swFloatingLegIndex, new Handle<Quote>(),forwardStart);
             RateHelper s3y = new SwapRateHelper(
                     new Handle<Quote>(s3yRate), new Period(3, TimeUnit.Years),
                     calendar, swFixedLegFrequency,
                     swFixedLegConvention, swFixedLegDayCounter,
                     swFloatingLegIndex, new Handle<Quote>(),forwardStart);
             RateHelper s5y = new SwapRateHelper(
                     new Handle<Quote>(s5yRate), new Period(5, TimeUnit.Years),
                     calendar, swFixedLegFrequency,
                     swFixedLegConvention, swFixedLegDayCounter,
                     swFloatingLegIndex, new Handle<Quote>(),forwardStart);
             RateHelper s10y = new SwapRateHelper(
                     new Handle<Quote>(s10yRate), new Period(10, TimeUnit.Years),
                     calendar, swFixedLegFrequency,
                     swFixedLegConvention, swFixedLegDayCounter,
                     swFloatingLegIndex, new Handle<Quote>(),forwardStart);
             RateHelper s15y = new SwapRateHelper(
                     new Handle<Quote>(s15yRate), new Period(15, TimeUnit.Years),
                     calendar, swFixedLegFrequency,
                     swFixedLegConvention, swFixedLegDayCounter,
                     swFloatingLegIndex, new Handle<Quote>(),forwardStart);


             /*********************
              **  CURVE BUILDING **
              *********************/

             // Any DayCounter would be fine.
             // ActualActual::ISDA ensures that 30 years is 30.0

             // 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);

             // 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>();

             /*********************
              * BONDS TO BE PRICED *
              **********************/

             // Common data
             double faceAmount = 100;

             // Pricing engine
             IPricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure);

             // Zero coupon bond
             ZeroCouponBond zeroCouponBond = new ZeroCouponBond(
                     settlementDays,
                     new UnitedStates(UnitedStates.Market.GovernmentBond),
                     faceAmount,
                     new Date(15, Month.August,2013),
                     BusinessDayConvention.Following,
                     116.92,
                     new Date(15, Month.August,2003));

             zeroCouponBond.setPricingEngine(bondEngine);

             // Fixed 4.5% US Treasury Note
             Schedule fixedBondSchedule = new Schedule(new Date(15, Month.May, 2007),
                     new Date(15,Month.May,2017), new Period(Frequency.Semiannual),
                     new UnitedStates(UnitedStates.Market.GovernmentBond),
                     BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

             FixedRateBond fixedRateBond = new FixedRateBond(
                     settlementDays,
                     faceAmount,
                     fixedBondSchedule,
                     new List<double>() { 0.045 },
                     new ActualActual(ActualActual.Convention.Bond),
                     BusinessDayConvention.ModifiedFollowing,
                     100.0, new Date(15, Month.May, 2007));

             fixedRateBond.setPricingEngine(bondEngine);

             // Floating rate bond (3M USD Libor + 0.1%)
             // Should and will be priced on another curve later...

             RelinkableHandle<YieldTermStructure> liborTermStructure = new RelinkableHandle<YieldTermStructure>();
             IborIndex libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure);
             libor3m.addFixing(new Date(17, Month.July, 2008),0.0278625);

             Schedule floatingBondSchedule = new Schedule(new Date(21, Month.October, 2005),
                     new Date(21, Month.October, 2010), new Period(Frequency.Quarterly),
                     new UnitedStates(UnitedStates.Market.NYSE),
                     BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, true);

             FloatingRateBond floatingRateBond = new FloatingRateBond(
                     settlementDays,
                     faceAmount,
                     floatingBondSchedule,
                     libor3m,
                     new Actual360(),
                     BusinessDayConvention.ModifiedFollowing,
                     2,
                     // Gearings
                     new List<double>() { 1.0 },
                     // Spreads
                     new List<double>() { 0.001 },
                     // Caps
                     new List<double>(),
                     // Floors
                     new List<double>(),
                     // Fixing in arrears
                     true,
                     100.0,
                     new Date(21, Month.October, 2005));

             floatingRateBond.setPricingEngine(bondEngine);

             // Coupon pricers
             IborCouponPricer pricer = new BlackIborCouponPricer();

             // optionLet volatilities
             double volatility = 0.0;
             Handle<OptionletVolatilityStructure> vol;
             vol = new Handle<OptionletVolatilityStructure>(
                                new ConstantOptionletVolatility(
                                     settlementDays,
                                     calendar,
                                     BusinessDayConvention.ModifiedFollowing,
                                     volatility,
                                     new Actual365Fixed()));

             pricer.setCapletVolatility(vol);
             Utils.setCouponPricer(floatingRateBond.cashflows(),pricer);

             // Yield curve bootstrapping
             forecastingTermStructure.linkTo(depoSwapTermStructure);
             discountingTermStructure.linkTo(bondDiscountingTermStructure);

             // We are using the depo & swap curve to estimate the future Libor rates
             liborTermStructure.linkTo(depoSwapTermStructure);

             /***************
              * BOND PRICING *
              ****************/

             // write column headings
             int[] widths = { 18, 10, 10, 10 };

            Console.WriteLine("{0,18}{1,10}{2,10}{3,10}", "", "ZC", "Fixed", "Floating");

            string separator = " | ";
            int width = widths[0]
                                 + widths[1]
                                          + widths[2]
                                                   + widths[3];
            string rule = "".PadLeft(width, '-'), dblrule = "".PadLeft(width, '=');
            string tab = "".PadLeft(8, ' ');

            Console.WriteLine(rule);

            Console.WriteLine("Net present value".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", 
                                zeroCouponBond.NPV(),
                                fixedRateBond.NPV(),
                                floatingRateBond.NPV());

            Console.WriteLine("Clean price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                                zeroCouponBond.cleanPrice(),
                                fixedRateBond.cleanPrice(),
                                floatingRateBond.cleanPrice());

            Console.WriteLine("Dirty price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                                zeroCouponBond.dirtyPrice(),
                                fixedRateBond.dirtyPrice(),
                                floatingRateBond.dirtyPrice());

            Console.WriteLine("Accrued coupon".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                                zeroCouponBond.accruedAmount(),
                                fixedRateBond.accruedAmount(),
                                floatingRateBond.accruedAmount());

            Console.WriteLine("Previous coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}",
                                "N/A",
                                fixedRateBond.previousCoupon(),
                                floatingRateBond.previousCoupon());

            Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}",
                              "N/A",
                              fixedRateBond.nextCoupon(),
                              floatingRateBond.nextCoupon());

            Console.WriteLine("Yield".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}",
                              zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual),
                              fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual),
                              floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual));

            Console.WriteLine();

            // Other computations
            Console.WriteLine("Sample indirect computations (for the floating rate bond): ");
            Console.WriteLine(rule);

            Console.WriteLine("Yield to Clean Price: {0:n2}",
                floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual),
                                                                   new Actual360(), Compounding.Compounded, Frequency.Annual,
                                                                   settlementDate));

            Console.WriteLine("Clean Price to Yield: {0:0.00%}",
                floatingRateBond.yield(floatingRateBond.cleanPrice(),new Actual360(), Compounding.Compounded, Frequency.Annual,
                                       settlementDate));

            /* "Yield to Price"
               "Price to Yield" */

            Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer);
            Console.WriteLine();

            Console.Write("Press any key to continue ...");
            Console.ReadKey();
        }
Exemple #18
0
        public void testBSMOperatorConsistency()
        {
            //("Testing consistency of BSM operators...");

             Vector grid = new Vector(10);
             double price = 20.0;
             double factor = 1.1;
             for (int i = 0; i < grid.size(); i++)
             {
            grid[i] = price;
            price *= factor;
             }

             double dx = Math.Log(factor);
             double r = 0.05;
             double q = 0.01;
             double sigma = 0.5;

             BSMOperator refer = new BSMOperator(grid.size(), dx, r, q, sigma);

             DayCounter dc = new Actual360();
             Date today = Date.Today;
             Date exercise = today + new Period(2, TimeUnit.Years);
             double residualTime = dc.yearFraction(today, exercise);

             SimpleQuote spot = new SimpleQuote(0.0);
             YieldTermStructure qTS = Utilities.flatRate(today, q, dc);
             YieldTermStructure rTS = Utilities.flatRate(today, r, dc);
             BlackVolTermStructure volTS = Utilities.flatVol(today, sigma, dc);
             GeneralizedBlackScholesProcess stochProcess = new GeneralizedBlackScholesProcess(
                                                        new Handle<Quote>(spot),
                                                        new Handle<YieldTermStructure>(qTS),
                                                        new Handle<YieldTermStructure>(rTS),
                                                        new Handle<BlackVolTermStructure>(volTS));
             BSMOperator op1 = new BSMOperator(grid, stochProcess, residualTime);
             PdeOperator<PdeBSM> op2 = new PdeOperator<PdeBSM>(grid, stochProcess, residualTime);

             double tolerance = 1.0e-6;
             Vector lderror = refer.lowerDiagonal() - op1.lowerDiagonal();
             Vector derror = refer.diagonal() - op1.diagonal();
             Vector uderror = refer.upperDiagonal() - op1.upperDiagonal();

             for (int i = 2; i < grid.size() - 2; i++)
             {
            if (Math.Abs(lderror[i]) > tolerance ||
                Math.Abs(derror[i]) > tolerance ||
                Math.Abs(uderror[i]) > tolerance)
            {
               Assert.Fail("inconsistency between BSM operators:\n"
                          + i + " row:\n"
                          + "expected:   "
                          + refer.lowerDiagonal()[i] + ", "
                          + refer.diagonal()[i] + ", "
                          + refer.upperDiagonal()[i] + "\n"
                          + "calculated: "
                          + op1.lowerDiagonal()[i] + ", "
                          + op1.diagonal()[i] + ", "
                          + op1.upperDiagonal()[i]);
            }
             }
             lderror = refer.lowerDiagonal() - op2.lowerDiagonal();
             derror = refer.diagonal() - op2.diagonal();
             uderror = refer.upperDiagonal() - op2.upperDiagonal();

             for (int i = 2; i < grid.size() - 2; i++)
             {
            if (Math.Abs(lderror[i]) > tolerance ||
                Math.Abs(derror[i]) > tolerance ||
                Math.Abs(uderror[i]) > tolerance)
            {
               Assert.Fail("inconsistency between BSM operators:\n"
                          + i + " row:\n"
                          + "expected:   "
                          + refer.lowerDiagonal()[i] + ", "
                          + refer.diagonal()[i] + ", "
                          + refer.upperDiagonal()[i] + "\n"
                          + "calculated: "
                          + op2.lowerDiagonal()[i] + ", "
                          + op2.diagonal()[i] + ", "
                          + op2.upperDiagonal()[i]);
            }
             }
        }
        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);
        }
    }
Exemple #20
0
        public VanillaSwap value()
        {
            Date startDate;

            if (effectiveDate_ != null)
            {
                startDate = effectiveDate_;
            }
            else
            {
                //int fixingDays = iborIndex_.fixingDays();
                Date refDate = Settings.evaluationDate();
                // if the evaluation date is not a business day
                // then move to the next business day
                refDate = floatCalendar_.adjust(refDate);
                Date spotDate = floatCalendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days));
                startDate = spotDate + forwardStart_;
                if (forwardStart_.length() < 0)
                {
                    startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Preceding);
                }
                else
                {
                    startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Following);
                }
            }

            Date endDate = terminationDate_;

            if (endDate == null)
            {
                if (floatEndOfMonth_)
                {
                    endDate = floatCalendar_.advance(startDate,
                                                     swapTenor_,
                                                     BusinessDayConvention.ModifiedFollowing,
                                                     floatEndOfMonth_);
                }
                else
                {
                    endDate = startDate + swapTenor_;
                }
            }

            Currency curr       = iborIndex_.currency();
            Period   fixedTenor = null;

            if (fixedTenor_ != null)
            {
                fixedTenor = fixedTenor_;
            }
            else
            {
                if ((curr == new EURCurrency()) ||
                    (curr == new USDCurrency()) ||
                    (curr == new CHFCurrency()) ||
                    (curr == new SEKCurrency()) ||
                    (curr == new GBPCurrency() && swapTenor_ <= new Period(1, TimeUnit.Years)))
                {
                    fixedTenor = new Period(1, TimeUnit.Years);
                }
                else if ((curr == new GBPCurrency() && swapTenor_ > new Period(1, TimeUnit.Years) ||
                          (curr == new JPYCurrency()) ||
                          (curr == new AUDCurrency() && swapTenor_ >= new Period(4, TimeUnit.Years))))
                {
                    fixedTenor = new Period(6, TimeUnit.Months);
                }
                else if ((curr == new HKDCurrency() ||
                          (curr == new AUDCurrency() && swapTenor_ < new Period(4, TimeUnit.Years))))
                {
                    fixedTenor = new Period(3, TimeUnit.Months);
                }
                else
                {
                    Utils.QL_FAIL("unknown fixed leg default tenor for " + curr);
                }
            }

            Schedule fixedSchedule = new Schedule(startDate, endDate,
                                                  fixedTenor, fixedCalendar_,
                                                  fixedConvention_, fixedTerminationDateConvention_,
                                                  fixedRule_, fixedEndOfMonth_,
                                                  fixedFirstDate_, fixedNextToLastDate_);

            Schedule floatSchedule = new Schedule(startDate, endDate,
                                                  floatTenor_, floatCalendar_,
                                                  floatConvention_, floatTerminationDateConvention_,
                                                  floatRule_, floatEndOfMonth_,
                                                  floatFirstDate_, floatNextToLastDate_);

            DayCounter fixedDayCount = null;

            if (fixedDayCount_ != null)
            {
                fixedDayCount = fixedDayCount_;
            }
            else
            {
                if (curr == new USDCurrency())
                {
                    fixedDayCount = new Actual360();
                }
                else if (curr == new EURCurrency() || curr == new CHFCurrency() || curr == new SEKCurrency())
                {
                    fixedDayCount = new Thirty360(Thirty360.Thirty360Convention.BondBasis);
                }
                else if (curr == new GBPCurrency() || curr == new JPYCurrency() || curr == new AUDCurrency() ||
                         curr == new HKDCurrency())
                {
                    fixedDayCount = new Actual365Fixed();
                }
                else
                {
                    Utils.QL_FAIL("unknown fixed leg day counter for " + curr);
                }
            }

            double?usedFixedRate = fixedRate_;

            if (fixedRate_ == null)
            {
                VanillaSwap temp = new VanillaSwap(type_, nominal_, fixedSchedule, 0.0, fixedDayCount,
                                                   floatSchedule, iborIndex_, floatSpread_, floatDayCount_);

                if (engine_ == null)
                {
                    Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure();
                    Utils.QL_REQUIRE(!disc.empty(), () =>
                                     "null term structure set to this instance of " + iborIndex_.name());
                    bool           includeSettlementDateFlows = false;
                    IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows);
                    temp.setPricingEngine(engine);
                }
                else
                {
                    temp.setPricingEngine(engine_);
                }

                usedFixedRate = temp.fairRate();
            }

            VanillaSwap swap = new VanillaSwap(type_, nominal_, fixedSchedule, usedFixedRate.Value, fixedDayCount,
                                               floatSchedule, iborIndex_, floatSpread_, floatDayCount_);

            if (engine_ == null)
            {
                Handle <YieldTermStructure> disc          = iborIndex_.forwardingTermStructure();
                bool           includeSettlementDateFlows = false;
                IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows);
                swap.setPricingEngine(engine);
            }
            else
            {
                swap.setPricingEngine(engine_);
            }

            return(swap);
        }
Exemple #21
0
		static void Main(string[] args) {
			DateTime timer = DateTime.Now;

			Date repoSettlementDate = new Date(14,Month.February,2000);;
			Date repoDeliveryDate = new Date(15,Month.August,2000);
			double repoRate = 0.05;
			DayCounter repoDayCountConvention = new Actual360();
			int repoSettlementDays = 0;
			Compounding repoCompounding = Compounding.Simple;
			Frequency repoCompoundFreq = Frequency.Annual;

			// assume a ten year bond- this is irrelevant
			Date bondIssueDate = new Date(15,Month.September,1995);
			Date bondDatedDate = new Date(15,Month.September,1995);
			Date bondMaturityDate = new Date(15,Month.September,2005);
			double bondCoupon = 0.08;
			Frequency bondCouponFrequency = Frequency.Semiannual;
			// unknown what calendar fincad is using
			Calendar bondCalendar = new NullCalendar();
			DayCounter bondDayCountConvention = new Thirty360(Thirty360.Thirty360Convention.BondBasis);
			// unknown what fincad is using. this may affect accrued calculation
			int bondSettlementDays = 0;
			BusinessDayConvention bondBusinessDayConvention = BusinessDayConvention.Unadjusted;
			double bondCleanPrice = 89.97693786;
			double bondRedemption = 100.0;
			double faceAmount = 100.0;


			Settings.setEvaluationDate(repoSettlementDate);

			RelinkableHandle<YieldTermStructure> bondCurve = new RelinkableHandle<YieldTermStructure>();
			bondCurve.linkTo(new FlatForward(repoSettlementDate,
											   .01, // dummy rate
											   bondDayCountConvention,
											   Compounding.Compounded,
											   bondCouponFrequency));

			/*
			boost::shared_ptr<FixedRateBond> bond(
						   new FixedRateBond(faceAmount,
											 bondIssueDate,
											 bondDatedDate,
											 bondMaturityDate,
											 bondSettlementDays,
											 std::vector<Rate>(1,bondCoupon),
											 bondCouponFrequency,
											 bondCalendar,
											 bondDayCountConvention,
											 bondBusinessDayConvention,
											 bondBusinessDayConvention,
											 bondRedemption,
											 bondCurve));
			*/

			Schedule bondSchedule = new Schedule(bondDatedDate, bondMaturityDate,
								  new Period(bondCouponFrequency),
								  bondCalendar,bondBusinessDayConvention,
								  bondBusinessDayConvention,
								  DateGeneration.Rule.Backward,false);
			FixedRateBond bond = new FixedRateBond(bondSettlementDays,
											 faceAmount,
											 bondSchedule,
											 new List<double>() { bondCoupon },
											 bondDayCountConvention,
											 bondBusinessDayConvention,
											 bondRedemption,
											 bondIssueDate);
			bond.setPricingEngine(new DiscountingBondEngine(bondCurve));

			bondCurve.linkTo(new FlatForward(repoSettlementDate,
									   bond.yield(bondCleanPrice,
												   bondDayCountConvention,
												   Compounding.Compounded,
												   bondCouponFrequency),
									   bondDayCountConvention,
									   Compounding.Compounded,
									   bondCouponFrequency));

			Position.Type fwdType = Position.Type.Long;
			double dummyStrike = 91.5745;

			RelinkableHandle<YieldTermStructure> repoCurve = new RelinkableHandle<YieldTermStructure>();
			repoCurve.linkTo(new FlatForward(repoSettlementDate,
											   repoRate,
											   repoDayCountConvention,
											   repoCompounding,
											   repoCompoundFreq));


			FixedRateBondForward bondFwd = new FixedRateBondForward(repoSettlementDate,
										 repoDeliveryDate,
										 fwdType,
										 dummyStrike,
										 repoSettlementDays,
										 repoDayCountConvention,
										 bondCalendar,
										 bondBusinessDayConvention,
										 bond,
										 repoCurve,
										 repoCurve);


			Console.WriteLine("Underlying bond clean price: " + bond.cleanPrice());
			Console.WriteLine("Underlying bond dirty price: " + bond.dirtyPrice());
			Console.WriteLine("Underlying bond accrued at settlement: "
				 + bond.accruedAmount(repoSettlementDate));
			Console.WriteLine("Underlying bond accrued at delivery:   "
				 + bond.accruedAmount(repoDeliveryDate));
			Console.WriteLine("Underlying bond spot income: "
				 + bondFwd.spotIncome(repoCurve));
			Console.WriteLine("Underlying bond fwd income:  "
				 + bondFwd.spotIncome(repoCurve)/
					repoCurve.link.discount(repoDeliveryDate));
			Console.WriteLine("Repo strike: " + dummyStrike);
			Console.WriteLine("Repo NPV:    " + bondFwd.NPV());
			Console.WriteLine("Repo clean forward price: "
				 + bondFwd.cleanForwardPrice());
			Console.WriteLine("Repo dirty forward price: "
				 + bondFwd.forwardPrice());
			Console.WriteLine("Repo implied yield: "
				 + bondFwd.impliedYield(bond.dirtyPrice(),
										 dummyStrike,
										 repoSettlementDate,
										 repoCompounding,
										 repoDayCountConvention));
			Console.WriteLine("Market repo rate:   "
				 + repoCurve.link.zeroRate(repoDeliveryDate,
										repoDayCountConvention,
										repoCompounding,
										repoCompoundFreq));

			Console.WriteLine("\nCompare with example given at \n"
				 + "http://www.fincad.com/support/developerFunc/mathref/BFWD.htm");
			Console.WriteLine("Clean forward price = 88.2408");
			Console.WriteLine("\nIn that example, it is unknown what bond calendar they are\n"
				 + "using, as well as settlement Days. For that reason, I have\n"
				 + "made the simplest possible assumptions here: NullCalendar\n"
				 + "and 0 settlement days.\n");


			Console.WriteLine("nRun completed in {0}", DateTime.Now - timer);

      Console.Write("Press any key to continue ...");
      Console.ReadKey();
		}
Exemple #22
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(numericalFix_ == NumericalFix.None || numericalFix_ == NumericalFix.Taylor, () =>
                             "numerical fix must be None or Taylor");
            Utils.QL_REQUIRE(accrualBias_ == AccrualBias.HalfDayBias || accrualBias_ == AccrualBias.NoBias, () =>
                             "accrual bias must be HalfDayBias or NoBias");
            Utils.QL_REQUIRE(forwardsInCouponPeriod_ == ForwardsInCouponPeriod.Flat ||
                             forwardsInCouponPeriod_ == ForwardsInCouponPeriod.Piecewise, () =>
                             "forwards in coupon period must be Flat or Piecewise");

            // it would be possible to handle the cases which are excluded below,
            // but the ISDA engine is not explicitly specified to handle them,
            // so we just forbid them too

            Actual365Fixed dc  = new Actual365Fixed();
            Actual360      dc1 = new Actual360();
            Actual360      dc2 = new Actual360(true);

            Date evalDate = Settings.evaluationDate();

            // check if given curves are ISDA compatible
            // (the interpolation is checked below)

            Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set");
            Utils.QL_REQUIRE(!probability_.empty(), () => "no probability term structure set");
            Utils.QL_REQUIRE(discountCurve_.link.dayCounter() == dc, () =>
                             "yield term structure day counter (" + discountCurve_.link.dayCounter() + ") should be Act/365(Fixed)");
            Utils.QL_REQUIRE(probability_.link.dayCounter() == dc, () =>
                             "probability term structure day counter (" + probability_.link.dayCounter() + ") should be "
                             + "Act/365(Fixed)");
            Utils.QL_REQUIRE(discountCurve_.link.referenceDate() == evalDate, () =>
                             "yield term structure reference date (" + discountCurve_.link.referenceDate()
                             + " should be evaluation date (" + evalDate + ")");
            Utils.QL_REQUIRE(probability_.link.referenceDate() == evalDate, () =>
                             "probability term structure reference date (" + probability_.link.referenceDate()
                             + " should be evaluation date (" + evalDate + ")");
            Utils.QL_REQUIRE(arguments_.settlesAccrual, () => "ISDA engine not compatible with non accrual paying CDS");
            Utils.QL_REQUIRE(arguments_.paysAtDefaultTime, () => "ISDA engine not compatible with end period payment");
            Utils.QL_REQUIRE((arguments_.claim as FaceValueClaim) != null, () =>
                             "ISDA engine not compatible with non face value claim");

            Date maturity = arguments_.maturity;
            Date effectiveProtectionStart = Date.Max(arguments_.protectionStart, evalDate + 1);

            // collect nodes from both curves and sort them
            List <Date> yDates = new List <Date>(), cDates = new List <Date>();

            var castY1 = discountCurve_.link as PiecewiseYieldCurve <Discount, LogLinear>;
            var castY2 = discountCurve_.link as InterpolatedForwardCurve <BackwardFlat>;
            var castY3 = discountCurve_.link as InterpolatedForwardCurve <ForwardFlat>;
            var castY4 = discountCurve_.link as FlatForward;

            if (castY1 != null)
            {
                if (castY1.dates() != null)
                {
                    yDates = castY1.dates();
                }
            }
            else if (castY2 != null)
            {
                yDates = castY2.dates();
            }
            else if (castY3 != null)
            {
                yDates = castY3.dates();
            }
            else if (castY4 != null)
            {
            }
            else
            {
                Utils.QL_FAIL("Yield curve must be flat forward interpolated");
            }

            var castC1 = probability_.link as InterpolatedSurvivalProbabilityCurve <LogLinear>;
            var castC2 = probability_.link as InterpolatedHazardRateCurve <BackwardFlat>;
            var castC3 = probability_.link as FlatHazardRate;

            if (castC1 != null)
            {
                cDates = castC1.dates();
            }
            else if (castC2 != null)
            {
                cDates = castC2.dates();
            }
            else if (castC3 != null)
            {
            }
            else
            {
                Utils.QL_FAIL("Credit curve must be flat forward interpolated");
            }

            // Todo check
            List <Date> nodes = yDates.Union(cDates).ToList();

            if (nodes.empty())
            {
                nodes.Add(maturity);
            }
            double nFix = (numericalFix_ == NumericalFix.None ? 1E-50 : 0.0);

            // protection leg pricing (npv is always negative at this stage)
            double protectionNpv = 0.0;

            Date   d0 = effectiveProtectionStart - 1;
            double P0 = discountCurve_.link.discount(d0);
            double Q0 = probability_.link.survivalProbability(d0);
            Date   d1;
            int    result = nodes.FindIndex(item => item > effectiveProtectionStart);

            for (int it = result; it < nodes.Count; ++it)
            {
                if (nodes[it] > maturity)
                {
                    d1 = maturity;
                    it = nodes.Count - 1; //early exit
                }
                else
                {
                    d1 = nodes[it];
                }
                double P1 = discountCurve_.link.discount(d1);
                double Q1 = probability_.link.survivalProbability(d1);

                double fhat  = Math.Log(P0) - Math.Log(P1);
                double hhat  = Math.Log(Q0) - Math.Log(Q1);
                double fhphh = fhat + hhat;

                if (fhphh < 1E-4 && numericalFix_ == NumericalFix.Taylor)
                {
                    double fhphhq = fhphh * fhphh;
                    protectionNpv +=
                        P0 * Q0 * hhat * (1.0 - 0.5 * fhphh + 1.0 / 6.0 * fhphhq -
                                          1.0 / 24.0 * fhphhq * fhphh +
                                          1.0 / 120 * fhphhq * fhphhq);
                }
                else
                {
                    protectionNpv += hhat / (fhphh + nFix) * (P0 * Q0 - P1 * Q1);
                }
                d0 = d1;
                P0 = P1;
                Q0 = Q1;
            }
            protectionNpv *= arguments_.claim.amount(null, arguments_.notional.Value, recoveryRate_);

            results_.defaultLegNPV = protectionNpv;

            // premium leg pricing (npv is always positive at this stage)

            double premiumNpv = 0.0, defaultAccrualNpv = 0.0;

            for (int i = 0; i < arguments_.leg.Count; ++i)
            {
                FixedRateCoupon coupon = arguments_.leg[i] as FixedRateCoupon;

                Utils.QL_REQUIRE(coupon.dayCounter() == dc ||
                                 coupon.dayCounter() == dc1 ||
                                 coupon.dayCounter() == dc2, () =>
                                 "ISDA engine requires a coupon day counter Act/365Fixed "
                                 + "or Act/360 (" + coupon.dayCounter() + ")");

                // premium coupons

                if (!arguments_.leg[i].hasOccurred(evalDate, includeSettlementDateFlows_))
                {
                    double x1 = coupon.amount();
                    double x2 = discountCurve_.link.discount(coupon.date());
                    double x3 = probability_.link.survivalProbability(coupon.date() - 1);

                    premiumNpv +=
                        coupon.amount() *
                        discountCurve_.link.discount(coupon.date()) *
                        probability_.link.survivalProbability(coupon.date() - 1);
                }

                // default accruals

                if (!new simple_event(coupon.accrualEndDate())
                    .hasOccurred(effectiveProtectionStart, false))
                {
                    Date   start  = Date.Max(coupon.accrualStartDate(), effectiveProtectionStart) - 1;
                    Date   end    = coupon.date() - 1;
                    double tstart = discountCurve_.link.timeFromReference(coupon.accrualStartDate() - 1) -
                                    (accrualBias_ == AccrualBias.HalfDayBias ? 1.0 / 730.0 : 0.0);
                    List <Date> localNodes = new List <Date>();
                    localNodes.Add(start);
                    //add intermediary nodes, if any
                    if (forwardsInCouponPeriod_ == ForwardsInCouponPeriod.Piecewise)
                    {
                        foreach (Date node in nodes)
                        {
                            if (node > start && node < end)
                            {
                                localNodes.Add(node);
                            }
                        }
                        //std::vector<Date>::const_iterator it0 = std::upper_bound(nodes.begin(), nodes.end(), start);
                        //std::vector<Date>::const_iterator it1 = std::lower_bound(nodes.begin(), nodes.end(), end);
                        //localNodes.insert(localNodes.end(), it0, it1);
                    }
                    localNodes.Add(end);

                    double defaultAccrThisNode = 0.0;
                    Date   firstnode           = localNodes.First();
                    double t0 = discountCurve_.link.timeFromReference(firstnode);
                    P0 = discountCurve_.link.discount(firstnode);
                    Q0 = probability_.link.survivalProbability(firstnode);

                    foreach (Date node in localNodes.Skip(1)) //for (++node; node != localNodes.Last(); ++node)
                    {
                        double t1    = discountCurve_.link.timeFromReference(node);
                        double P1    = discountCurve_.link.discount(node);
                        double Q1    = probability_.link.survivalProbability(node);
                        double fhat  = Math.Log(P0) - Math.Log(P1);
                        double hhat  = Math.Log(Q0) - Math.Log(Q1);
                        double fhphh = fhat + hhat;
                        if (fhphh < 1E-4 && numericalFix_ == NumericalFix.Taylor)
                        {
                            // see above, terms up to (f+h)^3 seem more than enough,
                            // what exactly is implemented in the standard isda C
                            // code ?
                            double fhphhq = fhphh * fhphh;
                            defaultAccrThisNode +=
                                hhat * P0 * Q0 *
                                ((t0 - tstart) *
                                 (1.0 - 0.5 * fhphh + 1.0 / 6.0 * fhphhq -
                                  1.0 / 24.0 * fhphhq * fhphh) +
                                 (t1 - t0) *
                                 (0.5 - 1.0 / 3.0 * fhphh + 1.0 / 8.0 * fhphhq -
                                  1.0 / 30.0 * fhphhq * fhphh));
                        }
                        else
                        {
                            defaultAccrThisNode +=
                                (hhat / (fhphh + nFix)) *
                                ((t1 - t0) * ((P0 * Q0 - P1 * Q1) / (fhphh + nFix) -
                                              P1 * Q1) +
                                 (t0 - tstart) * (P0 * Q0 - P1 * Q1));
                        }

                        t0 = t1;
                        P0 = P1;
                        Q0 = Q1;
                    }
                    defaultAccrualNpv += defaultAccrThisNode * arguments_.notional.Value *
                                         coupon.rate() * 365.0 / 360.0;
                }
            }

            results_.couponLegNPV = premiumNpv + defaultAccrualNpv;

            // upfront flow npv

            double upfPVO1 = 0.0;

            results_.upfrontNPV = 0.0;
            if (!arguments_.upfrontPayment.hasOccurred(
                    evalDate, includeSettlementDateFlows_))
            {
                upfPVO1 =
                    discountCurve_.link.discount(arguments_.upfrontPayment.date());
                if (arguments_.upfrontPayment.amount().IsNotEqual(0.0))
                {
                    results_.upfrontNPV = upfPVO1 * arguments_.upfrontPayment.amount();
                }
            }

            results_.accrualRebateNPV = 0.0;
            if (arguments_.accrualRebate != null &&
                arguments_.accrualRebate.amount().IsNotEqual(0.0) &&
                !arguments_.accrualRebate.hasOccurred(evalDate, includeSettlementDateFlows_))
            {
                results_.accrualRebateNPV =
                    discountCurve_.link.discount(arguments_.accrualRebate.date()) *
                    arguments_.accrualRebate.amount();
            }

            double upfrontSign = 1;

            if (arguments_.side == Protection.Side.Seller)
            {
                results_.defaultLegNPV    *= -1.0;
                results_.accrualRebateNPV *= -1.0;
            }
            else
            {
                results_.couponLegNPV *= -1.0;
                results_.upfrontNPV   *= -1.0;
            }

            results_.value = results_.defaultLegNPV + results_.couponLegNPV +
                             results_.upfrontNPV + results_.accrualRebateNPV;

            results_.errorEstimate = null;

            if (results_.couponLegNPV.IsNotEqual(0.0))
            {
                results_.fairSpread =
                    -results_.defaultLegNPV * arguments_.spread /
                    (results_.couponLegNPV + results_.accrualRebateNPV);
            }
            else
            {
                results_.fairSpread = null;
            }

            double upfrontSensitivity = upfPVO1 * arguments_.notional.Value;

            if (upfrontSensitivity.IsNotEqual(0.0))
            {
                results_.fairUpfront =
                    -upfrontSign * (results_.defaultLegNPV + results_.couponLegNPV +
                                    results_.accrualRebateNPV) /
                    upfrontSensitivity;
            }
            else
            {
                results_.fairUpfront = null;
            }

            if (arguments_.spread.IsNotEqual(0.0))
            {
                results_.couponLegBPS =
                    results_.couponLegNPV * Const.BASIS_POINT / arguments_.spread;
            }
            else
            {
                results_.couponLegBPS = null;
            }

            if (arguments_.upfront != null && arguments_.upfront.IsNotEqual(0.0))
            {
                results_.upfrontBPS =
                    results_.upfrontNPV * Const.BASIS_POINT / (arguments_.upfront);
            }
            else
            {
                results_.upfrontBPS = null;
            }
        }
Exemple #23
0
        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();
        }