.chapter14<-function(i=0){ " i Chapter 14: Finance Basics i Explanations - ---------------------------------- -- --------------------------- 1 fv value formula 21 Effective rate 2 : R program 22 : examples 3 : R program with help 23 conversion: Method I 4 pv formula 24 : method II formula 5 PV(one future cash flow) formula 25 : R code 6 a general formula 26 NPV definition and its rule 7 PV(perpetuity) 27 R code 8 PV(perpetuity,1st cash flow at k) 28 example 9 PV(annuity) 29 IRR definition and its rule 10 : derivation 30 : normal project/R code 11 : pv(annuity due) 31 : NPV profile 12 fv(annuity) 32 : multiple IRRs 13 fv(annuity due) 33 : search for multiple IRRS 14 pv(growing annuity) 34 Payback period and its rule 15 fv(growing annuity) 35 : example #1 16 one-line code for 10 formulas 36 : example #2 17 pv_f() plus a loop 37 : issues 18 price of a bond 38 Monotone's definition 19 Videos 39 : example 20 Links 40 : R code Example #1:>.c14 # see the above list Example #2:>.c14() # the same as the above Example #3:>.c14(1) # see the first explanation ";.zchapter14(i)} .n14chapter<-40 .zchapter14<-function(i){ if(i==0){ print(.c14) }else{ .printEachQ(14,i,.n14chapter) } } .c14<-.chapter14 .C14EXPLAIN1<-"From where to download R //////////////////////////////// Formula: fv= pv * (1+r)^n fv: future value pv: present value r : the effective period rate n: the number of periods /////////////////////////////// " .C14EXPLAIN2<-"launch/quit R, one line for this course //////////////////////////////// fv_f<-function(pv,r,n) pv*(1+r)^n /////////////////////////////// " .C14EXPLAIN3<-"Comment line and comment paragraph //////////////////////////////// fv_f<-function(pv,r,n){ \"Objective: calculate the future value for a given present value formula used: fv=pv*(1+r)^n Inputs fv: future value pv: present value r : effective period rate n: number of periods Example #1: > fv_f(100,0.1,1) Example #2:> fv_f(r=0.1,fv=100,n=1) Example #3> fv_f(r=0.1,fv=100,1) \"; fv<-pv*(1+r)^n return(fv) } //////////////////////////////// " .C14EXPLAIN4<-"3 ways to assign a value/values and how to show its value //////////////////////////////// pv formula fv pv = ------------- (1+r)^n fv: future value pv: present value r : effective period rate n: number of periods /////////////////////////////// " .C14EXPLAIN5<-"Use up and down arrow keys to recall the previous commands //////////////////////////////// pv_f<-function(fv,r,n){ \"Objective: calculate the present value for a given future value formula used: pv=fv/(1+r)^n Inputs fv: future value pv: present value r : effective period rate n: number of periods Example #1: > pv_f(100,0.1,1) [1] 90.90909 Example #2:> pv_f(r=0.1,fv=100,n=1) [1] 90.90909 Example #3> pv_f(r=0.1,fv=100,1) [1] 90.90909 \"; pv<-fv/(1+r)^n return(pv) } /////////////////////////////// " .C14EXPLAIN6<-"one general formula //////////////////////////////// s= a+ aq + aq^2 + aq^3 + .... a<1 a s= ------ (1-q) sum_f<-function(a,q){ if(q>1){ cat(\"Error message: q should be less than 1.\\n\") }else{ mySum<-a/(1-q) return(mySum) } } /////////////////////////////// " .C14EXPLAIN7<-"pv(perpetuity) //////////////////////////////// cash flows c c c c -> infinity |----------|----------|----------|----------| 1 2 3 4 -> infinity c pv(perpetuity) = --- R /////////////////////////////// " .C14EXPLAIN8<-"PV(perpetuity,1st cash flow at k) //////////////////////////////// cash flows c c -> infinity |-------|-------|-------| ... |-------| 1 2 3 k k+1 -> infinity c 1 pv(perpetuity) = ---* -------- R (1+r)^(k-1) /////////////////////////////// " .C14EXPLAIN9<-" PV(annuity) //////////////////////////////// Annuity: the same cash flows at the same intervals for just n periods [if the first cash flows at the end of the first period] Cash flows c c c c |-------|-------|-------| ... | 1 2 3 n //////////////////////////////// " .C14EXPLAIN10<-"pv(annuity) derivation //////////////////////////////// Logic: A annuity can be treated as two perpetuities. Assume that we receive $10 for the next 5 years. It can be treated as : 1) we receive $10 for forever 2) starting from year 6, we also pay $10 forever Why? The reason is that the formula of a perpetuity is so simple c c c c |-------|-------|-------| ... | 1 2 3 n 1) c c c c c -> infinity |-------|-------|-------| ... |------| 1 2 3 n n+1 -> infinity 2) -c -> infinity |-------|-------|-------| ... |------| 1 2 3 n n+1 -> infinity pv(annuity) = pv(perpetuity #1) - pv(perpetuity #2) = c/R - c/R *1/(1+R)^n = c/R (1 - 1/(1+R)^n) //////////////////////////////// " .C14EXPLAIN11<-"pv(annuity) R code //////////////////////////////// pv_annuity<-function(c,r,n)c/r*(1-1/(1+r)^n) /////////////////////////////// " .C14EXPLAIN12<-"fv(annuity) //////////////////////////////// fv_annuity<-function(c,r,n)c/r*((1+r)^n-1) /////////////////////////////// " .C14EXPLAIN13<-" fv(annuity due) //////////////////////////////// fv_annuity_due<-function(c,r,n)c/r*((1+r)^n-1)*(1+r) /////////////////////////////// " .C14EXPLAIN14<-"pv(growing annuity) //////////////////////////////// pv_growing_annuity<-function(c,r,n)c/(r-g)*(1-(1+g)^n/(1+r)^n) //////////////////////////////// " .C14EXPLAIN15<-"fv(growing annuity) //////////////////////////////// fv_growing_annuity<-function(c,r,n)c/(r-g)*((1+r)^n-(1+g)^n) /////////////////////////////// " .C14EXPLAIN16<-"one-line code for 10 finance formulas //////////////////////////////// fv_f<-function(pv,r,n) pv*(1+r)^n pv_f<-function(fv,r,n) fv/(1+r)^n # pv_perpetuity<-function(c,r) c/r pv_growing_perpetuity<-function(c,r,g=0) c/(r-g) # pv_annuity<-function(c,r,n)c/r*(1-1/(1+r)^n) pv_annuity_due<-function(c,r,n)c/r*(1-1/(1+r)^n)*(1+r) fv_annuity<-function(c,r,n)c/r*((1+r)^n-1) fv_annuity_due<-function(c,r,n)c/r*((1+r)^n-1)*(1+r) # pv_growing_annuity<-function(c,r,n)c/(r-g)*(1-(1+g)^n/(1+r)^n) fv_growing_annuity<-function(c,r,n)c/(r-g)*((1+r)^n-(1+g)^n) /////////////////////////////// " .C14EXPLAIN17<-"pv_f() plus a while or a for loop //////////////////////////////// pv_f<-function(fv,r,n) fv/(1+r)^n # total<-0.0 i<-1 c<-100 r<-0.1 # while(1==1){ pv<-pv_f(c,r,i) total<-total+pv i<-i+1 if(pv<0.001)break } print(final) /////////////////////////////// " .C14EXPLAIN18<-" //////////////////////////////// priceBond<-function(YTM,couponRate,freq,fv,T){ r<-YTM/freq c<-fv*couponRate/freq n<-T*freq pvCoupon<-c/r*(1-1/(1+r)^n) pvFV<-fv/(1+r)^n price<-pvCoupon+pvFV return(price) } /////////////////////////////// " .C14EXPLAIN19<-"Videos //////////////////////////////// 365 Financial Analyst,2000,How to Calculate a Project's NPV? (t5:12) https://www.youtube.com/watch?v=-cmQ5vk_BKk Edspira,2014, IRR (Internal Rate of Return) (t7:22) https://www.youtube.com/watch?v=OSDDrZZaV8E Edspira,2016, How to Calculate the Payback Period (t3:11) https://www.youtube.com/watch?v=iGImOv2rqHM /////////////////////////////// " .C14EXPLAIN20<-"Links //////////////////////////////// Yan, Yuxing, A 2-step approach to estimate an effective rate https://datayyy.com/doc_pdf/A_2step_approach_effective_rate.pdf /////////////////////////////// " .C14EXPLAIN21<-"Effective rate //////////////////////////////// Effective rate The Rs rate used in those formulas are all effective rates. /////////////////////////////// " .C14EXPLAIN22<-"Effective rate examples //////////////////////////////// 1) APR is 10% compounded semi-annually R(effective semi-annual rate) = 5% 2) APR is 8% compounded quarterly R(effective quarterly) = 2% 3) APR is 5% compounded daily R(effective daily rate) = 0.05/365 /////////////////////////////// " .C14EXPLAIN23<-"Effective conversion: Method I //////////////////////////////// Here is our 2-step approach: Step 1: Which effective rate is given? Step 2: convert one effective rate to another (apply the future value formula twice). Step 1: Since the APR is 10% compounding semiannually, we are given an effective semi-annual rate of 5% (10%/2). This is also true for other compounding frequencies. For example, if the compounding frequency is quarterly instead of semiannually, we are given an effective quarterly rate of 2.5% (0.1/4). Step 2: Assume that we deposit $1 today; we should receive the same amount in one year regardless of whether we apply an effective annual or semiannual rate. FV=1(1+0.05)^2 FV=1*(1+R)^1 In other words, we have 1(1+R(annual)=1(1+R(effective_semi)^2 Hence, we have R(annual)=(1+0.05)^2-1=0.1025. /////////////////////////////// " .C14EXPLAIN24<-" //////////////////////////////// /////////////////////////////// " .C14EXPLAIN25<-"R code: .rateYan() //////////////////////////////// .rateYan<-function(APR,method){ \"Objective : from one APR to another APR and effective rate APR : value of the given Annual Percentage Rate method : Converting method, e.g., 's2a', 's2q', 's2c' a for annual s for semi-annual q for quarterly m for monthly d for daily c for continuously Example 1: > .rateYan(0.1,'s2a') Two rates effective annual rate 0.1025 APR 0.1025 Example 2: > .rateYan(0.1,'s2q') Two rates effective quarterly rate 0.02469508 APR 0.09878031 \";.zrateYan(APR,method)} .zrateYan<-function(APR,rateA2rateB){ r=rateA2rateB if(nchar(r)!=3) stop(\"Wrong input for the 2nd variable\") if(substr(r,1,1)=='a') {n_in=1 } else if(substr(r,1,1)=='s') {n_in=2 } else if(substr(r,1,1)=='q') {n_in=4 } else if(substr(r,1,1)=='m') {n_in=12 } else if(substr(r,1,1)=='d') {n_in=365 } else if(substr(r,1,1)=='c') {n_in=1 }else{ return(-99) } if(substr(r,3,3)=='a') {n_out=1; label='annual' } else if(substr(r,3,3)=='s') {n_out=2; label='semi-annual' } else if(substr(r,3,3)=='q') {n_out=4; label='quarterly' } else if(substr(r,3,3)=='m') {n_out=12; label='monthly' } else if(substr(r,3,3)=='d') {n_out=365;label='daily' } else if(substr(r,3,3)=='c') {n_out=1; label='continuously' }else{ print('check your 2nd input. Tt should be s2a, s2q, etc') return(-99) } x=matrix(1,2) n=n_in/n_out if(substr(r,1,1)=='c') { x[1,1]<-exp(APR)^(1/n_out)-1 } else{ x[1,1]<-(1+APR/n_in)^n-1 } if(substr(r,3,3)=='c') { x[1,1]<-n_in*log(1+APR/n_in) } x[2,1]<-x[1,1]*n_out rownames(x)=c(paste('effective',label,'rate'), 'APR') colnames(x)<-\"Two rates\" return(x) } /////////////////////////////// " .C14EXPLAIN26<-"NPV definition and its rule //////////////////////////////// NPV (Net Present Value) is the difference between the sum of the present values of cash inflows and the sum of the present values of all the cash outflows. NPV Rule: if NPV(project) > 0 accept the project if NPV(project) < 0 reject the project /////////////////////////////// " .C14EXPLAIN27<-"NPV Example #1 //////////////////////////////// npv_f<-function(r,cashFlows){ n<-length(cashFlows) npv<-0 for(i in 1:n){ npv<-npv+cashFlows[i]/(1+r)^(i-1) } return(npv) } /////////////////////////////// " .C14EXPLAIN28<-" //////////////////////////////// r<-0.1 cashflows<-c(-400,100,200,200,200,200) npv_f(r,cashflows) [1] 267.2483 /////////////////////////////// " .C14EXPLAIN29<-"IRR definition and its rule //////////////////////////////// IRR stands for the Internal Rate of Return. It is the discount rate at which the NPV equals zero. Its associated decision rule is given below. IRR Rule: if IRR>Rc -> accept if IRR reject Rc the cost of capital /////////////////////////////// " .C14EXPLAIN30<-"normal project, R code //////////////////////////////// A normal project is defined as cash outflows first, then cash inflows. irr_f<-function(cashflows,bigV=100000){ irr<-2 rates<-seq(-1,1,1e-4) for(r in rates){ npv<-abs(npv_f(r,cashflows)) #print(npv) if(npv< bigV){ irr<-r bigV<-npv } } return(irr) } cashflows<-c(-100,90,50,30) irr_f(cashflows) # [1] 0.4069 /////////////////////////////// " .C14EXPLAIN31<-"NPV profile //////////////////////////////// rates<-seq(0,1,1e-1) cashflows<-c(-400,100,200,200,200,200) npvs<-npv_f(rates,cashflows) title<-\"NPV profile\" x<-\"Discount Rate\" plot(rates,npvs,main=title,xlab=x,ylab=\"NPV\",type='b',lwd=4) # add a line x1<-rates y1<-x1*0 lines(x1,y1,lwd=1) text(0.4, 106, labels=expression(\"NPV=0\") ,cex = 1) # y2<-seq(-300,400,1) irr<-irr_f(cashflows) x2<-rep(irr,length(y2)) lines(x2,y2,lwd=1) /////////////////////////////// " .C14EXPLAIN32<-"Issues with the IRR rule //////////////////////////////// For a normal project defined as cash outflows occurring before any cash inflows, the NPV and IRR rules usually offer the same conclusions. For abnormal projects, where some cash inflows are followed by cash outflows, the NPV and IRR rules might offer conflicting findings. When the future cash flows change signs n times, we might end up with different IRR estimates. There are several reasons why the NPV rule is preferred to the IRR rule. First, there might be no IRR that makes NPV equal to zero, i.e., we fail to find any IRR. Second, there might be multiple IRRs. This is true when the future cash flows change signs more than once. In other words, we might find two IRRs, 9% and 14%. If our cost of capital is 10%, we cannot apply the IRR rule to decide whether to choose or reject the project. Third, the reinvestment rate assumption underlying the IRR rule is unrealistic. For those cases, the NPV rule dominates the IRR rule. /////////////////////////////// " .C14EXPLAIN33<-"Search for multiple IRRs //////////////////////////////// irr_f3<-function(cashflows,bigV=100000){ smallV<-1e-5 a<--1+smallV rates<-seq(a,1,smallV) sign1<-sign(npv_f(a,cashflows)) # for(r in rates){ npv<-npv_f(r,cashflows) sign2<-sign(npv) if(sign1+sign2==0){ cat(\"irr =\",r,\"\\n\") sign1<-sign2 } } } # We can use the following cashflows to test the R code. cashflows<-c(-17,16,16,16,16,-52)*1000 irr_f3(cashflows) irr = 0.06767 irr = 0.6536 /////////////////////////////// " .C14EXPLAIN34<-"Payback period and its rule //////////////////////////////// The payback period is the number of years it takes to recover the initial investment. The Payback Rule Period is based on the following principle. Payback Period Rule: if T < Tc -> accept T > Tc -> reject T is an estimated payback period, and Tc is an acceptable minimum payback period. /////////////////////////////// " .C14EXPLAIN35<-"R code for IRRs //////////////////////////////// paybackPeriod_f<-function(cashflows){ # assume the first one is an investment (negative) total<-cashflows[1] if(total>0)stop('The first cash flow should be negative') cashInflows<-cashflows[-1] n<-length(cashInflows) for(i in 1:n){ total<-total+cashInflows[i] #print(total) if(total==0){ return(i) }else if(total>0){ partial<-total/cashInflows[i] return(i-1+partial) } } } We can have the following cashflows to test the above code. > cashflows<-c(-100,25,25,25,25,40,50) > paybackPeriod_f(cashflows) [1] 4 > cashflows<-c(-100,25,25,25,50,40,50) > paybackPeriod_f(cashflows) [1] 3.5 /////////////////////////////// " .C14EXPLAIN36<-"2nd example //////////////////////////////// > cashflows<-c(-100,25,25,25,50,40,50) > paybackPeriod_f(cashflows) [1] 3.5 /////////////////////////////// " .C14EXPLAIN37<-"Issues for the IRR Rule //////////////////////////////// The IRR Rule has many shortcomings. First, it ignores the time value of money: $100 today has the same value as $100 in two years. The first problem could be overcome using the Present Value Payback Rule, which applies the present value of all future cash flows instead of their face values, see one of the end-of-chapter problems. Second, it ignores the future cash flows after the payback period. The first case, as an illustration, is shown below. The cash flows in years 5 and 6 are ignored. /////////////////////////////// " .C14EXPLAIN38<-"Monotone function //////////////////////////////// A monotone function which is a function where its value is either entirely non-increasing or non-decreasing for a given input value. Binary search is a classic algorithm used to find a specific element in a sorted array or sequence. The algorithm operates by repeatedly dividing the search interval in half. If the value of the search key is less than the item in the middle of the interval, the algorithm narrows the interval to the lower half. Otherwise, it narrows it to the upper half. This process continues until the search key is found or the interval is empty. Binary search is highly efficient, with a time complexity of O(log n), making it much faster than linear search algorithms, especially for large datasets. It is a fundamental technique used in computer science for problems involving sorted data and is the backbone of more complex search and optimization algorithms. /////////////////////////////// " .C14EXPLAIN39<-"An illustration //////////////////////////////// Let’s use a simple example to explain the above concepts. Assume that we have a set of values of 1,2,3 up to 5000. For a randomly chosen value, we can write a for() loop to search all data sets, i.e., from 1 to 5000. This is called sequential search. If repeating our search many times, on average for each value we will run our loop 2,500 times. Let’s see how to apply a binary search. Assume that we choose a vale of 500. As the first step, we calculate midpoint 2500, i.e., as.integer((1+5000)/2). Since our value is less than the midpoint (500<2500), we drop up part (from 2500 to 5000). With just one comparison, we drop half our data set. /////////////////////////////// " .C14EXPLAIN40<-"R program //////////////////////////////// binary_search <- function(arr, target) { left <- 1 right <- length(arr) i<-1 while (left <= right) { i<-i+1 mid <- floor((left + right) / 2) if (arr[mid] == target) { return(c(mid,i)) # Target found, return index } else if (arr[mid] < target) { left <- mid + 1 # Search the right half } else { right <- mid - 1 # Search the left half } } return(-1) # Target not found } arr <- 1:5000 # Create a sorted array from 1 to 5000 target <- 700 # Define the target value index <- binary_search(arr, target) if (length(index)>1) { cat(\"Value\", target, \"found at index\", index, \"\\n\") } else { cat(\"Value\", target, \"not found in the array\\n\") } /////////////////////////////// "