leandropls

PL/pgSQL Functions for NPV and IRR

Feb 20th, 2023
2,055
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PL/SQL 2.28 KB | Source Code | 0 0
  1. -- The MIT License (MIT)
  2. --
  3. -- Copyright (c) 2023 Leandro Pereira de Lima e Silva
  4. --
  5. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  6. -- of this software and associated documentation files (the "Software"), to deal
  7. -- in the Software without restriction, including without limitation the rights
  8. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. -- copies of the Software, and to permit persons to whom the Software is
  10. -- furnished to do so, subject to the following conditions:
  11. --
  12. -- The above copyright notice and this permission notice shall be included in all
  13. -- copies or substantial portions of the Software.
  14. --
  15. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. -- SOFTWARE.
  22.  
  23. CREATE OR REPLACE FUNCTION npv(
  24.     "values" numeric[],
  25.     rate numeric,
  26.     months numeric DEFAULT 12,
  27.     derivative bool DEFAULT FALSE)
  28. returns numeric
  29. AS $$
  30. DECLARE
  31.     ret double precision;
  32.     k INTEGER;
  33. BEGIN
  34.     ret := 0;
  35.     FOR i IN 1..array_length(VALUES, 1) LOOP
  36.         k := CASE WHEN derivative THEN -i ELSE 1 END;
  37.         ret := ret + k * VALUES[i] / (1 + rate) ^ ((i - 1)  * (months / 12));
  38.     END LOOP;
  39.     RETURN ret;
  40. END;
  41. $$ language plpgsql;
  42.  
  43. CREATE OR REPLACE FUNCTION irr(
  44.     "values" numeric[],
  45.     months numeric DEFAULT 12,
  46.     guess numeric DEFAULT 0.1,
  47.     tol numeric DEFAULT 1e-12,
  48.     maxiter INTEGER DEFAULT 100)
  49. returns numeric
  50. AS $$
  51. DECLARE
  52.     val double precision;
  53.     der double precision;
  54.     new_guess double precision;
  55. BEGIN
  56.     FOR j IN 1..maxiter LOOP
  57.         val = npv(VALUES, guess, months);
  58.         der = npv(VALUES, guess, months, derivative := TRUE);
  59.         new_guess := guess - val / der;
  60.         IF ABS(guess - new_guess) <= tol THEN
  61.             RETURN guess;
  62.         END IF;
  63.         guess := new_guess;
  64.     END LOOP;
  65.     RETURN NULL;
  66. END;
  67. $$ language plpgsql;
Advertisement