Calculating IRR in Julia - julia

I can calculate NPV using
tvmnpv(i,cfo,cfall)=begin
n=collect(1:length(cfall));
cfo + sum(cfall./(1+i).^n)
end
where cfo is the initial cashflow at t=0, and cfall represents the following cashflows and i is the discount rate being used.
However, I can not find a way to calculate the IRR given the cashflows. I believe excel uses a function that scrolls through possible values until a value where cfo plus the discounted following cashflows equals zero is found. Can anyone point me in the right direction?
An example of desired output is as follows:
cfo=[-100];cfall=[30,30,30,30]
Out: 0.07713847
Therefore, the IRR is 7.713847%.
Thank you for your help.

Calculate the IRR is a Root-finding problem (find i for NPV=0).
One way to do this calculation, is to use the Roots.jl package (Pkg.add("Roots")), as following:
julia> using Roots
julia> tvmnpv(i,cfo,cfall)=begin
n=collect(1:length(cfall));
cfo + sum(cfall./(1+i).^n)
end
tvmnpv (generic function with 1 method)
julia> f(x)=tvmnpv(x, cfo, cfall)
f (generic function with 1 method)
julia> cfo=-100.0
-100.0
julia> cfall=[30, 30, 30, 30];
julia> fzero(f, [0.0, 1.0])
0.07713847295208355
The interval [0.0, 1.0] could be changed for better performance.
If you don't want to install the package, I would recommend you to implement the Bisection method, which is simple and efficient.
tested with Julia Version 0.5.0

The ActuaryUtilities package provides an internal_rate_of_return (also aliased asirr) function.

Related

Generating my own arbitrary polynomials in Julia

I have a problem where I need to generate my own monomial sequence of N terms and evaluate it numerically - a polynomial basis, mind you.
What I need is a function that I can generate. The problem is that (as far as I know) I can't iterate over a function I have already defined in order to keep adding terms of my own devising (the monomials), which is what I want. The only way I know how to add the terms that I want is manually, but that won't do.
Basically, I want something like...
N=4
#Code runs, and then I get something like the following:
f(x) = x^0 + c1*x + c2*x^2 + c3*x^3 + c4*x^4
And I want it to be a function that can be evaluated or differentiated via other packages.
Note: I want to operate on the coefficients in order to see if I can solve a problem where I assume the polynomial is the solution that I then have to optimize.
Yes, I know the package Polynomials.jl can tackle the aforementioned example quite readily and cleanly, but what I want is to be able to define each of the terms that I keep adding to the polynomial sequence myself, make them a trigonimetric function, an exponential, etc. Maybe I want to define the Fourier series, or whatever. I want to build my own polynomial base that I can then evaluate.
Like this:
N=4
#Code runs, and then I get the following:
f(x) = x^0 + c1*cos(x) + c2*sin(x) + c3*exp(3*x) + c4*x^4
I tried with Symbolics.jl, played with Polynomials.jl, tried to get it done with varargs, and nothing worked. I am genuinely stumped. Any help would be greatly appreciated, even if just to tell me "Go learn metaprogramming," or something like that.
Maybe this can help or at least gives you an insight:
julia> function myf(x, coefs)
myExpressions = [x^0, cos(x), sin(x), exp(3*x), x^4]
#assert length(coefs) == length(myExpressions) "The length of coefficients doesn't match the length of the expressions."
return coefs*myExpressions
end
julia> myf(1, [1 2 3 4 5])
1-element Vector{Float64}:
89.94716525891064
julia> myf(1, [1 2 3 4])
ERROR: AssertionError: The length of coefficients doesn't match the length of the expressions.

How to compute a high dimensional multiple integral with infinite bounds using vegas in Julia

I am trying to compute a high dimensional integral using Julia (>1400 dimensions). I am thus trying to do this using the function vegas, as it can presumably compute high dimensional integrals. However, vegas assumes that the domain of integration is [0,1]^n but my integral is over R^n. The documentation of vegas suggests a change of variables, but I cannot get it to work in multiple dimensions.
So, if I type in Julia the following integral in 2 dimensions:
using LinearAlgebra, Cuba
multinormal(x,μ,Σ) = det(2*π*Σ)^(-1/2)*exp(-1/2*(x-μ)'*inv(Σ)*(x-μ))
vegas((x,f)->f=multinormal(x,[0;0],[1 0;0 1]),2)
I get the result
Component:
1: 0.0 ± 7.025180405943273e-18 (prob.: -999.0)
Integrand evaluations: 1000
Number of subregions: 0
Note: The desired accuracy was reached
which assumes that the integral is over [0,1]^2.
Trying to compute the same integral over [0,infinity)^2, I tried the change of variables suggested here as
vegas((x,f)->f=multinormal(x./(1 .- x),[0;0],[1 0;0 1])./(1 .-x).^2,2)
which gives me the result
Component:
1: 0.0 ± 7.025180405943273e-18 (prob.: -999.0)
Integrand evaluations: 1000
Number of subregions: 0
Note: The desired accuracy was reached
But the result should be 0.5 rather than 0.
How could I compute this integral of the multivariate normal distribution with infinite integration limits using vegas?
If you use Quadrature.jl it'll perform the necessary changes of variables for you automatically. Then you just use [-Inf,Inf] bounds. See examples in the tests:
https://github.com/SciML/Quadrature.jl/blob/master/test/inf_integral_tests.jl
I ended up just approximating the integral as suggested here: https://stats.stackexchange.com/questions/228687/approximation-expectation-integral
For example, to compute the expected value E of a multivariate normally distributed variable x in two dimensions, I did:
using Distributions, LinearAlgebra
sampleSize = 1000;
dist = MvNormal([0;0],I);
x = rand(dist,sampleSize);
E = 1/sampleSize*sum([x[:,r] for r in 1:sampleSize])
The convenience of this approach is that it works very efficiently for high dimension (in my case the dimension of x is >1400).

Extracting derivatives (du/dt) from an ODE problem

I have multiple ODE problems that I am solving. where I need the solutions (u) and derivative of the solutions (du). For smaller ODEs it is practical for me to do the following
using DifferentialEquations
function SB(du,u,p,t)
du[1]=#. u[2]
du[2]=#. ((-0.5*u[2]^2)*(3-u[2]/(p[4]))+(1+(1-3*p[7])*u[2]/p[4])*((p[6]-p[5])/p[2]+2*p[1]/(p[2]*p[9]))*(p[9]/u[1])^(3*p[7])-2*p[1]/(p[2]*u[1])-4*p[3]*u[2]/(p[2]*u[1])-(1+u[2]/p[4])*(p[6]-p[5]+p[10]*sin(2*pi*p[8]*t))/p[2]-p[10]*u[1]*cos(2*pi*p[8]*t)*2*pi*p[8]/(p[2]*p[4]))/((1-u[2]/p[4])*u[1]+4*p[3]/(p[2]*p[4]))
end
R0=2e-6
ps=250e3
f=2e6
u0=([R0 0])
tspan=(0,100/f)
p=[0.0725, 998, 1e-3,1481, 0, 1.01e5,7/5,f, R0, ps]
prob = ODEProblem(SB,u0,tspan,p)
#time u = solve(prob,Tsit5(),alg_hints=[:stiff],saveat=0.01/f,reltol=1e-8,abstol=1e-8)
t=u.t
u2=#. ((-0.5*u[2,:]^2)*(3-u[2,:]/(p[4]))+(1+(1-3*p[7])*u[2,:]/p[4])*((p[6]-p[5])/p[2]+2*p[1]/(p[2]*p[9]))*(p[9]/u[1,:])^(3*p[7])-2*p[1]/(p[2]*u[1,:])-4*p[3]*u[2,:]/(p[2]*u[1,:])-(1+u[2,:]/p[4])*(p[6]-p[5]+p[10]*sin(2*pi*p[8]*t))/p[2]-p[10]*u[1,:]*cos(2*pi*p[8]*t)*2*pi*p[8]/(p[2]*p[4]))/((1-u[2,:]/p[4])*u[1,:]+4*p[3]/(p[2]*p[4]))
where u2 is bascially du[2] in the SB function. This quickly becomes impractical as the size of my ODEs grow (>500 coupled ODEs with >500X500 matrices). Is there way to ask DifferentialEquations.jl package (or any other way) to export du[i]s as it is solving the ODEs? I learned that DiffEqSensitivity.jl package is able to provide du/dps to check the sensitivity of the model to p. is there something similar to extract du/dts?
I would use two different components together. First, as you get to really large ODEs, you'll want to only save specific pieces of the solution, or reduced pieces. For this, the SavingCallback is very helpful.
http://diffeq.sciml.ai/latest/features/callback_library#SavingCallback-1
For example, the following solves an ODE and only saves the trace and the norm of the solution at each step:
using DiffEqCallbacks, OrdinaryDiffEq, LinearAlgebra
prob = ODEProblem((du,u,p,t) -> du .= u, rand(4,4), (0.0,1.0))
saved_values = SavedValues(Float64, Tuple{Float64,Float64})
cb = SavingCallback((u,t,integrator)->(tr(u),norm(u)), saved_values)
sol = solve(prob, Tsit5(), callback=cb)
Now you can use that to save what you need. The second piece is to use the integrator to get the derivatives. You can see that get_du! can be used to extract the current (already computed) derivative:
http://diffeq.sciml.ai/latest/basics/integrator#Misc-1
Additionally, you can make use of the interpolation on the integrator. integrator(t,Val{1}) will give the first derivative of the solution at the current t.
#ChrisRackauckas
I do need every time step that I am defining the solver to solve.
get_du!(out,integrator) gives me an array where all the points have the same value.
am I making a
mistake somewhere?
prob = ODEProblem(SB,u0,tspan,p)
Rdot=zeros(50001,2)
u = init(prob,SSPRK22(),dt=1e-9,reltol=1e-8,abstol=1e-8)
solve!(u)
get_du!(Rdot,u)
U=u.sol
basically derivative of the second output (du[2]) has to be equal to u2 defined in my previous post.`

Range for continuos distribution in Julia

I am trying to calculate the density function of a continuos random variable in range in Julia using Distributions, but I am not able to define the range. I used Truncator constructor to construct the distribution, but I have no idea how to define the range. By density function I mean P(a
Would appreciate any help. The distribution I'm using is Gamma btw!
Thanks
To get the maximum and minimum of the support of distribution d just write maximum(d) and minimum(d) respectively. Note that for some distributions this might be infinity, e.g. maximum(Normal()) is Inf.
What version of Julia and Distributions du you use? In Distribution v0.16.4, it can be easily defined with the second and third arguments of Truncated.
julia> a = Gamma()
Gamma{Float64}(α=1.0, θ=1.0)
julia> b = Truncated(a, 2, 3)
Truncated(Gamma{Float64}(α=1.0, θ=1.0), range=(2.0, 3.0))
julia> p = rand(b, 1000);
julia> extrema(p)
(2.0007680527633305, 2.99864177354943)
You can see the document of Truncated by typing ?Truncated in REPL and enter.

How can I resolve an exponential function for x in R?

I want to analyse a logarithmic growth curve in more detail. Especially I would like to kow the time point when the slope becomes >0 (which is the starting point of growth after a lag phase).
Therefore I fitted a logarithmic function to my growth data with the grofit package of R. I got values for the three parameters (lambda, mu, maximal assymptote).
Now I thought, I could use the first derivative of the logarithmic growth function to put mu=0 (the slope of any time point during growth) and this way solve the equation for the time (x). I'm not sure if this is possible, since the mu=0 will be correct for a longer timespan at the beginning of the curve (and no unique timepoint). But maybe I could approximate to that point by putting mu=0.01. This should be more specific.
Anyway I used the Deriv package to find the first derivative of my logarithmic function:
Deriv(a/(1+exp(((4*b)/a)*(c-x)+2)), "x")
where a=assymptote, b=maximal slope, c=lambda.
As a result I got:
{.e2 <- exp(2 + 4 * (b * (c - x)/a))
4 * (.e2 * b/(.e2 + 1)^2)}
Or in normal writing:
f'(x)=(4*exp(2+((4b(c-x))/a))*b)/((exp(2+((4b(c-x))/a))+1)^2)
Now I would like to solve this function for x with f'(x)=0.01. Can anyone tell me, how best to do it?
Also, do you have comments on my way of thinking or the R functions I used?
Thank you.
Anne
Using a root solving function is more appropriate than using an optimization function.
I'll give an example with two packages.
It would also be a good idea to plot the function for a range of values.
Like this:
curve(fn,-.1,.1)
You can see that using the base R function uniroot will present problems since it needs function values at the endpoints of the interval to be of opposite sign.
Using package nleqslv like this
library(nleqslv)
nleqslv(1,fn)
gives
$x
[1] 0.003388598
$fvec
[1] 8.293101e-10
$termcd
[1] 1
$message
[1] "Function criterion near zero"
<more info> ......
Using function fsolve from package pracma
library(pracma)
fsolve(fn,1)
gives
$x
[1] 0.003388585
$fval
[1] 3.136539e-10
The solutions given by both packages are very close to each other.
Might not be the best approach but you can use the optim function to find the solution. Check the code below, I am basically trying to find the value of x which minimizes abs(f(x) - 0.01)
There starting seed value for x may be important, the optim function might not converge for some seeds.
fn <- function(x){
a <- 1
b<- 1
c <- 1
return( abs((4*exp(2+((4*b*(c-x))/a))*b)/ ((exp(2+((4*b*(c-x))/a))+1)^2) - 0.01) )
}
x <- optim(10,fn)
x$par
Thank you very much for your efforts. Unfortunately, none of the above solutions worked for me :-(
I figured the problem out the old fashioned way (pencil + paper + mathematics book).
Have a good day
Anne

Resources