fastcashflow.transition의 소스 코드
"""IFRS 17 transition -- the fair value approach.
On first applying IFRS 17 an entity must measure its in-force contracts.
Where the full retrospective approach -- measuring as if the standard had
always applied, which is what ``measure`` does from inception -- is
impracticable, IFRS 17 permits the fair value approach (paragraphs
C20-C24): the CSM at the transition date is the fair value of the
contracts less their fulfilment cash flows.
``transition`` takes a measurement of the in-force book at the transition
date and a supplied fair value, and re-sets the CSM on that basis. Contract
modification and derecognition are not separate machinery here: a
modification that does not derecognise the contract (paragraph 73) is a
change in fulfilment cash flows for future service -- the assumption
revision of ``roll_forward`` -- and derecognition through lapse or
surrender is the in-force experience of ``roll_forward``.
"""
from __future__ import annotations
from dataclasses import replace
import numpy as np
from fastcashflow._typing import FloatArray
from fastcashflow.engine import GMMMeasurement
from fastcashflow.numerics import _csm_roll
[문서]
def transition(measurement: GMMMeasurement, fair_value: FloatArray) -> GMMMeasurement:
"""Re-set the CSM on the IFRS 17 fair value transition basis.
``measurement`` is a measurement of the in-force book at the transition
date -- its inception column being that date. ``fair_value`` is the
``(n_mp,)`` fair value of each contract or group. The CSM becomes
``max(0, fair_value - fulfilment cash flows)``, any excess of the
fulfilment cash flows over the fair value falling into the loss
component, and is rolled forward from there.
Returns a measurement with the re-set CSM and loss component; the BEL
and RA are unchanged. It flows on into :func:`~fastcashflow.roll_forward`,
:func:`~fastcashflow.reconcile` and :func:`~fastcashflow.report`.
"""
if measurement.bel_path is None:
raise ValueError(
"transition() requires a full=True measurement; the trajectory "
"fields are None on the full=False fast path. Call measure(..., full=True)."
)
fair_value = np.asarray(fair_value, dtype=np.float64)
n_mp = measurement.bel_path.shape[0]
if fair_value.shape != (n_mp,):
raise ValueError(f"fair_value must have one entry per row ({n_mp})")
fcf0 = measurement.bel_path[:, 0] + measurement.ra_path[:, 0]
csm0 = np.maximum(0.0, fair_value - fcf0)
loss_component = np.maximum(0.0, fcf0 - fair_value)
# Per-month rate curve implied by the measurement's discount factors --
# ratio of consecutive start-of-month factors. Carries the locked-in curve
# even if it is non-flat. The last axis is time, so this is (n_time,) for a
# single basis or (n_mp, n_time) for a segmented (per-row-curve) measurement.
monthly_rate = (measurement.discount_bom[..., :-1]
/ measurement.discount_bom[..., 1:]) - 1.0
csm, csm_accretion, csm_release = _csm_roll(
csm0, np.ascontiguousarray(measurement.cashflows.inforce), monthly_rate
)
return replace(
measurement,
csm=csm[:, 0],
csm_path=csm,
csm_accretion=csm_accretion,
csm_release=csm_release,
loss_component=loss_component,
)