-
-
Notifications
You must be signed in to change notification settings - Fork 85
/
Copy path_cfinancial.pyx
78 lines (65 loc) · 2.43 KB
/
_cfinancial.pyx
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
from libc.math cimport NAN, INFINITY, log
cimport cython
cdef double nper_inner_loop(
const double rate_,
const double pmt_,
const double pv_,
const double fv_,
const double when_
) nogil:
if rate_ == 0.0 and pmt_ == 0.0:
return INFINITY
if rate_ == 0.0:
with cython.cdivision(True):
# We know that pmt_ != 0, we don't need to check for division by 0
return -(fv_ + pv_) / pmt_
if rate_ <= -1.0:
return NAN
with cython.cdivision(True):
# We know that rate_ != 0, we don't need to check for division by 0
z = pmt_ * (1.0 + rate_ * when_) / rate_
return log((-fv_ + z) / (pv_ + z)) / log(1.0 + rate_)
@cython.boundscheck(False)
@cython.wraparound(False)
def nper(
const double[::1] rates,
const double[::1] pmts,
const double[::1] pvs,
const double[::1] fvs,
const double[::1] whens,
double[:, :, :, :, ::1] out):
cdef:
Py_ssize_t rate_, pmt_, pv_, fv_, when_
for rate_ in range(rates.shape[0]):
for pmt_ in range(pmts.shape[0]):
for pv_ in range(pvs.shape[0]):
for fv_ in range(fvs.shape[0]):
for when_ in range(whens.shape[0]):
# We can have several ``ZeroDivisionErrors``s here
# At the moment we want to replicate the existing function as
# closely as possible however we should return financially
# sensible results here.
try:
res = nper_inner_loop(
rates[rate_], pmts[pmt_], pvs[pv_], fvs[fv_], whens[when_]
)
except ZeroDivisionError:
res = NAN
out[rate_, pmt_, pv_, fv_, when_] = res
@cython.boundscheck(False)
@cython.cdivision(True)
def npv(const double[::1] rates, const double[:, ::1] values, double[:, ::1] out):
cdef:
Py_ssize_t i, j, t
double acc
with nogil:
for i in range(rates.shape[0]):
for j in range(values.shape[0]):
acc = 0.0
for t in range(values.shape[1]):
if rates[i] == -1.0:
acc = NAN
break
else:
acc = acc + values[j, t] / ((1.0 + rates[i]) ** t)
out[i, j] = acc