-- The MIT License (MIT) -- -- Copyright (c) 2023 Leandro Pereira de Lima e Silva -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in all -- copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -- SOFTWARE. create or replace function npv( "values" numeric[], rate numeric, months numeric default 12, derivative bool default false) returns numeric as $$ declare ret double precision; k integer; begin ret := 0; for i in 1..array_length(values, 1) loop k := case when derivative then -i else 1 end; ret := ret + k * values[i] / (1 + rate) ^ ((i - 1) * (months / 12)); end loop; return ret; end; $$ language plpgsql; create or replace function irr( "values" numeric[], months numeric default 12, guess numeric default 0.1, tol numeric default 1e-12, maxiter integer default 100) returns numeric as $$ declare val double precision; der double precision; new_guess double precision; begin for j in 1..maxiter loop val = npv(values, guess, months); der = npv(values, guess, months, derivative := true); new_guess := guess - val / der; if abs(guess - new_guess) <= tol then return guess; end if; guess := new_guess; end loop; return null; end; $$ language plpgsql;