:orphan: ================================================== モデル2 ================================================== | キャッシュフロー計算を行いプロフィットマージンを計算するまでのモデルです。 | :doc:`1200_tutorial2` で説明しています。 .. raw:: html .. raw:: html
    // ベース計算クラス
    calculation Base {

    // ユーティリティ変数・関数
    module Util{

        int max_x = 130
        int max_t = 100

    }

    // P基礎基数
    module CT_P{

        @range = x
        @range_last = Util.max_x

        string sex = Inf.get_string("sex")

        double CIR = Asm.get_double("CIR_P")
        double[] qx =
            if (sex == "M"){ Asm.get_double("qx_m_SLT1996", x) }
            else           { Asm.get_double("qx_f_SLT1996", x) }

        double[] lx = if (x == 0) { 1.0 }
                      else        { Utl.max(lx(x-1) - d_x(x-1), 0.0) }
        double[] d_x = lx(x) * qx(x)

        double v = 1.0 / (1.0 + CIR)
        double[] vx = if(x == 0) { 1.0 }
                      else       { vx(x-1) * v }

        double[] Dx = lx(x) * vx(x)
        double[] Cx = d_x(x) * vx(x) * v ^ 0.5
        double[] Nx =
            if (x >= Util.max_x) { Dx(x) }
            else                 { Dx(x) + Nx(x+1) }

        double[] Mx =
            if (x >= Util.max_x) { Cx(x) }
            else                 { Cx(x) + Mx(x + 1) }

        // 終身年金現価
        function double annuity_x(int x) =
            if (Dx(x) <= 0) { 0.0 }
            else            { Nx(x) / Dx(x) }

        // 終身年金現価(月単位支払)
        function double annuity_x_12(int x) =
            if (Dx(x) <= 0) { 0.0 }
            else { annuity_x(x) - (12.0 - 1.0)/(2.0 * 12.0) }

        // n年支払年金現価
        function double annuity_xn(int x, int n) =
            if (Dx(x) <= 0 || n < 0) { 0.0 }
            else { (Nx(x) - Nx(x + n)) / Dx(x) }

        // n年支払年金現価(月単位支払)
        function double annuity_xn_12(int x, int n) =
            if (Dx(x) <= 0 || n < 0) { 0.0 }
            else { annuity_xn(x, n) - (12.0 - 1.0)/(2.0 * 12.0) * (1.0 - Dx(x+n) / Dx(x)) }

    }

    // V基礎基数
    module CT_V{

        @range = x
        @range_last = Util.max_x

        string sex = Inf.get_string("sex")

        double CIR = Asm.get_double("CIR_V")
        double[] qx =
            if (sex == "M"){ Asm.get_double("qx_m_SLT1996", x) }
            else           { Asm.get_double("qx_f_SLT1996", x) }

        double[] lx = if (x == 0) { 1.0 }
                      else        { Utl.max(lx(x-1) - d_x(x-1), 0.0) }
        double[] d_x = lx(x) * qx(x)

        double v = 1.0 / (1.0 + CIR)
        double[] vx = if(x == 0) { 1.0 }
                      else       { vx(x-1) * v }

        double[] Dx = lx(x) * vx(x)
        double[] Cx = d_x(x) * vx(x) * v ^ 0.5
        double[] Nx =
            if (x >= Util.max_x) { Dx(x) }
            else                 { Dx(x) + Nx(x+1) }

        double[] Mx =
            if (x >= Util.max_x) { Cx(x) }
            else                 { Cx(x) + Mx(x + 1) }

        // 終身年金現価
        function double annuity_x(int x) =
            if (Dx(x) <= 0) { 0.0 }
            else            { Nx(x) / Dx(x) }

        // 終身年金現価(月単位支払)
        function double annuity_x_12(int x) =
            if (Dx(x) <= 0) { 0.0 }
            else { annuity_x(x) - (12.0 - 1.0)/(2.0 * 12.0) }

        // n年支払年金現価
        function double annuity_xn(int x, int n) =
            if (Dx(x) <= 0 || n < 0) { 0.0 }
            else { (Nx(x) - Nx(x + n)) / Dx(x) }

        // n年支払年金現価(月単位支払)
        function double annuity_xn_12(int x, int n) =
            if (Dx(x) <= 0 || n < 0) { 0.0 }
            else { annuity_xn(x, n) - (12.0 - 1.0)/(2.0 * 12.0) * (1.0 - Dx(x+n) / Dx(x)) }

    }

    // レート計算
    module Rate{

        @range = t
        @range_last = Util.max_t

        // 契約情報
        int x = Inf.get_int("x")
        int n = Inf.get_int("n")
        int m = Inf.get_int("m")
        string sex = Inf.get_string("sex")

        // 予定事業費
        double gamma = 0.0
        double alpha = 0.015
        double beta =  0.03
        double zill_alpha = alpha

        // 年払保険料(簡単のため単に12倍としている)
        double grossP = baseP * 12.0

        // 月払保険料
        double baseP =
              ( benefit_P(0) + alpha + CT_P.annuity_xn(x, n) * gamma )
                / ( (1.0 - beta) * CT_P.annuity_xn_12(x, m) * 12.0 )

        // 純保険料
        double netP_P = (benefit_P(0) + CT_P.annuity_xn(x, n) * gamma) / CT_P.annuity_xn(x, m)
        double netP_V = (benefit_V(0) + CT_V.annuity_xn(x, n) * gamma) / CT_V.annuity_xn(x, m)

        // 経過t年での給付現価
        double[] benefit_P = if (t > n)                     { 0.0 }
                             elseif (CT_P.Dx(x + t) <= 0.0) { 0.0 }
                             else   { (CT_P.Mx(x + t) - CT_P.Mx(x + n) + CT_P.Dx(x + n)) / CT_P.Dx(x + t) }
        double[] benefit_V = if (t > n)                     { 0.0 }
                             elseif (CT_V.Dx(x + t) <= 0.0) { 0.0 }
                             else   { (CT_V.Mx(x + t) - CT_V.Mx(x + n) + CT_V.Dx(x + n)) / CT_V.Dx(x + t) }

        // NetV, 解約返戻金、全チルV
        double[] netV_P =
            if (t == 0 || t > n)           { 0.0 }
            elseif (CT_P.Dx(x + t) <= 0.0) { 0.0 }
            else {   benefit_P(t)
                   + CT_P.annuity_xn(x + t, n - t) * gamma
                   - CT_P.annuity_xn(x + t, m - t) * netP_P
                 }

        double[] netV_V =
            if (t == 0 || t > n)           { 0.0 }
            elseif (CT_V.Dx(x + t) <= 0.0) { 0.0 }
            else {   benefit_V(t)
                   + CT_V.annuity_xn(x + t, n - t) * gamma
                   - CT_V.annuity_xn(x + t, m - t) * netP_V
                 }

        double[] CV =
            if (t < 10) { Utl.max( netV_P(t) - zill_alpha * (10.0 - t) / 10.0, 0.0) }
            else        { netV_P(t) }

        double[] azilV_V =
            if (t < m)
                 { netV_V(t) - zill_alpha * CT_V.annuity_xn(x + t, m - t) / CT_V.annuity_xn(x, m) }
            else { netV_V(t) }

    }

    // キャッシュフロー
    module CashFlow{

        @range = t
        @range_last = Util.max_t

        // 契約情報
        string plan = Inf.get_string("plan")
        int x = Inf.get_int("x")
        int n = Inf.get_int("n")
        int m = Inf.get_int("m")
        string sex = Inf.get_string("sex")
        double S = Inf.get_double("S")

        // 前提(死亡率・解約率・選択効果)
        double[] qx_crude =
            if (t == 0)         { 0.0 }
            elseif (sex == "M") { Asm.get_double("qx_m_SLT1996", x + t - 1) }
            else                { Asm.get_double("qx_f_SLT1996", x + t - 1) }
        double[] qwx_crude = Asm.get_double("qwx_crude", t)
        double[] selection_factor = Asm.get_double("selection_factor_death", t)
        double[] comm_ratio = 0.0

        // 給付の定義
        double[] death_benefit_perS =
                if (t == 0 || t > n) { 0.0 }
                else                 { 1.0 }
        double[] surrender_benefit_perS =
                if (t == 0 || t > n) { 0.0 }
                else                 { Rate.CV(t) }
        double[] endow_benefit_perS =
                if (t == n) { 1.0 }
                else        { 0.0 }

        // ユニットコスト
        double expense_acq_perS = Asm.get_double("expense_acq_perS")
        double expense_maint_paying_perS = Asm.get_double("expense_maint_paying_perS")
        double expense_maint_paid_perS = Asm.get_double("expense_maint_paid_perS")

        // 金利
        double[] investment_yield = Asm.get_double("investment_yield", t)
        double[] discount_yield = investment_yield(t)

        // 生命表
        double[] qx =  if (t == 0 || t > n)         { 0.0 }
                       elseif (qx_crude(t) >= 1.0 ) { 1.0 }
                       else                         { Utl.clip(qx_crude(t) * selection_factor(t), 0.0, 1.0) }
        double[] qwx = if (t == 0 || t > n) { 0.0 }
                            else { Utl.clip(qwx_crude(t), 0.0, 1.0) }

        double[] lx_beg = if (t == 0) { 0.0 }
                         else { lx_end_after_mat(t - 1) }
        double[] lx_mid = if (t == 0) { 0.0 }
                         else { (lx_beg(t) + lx_end(t)) / 2.0 }
        double[] lx_pay = if (t <= m) { lx_beg(t) }
                         else { 0.0 }
        double[] lx_end = if (t == 0) { 1.0 }
                         else { Utl.max(lx_beg(t) - d_x(t) - dwx(t), 0.0) }
        double[] lx_end_after_mat = if (t >= n) { 0.0 }
                                   else { lx_end(t) }
        double[] d_x = if (t == 0) { 0.0 }
                       else { lx_beg(t) * qx(t) * (1.0 - qwx(t) / 2.0) }
        double[] dwx = if (t == 0) { 0.0 }
                       else { lx_beg(t) * qwx(t) * (1.0 - qx(t) / 2.0) }

        // キャッシュフロー項目
        double[] premium_income = lx_pay(t) * Rate.grossP * S
        double[] commission = premium_income(t) * comm_ratio(t)
        double[] death_benefit = d_x(t) * S * death_benefit_perS(t)
        double[] surrender_benefit = dwx(t) * S * surrender_benefit_perS(t)
        double[] endow_benefit = lx_end(t) * S * endow_benefit_perS(t)

        double[] medical_benefit = 0.0
        double[] annuity_benefit = 0.0
        double[] unpaid_cashout = 0.0

        double[] init_expense = if (t == 1) { lx_beg(t) * S * expense_acq_perS }
                                else        { 0.0 }
        double[] maint_expense = if (t == 0 || t > n) { 0.0 }
                                 elseif (t <= m)      { lx_mid(t) * S * expense_maint_paying_perS }
                                 else                 { lx_mid(t) * S * expense_maint_paid_perS }
        double[] investment_income = investment_asset(t) * investment_yield(t)
        double[] reserve_increase = if (t == 0) { 0.0 }
                                    else        { reserve(t) - reserve(t-1) }

        double[] profit_before_tax = CF_beg(t) + CF_mid(t) + CF_end(t) + investment_income(t) - reserve_increase(t)

        double[] CF_beg = premium_income(t) - (commission(t) + init_expense(t))
        double[] CF_mid = - (death_benefit(t) + surrender_benefit(t) + medical_benefit(t) + annuity_benefit(t)
                             + unpaid_cashout(t) + maint_expense(t) )
        double[] CF_end = - (endow_benefit(t))

        // ストック項目
        double[] premium_reserve = lx_end_after_mat(t) * Rate.netV_V(t) * S
        double[] unpaid_prem_reserve = 0.0
        double[] reserve = premium_reserve(t) + unpaid_prem_reserve(t)

        double[] CV_end = lx_end_after_mat(t) * Rate.CV(t)  * S
        double[] azilV_end = lx_end_after_mat(t) * Rate.azilV_V(t) * S

        double[] investment_asset =
                if (t == 0) { 0.0 }
                else { reserve(t - 1) + CF_beg(t) + CF_mid(t) * 0.5 }

        // ディスカウントファクター・現価
        double[] discount_factor_beg = if (t == 0) { 1.0 }
                                       else { discount_factor_end(t-1) }
        double[] discount_factor_mid = if (t == 0) { 1.0 }
                                       else { discount_factor_end(t-1) / ((1 + discount_yield(t)) ^ 0.5) }
        double[] discount_factor_end = if (t == 0) { 1.0 }
                                       else { discount_factor_end(t-1) / (1 + discount_yield(t)) }

        double[] PV_profit_before_tax = Utl.pv(profit_before_tax, discount_factor_end, discount_factor_end)
        double[] PV_premium_income    = Utl.pv(premium_income, discount_factor_end, discount_factor_beg)
        double profit_margin_before_tax = PV_profit_before_tax(0)  / PV_premium_income(0)

    }

    // 現価およびプロフィットマージンの出力
    module OutputProfitability{

        double profit_margin_before_tax  = CashFlow.profit_margin_before_tax
        double PV_profit_before_tax = CashFlow.PV_profit_before_tax(0)
        double PV_premium_income    = CashFlow.PV_premium_income(0)

    }

    // 基本的なBSPL項目の出力
    module OutputBSPL{

        @range = t
        @range_last = Util.max_t

        // キャッシュフロー項目
        double[] premium_income    = CashFlow.premium_income(t)
        double[] commission        = CashFlow.commission(t)
        double[] death_benefit     = CashFlow.death_benefit(t)
        double[] medical_benefit   = CashFlow.medical_benefit(t)
        double[] endow_benefit     = CashFlow.endow_benefit(t)
        double[] annuity_benefit   = CashFlow.annuity_benefit(t)
        double[] surrender_benefit = CashFlow.surrender_benefit(t)
        double[] unpaid_cashout    = CashFlow.unpaid_cashout(t)
        double[] init_expense      = CashFlow.init_expense(t)
        double[] maint_expense     = CashFlow.maint_expense(t)
        double[] investment_income = CashFlow.investment_income(t)
        double[] reserve_increase  = CashFlow.reserve_increase(t)
        double[] profit_before_tax = CashFlow.profit_before_tax(t)

        // ストック項目
        double[] premium_reserve = CashFlow.premium_reserve(t)
        double[] unpaid_prem_reserve = CashFlow.unpaid_prem_reserve(t)
        double[] reserve = CashFlow.reserve(t)
        double[] CV_end = CashFlow.CV_end(t)
        double[] azilV_end = CashFlow.azilV_end(t)
        double[] investment_asset = CashFlow.investment_asset(t)

        double[] lx_end = CashFlow.lx_end(t)
    }

    }