Created
August 18, 2020 16:44
-
-
Save tanglebones/0ddd0d24b58ac21781d51a8e6db32e46 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE FUNCTION array_xirr(flows double precision[], force_period double precision) RETURNS double precision | |
LANGUAGE plpgsql | |
AS | |
$$ | |
DECLARE | |
v FLOAT8; | |
rate FLOAT8; | |
firstday FLOAT8; | |
period FLOAT8; | |
exp FLOAT8; | |
periods FLOAT8; | |
npv FLOAT8; | |
dnpv FLOAT8; | |
iter INTEGER; | |
n INTEGER; | |
i INTEGER; | |
BEGIN | |
-- RAISE NOTICE '%', flows; | |
IF flows IS NULL | |
THEN | |
RETURN NULL; | |
END IF; | |
n = array_upper(flows, 1); | |
IF n = 0 | |
THEN | |
RETURN NULL; | |
END IF; | |
-- arrays are 1's based. | |
firstday = flows [1] [1]; | |
period = flows [n] [1] - firstday; | |
IF period > 365.25 | |
THEN | |
period = 365.25; | |
END IF; | |
IF force_period IS NOT NULL AND force_period > 0 | |
THEN | |
period = force_period; | |
END IF; | |
IF period <= 0 | |
THEN | |
RETURN 0; | |
END IF; | |
-- RAISE NOTICE '%', period; | |
rate = 0; | |
FOR iter IN 1 .. 50 | |
LOOP | |
-- compute npv and dnpv | |
npv = 0; | |
dnpv = 0; | |
exp = rate + 1; | |
IF exp <= 0 | |
THEN | |
RETURN -1; | |
END IF; | |
FOR i IN 1 .. n | |
LOOP | |
periods = (flows [i] [1] - firstday) / period; | |
v = flows [i] [2]; | |
npv = npv + v * power(exp, -periods); | |
dnpv = dnpv - periods * v * power(exp, -periods - 1); | |
END LOOP; | |
-- RAISE NOTICE 'r=% i=% npv=% dnpv=%', rate, iter, npv, dnpv; | |
IF npv < 0.0000001 AND npv > -0.0000001 | |
THEN | |
RETURN rate; | |
END IF; | |
IF dnpv < 0.0000001 AND dnpv > -0.0000001 | |
THEN | |
rate = rate + 1; | |
ELSE | |
rate = rate - (npv / dnpv); | |
END IF; | |
END LOOP; | |
RETURN NULL; | |
END; | |
$$; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment