powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / Oracle [игнор отключен] [закрыт для гостей] / XIRR function in PL/SQL ?
9 сообщений из 34, страница 2 из 2
XIRR function in PL/SQL ?
    #38010526
hexceptтакой вот г...кодА насколько модель оказалась быстрее PL/SQL?
...
Рейтинг: 0 / 0
XIRR function in PL/SQL ?
    #38023647
grago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Это решение было описано выше.
Увы, не совпадает с бух.эталоном - Excel-ем..
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
XIRR function in PL/SQL ?
    #38724425
_Nastia_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день

Очень помог данный топик когда делала расчет ПСК, а теперь вот новый закон вышел, формула изменилась с 21.07.2014 . Кто-нибудь реализовывал ее уже?
...
Рейтинг: 0 / 0
XIRR function in PL/SQL ?
    #38724500
j2k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Nastia_, Реализовывали, но пока ЦБ не даст разъяснения как ОНИ ее будут считать, все равно у всех будет по разному :) т.к. там слишком двоякие формулировки используются.
...
Рейтинг: 0 / 0
XIRR function in PL/SQL ?
    #38863305
Фотография May12
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторКто-нибудь реализовывал расчет ПСК на MS SQL или Java уже?
Поделитесь, пожалуйста. Добра вам.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
XIRR function in PL/SQL ?
    #39863332
Херург
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не врублюсь, что не так.
Есть вот такие данные:
-151012768731.12.18-12789681107.01.1949587359.4431.01.19-61323424.8101.02.19-36562446.3925.02.19-35316612.6326.02.19-36540049.5815.04.19-6895856.78723.04.19-51712892.9529.04.1951869877.0509.05.1927445324.9210.05.1945919585.2413.05.1937121868.3315.05.1977442350.6723.05.19-173754425.913.06.19-42441539.4927.06.1944388616.3111.07.19-17468777.7919.07.1984595194.2517.09.19

Функция с аналитикой выпадает с ошибкой: ORA-01428: argument '-8.8033219426' is out of range
Происходит это на строке:
Код: plsql
1.
ss[any]=s[CV()]*power(x[1],dat[CV()]/365)


Т.к. при возведении в степень отрицательного числа степень должна быть целочисленная, а здесь получается отрицательное значение пытаемся возвести в дробную степень.
Как надо поправить этот алгоритм?
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
XIRR function in PL/SQL ?
    #40121950
yon_brover
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спустя продолжительное время, выдался случай проверить функции, предложенные в этом многолетнем треде и вынести свой вердикт, какая функция самая правильная и совпадает с XIRR/ЧИСТВНДОХ в Excel. Оставлю свой результат для потомков.

Функцию, которую предложил Volder второй в посте от 23 авг 07, 15:36, а также затем повторил hexcept 23 окт 12, 19:13, я бы отверг, как не прошедшую тестирование. Как отметил Херург 18 сен 19, 14:27, при некоторых начальных данных этот численный метод расходится и возникает попытка возвести отрицательное число в нецелую степень: ORA-01428: argument '-8.8033219426' is out of range.
Есть у этой функции и другой недостаток, что например, на данных
22.12.2021-10031.12.2021101
вышеозначенная функция выдаёт результат 0.448177, в то время как XIRR/ЧИСТВНДОХ в Excel выдаёт 0.497117 (приведены результаты в долях, а не в процентах)

Куда лучше оказалась функция, которую предложил Serg Kravchenko 2 сен 07, 11:32, однако в ней был недостаток, что не вовремя делался "exit when". В доработанном виде, эта функция выглядит, как приведено ниже. Рекомендую её к использованию.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
create or replace type t_date_array is varray(200000) of date;
create or replace type t_amount_array is varray(200000) of number;

create or replace function xirr(eff_rate_dataset varchar2) return number as
  p_date_array   t_date_array := t_date_array();
  p_amount_array t_amount_array := t_amount_array();
  c_cur          sys_refcursor;
  type t_cur is record(
    dt   date,
    summ number);
  r_cur      t_cur;
  z          number := 0;
  step_limit number := 0;
  temp       number;
  step       number := 0.001;
  d          number := 0.5;
  l_maxdate  date;
  l_mindate  date;
begin
  open c_cur for eff_rate_dataset;
  loop
    fetch c_cur
      into r_cur;
    exit when c_cur%notfound;
    p_date_array.extend;
    p_date_array(p_date_array.last) := r_cur.dt;
    p_amount_array.extend;
    p_amount_array(p_amount_array.last) := r_cur.summ;
  end loop;
  l_maxdate := p_date_array(1);
  l_mindate := p_date_array(1);
  for i in 1 .. p_date_array.count loop
    if p_date_array(i) > l_maxdate then
      l_maxdate := p_date_array(i);
    end if;
    if p_date_array(i) < l_mindate then
      l_mindate := p_date_array(i);
    end if;
  end loop;
  loop
    temp := p_amount_array(1);
    for i in 2 .. p_amount_array.count loop
      temp := temp +
              p_amount_array(i) /
              power(1 + d, (p_date_array(i) - p_date_array(1)) / 365);
    end loop;
    if temp > 0 and z = 0 then
      step := step / 2;
      z    := 1;
    end if;
    if temp < 0 and z = 1 then
      step := step / 2;
      z    := 0;
    end if;
    exit when round(temp * 100000) = 0 or step_limit = 100000;
    if z = 0 then
      d := d - step;
    else
      d := d + step;
    end if;
    step_limit := step_limit + 1;
  end loop;
  return round(d, 6);
end;


Примеры использования:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
select xirr('select to_date(''22.12.2021'',''dd.mm.yyyy'') dt, -100 summ from dual union all
             select to_date(''31.12.2021'',''dd.mm.yyyy'') dt, 101 summ from dual') val from dual;

select xirr('select to_date(''03.11.2020'',''dd.mm.yyyy'') dt, -103860 summ from dual union all
             select to_date(''25.12.2020'',''dd.mm.yyyy'') dt, -85470 summ from dual union all
             select to_date(''13.01.2021'',''dd.mm.yyyy'') dt, -76067 summ from dual union all
             select to_date(''09.02.2021'',''dd.mm.yyyy'') dt, -299049 summ from dual union all
             select to_date(''30.07.2021'',''dd.mm.yyyy'') dt, 21.5 summ from dual union all
             select to_date(''31.07.2021'',''dd.mm.yyyy'') dt, 23.9 summ from dual union all
             select to_date(''16.12.2021'',''dd.mm.yyyy'') dt, 476370 summ from dual') val from dual;

select xirr('select to_date(''31.12.2018'',''dd.mm.yyyy'') dt, -1510127687 summ from dual union all
             select to_date(''07.01.2019'',''dd.mm.yyyy'') dt, -127896811 summ from dual union all
             select to_date(''31.01.2019'',''dd.mm.yyyy'') dt, 49587359.44 summ from dual union all
             select to_date(''01.02.2019'',''dd.mm.yyyy'') dt, -61323424.81 summ from dual union all
             select to_date(''25.02.2019'',''dd.mm.yyyy'') dt, -36562446.39 summ from dual union all
             select to_date(''26.02.2019'',''dd.mm.yyyy'') dt, -35316612.63 summ from dual union all
             select to_date(''15.04.2019'',''dd.mm.yyyy'') dt, -36540049.58 summ from dual union all
             select to_date(''23.04.2019'',''dd.mm.yyyy'') dt, -6895856.787 summ from dual union all
             select to_date(''29.04.2019'',''dd.mm.yyyy'') dt, -51712892.95 summ from dual union all
             select to_date(''09.05.2019'',''dd.mm.yyyy'') dt, 51869877.05 summ from dual union all
             select to_date(''10.05.2019'',''dd.mm.yyyy'') dt, 27445324.92 summ from dual union all
             select to_date(''13.05.2019'',''dd.mm.yyyy'') dt, 45919585.24 summ from dual union all
             select to_date(''15.05.2019'',''dd.mm.yyyy'') dt, 37121868.33 summ from dual union all
             select to_date(''23.05.2019'',''dd.mm.yyyy'') dt, 77442350.67 summ from dual union all
             select to_date(''13.06.2019'',''dd.mm.yyyy'') dt, -173754425.9 summ from dual union all
             select to_date(''27.06.2019'',''dd.mm.yyyy'') dt, -42441539.49 summ from dual union all
             select to_date(''11.07.2019'',''dd.mm.yyyy'') dt, 44388616.31 summ from dual union all
             select to_date(''19.07.2019'',''dd.mm.yyyy'') dt, -17468777.79 summ from dual union all
             select to_date(''17.09.2019'',''dd.mm.yyyy'') dt, 84595194.25 summ from dual') val from dual;
...
Рейтинг: 0 / 0
XIRR function in PL/SQL ?
    #40122026
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Надеюсь, Вы это творчество в продуктив не запустили?
Оформите хотя бы как нормальную агрегатку...
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
create or replace type TXirrAmtDt as object( amount number, dt date)
/

Type created

create type TXirrAmtDtTab as table of TXirrAmtDt
/

Type created

create or replace type TXirrImpl as object
( firstDate date,
  xirrValues TXirrAmtDtTab,
  static function ODCIAggregateInitialize(sctx IN OUT TXirrImpl)return number,
  member function ODCIAggregateIterate(self IN OUT TXirrImpl, value IN TXirrAmtDt) return number,
  member function ODCIAggregateTerminate(self IN TXirrImpl, returnValue OUT number, flags IN number) return number,
  member function ODCIAggregateMerge(self IN OUT TXirrImpl, ctx2 IN TXirrImpl) return number
)
/

Type created

create or replace type body TXirrImpl is
static function ODCIAggregateInitialize(sctx IN OUT TXirrImpl)
return number is
begin
  sctx := TXirrImpl(date'3000-01-01',TXirrAmtDtTab());
  return ODCIConst.Success;
end;
member function ODCIAggregateIterate(self IN OUT TXirrImpl, value IN TXirrAmtDt) return number is
begin
	self.xirrValues.extend;
	self.xirrValues(self.xirrValues.count) := value;
	firstDate := least(value.dt, firstDate);
  return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(self IN TXirrImpl, returnValue OUT number, flags IN number) return number is
  z          number := 0;
  step_limit number := 0;
  temp       number;
  step       number := 0.001;
  d          number := 0.5;
begin
  loop
    temp := self.xirrValues(1).amount;
    for i in 2 .. self.xirrValues.count loop
      temp := temp +
              self.xirrValues(i).amount /
              power(1 + d, (self.xirrValues(i).dt - firstDate) / 365);
    end loop;
    if temp > 0 and z = 0 then
      step := step / 2;
      z    := 1;
    end if;
    if temp < 0 and z = 1 then
      step := step / 2;
      z    := 0;
    end if;
    exit when round(temp * 100000) = 0 or step_limit = 100000;
    if z = 0 then
      d := d - step;
    else
      d := d + step;
    end if;
    step_limit := step_limit + 1;
  end loop;
  returnValue := round(d, 6);
  return ODCIConst.Success;
end;
member function ODCIAggregateMerge(self IN OUT TXirrImpl, ctx2 IN TXirrImpl) return number is
begin
	self.xirrValues.extend(ctx2.xirrValues.count);
  for i in 1..ctx2.xirrValues.count loop
		self.xirrValues(self.xirrValues.count) := ctx2.xirrValues(i);
  end loop;
  return ODCIConst.Success;
end;
end;
/

Type body created

CREATE OR replace FUNCTION xirr (input TXirrAmtDt) RETURN NUMBER AGGREGATE USING TXirrImpl;
/

Function created

with t as (  select 'Ex1' exNo, to_date('22.12.2021','dd.mm.yyyy') dt, -100 summ from dual union all
             select 'Ex1', to_date('31.12.2021','dd.mm.yyyy') dt, 101 summ from dual union all
             select 'Ex2', to_date('03.11.2020','dd.mm.yyyy') dt, -103860 summ from dual 
             union all
             select 'Ex2', to_date('25.12.2020','dd.mm.yyyy') dt, -85470 summ from dual union all
             select 'Ex2', to_date('13.01.2021','dd.mm.yyyy') dt, -76067 summ from dual union all
             select 'Ex2', to_date('09.02.2021','dd.mm.yyyy') dt, -299049 summ from dual union all
             select 'Ex2', to_date('30.07.2021','dd.mm.yyyy') dt, 21.5 summ from dual union all
             select 'Ex2', to_date('31.07.2021','dd.mm.yyyy') dt, 23.9 summ from dual union all
             select 'Ex2', to_date('16.12.2021','dd.mm.yyyy') dt, 476370 summ from dual
             union all
             select 'Ex3', to_date('31.12.2018','dd.mm.yyyy') dt, -1510127687 summ from dual union all
             select 'Ex3', to_date('07.01.2019','dd.mm.yyyy') dt, -127896811 summ from dual union all
             select 'Ex3', to_date('31.01.2019','dd.mm.yyyy') dt, 49587359.44 summ from dual union all
             select 'Ex3', to_date('01.02.2019','dd.mm.yyyy') dt, -61323424.81 summ from dual union all
             select 'Ex3', to_date('25.02.2019','dd.mm.yyyy') dt, -36562446.39 summ from dual union all
             select 'Ex3', to_date('26.02.2019','dd.mm.yyyy') dt, -35316612.63 summ from dual union all
             select 'Ex3', to_date('15.04.2019','dd.mm.yyyy') dt, -36540049.58 summ from dual union all
             select 'Ex3', to_date('23.04.2019','dd.mm.yyyy') dt, -6895856.787 summ from dual union all
             select 'Ex3', to_date('29.04.2019','dd.mm.yyyy') dt, -51712892.95 summ from dual union all
             select 'Ex3', to_date('09.05.2019','dd.mm.yyyy') dt, 51869877.05 summ from dual union all
             select 'Ex3', to_date('10.05.2019','dd.mm.yyyy') dt, 27445324.92 summ from dual union all
             select 'Ex3', to_date('13.05.2019','dd.mm.yyyy') dt, 45919585.24 summ from dual union all
             select 'Ex3', to_date('15.05.2019','dd.mm.yyyy') dt, 37121868.33 summ from dual union all
             select 'Ex3', to_date('23.05.2019','dd.mm.yyyy') dt, 77442350.67 summ from dual union all
             select 'Ex3', to_date('13.06.2019','dd.mm.yyyy') dt, -173754425.9 summ from dual union all
             select 'Ex3', to_date('27.06.2019','dd.mm.yyyy') dt, -42441539.49 summ from dual union all
             select 'Ex3', to_date('11.07.2019','dd.mm.yyyy') dt, 44388616.31 summ from dual union all
             select 'Ex3', to_date('19.07.2019','dd.mm.yyyy') dt, -17468777.79 summ from dual union all
             select 'Ex3', to_date('17.09.2019','dd.mm.yyyy') dt, 84595194.25 summ from dual             )
select exNo, xirr(TXirrAmtDt(summ,dt)) xirr_value
  from t
 group by exNo
;

EXNO XIRR_VALUE
---- ----------
Ex1    0.497117
Ex2   -0.167186
Ex3   -0.990952

SQL> 

...
Рейтинг: 0 / 0
XIRR function in PL/SQL ?
    #40122099
yon_brover
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous, этот код я в продуктив не запускал, а только проверил на своей локальной машине для личных вычислений.
Спасибо за вашу переработку функции в агрегатную. Пригодится потомкам.
...
Рейтинг: 0 / 0
9 сообщений из 34, страница 2 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / XIRR function in PL/SQL ?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]