-
Notifications
You must be signed in to change notification settings - Fork 0
/
gofin.go
377 lines (313 loc) · 12.7 KB
/
gofin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
package gofin
import (
"math"
)
// FutureValueAnnuity returns the future value of an annuity.
// The future value of an annuity is the sum of the cash flows multiplied by 1 plus the interest rate to the power of the period number minus 1 divided by the interest rate.
// The interest rate must be greater than zero to avoid division by zero.
// FV= C * ((1 + r)^n - 1) / r
// FV is the future value,
// C is the cash flow at the end of each period,
// r is the interest rate,
// n is the number of periods.
func FutureValueAnnuity(payment, interestRate float64, periods int) float64 {
if interestRate == 0 {
// Avoid division by zero
return 0.0
}
return payment * ((math.Pow(1+interestRate, float64(periods)) - 1) / interestRate)
}
// FutureValue returns the future value of an investment based on periodic, constant payments and a constant interest rate.
// FV= C * ((1 + r)^n - 1) / r
// FV is the future value,
// C is the cash flow at the end of each period,
// r is the interest rate,
// n is the number of periods.
func FutureValue(presentValue, interestRate float64, periods int) float64 {
return presentValue * math.Pow(1+interestRate, float64(periods))
}
// NetPresentValue function calculates the net present value of a series of cash flows given an
// interest rate and number of periods.
// NPV = sum(C / (1 + r)^t)
// NPV is the net present value,
// C is the cash flow at the end of each period,
// r is the interest rate,
// t is the number of periods.
func NetPresentValue(interestRate float64, periods int, cashFlows []float64) float64 {
npv := 0.0
for i := 0; i < len(cashFlows); i++ {
npv += cashFlows[i] / math.Pow(1+interestRate, float64(i))
}
return npv
}
// PresentValue function calculates the present value of a future amount given an interest rate and
// number of periods.
// PV = FV / (1 + r)^t
// PV is the present value,
// FV is the future value,
// r is the interest rate,
// t is the number of periods.
func PresentValue(futureValue, interestRate float64, periods int) float64 {
return futureValue / math.Pow(1+interestRate, float64(periods))
}
// The function calculates the present value of an annuity given an interest rate, number of periods,
// and cash flows.
// PV = sum(C / (1 + r)^t)
// PV is the present value,
// C is the cash flow at the end of each period,
// r is the interest rate,
// t is the number of periods.
func PresentValueAnnuity(interestRate float64, periods int, cashFlows []float64) float64 {
presentValueAnnuity := 0.0
for i := 0; i < len(cashFlows); i++ {
presentValueAnnuity += cashFlows[i] / math.Pow(1+interestRate, float64(i))
}
return presentValueAnnuity
}
// HoldingPeriodReturn calculates the holding period return (HPR)
func HoldingPeriodReturn(initialValue, finalValue float64) float64 {
return (finalValue - initialValue) / initialValue
}
// GeometricMeanReturn calculates the geometric mean return over multiple holding periods
func GeometricMeanReturn(holdingPeriodReturns []float64) float64 {
totalLogReturns := 0.0
numReturns := len(holdingPeriodReturns)
if numReturns == 0 {
return 0.0 // Avoid division by zero
}
for _, hpr := range holdingPeriodReturns {
totalLogReturns += math.Log(1 + hpr)
}
geometricMean := math.Exp(totalLogReturns/float64(numReturns)) - 1
return geometricMean
}
// GeometricMeanReturnAnnualized calculates the geometric mean annualized return over multiple holding periods
func GeometricMeanReturnAnnualized(initialValues, finalValues []float64, holdingPeriods []float64) float64 {
totalLogReturns := 0.0
numReturns := len(initialValues)
if numReturns == 0 {
return 0.0 // Avoid division by zero
}
for i := 0; i < numReturns; i++ {
annualizedReturn := HoldingPeriodReturnAnnualized(initialValues[i], finalValues[i], holdingPeriods[i])
totalLogReturns += math.Log(1 + annualizedReturn)
}
geometricMean := math.Exp(totalLogReturns/float64(numReturns)) - 1
return geometricMean
}
// HoldingPeriodReturn calculates the holding period return (HPR)
// as a percentage
func HoldingPeriodReturnPercentage(initialValue, finalValue float64) float64 {
return ((finalValue - initialValue) / initialValue)*100
}
// DiscountedPaybackPeriod calculates the discounted payback period
func DiscountedPaybackPeriod(initialInvestment float64, cashInflows []float64, discountRate float64) int {
netPresentValue := -initialInvestment
for i, cashInflow := range cashInflows {
discountedCashFlow := cashInflow / math.Pow(1+discountRate, float64(i+1))
netPresentValue += discountedCashFlow
if netPresentValue >= 0 {
return i + 1
}
}
return -1 // Indicates that the payback period was not reached within the given cash inflows
}
// InternalRateOfReturn calculates the Internal Rate of Return (IRR) using an iterative method
func InternalRateOfReturn(initialInvestment float64, cashFlows []float64) float64 {
const maxIterations = 1000
const tolerance = 1e-6
irr := 0.1 // Initial guess for the IRR
for i := 0; i < maxIterations; i++ {
previousIRR := irr
// Calculate the NPV using the current guess for IRR
npv := -initialInvestment
for j, cashFlow := range cashFlows {
npv += cashFlow / math.Pow(1+irr, float64(j+1))
}
// Calculate the derivative of NPV with respect to IRR
derivative := 0.0
for j, cashFlow := range cashFlows {
derivative -= float64(j+1) * cashFlow / math.Pow(1+irr, float64(j+2))
}
// Update the guess for IRR using the Newton-Raphson method
irr -= npv / derivative
// Check for convergence
if math.Abs(irr-previousIRR) < tolerance {
return irr
}
}
return 0.0
}
// PaybackPeriod calculates the payback period
func PaybackPeriod(initialInvestment float64, cashInflows []float64) int {
cumulativeCashFlow := -initialInvestment
for i, cashInflow := range cashInflows {
cumulativeCashFlow += cashInflow
if cumulativeCashFlow >= 0 {
return i + 1
}
}
return -1 // Indicates that the payback period was not reached within the given cash inflows
}
// AverageReturn calculates the average return over multiple holding periods
func AverageReturn(holdingPeriodReturns []float64) float64 {
totalReturns := 0.0
numReturns := len(holdingPeriodReturns)
if numReturns == 0 {
return 0.0 // Avoid division by zero
}
for _, hpr := range holdingPeriodReturns {
totalReturns += hpr
}
return totalReturns / float64(numReturns)
}
// AverageReturnAnnualized calculates the average annualized return over multiple holding periods
func AverageReturnAnnualized(initialValues, finalValues []float64, holdingPeriods []float64) float64 {
totalAnnualizedReturns := 0.0
numReturns := len(initialValues)
if numReturns == 0 {
return 0.0 // Avoid division by zero
}
for i := 0; i < numReturns; i++ {
annualizedReturn := HoldingPeriodReturnAnnualized(initialValues[i], finalValues[i], holdingPeriods[i])
totalAnnualizedReturns += annualizedReturn
}
return totalAnnualizedReturns / float64(numReturns)
}
// HoldingPeriodReturnAnnualized calculates the annualized holding period return (HPR)
func HoldingPeriodReturnAnnualized(initialValue, finalValue float64, holdingPeriodInYears float64) float64 {
hpr := HoldingPeriodReturn(initialValue, finalValue)
return math.Pow(1+hpr, 1/holdingPeriodInYears) - 1
}
// HoldingPeriodReturnAnnualized calculates the annualized holding period return (HPR)
// as a percentage
func HoldingPeriodReturnAnnualizedPercentage(initialValue, finalValue float64, holdingPeriodInYears float64) float64 {
hpr := HoldingPeriodReturn(initialValue, finalValue)
return (math.Pow(1+hpr, 1/holdingPeriodInYears) - 1)*100
}
func PresentValueAnnuityDue(interestRate float64, periods int, cashFlows []float64) float64 {
presentValueAnnuityDue := 0.0
for i := 0; i < len(cashFlows); i++ {
presentValueAnnuityDue += cashFlows[i] / math.Pow(1+interestRate, float64(i))
}
return presentValueAnnuityDue
}
// PresentValuePerpetuity returns the present value of a perpetuity.
// The present value of a perpetuity is the cash flow divided by the discount rate.
// The interest rate must be greater than zero to avoid division by zero.
// PV= (C / r)
// PV is the present value,
// C is the cash flow at the end of the first period,
// r is the discount rate.
func PresentValuePerpetuity(interestRate, cashFlow float64) float64 {
if interestRate == 0 {
// Avoid division by zero.
return 0.0
}
return cashFlow / interestRate
}
// ModifiedInternalRateOfReturn calculates the Modified Internal Rate of Return (MIRR)
func ModifiedInternalRateOfReturn(initialInvestment float64, cashOutflows []float64, cashInflows []float64, financeRate float64) float64 {
npvOutflows := -initialInvestment
for i, cashOutflow := range cashOutflows {
npvOutflows += cashOutflow / math.Pow(1+financeRate, float64(i+1))
}
npvInflows := 0.0
for i, cashInflow := range cashInflows {
npvInflows += cashInflow / math.Pow(1+financeRate, float64(i+1))
}
mirr := math.Pow((npvInflows / -npvOutflows), 1/float64(len(cashOutflows))) - 1
return mirr
}
// PresentValuePerpetuityDue returns the present value of a perpetuity due.
// The present value of a perpetuity due is the cash flow divided by the discount rate multiplied by 1 plus the discount rate.
// The interest rate must be greater than zero to avoid division by zero.
// PV= (C / r) * (1 / (1+r))
// PV is the present value,
// C is the cash flow at the end of the first period,
// r is the discount rate.
func PresentValuePerpetuityDue(interestRate, cashFlow float64) float64 {
if interestRate == 0 {
// Avoid division by zero.
return 0.0
}
return cashFlow / interestRate * (1 / (1 + interestRate))
}
func InterestRateGrowingPerpetuity(presentValue, cashFlow, growthRate float64) float64 {
return cashFlow/presentValue + growthRate
}
func InterestRateGrowingAnnuity(presentValue, cashFlows, growthRate float64) float64 {
return cashFlows/presentValue + growthRate
}
// TODO: fix this
func InterestRateGrowingAnnuityDue(presentValue, cashFlows, growthRate float64) float64 {
return cashFlows/presentValue + growthRate
}
func InterestRateAnnuity(presentValue, cashFlows float64) float64 {
return cashFlows / presentValue
}
func InterestRateAnnuityDue(presentValue, cashFlows float64) float64 {
return cashFlows / presentValue
}
// TODO: fix this
func InterestRatePerpetuityDue(presentValue, cashFlow float64) float64 {
return cashFlow / presentValue
}
// TODO: fix this
func InterestRateGrowingPerpetuityDue(presentValue, cashFlow, growthRate float64) float64 {
return cashFlow/presentValue + growthRate
}
func InterestRate(presentValue, futureValue float64, periods int) float64 {
return math.Pow(futureValue/presentValue, 1/float64(periods)) - 1
}
func InterestRateContinuousCompounding(presentValue, futureValue float64, periods int) float64 {
return math.Log(futureValue/presentValue) / float64(periods)
}
func InterestRatePerpetuity(presentValue, cashFlow float64) float64 {
return cashFlow / presentValue
}
func PresentValueGrowingAnnuity(interestRate, growthRate float64, periods int, cashFlows []float64) float64 {
pv := 0.0
for i := 0; i < len(cashFlows); i++ {
pv += cashFlows[i] / math.Pow(1+interestRate, float64(i+1))
}
return pv
}
// TODO: fix this
func PresentValueGrowingAnnuityDue(interestRate, growthRate float64, periods int, cashFlows []float64) float64 {
pv := 0.0
for i := 0; i < len(cashFlows); i++ {
pv += cashFlows[i] / math.Pow(1+interestRate, float64(i))
}
return pv
}
// PresentValueGrowingPerpetuity returns the present value of a growing perpetuity.
// The present value of a growing perpetuity is the cash flow divided by the difference between the discount rate and the growth rate.
// The interest rate must be greater than the growth rate to avoid division by zero.
// PV= (C / r−g)
// PV is the present value,
// C is the cash flow at the end of the first period,
// r is the discount rate,
// g is the growth rate.
func PresentValueGrowingPerpetuity(interestRate, growthRate, cashFlow float64) float64 {
if interestRate <= growthRate {
// Ensure the interest rate is greater than the growth rate to avoid division by zero.
return 0.0
}
return cashFlow / (interestRate - growthRate)
}
// PresentValueGrowingPerpetuityDue returns the present value of a growing perpetuity due.
// The present value of a growing perpetuity due is the cash flow divided by the difference between the discount rate and the growth rate multiplied by 1 plus the discount rate.
// The interest rate must be greater than the growth rate to avoid division by zero.
// PV= (C / r−g) * (1 / (1+r))
// PV is the present value,
// C is the cash flow at the end of the first period,
// r is the discount rate,
// g is the growth rate.
func PresentValueGrowingPerpetuityDue(interestRate, growthRate, cashFlow float64) float64 {
if interestRate <= growthRate {
// Ensure the interest rate is greater than the growth rate to avoid division by zero.
return 0.0
}
return (cashFlow / (interestRate - growthRate)) * (1 / (1 + interestRate))
}