内部收益率 IRR XIRR

存过调用irr

create or replace package PKG_BATCH as
/******************************************************************************
   创建作者:lijunyu
   创建日期:2018-01-10
   功能描述:封包日后的第一个还款日批处理
   实现逻辑:
  ******************************************************************************/
procedure PACKAGEDATE_FIRST_RETENDATE;

/******************************************************************************
   创建作者:lijunyu
   创建日期:2018-01-10
   功能描述:基础资产IRR计算批处理
   实现逻辑:
  ******************************************************************************/
procedure ASSET_IRR_CAL;

end PKG_BATCH;
/
create or replace package body PKG_BATCH as
  /******************************************************************************
   创建作者:lijunyu
   创建日期:2018-01-10
   功能描述:封包日后的第一个还款日批处理
   实现逻辑:
  ******************************************************************************/
  procedure PACKAGEDATE_FIRST_RETENDATE as
  begin  
    merge into assetportfoliostructure b
    using (select b.id, min(d.returndate) PAYDATEAFTERPACKAGE
             from assetschedule d, assetportfoliostructure b
            where b.assetcode = d.assetcode
              and d.returndate >= b.intpacketdate
              and b.isPAYDATEAFTERPACKAGE = 'N'
            group by b.id) e
    on (b.id = e.id)
    when matched then
      update
         set PAYDATEAFTERPACKAGE     = e.PAYDATEAFTERPACKAGE,
             b.isPAYDATEAFTERPACKAGE = 'Y';
    commit;
  end PACKAGEDATE_FIRST_RETENDATE;

  /******************************************************************************
   创建作者:lijunyu
   创建日期:2018-01-10
   功能描述:基础资产IRR计算批处理
   实现逻辑:
  ******************************************************************************/
  procedure ASSET_IRR_CAL as
  begin
    DECLARE
      PAA        t_amount_array; --金额集合
      v_Return   number; --返回IRR
      cnt        number; --计数
      asset_code varchar2(64); --借据编号
      V_index    number;
    BEGIN
      -- Modify the code to initialize the variable  
      declare
        --游标
        cursor c_job is
          select c.payinteresttotal,
                 c.payprincipaltotal,
                 c.basenominal,
                 c.assetcode
            from assetschedule c, assetportfoliostructure a
           where c.assetcode = a.assetcode
             and a.isINSIDEYIELD = 'N'
          -- and a.assetcode like 'XFJR121%'
           order by c.assetcode, c.returndate;
        code c_job%rowtype;
      begin
        cnt        := 2;
        asset_code := '';
        PAA        := t_amount_array();
        V_index    := 0;
        for code in c_job loop
          if asset_code = code.assetcode then
            PAA.EXTEND;
            PAA(cnt) := code.payinteresttotal + code.payprincipaltotal;
            cnt := cnt + 1;
          else
            if PAA.count > 0 then
              --计算IRR
              v_Return := IRR(PAA);
              -- DBMS_OUTPUT.PUT_LINE(asset_code || 'IRR = ' || v_Return );
              --修改IRR值
              if v_Return is not null then
                if v_Return >= 0 then
                  update assetportfoliostructure bb
                     set bb.INSIDEYIELD = v_Return, bb.isINSIDEYIELD = 'Y'
                   where bb.assetcode = asset_code;
                  V_index := V_index + 1;
                  if V_index > 10 then
                    commit;
                  end if;
                end if;
              end if;
            end if;
            -- 把新的借据编号赋给assetcode
            asset_code := code.assetcode;
            --第一个
            PAA := t_amount_array(0 - code.basenominal);
            cnt := 2;
          end if;
        end loop;
      end;
    END;
  end ASSET_IRR_CAL;

end PKG_BATCH;
/

irr.fnc:

create or replace function IRR(p_amount_array in t_amount_array) return number is
PDA P_DATE_ARRAY;
begin
  PDA := P_DATE_ARRAY() ; -- initialize Varray with NULL, count=0
  for i in 1 .. p_amount_array.count
  loop
    PDA.EXTEND; 
    PDA(i) := sysdate + 365*(i-1);
  end loop;
  Return XIRR(P_DATE_ARRAY => PDA,P_AMOUNT_ARRAY => p_amount_array);
end IRR;
/

xirr.fnc:

create or replace function XIRR(p_date_array in p_date_array, p_amount_array in t_amount_array) return number is
begin
   declare
      z number := 0;
      step_limit number := 0;
      temp number;
      rtn_err number := -9999999;
      step number := 0.1;
      d number := 0.5;
      l_MaxDate date;
      l_MinDate date;
      srok number;
    begin
      l_MaxDate := p_date_array(1);
      l_MinDate := p_date_array(1);
      -- 5@2K9 ?@>E>4: ?>8A: <0:A. 40BK 8 =0;8G8O E>BO 1K >4=>3> <88=CA0 8 ?;NA0 2 ?>B>:0E
      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;
      select months_between(l_MaxDate, l_MinDate)
      into srok
      from dual;
      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;
        if (z = 0) then
            d := d - step;
        else
            d := d + step;
        end if;
        step_limit := step_limit + 1;
        if (step_limit = 10000) then
          return rtn_err; -- a kind of error
          exit;
        end if;
        exit when(round(temp * 100000) = 0);
      end loop;
        return d;
    EXCEPTION
        WHEN OTHERS THEN
        return rtn_err;
    end;
end XIRR;
/

猜你喜欢

转载自blog.csdn.net/li371490890/article/details/81503926