На просторах Интернета не сложно найти SQL функцию, которая считала бы аннуитетный платёж по данным о величине кредита, процентной ставке и сроку кредита. Но вот готовой функции для другой задачи, а именно поиска процентной ставки по данным об аннуитете, сроке и величине кредита, мне найти не удалось. Решение данной задачи не тривиальное и требует применения численных методов. В Excel есть очень удобная для этого функция СТАВКА(), на аналог которой на языке PHP я наткнулся на StackOverflow. Мне оставалось только переписать код для SQL. Результат можно увидеть ниже.

nper — количество платёжных периодов; pmt — аннуитетный платёж; pv — величина кредита. Для поиска решения используется метод хорд.

CREATE OR REPLACE FUNCTION RATE (nper NUMBER, pmt NUMBER, pv NUMBER) RETURN NUMBER
  AS v_result NUMBER;
  fv NUMBER:= 0.0;
  s_type INT:= 0;
  guess NUMBER := 0.1;
  FINANCIAL_MAX_ITERATIONS INT := 5000; --количество итераций
  FINANCIAL_PRECISION NUMBER:= 1.0e-08; --точность
  y NUMBER;
  y0 NUMBER;
  y1 NUMBER;
  f NUMBER;
  i NUMBER;
  x0 NUMBER;
  x1 NUMBER;
BEGIN
v_result := guess;
 
IF (abs(v_result) < FINANCIAL_PRECISION) THEN
y := pv * (1 + nper * v_result) + pmt * (1 + v_result * s_type) * nper + fv;
ELSE
f := EXP(nper * ln(1 + v_result));
y := pv * f + pmt * (1 / v_result + s_type) * (f - 1) + fv;
END IF;
y0 := pv + pmt * nper + fv;
y1 := pv * f + pmt * (1 / v_result + s_type) * (f - 1) + fv;
 
-- поиск корня методом хорд
i := 0;
x0 := 0;
x1 := v_result;
while ((abs(y0 - y1) > FINANCIAL_PRECISION) AND (i < FINANCIAL_MAX_ITERATIONS)) loop
     v_result := (y1 * x0 - y0 * x1) / (y1 - y0);
     x0 := x1;
     x1 := v_result;
     IF ((nper * abs(pmt)) > (pv - fv)) THEN
         x1 := abs(x1);
     END IF;
     IF (abs(v_result) < FINANCIAL_PRECISION) THEN
         y := pv * (1 + nper * v_result) + pmt * (1 + v_result * s_type) * nper + fv;
     ELSE
         f := EXP(nper * ln(1 + v_result));
         y := pv * f + pmt * (1 / v_result + s_type) * (f - 1) + fv;
     END IF;
     y0 := y1;
     y1 := y;
     i:=i+1;
END loop;
    RETURN v_result;
END;
Теги: