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