Friday, May 05, 2023

Calculating the Yield To Maturity (YTM) of a bond with Python coding

 


This equation is to calculate the present value of a bond based on the interest rate (r) which is usually fluctuating over years to calculate the present value of this bond.

The Yield To Maturity (YTM) is calculated under a given market price at the current time period which is substituted to the present value (PV). The Yield To Maturity (YTM) is the fixed value substituted to the interest rate (r).

It applies the built-in function of "newton" from "scripy.optimize" quoted from https://stackoverflow.com/questions/66431104/python-yield-to-maturity-finance-bonds to calculating the YTM. 

The following codes are the codes to calculate the YTM of the bond.

# The Newton Optimisation of calculating the Yield To Maturity (YTM) of bond.
import math
from scipy.optimize import newton
import matplotlib.pyplot as plt 

# Define a function to calculate the present value of a bond
F=1000 # The face value of bond
c=0.08 # The coupon payment payment rate per face value
M=F*c # The coupon payment value with the given payment rate
m=2 # Frequency of the coupon payment. E.g. Semi-annual payment so twice a year 
t=6 # The year from now to the maturity date
n=t*m
mktprc=980 # The market value 
Guess=0.28 # Just a randomly selected number, but don't make it too diverged from the estimated YTM

print('\033[1m --- \033[4m YTM calculation \033[0m --- \033[0m')
def pv_bond(ytm):
    pv = 0
    for i in range(n):
        # Calculate present value of each coupon payment
        pv += M/m*math.exp(-1*ytm/m*i)   # coupons present value
    # Add present value of face value to total present value
    return pv+F*math.exp(-1*ytm/m*i) # Define a function to calculate the difference between market price and calculated price
def diff(ytm):
    return market_price - pv_bond(ytm=ytm)
market_price=mktprc #put ur market price based on task #3 # Use Newton-Raphson method to find root of diff function (i.e., YTM)
ytm = newton(func=diff,x0=Guess) 
print(f'The yield to maturity (YTM) is: {ytm:.2%}') # showing to the 2nd decimal place 

# Caluculating the bond's present value based on the interest rate = the YTM
print('\033[1m --- \033[4m Bond value calculation \033[0m --- \033[0m')
pv=0
for i in range(n):
    # Calculate present value of each coupon payment
    pv += M/m*math.exp(-1*ytm/m*i)  # coupons present value
    print(i*15,'months',i/2,'th year Interest Rate:',round(ytm,3),'%','  Coupons:',round(pv,2))
# Add the present total values of coupons to the the present value of the bond
P=F*math.exp(-1*ytm/m*i)+pv
print(f'The bound price based on the constrant rate {ytm:.2%} is {round(P,2)} .')



The result will be shown as 

Saturday, April 15, 2023

Nothing to be afraid of the Artificial Intelligence (AI)

I always wonder why people tend to be afraid of the AI so much. It sounds just a resemblance to those industrial workers kicked out of their factory job when a new machinery was introduced during the industrial revolution. I actually believe that the further AI development will rather make humanity thrive instead of being destroyed.

I have realised that people in general tend to overestimate the artificial intelligence (AI) because of what the media agitate. The AI is just an application whose capacity really depends on the underneath structure, the infrastructure and the platform. Well, there is no worry to be afraid of the AI taking over humans. The AI is more intelligent for some field but not all the fields which humans are familiar with. 



Moreover, the neuron network of the AI and the humans are completely different. The brain cells and the nerves of humans and the majority natural creatures are interrelated with the other organs of their body. For instance, gut heavily influences their thought process and mindset. In contrast, the AI thought process and neuron networks are self-contained inside their CPI and memory.

Sunday, April 09, 2023

Brownian Motion -> Wiener Process -> Ito Process

This is the mathematical and statistical model referring to a physics theory. Originally, this was invented to predict the randomly floating atoms' movement. This is applied to financial modelling to predict the random walk movement of stock prices. 

Wiener process is derived from the model of Brownian motion to take an account of the variance varying differently from Brownian motion. The popular model is Ito Process invented by Prof. Kiyoshi Ito, Japanese mathematician, which is the derivation of Wiener process. 
 
Ito-Process is more practical to explain in the financial market modelling because the future expected prices of financial assets often drift away from the current point. 

The equation introduced here shows the differential of the variable in the time series. The drift coefficient denotes the lagging effect or the seasonal effect of the variable at a certain time period. The diffusion coefficient is simply the random walk part based on the normally distributed random variable while its theoretical explanation is far more complicated than explained here. 
 
With Python, the diffusion is described as numpy.random.normal(0,SD) where SD stands for standard deviation or volatility in the financial modelling.

After plotting the time series, the expected value at the target time period tends to form a normal distribution. Then, the expected value is calculated under the given confidence interval with the confidence level (usually 95%) / the significance level (usually 5%). In case, it had better test the normality to avoid the bias. 
 
Together with the unit root test assessing the stationarity of financial market and the capital asset pricing model indicating the assets' profitability and risk, the random walk model based on Ito process are popularly used in the financial market analyses.



Thursday, January 26, 2023

Adam Smith's grave in Canongate Kirkyard on the Royal Mile, Edinburgh, S...

 


Adam Smith's grave in Canongate Kirkyard on the Royal Mile, Edinburgh, Scotland, UK. Whenever I visit Edinburgh, I give Adam Smith, the father of economics, a prayer.

 This newly started YouTube channel exhibits various short videos of Scotland.

Please visit to watch! Cheers!

 

 


 

Tuesday, January 17, 2023

Python Experiment: Macroeconomic Theory: Income Price Inflation Control Simulator in the ADAS model


 I have created a macroeconomic policy simulator with Python programming. 

This refers to the aggregate demand and supply interaction based on the simplified IS-LM interaction influencing the aggregate demand (AD) and the labour market and the capital cost influencing the short-run aggregate supply (AS). These curves are composed of the two main parameters, the aggregate income level and the price level, as well as the money supply (MS) basing the IS-LM, and the wage index (W) basing the labour market. 

My Python codes are as follows: 

# Default Parameters
import random
Y=[20,30]  # The aggregate income level: Change here to see each effect
P=[100,102] # The price level: Change here to see each effect
W=[10]
WB=0.2
MS=[100]
rHD=10 
CapCost=[10]

# Function representing the price inflation
def PrInf():
    return ((P[-1]-P[-2])/P[-2])

PrInf()

# Higher function
# The aggregate demand influence
def Y_Inv(MSlmis,Ylmis,dp):
    r_MS=pow(MSlmis/10,-1.05)+rHD*(PrInf()) #LM side
    return pow(Ylmis,-1*(r_MS-PrInf())) #IS-side

Y_Inv(MS[-1],Y[-1],PrInf())

# A part of the short-run aggregate supply influence (The Labour Market).
def Y_Lab(Wlab,Plab):
    return (50-(50/(Wlab/Plab)))/100

Y_Lab(W[-1],1+PrInf()+0.000001)


def AggregateDemandCurve(Ydd):
    Pd=Y_Inv(MS,Ydd)/Ydd
    return Pd

def AggregateSupplyCurve(Wlab,Plab,Css):
    Ps=Css+Y_Lab(Wlab,Plab)
    return Ps
    

def AggregateSupplyCurveShift(Y1,Y2,Pinv):
    dp=(Y_Inv(MS[-1],Y1,Pinv))-(Y_Inv(MS[-1],Y2,Pinv)) #AggregateDemandCurve(Yd1)-AggregateDemandCurve(Yd2)
    return dp

print(Y_Inv(MS[-1],Y[-1],PrInf()),Y[-1],PrInf())
print(Y_Inv(MS[-1],Y[-2],PrInf()),Y[-2],PrInf())
AggregateSupplyCurveShift(Y[-1],Y[-2],PrInf())


def AggregateDemandCurveShift(Y1,Y2,Wlab,Plab,Csd):
    dp = (Csd+(Y_Lab(Wlab,Plab)*(1+WB*(Y1-Y2)/Y2)))-(Csd+Y_Lab(Wlab,Plab)) #AggregateSupplyCurve(Yd1)-AggregateSupplyCurve(Yd2)
    return dp

print(CapCost[-1]+(Y_Lab(W[-1],PrInf())*(1+WB*(Y[-1]-Y[-2])/Y[-2])))
print(CapCost[-1]+Y_Lab(W[-1],PrInf()))
           
AggregateDemandCurveShift(Y[-1],Y[-2],W[-1],PrInf(),CapCost[-1])

# Calculating the average aggregate income level across all over the time period to generate the long-run aggregate supply interaction
def Ymean():
    Ysum=0
    for i in range(len(Y)):
        Ysum=Ysum+Y[i]
    return Ysum/len(Y)
Ymean()

# Main function: The interaction of the aggregate demand and the short-run aggregate supply
def Shift1(MSlmis=MS,Y1=Y[-1],Y2=Y[-2],Wlab=W,Plab=PrInf(),Csd=CapCost[-1],Pinv=PrInf()):
    OutputGap=Y[-1]-Ymean()
    PriceInflation=((P[-1]-P[-2])/P[-2])
    if (OutputGap>0.05) & (PriceInflation>0.0001): # Positive Inflation
        dP=AggregateDemandCurveShift(Y1,Y2,Wlab,Plab,Csd)
        P.append(P[-1]*(1+dP))
        print(dP)
        MS.append(MS[-1]*(1+OutputGap/Ymean()))
        print(MS[-1])
        Y.append(Y[-1]*(1+(Y_Inv(MS[-1],Y[-1],dP)-Y_Inv(MS[-2],Y[-1],PriceInflation))))
        W.append(W[-1])
        CapCost.append(CapCost[-1])
    elif (OutputGap<-0.05) & (PriceInflation>0.0001): # Negative Inflation
        dP=AggregateSupplyCurveShift(Y1,Y2,Pinv)
        P.append(P[-1]*(1+dP))
        print(dP)
        W.append(W[-1]*(1+Ymean()/OutputGap))
        CapCost.append((1+dP)*CapCost[-1])
        print(W[-1])
        Y.append(Y[-1]*(CapCost[-1]/CapCost[-2]+(Y_Lab(W[-1],dP)-Y_Lab(W[-2],PriceInflation))))
        MS.append(MS[-1])
    elif (OutputGap<-0.05) & (PriceInflation<-0.0001): # Deflation
        dP=AggregateDemandCurveShift(Y1,Y2,Wlab,Plab,Csd)
        P.append(P[-1]*(1+dP))
        print(dP)
        MS.append(MS[-1]*(1+OutputGap/Ymean()))
        print(MS[-1])
        Y.append(Y[-1]*(1+(Y_Inv(MS[-1],Y[-1],dP)-Y_Inv(MS[-2],Y[-1],PriceInflation))))
        W.append(W[-1])
        CapCost.append(CapCost[-1])
    elif (OutputGap<-0.05) & (PriceInflation<-0.0001): # Dereguation
        dP=AggregateSupplyCurveShift(Y1,Y2,Pinv)
        P.append(P[-1]*(1+dP))
        print(dP)
        W.append(W[-1]*(1+Ymean()/OutputGap))
        CapCost.append((1+dP)*CapCost[-1])
        print(W[-1])
        Y.append(Y[-1]*(CapCost[-1]/CapCost[-2]+(Y_Lab(W[-1],dP)-Y_Lab(W[-2],PriceInflation))))
        MS.append(MS[-1])
    else: 
        print("Nothing")
    
    print(OutputGap,P,Y)

  # See the result
Shift1(MS[-1],Y[-1],Y[-2],W[-1],PrInf(),CapCost[-1])

print(Y)
print(P)
print(MS)
print(W)
print(CapCost)