예제 #1
0
 public ForwardTypePayoff(Position.Type type, double strike)
 {
     type_ = type;
     strike_ = strike;
     if (strike < 0.0)
         throw new ApplicationException("negative strike given");
 }
예제 #2
0
      // Handle<YieldTermStructure> discountCurve = Handle<YieldTermStructure>());
      public ForwardRateAgreement(Date valueDate, Date maturityDate, Position.Type type, double strikeForwardRate,
                                  double notionalAmount, IborIndex index, Handle<YieldTermStructure> discountCurve)
         : base(index.dayCounter(), index.fixingCalendar(), index.businessDayConvention(), index.fixingDays(), new Payoff(),
                 valueDate, maturityDate, discountCurve) {

         fraType_ = type;
         notionalAmount_ = notionalAmount;
         index_ = index;

         if (notionalAmount <= 0.0)
            throw new ApplicationException("notional Amount must be positive");

         // do I adjust this ?
         // valueDate_ = calendar_.adjust(valueDate_,businessDayConvention_);
         Date fixingDate = calendar_.advance(valueDate_, -settlementDays_, TimeUnit.Days);
         forwardRate_ = new InterestRate(index.fixing(fixingDate), index.dayCounter(), Compounding.Simple, Frequency.Once);
         strikeForwardRate_ = new InterestRate(strikeForwardRate, index.dayCounter(), Compounding.Simple, Frequency.Once);
         double strike = notionalAmount_ * strikeForwardRate_.compoundFactor(valueDate_, maturityDate_);
         payoff_ = new ForwardTypePayoff(fraType_, strike);
         // incomeDiscountCurve_ is irrelevant to an FRA
         incomeDiscountCurve_ = discountCurve_;
         // income is irrelevant to FRA - set it to zero
         underlyingIncome_ = 0.0;
         
         index_.registerWith(update);
      }
예제 #3
0
 public DigitalIborLeg withLongPutOption(Position.Type type)
 {
     longPutOption_ = type;
      return this;
 }
예제 #4
0
 public DigitalIborLeg(Schedule schedule, IborIndex index)
 {
     schedule_ = schedule;
      index_ = index;
      paymentAdjustment_ = BusinessDayConvention.Following;
      inArrears_ = false;
      longCallOption_ = Position.Type.Long;
      callATM_ = false;
      longPutOption_ = Position.Type.Long;
      putATM_ = false;
 }
예제 #5
0
 public DigitalCmsLeg withLongCallOption(Position.Type type)
 {
     longCallOption_ = type;
      return this;
 }
예제 #6
0
 // Factory - for Leg generators
 public virtual CashFlow factory(FloatingRateCoupon underlying, double?callStrike, Position.Type callPosition, bool isCallATMIncluded, double?callDigitalPayoff, double?putStrike, Position.Type putPosition, bool isPutATMIncluded, double?putDigitalPayoff, DigitalReplication replication)
 {
     return(new DigitalCoupon(underlying, callStrike, callPosition, isCallATMIncluded, callDigitalPayoff, putStrike, putPosition, isPutATMIncluded, putDigitalPayoff, replication));
 }
예제 #7
0
        public static List <CashFlow> FloatingDigitalLeg <InterestRateIndexType, FloatingCouponType, DigitalCouponType>(List <double> nominals,
                                                                                                                        Schedule schedule,
                                                                                                                        InterestRateIndexType index,
                                                                                                                        DayCounter paymentDayCounter,
                                                                                                                        BusinessDayConvention paymentAdj,
                                                                                                                        List <int> fixingDays,
                                                                                                                        List <double> gearings,
                                                                                                                        List <double> spreads,
                                                                                                                        bool isInArrears,
                                                                                                                        List <double> callStrikes,
                                                                                                                        Position.Type callPosition,
                                                                                                                        bool isCallATMIncluded,
                                                                                                                        List <double> callDigitalPayoffs,
                                                                                                                        List <double> putStrikes,
                                                                                                                        Position.Type putPosition,
                                                                                                                        bool isPutATMIncluded,
                                                                                                                        List <double> putDigitalPayoffs,
                                                                                                                        DigitalReplication replication)
            where InterestRateIndexType : InterestRateIndex, new()
            where FloatingCouponType : FloatingRateCoupon, new()
            where DigitalCouponType : DigitalCoupon, new()
        {
            int n = schedule.Count;

            if (nominals.Count == 0)
            {
                throw new ArgumentException("no nominal given");
            }
            if (nominals.Count > n)
            {
                throw new ArgumentException(
                          "too many nominals (" + nominals.Count + "), only " + n + " required");
            }
            if (gearings != null && gearings.Count > n)
            {
                throw new ArgumentException(
                          "too many gearings (" + gearings.Count + "), only " + n + " required");
            }
            if (spreads != null && spreads.Count > n)
            {
                throw new ArgumentException(
                          "too many spreads (" + spreads.Count + "), only " + n + " required");
            }
            if (callStrikes.Count > n)
            {
                throw new ArgumentException(
                          "too many nominals (" + callStrikes.Count + "), only " + n + " required");
            }
            if (putStrikes.Count > n)
            {
                throw new ArgumentException(
                          "too many nominals (" + putStrikes.Count + "), only " + n + " required");
            }


            List <CashFlow> leg = new List <CashFlow>();

            // the following is not always correct
            Calendar calendar = schedule.calendar();

            Date refStart, start, refEnd, end;
            Date paymentDate;

            for (int i = 0; i < n; ++i)
            {
                refStart    = start = schedule.date(i);
                refEnd      = end = schedule.date(i + 1);
                paymentDate = calendar.adjust(end, paymentAdj);
                if (i == 0 && !schedule.isRegular(i + 1))
                {
                    BusinessDayConvention bdc = schedule.businessDayConvention();
                    refStart = calendar.adjust(end - schedule.tenor(), bdc);
                }
                if (i == n - 1 && !schedule.isRegular(i + 1))
                {
                    BusinessDayConvention bdc = schedule.businessDayConvention();
                    refEnd = calendar.adjust(start + schedule.tenor(), bdc);
                }
                if (Utils.Get(gearings, i, 1.0) == 0.0)   // fixed coupon
                {
                    leg.Add(new
                            FixedRateCoupon(Utils.Get(nominals, i, 1.0),
                                            paymentDate,
                                            Utils.Get(spreads, i, 1.0),
                                            paymentDayCounter,
                                            start, end, refStart, refEnd));
                }
                else     // floating digital coupon
                {
                    FloatingCouponType underlying = new FloatingCouponType().factory(
                        Utils.Get(nominals, i, 1.0),
                        paymentDate, start, end,
                        Utils.Get(fixingDays, i, index.fixingDays()),
                        index,
                        Utils.Get(gearings, i, 1.0),
                        Utils.Get(spreads, i, 0.0),
                        refStart, refEnd,
                        paymentDayCounter, isInArrears) as FloatingCouponType;

                    DigitalCouponType digitalCoupon = new DigitalCouponType().factory(
                        underlying,
                        Utils.toNullable(Utils.Get(callStrikes, i, Double.MinValue)),
                        callPosition,
                        isCallATMIncluded,
                        Utils.toNullable(Utils.Get(callDigitalPayoffs, i, Double.MinValue)),
                        Utils.toNullable(Utils.Get(putStrikes, i, Double.MinValue)),
                        putPosition,
                        isPutATMIncluded,
                        Utils.toNullable(Utils.Get(putDigitalPayoffs, i, Double.MinValue)),
                        replication) as DigitalCouponType;

                    leg.Add(digitalCoupon);
                }
            }
            return(leg);
        }
예제 #8
0
        //! Constructors
        //! general constructor
        public DigitalCoupon(FloatingRateCoupon underlying,
                             double?callStrike              = null,
                             Position.Type callPosition     = Position.Type.Long,
                             bool isCallATMIncluded         = false,
                             double?callDigitalPayoff       = null,
                             double?putStrike               = null,
                             Position.Type putPosition      = Position.Type.Long,
                             bool isPutATMIncluded          = false,
                             double?putDigitalPayoff        = null,
                             DigitalReplication replication = null)
            : base(underlying.date(), underlying.nominal(), underlying.accrualStartDate(), underlying.accrualEndDate(), underlying.fixingDays, underlying.index(), underlying.gearing(), underlying.spread(), underlying.referencePeriodStart, underlying.referencePeriodEnd, underlying.dayCounter(), underlying.isInArrears())
        {
            if (replication == null)
            {
                replication = new DigitalReplication();
            }

            underlying_          = underlying;
            callCsi_             = 0.0;
            putCsi_              = 0.0;
            isCallATMIncluded_   = isCallATMIncluded;
            isPutATMIncluded_    = isPutATMIncluded;
            isCallCashOrNothing_ = false;
            isPutCashOrNothing_  = false;
            callLeftEps_         = replication.gap() / 2.0;
            callRightEps_        = replication.gap() / 2.0;
            putLeftEps_          = replication.gap() / 2.0;
            putRightEps_         = replication.gap() / 2.0;
            hasPutStrike_        = false;
            hasCallStrike_       = false;
            replicationType_     = replication.replicationType();


            Utils.QL_REQUIRE(replication.gap() > 0.0, () => "Non positive epsilon not allowed");

            if (putStrike == null)
            {
                Utils.QL_REQUIRE(putDigitalPayoff == null, () => "Put Cash rate non allowed if put strike is null");
            }

            if (callStrike == null)
            {
                Utils.QL_REQUIRE(callDigitalPayoff == null, () => "Call Cash rate non allowed if call strike is null");
            }

            if (callStrike != null)
            {
                Utils.QL_REQUIRE(callStrike >= 0.0, () => "negative call strike not allowed");

                hasCallStrike_ = true;
                callStrike_    = callStrike.GetValueOrDefault();
                Utils.QL_REQUIRE(callStrike_ >= replication.gap() / 2.0, () => "call strike < eps/2");

                switch (callPosition)
                {
                case Position.Type.Long:
                    callCsi_ = 1.0;
                    break;

                case Position.Type.Short:
                    callCsi_ = -1.0;
                    break;

                default:
                    Utils.QL_FAIL("unsupported position type");
                    break;
                }
                if (callDigitalPayoff != null)
                {
                    callDigitalPayoff_   = callDigitalPayoff.GetValueOrDefault();
                    isCallCashOrNothing_ = true;
                }
            }
            if (putStrike != null)
            {
                Utils.QL_REQUIRE(putStrike >= 0.0, () => "negative put strike not allowed");
                hasPutStrike_ = true;
                putStrike_    = putStrike.GetValueOrDefault();
                switch (putPosition)
                {
                case Position.Type.Long:
                    putCsi_ = 1.0;
                    break;

                case Position.Type.Short:
                    putCsi_ = -1.0;
                    break;

                default:
                    Utils.QL_FAIL("unsupported position type");
                    break;
                }
                if (putDigitalPayoff != null)
                {
                    putDigitalPayoff_   = putDigitalPayoff.GetValueOrDefault();
                    isPutCashOrNothing_ = true;
                }
            }

            switch (replicationType_)
            {
            case Replication.Type.Central:
                // do nothing
                break;

            case Replication.Type.Sub:
                if (hasCallStrike_)
                {
                    switch (callPosition)
                    {
                    case Position.Type.Long:
                        callLeftEps_  = 0.0;
                        callRightEps_ = replication.gap();
                        break;

                    case Position.Type.Short:
                        callLeftEps_  = replication.gap();
                        callRightEps_ = 0.0;
                        break;

                    default:
                        Utils.QL_FAIL("unsupported position type");
                        break;
                    }
                }
                if (hasPutStrike_)
                {
                    switch (putPosition)
                    {
                    case Position.Type.Long:
                        putLeftEps_  = replication.gap();
                        putRightEps_ = 0.0;
                        break;

                    case Position.Type.Short:
                        putLeftEps_  = 0.0;
                        putRightEps_ = replication.gap();
                        break;

                    default:
                        Utils.QL_FAIL("unsupported position type");
                        break;
                    }
                }
                break;

            case Replication.Type.Super:
                if (hasCallStrike_)
                {
                    switch (callPosition)
                    {
                    case Position.Type.Long:
                        callLeftEps_  = replication.gap();
                        callRightEps_ = 0.0;
                        break;

                    case Position.Type.Short:
                        callLeftEps_  = 0.0;
                        callRightEps_ = replication.gap();
                        break;

                    default:
                        Utils.QL_FAIL("unsupported position type");
                        break;
                    }
                }
                if (hasPutStrike_)
                {
                    switch (putPosition)
                    {
                    case Position.Type.Long:
                        putLeftEps_  = 0.0;
                        putRightEps_ = replication.gap();
                        break;

                    case Position.Type.Short:
                        putLeftEps_  = replication.gap();
                        putRightEps_ = 0.0;
                        break;

                    default:
                        Utils.QL_FAIL("unsupported position type");
                        break;
                    }
                }
                break;

            default:
                Utils.QL_FAIL("unsupported position type");
                break;
            }

            underlying.registerWith(update);
        }
예제 #9
0
 public DigitalIborLeg withLongPutOption(Position.Type type)
 {
     longPutOption_ = type;
     return(this);
 }
예제 #10
0
파일: FRA.cs 프로젝트: igitur/qlnet
        static void Main()
        {
            DateTime timer = DateTime.Now;

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

            RelinkableHandle <YieldTermStructure> euriborTermStructure = new RelinkableHandle <YieldTermStructure>();
            IborIndex euribor3m = new Euribor3M(euriborTermStructure);

            Date todaysDate = new Date(23, Month.May, 2006);

            Settings.setEvaluationDate(todaysDate);

            Calendar calendar       = euribor3m.fixingCalendar();
            int      fixingDays     = euribor3m.fixingDays();
            Date     settlementDate = calendar.advance(todaysDate, fixingDays, TimeUnit.Days);

            Console.WriteLine("Today: " + todaysDate.DayOfWeek + ", " + todaysDate);
            Console.WriteLine("Settlement date: " + settlementDate.DayOfWeek + ", " + settlementDate);


            // 3 month term FRA quotes (index refers to monthsToStart)
            double[] threeMonthFraQuote = new double[10];

            threeMonthFraQuote[1] = 0.030;
            threeMonthFraQuote[2] = 0.031;
            threeMonthFraQuote[3] = 0.032;
            threeMonthFraQuote[6] = 0.033;
            threeMonthFraQuote[9] = 0.034;

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


            // FRAs
            SimpleQuote fra1x4Rate  = new SimpleQuote(threeMonthFraQuote[1]);
            SimpleQuote fra2x5Rate  = new SimpleQuote(threeMonthFraQuote[2]);
            SimpleQuote fra3x6Rate  = new SimpleQuote(threeMonthFraQuote[3]);
            SimpleQuote fra6x9Rate  = new SimpleQuote(threeMonthFraQuote[6]);
            SimpleQuote fra9x12Rate = new SimpleQuote(threeMonthFraQuote[9]);

            RelinkableHandle <Quote> h1x4  = new RelinkableHandle <Quote>();  h1x4.linkTo(fra1x4Rate);
            RelinkableHandle <Quote> h2x5  = new RelinkableHandle <Quote>();  h2x5.linkTo(fra2x5Rate);
            RelinkableHandle <Quote> h3x6  = new RelinkableHandle <Quote>();  h3x6.linkTo(fra3x6Rate);
            RelinkableHandle <Quote> h6x9  = new RelinkableHandle <Quote>();  h6x9.linkTo(fra6x9Rate);
            RelinkableHandle <Quote> h9x12 = new RelinkableHandle <Quote>(); h9x12.linkTo(fra9x12Rate);

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

            DayCounter            fraDayCounter = euribor3m.dayCounter();
            BusinessDayConvention convention    = euribor3m.businessDayConvention();
            bool endOfMonth = euribor3m.endOfMonth();

            RateHelper fra1x4 = new FraRateHelper(h1x4, 1, 4,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra2x5 = new FraRateHelper(h2x5, 2, 5,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra3x6 = new FraRateHelper(h3x6, 3, 6,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra6x9 = new FraRateHelper(h6x9, 6, 9,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra9x12 = new FraRateHelper(h9x12, 9, 12,
                                                   fixingDays, calendar, convention,
                                                   endOfMonth, fraDayCounter);


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

            fraInstruments.Add(fra1x4);
            fraInstruments.Add(fra2x5);
            fraInstruments.Add(fra3x6);
            fraInstruments.Add(fra6x9);
            fraInstruments.Add(fra9x12);

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


            // Term structures used for pricing/discounting
            RelinkableHandle <YieldTermStructure> discountingTermStructure = new RelinkableHandle <YieldTermStructure>();

            discountingTermStructure.linkTo(fraTermStructure);


            /***********************
            ***  construct FRA's ***
            ***********************/

            Calendar fraCalendar = euribor3m.fixingCalendar();
            BusinessDayConvention fraBusinessDayConvention = euribor3m.businessDayConvention();

            Position.Type fraFwdType    = Position.Type.Long;
            double        fraNotional   = 100.0;
            const int     FraTermMonths = 3;

            int[] monthsToStart = new [] { 1, 2, 3, 6, 9 };

            euriborTermStructure.linkTo(fraTermStructure);

            Console.WriteLine("\nTest FRA construction, NPV calculation, and FRA purchase\n");

            int i;

            for (i = 0; i < monthsToStart.Length; i++)
            {
                Date fraValueDate = fraCalendar.advance(
                    settlementDate, monthsToStart[i], TimeUnit.Months,
                    fraBusinessDayConvention);

                Date fraMaturityDate = fraCalendar.advance(
                    fraValueDate, FraTermMonths, TimeUnit.Months,
                    fraBusinessDayConvention);

                double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]];

                ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate,
                                                                      fraFwdType, fraStrikeRate,
                                                                      fraNotional, euribor3m,
                                                                      discountingTermStructure);

                Console.WriteLine("3m Term FRA, Months to Start: " + monthsToStart[i]);

                Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate);
                Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate());
                Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]);
                Console.WriteLine("FRA spot value: " + myFRA.spotValue());
                Console.WriteLine("FRA forward value: " + myFRA.forwardValue());
                Console.WriteLine("FRA implied Yield: {0:0.00%}",
                                  myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter));
                Console.WriteLine("market Zero Rate: {0:0.00%}",
                                  discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple));
                Console.WriteLine("FRA NPV [should be zero]: {0}\n", myFRA.NPV());
            }



            Console.WriteLine("\n");
            Console.WriteLine("Now take a 100 basis-point upward shift in FRA quotes and examine NPV\n");


            const double BpsShift = 0.01;

            threeMonthFraQuote[1] = 0.030 + BpsShift;
            threeMonthFraQuote[2] = 0.031 + BpsShift;
            threeMonthFraQuote[3] = 0.032 + BpsShift;
            threeMonthFraQuote[6] = 0.033 + BpsShift;
            threeMonthFraQuote[9] = 0.034 + BpsShift;

            fra1x4Rate.setValue(threeMonthFraQuote[1]);
            fra2x5Rate.setValue(threeMonthFraQuote[2]);
            fra3x6Rate.setValue(threeMonthFraQuote[3]);
            fra6x9Rate.setValue(threeMonthFraQuote[6]);
            fra9x12Rate.setValue(threeMonthFraQuote[9]);


            for (i = 0; i < monthsToStart.Length; i++)
            {
                Date fraValueDate = fraCalendar.advance(
                    settlementDate, monthsToStart[i], TimeUnit.Months,
                    fraBusinessDayConvention);

                Date fraMaturityDate = fraCalendar.advance(
                    fraValueDate, FraTermMonths, TimeUnit.Months,
                    fraBusinessDayConvention);

                double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]] - BpsShift;

                ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate,
                                                                      fraFwdType, fraStrikeRate,
                                                                      fraNotional, euribor3m,
                                                                      discountingTermStructure);

                Console.WriteLine("3m Term FRA, 100 notional, Months to Start: " + monthsToStart[i]);
                Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate);
                Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate());
                Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]);
                Console.WriteLine("FRA spot value: " + myFRA.spotValue());
                Console.WriteLine("FRA forward value: " + myFRA.forwardValue());
                Console.WriteLine("FRA implied Yield: {0:0.00%}",
                                  myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter));
                Console.WriteLine("market Zero Rate: {0:0.00%}",
                                  discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple));
                Console.WriteLine("FRA NPV [should be positive]: {0}\n", myFRA.NPV());
            }

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

            Console.Write("Press any key to continue ...");
            Console.ReadKey();
        }
 public DigitalIborLeg withLongCallOption(Position.Type type)
 {
    longCallOption_ = type;
    return this;
 }
예제 #12
0
 public DigitalCmsLeg withLongCallOption(Position.Type type)
 {
     longCallOption_ = type;
     return(this);
 }
예제 #13
0
 public ForwardTypePayoff(Position.Type type, double strike)
 {
     type_   = type;
     strike_ = strike;
     Utils.QL_REQUIRE(strike >= 0.0, () => "negative strike given");
 }
예제 #14
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();
        }