Jackpotjoy

## Bond Calcuation with C#

I've been read a tutorial about C# in last 2 days . Before that, I haven't read a single line of C# code in since I started to programming.  C# syntax is very similar to C++ and Java . But develop in C# is not easy as its syntax seems.  I've wrote some trivial codes about some financial calculation of a bond, it's quite similar to the code I've written before in Python, but this one focus  more  in a risk neutral perspective.

## Basic Bond Class with No Coupon

class ZeroBond{
protected float price; // current price for bond
protected float riskFreeRate;
protected float faceValue;
// constuctor
public ZeroBond(float price, float riskFreeRate, float faceValue){
this.price = price;
this.riskFreeRate = riskFreeRate;
this.faceValue = faceValue;
}}

### Value a Non-Coupon Bond with  Risk Neutral Binomial Method

I won't go to detail about what is a Risk Neutral  or what's the Binomial Method . In short , a risky bond equals to short position on put plus a risk-free bond .

$B(t,T) = B_{risk free}(t,T)-P(t,T,K)$

To estimate the value of bond $B(t,T)$, it is easy to get the data of risk free bond ,like Treasury Bond . but , how to evaluate the value of $P(t,T,K)$ ?

Price of a Put given Risk Neutral Binomial Method. $\pi$ is the probability of upward change of price and K is the face value of bond , $V_{d}\left ( 1 \right )$ is the downward price of the bond and this value can be access via multiply a change rate with initial price of bond $V_{0}$ . Question remains that : how to estimate the probability of upward change of price ? the value of $\pi$ ?

$P(0) = \frac{1}{1+r}\left [ \pi * 0 + \left ( 1-\pi \right )*\left ( K-V_{d}\left ( 1 \right ) \right ) \right ]$

We can infer the value of $\pi$ by assumption that current price of bond is present value of expectation of future 2 prices( upward&downward ). If we input current price, estimation of change rate and risk free rate, then we will get $\pi$ probability of upward price changing.

$V(0)=\frac{1}{1+r}(\pi * V_{u}(1)+(1-\pi)*V_{d}(1))$

C# Code :

public float CalRiskNetrualProbWithBinomialOption(float ChangeRate)
{
// calculate risk neutrual probability for upward of prices
return (this.price * (1 + this.riskFreeRate) - this.price * (1 - ChangeRate)) /
(this.price * (1 + ChangeRate) - this.price * (1 - ChangeRate));
}
public float CalPutWithBinomialOption(float ChangeRate){
// calculate 1 period bond put option price with binomial change price
float upwardProb = this.CalRiskNetrualProbWithBinomialOption(ChangeRate);
return (1 - upwardProb) * (this.faceValue - this.price * (1 - ChangeRate)) / (1 + this.riskFreeRate);
}

After we have the put price for the risky bond , we now may calculate the risky bond price by discount risk free bond minus the put price .

public float CalRiskNetrualPriceWithBinomialOption(float ChangeRate) {
// calculate risk neutral price with Binomial Option
return this.faceValue / (1 + this.riskFreeRate) - this.CalPutWithBinomialOption(ChangeRate);
}

### Default Bond with a Recovery

Consider a risky zero-coupon, one-period debt with the face value of K (i.e., promising a cash
flow of K at maturity in one period). Given the expected recovery for this bond in case of default, R,
then the bond has an expected payoff of K × R in default with the probability λ (the probability of
default) and, of course, a payoff of K in the absence of default with the probability of (1 – λ). (From CAIA text book , page:631). A risky bond value can be expressed as the sum of the discounted cash flows as below:

$B(0,1)=\lambda *\frac{K * R}{(1+r)} + (1-\lambda)*\frac{K}{(1+r)}$

Thus , we may input a recovery rate and then get the price of risky bond:

public float CalRiskNetrualPriceWithRecovery(float RecoveryRate, float DefaultProb){
return DefaultProb * this.faceValue * RecoveryRate / (this.riskFreeRate + 1) +
(1 - DefaultProb) * this.faceValue / (this.riskFreeRate + 1);
}

## Basic Bond Class with Coupon

The class Bond inherits the "ZeroBond", and has its own member like "interestRate","PaymentsPerYear","TimeToMaturity" etc

class Bond : ZeroBond{
private float interestRate; // Interest Rate for Bond
private int paymentsPerYear; // #Only implement "1" for now # 1 for interest paid yearly and 2 for interest paid semi-yearly
private float term; // Maturity Term
private float timeToMaturity;
public Bond(float price, float riskFreeRate, float faceValue , float interestRate, int paymentsPerYear, float term, float timeToMaturity)
: base(price, riskFreeRate, faceValue){
this.interestRate = interestRate;
this.paymentsPerYear = paymentsPerYear;
this.term = term;
this.timeToMaturity = timeToMaturity;
}
}

#### Calculate Present Value (continuously compound)

I wrote two method to get a float array of payment dates and cash flow , then using Math.E , Math.pow() to discount the cash flow to present value.

// Cash flows including interest and principle at last payment
public float[] GetCashFlow(){
int timesOfPayments = (int)Math.Ceiling(this.timeToMaturity * this.paymentsPerYear);
float[] cf = new float[timesOfPayments];
float interest = this.interestRate * this.faceValue;
for(int i = 0; i < timesOfPayments; i++){
cf[i] = interest;
}
cf[ timesOfPayments-1 ] += this.faceValue;
return cf;
}
//cash flow payment dates
public float[] GetTerm(){
float ytm = this.timeToMaturity;
return Enumerable.Range(0, (int)Math.Ceiling(ytm)).Select(i => (float)Math.Round(i + (ytm - (int)ytm), 1)).ToArray();
}
// caluclate Present Value
public float CalPresentValue(float discountRate){
float[] term = this.GetTerm();
float[] cfs = this.GetCashFlow();
float presentValue = 0f;
for (int j = 0; j < cfs.Length; j++){
presentValue += (float)(Math.Pow(Math.E, -1 * term[j] * discountRate) * cfs[j]);
}
return presentValue;
}

#### Calculate Yield To Maturity

Yield to Maturity is a discount rate that will equals the present value of cash flow to the current price of the bond . I wrote a bi-sect method to calculate this rate . "maxIteration" is set with 1000 up to prevent infinite looping and this method assume that discount rate between 0.001 to 0.999 .

public float CalYield(float eps){
float des = 0.0f;
const int maxIteration = 1000;
int iterNum = 0;
float y = 0.04f;
float h = 0.999f;
float l = 0.001f;
do{
des = this.CalPresentValue(y) - this.price;
if (des > 0){
l = y;
y = (y + h) / 2;
}else{
h = y;
y = (y + l) / 2;
}
//Console.WriteLine(Math.Abs(des));
iterNum++;
}while ((Math.Abs(des) > eps) && (iterNum <= maxIteration));
return y;
}

#### Calculate Macaulay  Duration

Macaulay duration is the weighted average maturity of cash flows with formula below :

$MacDuartion = \sum_{i=1}^{n}t_{i}\frac{PV_{i}}{V}$

$PV_{i}$ stands for the present value of cash flow at time i , V stands for the current price.

// Calculate Macaulay  Duration
public float CalDuration(float discountRate){
float PV = this.CalPresentValue(discountRate);
float[] term = this.GetTerm();
float[] cfs = this.GetCashFlow();
float duration = 0f;
for (int i = 0; i < term.Length; i++){
duration += term[i] * (float)Math.Pow(Math.E, (-1 * term[i] * this.riskFreeRate)) * cfs[i] / PV;
}
return duration;
}

## Example：

static void Main(string[] args){
// a zero bond with price 100.00 , risk free rate 0.05 , and face value 80.0
ZeroBond zero_bnd = new ZeroBond(100.0f,0.05f,80f);
// single period calculation with 2 possible result;
Console.WriteLine("Downside Probibility");
Console.WriteLine(zero_bnd.CalRiskNetrualProbWithBinomialOption(0.3f));
Console.WriteLine("Put Value");
Console.WriteLine(zero_bnd.CalPutWithBinomialOption(0.3f));
Console.WriteLine("Risk Neutral Price");
Console.WriteLine(zero_bnd.CalRiskNetrualPriceWithBinomialOption(0.3f));
//Bond with current price 103.3, risk free rate 0.05, face value 100
// coupon rate 0.03, pays yearly with 4 yr term and 3.32 years remains
Bond int_bnd = new Bond(103.3f, 0.05f, 100f, 0.03f, 1, 4, 3.32f);
Console.WriteLine(int_bnd.GetCashFlow());
// calculate present value of all cash flow
Console.WriteLine("Calculate the Present Value ");
Console.WriteLine(int_bnd.CalPresentValue(0.05f));
Console.WriteLine("Yield to Maturity, with eps 0.0001 ");
Console.WriteLine(int_bnd.CalYield(0.0001f));
// calculation Macauley Duration
Console.WriteLine("Duration");
Console.WriteLine(int_bnd.CalDuration(0.02f));
}