API reference#

Inputs#

class fastcashflow.ModelPoints(issue_age, premium, term_months, benefits=None, maturity_benefit=None, annuity_payment=None, disability_income=None, disability_benefit=None, surrender_base_amount=None, contract_boundary_months=None, premium_term_months=None, premium_frequency_months=None, annuity_frequency_months=None, account_value=None, minimum_crediting_rate=None, minimum_death_benefit=None, minimum_accumulation_benefit=None, coverage_index=None, coverage_amount=None, coverage_offset=None, coverage_waiting=None, coverage_reduction_end=None, coverage_reduction_factor=None, coverage_step_month=None, coverage_step_factor=None, coverage_escalation_annual=None, coverage_escalation_cap=None, count=None, sex=None, state=None, issue_class=None, elapsed_months=None, product=None, channel=None, calculation_methods=None, coverage_codes=None, issue_date=None, attributes=None, mp_id=None)[소스]#

Columnar model point data.

Every scalar field is a numpy array of length n_mp; the model-point axis is the vectorised dimension throughout the engine. Monetary amounts are stated per single policy; count is how many policies the model point stands for – it defaults to one (one row per policy: seriatim), and a larger value scales the policy linearly through the projection.

A policy’s claim benefits are a variable-length list of coverages (see fastcashflow.coverage), held in CSR (Compressed Sparse Row) form so the kernels loop them generically – new benefit types add no fields:

  • coverage_index[k] – the coverage code; an integer index into Basis.coverages (entry i of that tuple lives at code i). No code is reserved.

  • coverage_amount[k] – the benefit amount of coverage k.

  • coverage_offset(n_mp+1,); policy mp’s coverages are the slice [coverage_offset[mp] : coverage_offset[mp+1]].

Each coverage may carry a benefit rule: coverage_waiting (months from issue with no benefit) and coverage_reduction_end / coverage_reduction_factor (a benefit multiplier in force until a cut-off month). Both are CSR arrays aligned with coverage_index and default to off – no waiting, full benefit.

The coverage list is built one of two ways. benefits is the general form: a {cov_idx: amount array} map keyed by coverage code (the index into Basis.coverages). Or pass the CSR arrays coverage_index / coverage_amount / coverage_offset directly – the preferred form for a portfolio with per-coverage benefit rules (waiting / reduction periods).

Premiums and survival benefits stay as plain fields – they do not proliferate the way claim benefits do:

  • premium – premium charged each payment occurrence.

  • premium_term_months – months the level premium is collected, defaulting to the full coverage term.

  • premium_frequency_months – months between level-premium payments (1 monthly, 3 quarterly, 6 half-yearly, 12 annual), defaulting to 1.

  • maturity_benefit – benefit on survival to the end of the term.

  • annuity_payment – survival income paid each payout occurrence.

  • annuity_frequency_months – months between annuity payouts, defaulting to 1.

  • disability_income – income paid each month a benefit state is occupied (disability income on a disabled state).

  • disability_benefit – lump sum paid when a lump-sum transition fires (a disability lump sum on becoming disabled).

매개변수:
property n_mp: int#

Number of model points.

axis(name)[소스]#

Resolve a grouping axis to a (n_mp,) label array by name.

Used by fastcashflow.group() to aggregate on any axis. Resolution order: the derived issue_year (calendar year of issue_date); the named source fields product / channel / issue_date; then any key in attributes (portfolio_id, profitability_group, risk_class, …). Raises KeyError listing the available axes when the name is unknown.

매개변수:

name (str)

반환 형식:

ndarray

classmethod single(issue_age, premium, term_months, benefits=None, maturity_benefit=0.0, annuity_payment=0.0, disability_income=0.0, disability_benefit=0.0, premium_term_months=None, premium_frequency_months=1, annuity_frequency_months=1, account_value=0.0, minimum_crediting_rate=0.0, minimum_death_benefit=0.0, minimum_accumulation_benefit=0.0, count=1.0, sex=0, state=0, calculation_methods=None)[소스]#

Build a single-model-point set – a convenience for hand checks.

benefits is the per-coverage benefit-amount map keyed by coverage code (the index into Basis.coverages); pass {0: 1_000_000.0} to attach the benefit to the first registered coverage. None means no claim benefits.

매개변수:
반환 형식:

ModelPoints

subset(indices)[소스]#

Return a new ModelPoints carrying the rows at indices.

Per-row fields (issue_age, premium, …) and the segment metadata (product, channel) are sliced. The coverage CSR is rebuilt: each selected row’s coverage slice coverage_index[coverage_offset[i]:coverage_offset[i+1]] is concatenated, and coverage_offset is reset to the new running cumulative sum. Used by fastcashflow.gmm.measure() to split a portfolio by (product, channel) before per-segment measurement.

indices is expected to select distinct rows – it is a row selection, not a gather. As an optimisation the result skips the re-validation the constructor runs (the parent was already validated), so a repeated index (subset([0, 0])) would carry a duplicate mp_id the constructor would otherwise reject. Every engine caller passes a unique segment index, so this is safe on the hot path; pass distinct indices when calling it directly.

반환 형식:

ModelPoints

class fastcashflow.Basis(mortality_annual, lapse_annual, discount_annual, ra_confidence, mortality_cv, expense_items=(), expense_inflation=0.0, surrender_value_curve=None, surrender_value_basis='cum_premium_factor', waiver_incidence_annual=None, lapse_paidup_annual=None, premium_factor_annual=None, annuity_factor_annual=None, ci_incidence_annual=None, ci_reincidence_annual=None, disability_recovery_annual=None, state_mortality_annual=None, longevity_cv=0.0, morbidity_cv=0.0, expense_cv=0.0, disability_cv=0.0, ra_method='confidence_level', cost_of_capital_rate=0.06, investment_return=0.0, fund_fee=0.0, settlement_pattern=None, coverages=(), state_model=None)[소스]#

Deterministic assumption set – no assumption changes over time.

매개변수:
  • mortality_annual (collections.abc.Callable[[numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]]]) –

    Annual mortality-rate callable. Like every rate function on Basis, it takes the unified five positional grids (sex, issue_age, duration, issue_class, elapsed) and returns an array of annual rates of the same shape – see RateFn (in fastcashflow._typing) for the full contract: sex (0 male, 1 female), issue_age (years), duration (completed policy years, 0-based), issue_class (at-issue / underwriting class), elapsed (semi-Markov sojourn). A table without a given axis broadcasts over it. The engine converts the annual rate to a monthly one (see annual_to_monthly()). A select-and-ultimate basis lets the rate depend on duration within the select period and on attained age (issue_age + duration) beyond it; that logic lives in this callable, not the engine.

    A legacy three-arg (sex, issue_age, duration) callable still works (it is auto-wrapped to the five-arg shape). WARNING: do not bake a constant in as a fourth default parameter – lambda s, a, d, f=factor: ... is read as a four-arg rate, and the engine passes issue_class into f, silently overriding it (wrong rates, no error). Capture the constant in a closure instead.

  • lapse_annual (collections.abc.Callable[[numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]]]) – Same five-arg RateFn shape as mortality_annual. Typical lapse depends only on duration, but the signature also lets a table key on sex / issue_age / issue_class when the workbook carries those axes (the engine reads the callable on the full grid either way).

  • discount_annual (float | numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]]) – Annual locked-in discount rate (Sec. 36). Either a flat scalar or a per-year (n_years,) array; the engine expands either to a per-month rate curve via fastcashflow.curves.discount_monthly_curve(). Used for discounting cash flows and for CSM interest accretion.

  • expense_items (tuple[fastcashflow.basis.ExpenseItem, ...]) – Row-form expense ledger – a tuple of ExpenseItem. Each row carries an expense type label (acquisition / maintenance / collection / LAE / overhead – free-form), a EXPENSE_BASES dispatch key and a numeric value. The engine projects every row through derive_expense_components() into the kernel-side primitives (alpha / beta / gamma / LAE fractions). An empty tuple is the no-expense basis.

  • expense_inflation (float | numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]]) – Global annual inflation applied to the recurring expense items (gamma_fixed and lae_pro_rata). Either a flat scalar – closed-form (1+i)^(t/12) growth – or a per-year (n_years,) array (compounds across years, in-year fractional ramp on the current year, held flat past the end). Macro-economic assumption, defined once per segment; the I/O layer points the segments sheet at one named scenario in the inflation_tables sheet (analogous to discount_annual / discount_tables). Does not apply to the two _init bases (one-time at t=0) or to premium_pct (which already rides the premium).

  • ra_confidence (float) – Confidence level for the Risk Adjustment (e.g. 0.75). The RA lifts the liability from its best estimate to this percentile.

  • mortality_cv (float) – Coefficient of variation of death claims – the mortality-risk component of the RA.

  • waiver_incidence_annual (collections.abc.Callable[[numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.int64]]], numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]]] | None) – Maps (sex, issue_age, duration_years) to an array of annual waiver-incidence rates – the rate at which active in-force transitions to the premium-waived state. Same signature as mortality_annual. None means no transitions: every model point keeps its input state for the whole projection. The spelling matches the standard actuarial term incidence – a per-unit-time event rate – used by the rest of the engine for analogous rates (ci_incidence_annual, ci_reincidence_annual).

  • longevity_cv (float) – Coefficient of variation of survival benefits (maturity benefits and annuity payments) – the longevity-risk component of the RA. The RA components are added (the natural mortality / longevity hedge is not credited – conservative for mixed contracts).

  • morbidity_cv (float) – Coefficient of variation of morbidity claims (hospitalisation, surgery, outpatient) – the morbidity-risk component of the RA.

  • expense_cv (float) – Coefficient of variation of expense cash flows – the expense-risk component of the Risk Adjustment. VFA-only in v1: measure_vfa uses it directly, but the GMM cl_margin in measure does not yet read this field (it sums the mortality / morbidity / disability / longevity components only). Adding the expense term to the GMM RA – and so closing the gap to the IFRS 17 non-financial-risk RA – is future work; setting expense_cv on a GMM portfolio currently has no effect.

  • disability_cv (float) – Coefficient of variation of disability cash flows – disability income and the on-transition lump sum – the disability-risk component of the Risk Adjustment.

  • ra_method (str) – Which Risk Adjustment technique to use – "confidence_level" (the default; a percentile margin on the benefit present values) or "cost_of_capital". The cost-of-capital method is available through measure(..., full=True); the fast path (full=False) computes the confidence-level RA.

  • cost_of_capital_rate (float) – Annual cost-of-capital rate for the cost-of-capital RA – the rate charged on the non-financial-risk capital held over the run-off.

  • investment_return (float) – Annual return earned on the underlying items backing an account-value (VFA) contract.

  • fund_fee (float) – Annual variable-fee rate – the entity’s share of the underlying items, deducted from the account value each period (VFA).

  • settlement_pattern (numpy.ndarray[tuple[Any, ...], numpy.dtype[numpy.float64]] | None) – Claims run-off pattern – the fractions of an incurred claim paid in the month it is incurred, the next month, and so on, summing to 1. None settles every claim immediately. It measures the liability for incurred claims and discounts claims to their payment dates in the best-estimate liability.

  • coverages (tuple[fastcashflow.basis.CoverageRate, ...]) – Ordered tuple of CoverageRate – the rate-driven coverages (death-type, morbidity and diagnosis), one per coverage code. No code is reserved: entry i lives at code i, the integer the portfolio’s coverage_index CSR uses to index this tuple. A contract’s death coverage, if any, is just one entry whose rate_table typically references the same mortality table the engine uses as the in-force decrement (mortality_annual) – the two are different mathematical quantities (decrement vs claim payout) that happen to share a table in most products. The taxonomy side – whether a coverage code runs as a diagnosis pool vs a recurring claim – lives on the portfolio (fastcashflow.modelpoints.ModelPoints.calculation_methods), not here.

  • state_model (fastcashflow.statemodel.StateModel | None) – The product’s in-force state machine – a StateModel declaring the transient states, their transitions and which states pay premium or a benefit. None uses the default active / waiver model (WAIVER_MODEL); the waiver_incidence_annual rate then drives the active -> waiver transition. A product with a different state set supplies its own.

  • surrender_value_curve (ndarray[tuple[Any, ...], dtype[float64]] | None)

  • surrender_value_basis (str)

  • lapse_paidup_annual (Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]] | None)

  • premium_factor_annual (Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]] | None)

  • annuity_factor_annual (Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]] | None)

  • ci_incidence_annual (Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]] | None)

  • ci_reincidence_annual (Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]] | None)

  • disability_recovery_annual (Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]] | None)

  • state_mortality_annual (dict[str, Callable[[ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]], ndarray[tuple[Any, ...], dtype[int64]]], ndarray[tuple[Any, ...], dtype[float64]]]] | None)

property discount_monthly: float#

First-year monthly discount rate, used as a representative scalar.

Reserved for the few places that need a single rate – the claims settlement-pattern present-value factor (Sec. 40 / B71) – where the in-year rate is the right reference. The per-month rate curve the kernels consume is composed by fastcashflow.curves.discount_monthly_curve(), which handles both a flat scalar and a per-year curve uniformly.

class fastcashflow.CoverageRate(code, rate)[소스]#

One rate-driven coverage’s assumption – a coverage code and how it runs.

매개변수:

참고

Whether a coverage runs as a depleting diagnosis pool vs a recurring claim, and which risk class the RA prices it as, is derived from the portfolio-level CalculationMethod taxonomy (the calculation_methods.csv file, surfaced as fastcashflow.modelpoints.ModelPoints.calculation_methods). Those two flags do not live on CoverageRate.

class fastcashflow.CalculationMethod(*values)[소스]#

How a benefit pays out – the engine’s calculation routing key.

Five uniform methods: every rate-driven death coverage (main contract or attached, accidental or all-cause, ADB / disease / disaster) is the same DEATH method; the rate table is what differentiates them. The method is purely a calculation-routing label – there is no “main-contract” method, because the engine has no reserved coverage slot.

str, Enum – members compare equal to their string value (CalculationMethod.MORBIDITY == "MORBIDITY"), so existing numpy array comparisons and dict keys keep working unchanged.

class fastcashflow.ExpenseItem(expense_type, basis, value)[소스]#

One typed entry in the expense ledger.

Each row is dispatched by basis and contributes its value into the kernel-side expense primitives. Inflation is not a row attribute – it lives on Basis (expense_inflation, matching the way discount_annual lives on Basis), so a company’s economic basis is named in one place and every inflation-bearing row picks it up automatically.

매개변수:
  • expense_type (str) – Free-form label for reporting / audit (e.g. "acquisition", "maintenance", "collection", "LAE", "overhead"). Engine ignores it; show_trace and describe_basis echo it.

  • basis (str) – Dispatch key – one of EXPENSE_BASES. The five values follow the Korean actuarial alpha / beta / gamma convention plus a dedicated LAE (Loss Adjustment Expense) slot, each split into pro_rata (proportional to a base amount) or fixed (per-policy flat).

  • value (float) – Numeric value – a fraction (0..1) for the _pro_rata bases, an amount per policy for the _fixed bases.

참고

The basis decides whether the global expense_inflation applies: gamma_fixed and lae_pro_rata recur every month and so inflate; the two alpha_* bases pay once at t=0 and beta_pro_rata rides the premium itself, so a second inflation factor would double-count.

fastcashflow.derive_expense_components(expense_items, n_time, inflation_index=None)[소스]#

Project expense_items onto the five kernel-side primitives.

Returns (alpha_pro_rata, alpha_fixed, beta_pro_rata, gamma_fixed, lae_pro_rata):

  • alpha_pro_rata – sum of value over alpha_pro_rata rows. Paid at t=0 on annualized premium.

  • alpha_fixed – sum of value over alpha_fixed rows. Paid at t=0 per policy.

  • beta_pro_rata – sum of value over beta_pro_rata rows. Charged each premium-paying month on the actual premium.

  • gamma_fixed[t] – per-month per-policy maintenance: each gamma_fixed row contributes value / 12 * inflation_index[t].

  • lae_pro_rata[t] – LAE (Loss Adjustment Expense) fraction: each lae_pro_rata row contributes value * inflation_index[t]. Applied to the month’s claim + morbidity + disability total.

inflation_index is the (n_time,) per-month inflation multiplier produced by fastcashflow.curves.inflation_index(); a scalar economic expense_inflation = i gives inflation_index[t] = (1+i)^(t/12) and a per-year curve compounds across years. Pass None for a no-inflation basis (every month equal to 1.0).

매개변수:
반환 형식:

tuple[float, float, float, ndarray[tuple[Any, …], dtype[float64]], ndarray[tuple[Any, …], dtype[float64]]]

fastcashflow.EXPENSE_BASES = ('alpha_pro_rata', 'alpha_fixed', 'beta_pro_rata', 'gamma_fixed', 'lae_pro_rata')#

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable’s items.

If the argument is a tuple, the return value is the same object.

fastcashflow.RA_METHODS = ('confidence_level', 'cost_of_capital')#

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable’s items.

If the argument is a tuple, the return value is the same object.

fastcashflow.SURRENDER_VALUE_BASES = ('cum_premium_factor', 'amount_per_policy', 'amount_per_unit')#

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable’s items.

If the argument is a tuple, the return value is the same object.

fastcashflow.RISK_MORTALITY = 0#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

fastcashflow.RISK_MORBIDITY = 1#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

Measurement (GMM)#

fastcashflow.gmm.measure(model_points, basis, *, full=True, backend='cpu', discount_curve=None, segment_by=None)[소스]#

GMM measurement – the single entry point.

full=True (default) returns the complete roll-forward: the (n_mp,) inception headline and the (n_mp, n_time+1) *_path trajectories. Those trajectories make it memory-bound – several dense (n_mp, n_time+1) float64 arrays, on the order of ~100 KB per model point for a long horizon, so a million-policy full=True run needs ~100 GB and will OOM on a typical box. full=False is the fused, memory-minimal fast path – it fills only the headline (*_path are None) at a few hundred bytes per model point, and is the right choice for large-scale valuation; reserve full=True for movement analysis or per-segment / chunked runs.

basis may be a single Basis (uniform portfolio) or a {(product, channel): Basis} dict; with a dict each segment is routed to its own basis. segment_by names the routing axes (resolved via ModelPoints.axis(), so any attributes column works) and the dict keys are tuples of those axes in order. Left as None (the default) it is taken from the basis: a SegmentedBasis from read_basis() carries the axes its workbook declared, and a plain dict falls back to ("product", "channel"). So a workbook keyed by (product, channel, risk_class) routes by all three with no extra argument; passing segment_by explicitly overrides. Cost scales with the number of distinct segments, not the number of axes. backend ("cpu"/"gpu") and discount_curve apply to the fast path only.

매개변수:
반환 형식:

GMMMeasurement

fastcashflow.gmm.measure_aggregate(model_points, basis, *, chunk_size=200000)[소스]#

Portfolio-aggregate full=True measurement in bounded memory.

measure(full=True) materialises dense (n_mp, n_time+1) trajectories – ~100 KB per model point – so a million-policy book needs ~100 GB and OOMs. But BEL / RA / CSM are additive across contracts, so the portfolio’s liability run-off is the per-model-point trajectories summed over the model-point axis. This runs the full trajectory kernel over row-blocks of chunk_size model points and accumulates only that (n_time+1,) sum, so peak memory is O(chunk_size x n_time) regardless of n_mp.

Returns an AggregateMeasurement (scalar totals + aggregate bel_path / ra_path / csm_path). For the per-model-point detail (movement, in-force slicing) use measure() on a book small enough to hold every trajectory. basis may be a single Basis or a per-segment dict, routed per chunk exactly as measure() routes it.

매개변수:
반환 형식:

AggregateMeasurement

fastcashflow.gmm.measure_inforce(model_points, basis, state, *, period_months=None, full=True)[소스]#

In-force subsequent measurement (IFRS 17 Sec. 44) at the valuation date.

The single entry point for settlement / period-close valuation of an in-force book. Each model point is valued at its elapsed_months duration, and the prior period’s closing CSM (state.prior_csm) is carried forward – accreted at state.lock_in_rate and released over coverage units across period_months (default 12).

The bel / ra are re-based to the valuation date: the projection runs from inception, so the slice is scaled by count / inforce[elapsed] to set the as-of in-force to the input count – exact for every cash flow linear in the in-force (premium, claim, morbidity, expense, maturity, annuity, and the amount_per_policy / amount_per_unit surrender value). The one approximation is the cum_premium_factor surrender mode: it reconstructs the base from the projected cumulative premium (lapse x cum_premium x factor), which ignores premiums paid before the valuation date, so it is path-dependent and only sample-grade. A UserWarning fires only in that mode (basis carries a cum_premium_factor surrender curve and any elapsed_months > 0); the contractual amount_per_policy / amount_per_unit curves are linear in the in-force and re-base exactly, so they are the production-grade surrender input and warn-free.

state is the InforceState returned by read_inforce_policies() (it carries prior_csm / lock_in_rate, plus the elapsed_months / count reconciled onto model_points). model_points and state must be reconciled by apply_inforce_state() first – read_inforce_policies returns the pair already reconciled; the two-file path (read_model_points + read_inforce_state) calls it explicitly. A model_points whose elapsed_months / count disagree with state is rejected (a stale snapshot must not borrow a fresh state’s CSM). full=True (default) returns the BEL / RA / CSM trajectories and cash flows for movement analysis; full=False returns just the headline numbers (faster).

Sec. 44 onerous unlocking and experience adjustments are not yet folded in here (loss_component is zero in this mode); use roll_forward() with prior and current measurements for the full movement.

매개변수:
반환 형식:

GMMMeasurement

class fastcashflow.GMMMeasurement(bel, ra, csm, loss_component, bel_path=None, ra_path=None, csm_path=None, csm_accretion=None, csm_release=None, lic=None, cashflows=None, discount_bom=None, discount_mid=None, model_points=None, group_labels=None, group_sizes=None)[소스]#

IFRS 17 GMM measurement: BEL, RA and CSM.

The headline fields (bel, ra, csm, loss_component) are (n_mp,) inception values and are always present.

The trajectory fields are the roll-forward over time and are populated only by measure(..., full=True); on the headline-only fast path (full=False) they are None. bel_path / ra_path / csm_path are the (n_mp, n_time+1) trajectories whose column 0 is the inception value (so bel == bel_path[:, 0] when full). The CSM roll-forward decomposes as csm_path[:, t+1] = csm_path[:, t] + csm_accretion[:, t] - csm_release[:, t]. lic is the liability for incurred claims – zero unless a claims settlement pattern is set, which also discounts claims to their payment dates in the BEL.

매개변수:
class fastcashflow.AggregateMeasurement(bel, ra, csm, loss_component, bel_path, ra_path, csm_path)[소스]#

Portfolio-aggregate GMM trajectories – the scalable full=True view.

BEL / RA / CSM are additive across contracts, so a large book’s liability run-off is its per-model-point trajectories summed over the model-point axis. This holds only that sum: the scalar inception totals plus the (n_time+1,) aggregate bel_path / ra_path / csm_path (column 0 is inception, so bel == bel_path[0]). It is what measure_aggregate() returns, computed in bounded memory so it works where a per-model-point measure(full=True) would OOM.

매개변수:

Premium allocation approach#

fastcashflow.paa.measure(model_points, basis, *, revenue_basis='time')#

Measure a portfolio under the Premium Allocation Approach.

The LRC rolls forward as LRC[t+1] = LRC[t] + premium[t] - revenue[t] from LRC[0] = 0 – premiums received build it up, insurance revenue releases it. A single-premium contract gives the textbook pro-rata unearned premium reserve.

revenue_basis selects the Sec. B126 allocation of insurance revenue, which always sums to the total premium:

  • "time" – B126(a), passage of time: the premium earned straight-line over the coverage period (the default).

  • "claims" – B126(b), the expected timing of incurred claims and expenses; for when the release of risk differs significantly from the passage of time. A policy with no service expense has no such pattern and falls back to "time".

The onerous test reuses the GMM fulfilment cash flows: a contract whose inception fulfilment cash flows are a net outflow carries that outflow as a loss component.

매개변수:
반환 형식:

PAAMeasurement

class fastcashflow.PAAMeasurement(lrc, loss_component, fcf=None, lrc_path=None, revenue=None, service_expense=None, lic=None, cashflows=None, model_points=None, group_labels=None, group_sizes=None)[소스]#

PAA measurement – the Liability for Remaining Coverage and the underwriting result released from it.

lrc is an (n_mp, n_time+1) trajectory; column 0 is the inception LRC. revenue and service_expense are (n_mp, n_time) – the insurance revenue earned and the insurance service expense incurred each month. service_result (a property) is their difference. lic is the (n_mp, n_time+1) liability for incurred claims – claims build it up as they are incurred and run it off as they are paid.

매개변수:
property service_result: ndarray[tuple[Any, ...], dtype[float64]]#

Insurance service result – revenue less service expense.

Variable fee approach#

fastcashflow.vfa.measure(model_points, basis, return_scenarios=None)#

Measure a direct-participation portfolio under the Variable Fee Approach.

The account value rolls forward as AV[t+1] = AV[t] * (1 + max(r, g)) * (1 - f) – the credited rate (the underlying-items return r floored at any guaranteed rate g) less the variable fee f – from AV[0] = the model point’s account_value. A surrender pays the account value; a death exit pays max(account value, minimum_death_benefit) (GMDB) and the survivors reaching term pay max(account value, minimum_accumulation_benefit) (GMAB), so the excess over the account value is each guarantee’s intrinsic cost. When return_scenarios is given, each guarantee’s time value (the extra cost from return volatility) is folded into the CSM too – the credit-rate guarantee through the account-value growth, the GMDB and GMAB floors as put options on the account value.

BEL is the present value of benefits and expenses less the premium, all at the underlying-items return; the CSM is max(0, -(BEL + RA)) – the entity’s unearned variable fee – accreted at the same return and released by coverage units. The RA is a confidence-level margin for expense risk.

BEL, RA and CSM are returned as month-by-month trajectories. The deterministic BEL carries the guarantee’s intrinsic value only; when return_scenarios – an (n_scenarios, n_time) array of monthly underlying-items returns – is supplied, the time value of the guarantee enters the inception fulfilment cash flows too, so the CSM absorbs it, and time_value records that amount per model point.

매개변수:
반환 형식:

VFAMeasurement

class fastcashflow.VFAMeasurement(bel, ra, csm, variable_fee, time_value, loss_component, bel_path=None, ra_path=None, csm_path=None, account_value_path=None, csm_accretion=None, csm_release=None, lic=None, discount_bom=None, cashflows=None, model_points=None, group_labels=None, group_sizes=None)[소스]#

VFA measurement of a direct-participation (account-value) portfolio.

account_value, bel, ra and csm are (n_mp, n_time+1) trajectories – column 0 is the inception figure, the RA being a confidence-level margin for expense risk. The BEL is reported net of the account value the entity holds. The CSM is accreted at the underlying-items return and released by coverage units:

csm[:, t+1] = csm[:, t] + csm_accretion[:, t] - csm_release[:, t]

variable_fee is the present value of the entity’s fee – its share of the underlying items. loss_component and time_value are (n_mp,) inception figures; the time value of the guarantee drives the CSM but is reported separately from bel.

매개변수:
fastcashflow.vfa.tvog(model_points, basis, return_scenarios)#

Measure the time value of a VFA contract’s minimum guarantee.

return_scenarios is an (n_scenarios, n_time) array of monthly underlying-items returns – one path per scenario, n_time being the projection horizon. The model points must carry a non-zero minimum_crediting_rate (otherwise there is no guarantee to value); in v1 the rate is taken as a portfolio-wide scalar (per-MP varying rates with stochastic returns are a future extension), so the column is required to be uniform across rows.

The guarantee cost is the present value of account-value benefits in excess of the no-guarantee benefits. Its mean over the scenarios is the total value; the cost in the central scenario (investment_return) is the intrinsic value; the difference is the time value (TVOG).

매개변수:
반환 형식:

TVOGResult

class fastcashflow.TVOGResult(guarantee_cost, intrinsic_value, time_value)[소스]#

The cost of a minimum guarantee, split into intrinsic and time value.

guarantee_cost is the (n_scenarios,) present value of the guarantee under each scenario – its distribution. intrinsic_value is the cost in the central (deterministic) scenario; time_value is the TVOG, the mean cost in excess of the intrinsic value; and total_value is their sum, the guarantee’s full economic cost.

매개변수:
property total_value: float#

Intrinsic value plus time value – the guarantee’s full cost.

Tracing and validation#

Per-contract tracers that unfold a single model point’s measurement as an ASCII tree – which segment, table and rate feed each step, the year-by-year rates and cash flows, and the anchor-month discount / BEL / CSM. Used for hand-calculation validation, learning and debugging. Each measurement approach has its own tracer.

fastcashflow.gmm.trace(mp_index, model_points, basis, *, file=None)#

Print a tree of how one model point’s BEL / RA / CSM is computed.

매개변수:
  • mp_index (int) – 0-based row index in model_points.

  • model_points (ModelPoints) – Portfolio ModelPoints. The function slices to a single row before running measure(), so a 1M-row portfolio does not pay for the trace of one contract.

  • basis (Basis | dict) – A single Basis, or the dict returned by fastcashflow.io.read_basis() / fastcashflow.io.load_sample_basis(). With the dict form the function looks up the segment via the model point’s (product, channel).

  • file (IO | None) – Where to write. None writes to sys.stdout.

  • calculation (Use it when an engine result disagrees with a hand)

  • segment (tree shows the)

  • tables

  • values (rate)

  • roll- (cash flows and)

  • step (forward step by)

  • glance. (so the diverging step is visible at a)

반환 형식:

None

fastcashflow.gmm.trace_diff(mp_index, model_points, basis_a, basis_b, *, label_a='before', label_b='after', file=None)#

Print a tree of how the BEL / RA / CSM of one model point moves when basis change.

매개변수:
  • mp_index (int) – 0-based row index in model_points.

  • model_points (ModelPoints) – Portfolio ModelPoints. Subset to the single row before each measure() so the diff cost stays proportional to one MP.

  • basis_a (Basis | dict) – Two basis to compare. Either a Basis or the dict from fastcashflow.io.read_basis(). With dicts, each is routed independently by the model point’s (product, channel) – comparing two segments is also fine.

  • basis_b (Basis | dict) – Two basis to compare. Either a Basis or the dict from fastcashflow.io.read_basis(). With dicts, each is routed independently by the model point’s (product, channel) – comparing two segments is also fine.

  • label_a (str) – Short labels for the two columns in the printed diff (e.g. "baseline" vs "mortality+10%"). Default "before" / "after".

  • label_b (str) – Short labels for the two columns in the printed diff (e.g. "baseline" vs "mortality+10%"). Default "before" / "after".

  • file (IO | None) – Where to write. None writes to sys.stdout.

  • Sections

  • --------

  • identity) (1. Header (the model-point)

  • names) (2. Labels (the two basis)

  • differ (3. Assumption changes -- only the fields that)

  • side (4. Rate deltas -- year-by-year annual rates side by)

  • component (5. Cash flow deltas -- annual sum of each cash-flow)

  • months (7. BEL / CSM deltas at anchor)

  • months

  • loss_component (8. Final -- BEL / RA / FCF / CSM /) – percentage change

  • and (with absolute) – percentage change

  • so (Equal values are suppressed from the assumption-change section)

  • moved. (the eye lands on what actually)

반환 형식:

None

fastcashflow.gmm.trace_bel_step(mp_index, model_points, basis, *, months=None, file=None)#

Print, term by term, how one model point’s BEL[t] is built.

The kernel runs the IFRS 17 backward recursion:

BEL[t] = annuity[t] - premium[t]
       + (claim + morbidity + disability + expense + surrender)[t]
         * (1 + i[t])^(-1/2)
       + BEL[t+1] * (1 + i[t])^(-1)

seeded by BEL[term] = maturity_benefit. This function unrolls the equation at chosen months: prints each cash-flow component at t, the half-month and full-month discount factors, the mid-term piece (cash flows at mid-month) and the tail piece (carry from the next month), then the resulting BEL[t] against the engine’s value. When the printed identity holds the engine and a hand calculation are in agreement; when it does not, the offending term is right there in the row.

매개변수:
  • mp_index (int) – 0-based row index in model_points.

  • model_points (ModelPoints) – Portfolio ModelPoints. Subset to the single row before running measure().

  • basis (Basis | dict) – A Basis or the dict from fastcashflow.io.read_basis() (routed by the row’s (product, channel) like show_trace()).

  • months (list[int] | None) – Anchor months at which to unroll the recursion. None uses {0, 12, term//2, term-1, term} – inception, end of year 1, the half-way point, the last recursion step, and the seed. Out-of-range entries are ignored.

  • file (IO | None) – Where to write. None -> sys.stdout.

반환 형식:

None

fastcashflow.gmm.trace_csm_step(mp_index, model_points, basis, *, months=None, file=None)#

Print, term by term, how one model point’s CSM[t] is built.

The kernel runs the forward recursion:

csm[0]   = max(0, -(BEL[0] + RA[0]))
csm[t]   = csm[t-1] + accretion[t-1] - release[t-1]
accretion[t-1] = csm[t-1] * i[t-1]
release[t-1]   = (csm[t-1] + accretion[t-1])
                 * coverage_units[t-1] / sum(coverage_units[t-1:])

coverage_units is the in-force survival series. This function unrolls the step at chosen months: prints the prior CSM, the monthly rate, the accretion, the coverage-unit share consumed in that month, the release amount, and the resulting CSM[t] against the engine’s value.

For an onerous contract (csm[0] == 0), every subsequent step is zero too – the printed trace then visibly says so, which is itself useful when checking that the engine is honouring the floor.

매개변수:
  • mp_index (int) – 0-based row index in model_points.

  • model_points (ModelPoints) – Same shape as show_trace_bel_step().

  • basis (Basis | dict) – Same shape as show_trace_bel_step().

  • file (IO | None) – Same shape as show_trace_bel_step().

  • months (list[int] | None) – Months at which to unroll the step (each row shows the computation that produced csm[t] from csm[t-1]). None uses {1, 12, term//2, term}. Out-of-range entries are ignored. t = 0 is the seed and is always printed regardless of months.

반환 형식:

None

fastcashflow.vfa.trace(mp_index, model_points, basis, *, return_scenarios=None, file=None)#

Print a tree of how one VFA model point’s BEL / RA / CSM is computed.

The VFA (variable-fee, account-value) counterpart of show_trace(). It slices to a single row, runs measure_vfa(), and shows the account-value trajectory, the GMDB / GMAB floors (where the guarantee bites), the variable fee and the BEL / RA / CSM – plus the guarantee time value (TVOG) when return_scenarios is supplied. Use it on direct-participation contracts; show_trace() traces the GMM measure and does not cover the account-value mechanic.

매개변수:
반환 형식:

None

fastcashflow.paa.trace(mp_index, model_points, basis, *, revenue_basis='time', file=None)#

Print a tree of how one PAA model point’s LRC / revenue / LIC is built.

The PAA (Premium Allocation Approach, the short-duration simplification) counterpart of show_trace(). PAA has no CSM – the liability for remaining coverage (LRC) is an unearned-premium-style balance – so the tree shows the LRC roll-forward (premium in, revenue released), the insurance service result (revenue less service expense) and the liability for incurred claims (LIC). Use it on PAA contracts; show_trace() traces the GMM measure (BEL / RA / CSM).

매개변수:
반환 형식:

None

Reinsurance#

fastcashflow.reinsurance.measure(model_points, basis, treaty)#

Measure a reinsurance contract held over a direct portfolio.

treaty describes how the cover cedes the direct cash flows – e.g. QuotaShare(cession=0.5). The BEL is the present value of reinsurance premiums less recoveries; the RA is the margin on the ceded claims (the risk transferred). The CSM is -(BEL - RA) – the net cost or gain of the cover – and may be negative; it is accreted and released by coverage units like a direct contract’s CSM, but with no loss component (paragraph 65).

매개변수:
반환 형식:

ReinsuranceMeasurement

class fastcashflow.reinsurance.QuotaShare(cession)[소스]#

Proportional reinsurance – cede a fixed fraction of claims and premiums.

cession (in [0, 1]) is the ceded fraction: the cedant recovers that fraction of its claims and pays the same fraction of its premiums as reinsurance premium.

매개변수:

cession (float)

class fastcashflow.reinsurance.ReinsuranceMeasurement(bel, ra, csm, csm_path=None, csm_accretion=None, csm_release=None, recovery=None, reinsurance_premium=None, cashflows=None, discount_bom=None, model_points=None, group_labels=None, group_sizes=None)[소스]#

Measurement of a reinsurance contract held.

Headline bel, ra and csm are (n_mp,) inception figures – bel is the present value of reinsurance premiums less recoveries (a net cost when positive), ra is the risk transferred, csm is the inception net cost or gain (may be negative). The trajectory fields are populated only on the full path; csm_path reconciles as csm_path[:, t+1] = csm_path[:, t] + csm_accretion[:, t] - csm_release[:, t].

매개변수:

Pricing#

fastcashflow.solve_premium(model_points, basis, *, break_even=False, margin=None, csm=None)[소스]#

Solve the level premium that meets a profitability target.

Exactly one target must be given:

  • break_even – the lowest non-onerous premium (FCF = 0, zero CSM).

  • margin – a profit margin, CSM / PV(premiums) = margin (e.g. 0.10 for 10%); must satisfy 0 <= margin < 1.

  • csm – an absolute target CSM (profit) per model point.

Every product field of model_points is used as given – only premium is ignored, since it is the unknown being solved for. Returns the solved premium per model point, shape (n_mp,).

매개변수:
반환 형식:

ndarray[tuple[Any, …], dtype[float64]]

Reporting#

fastcashflow.report(measurement)[소스]#
fastcashflow.report(measurement)
fastcashflow.report(measurement)
fastcashflow.report(measurement)

Assemble the IFRS 17 report from a GMM, PAA or VFA measurement.

See the module docstring for the basis (IFRS 17 paragraphs B120-B124). Dispatches on the measurement type; a new model registers its own report with @report.register.

반환 형식:

Report

class fastcashflow.Report(insurance_revenue, insurance_service_expense, insurance_service_result, insurance_finance_expense, bel_finance_expense, ra_finance_expense, csm_finance_expense, loss_component, csm_opening, csm_accretion, csm_release, csm_closing)[소스]#

IFRS 17 reporting figures, period by period.

Each flow array is shaped (n_mp, n_time) – one row per model point, one column per month; loss_component is (n_mp,) – the onerous loss at inception. insurance_service_result is revenue less service expense; insurance_finance_expense is signed (positive an expense). The CSM analysis of change reconciles as csm_opening + csm_accretion - csm_release = csm_closing (the CSM columns are zero for a PAA measurement, which has no CSM).

insurance_finance_expense is also disaggregated by source (IFRS 17 B130-B136) into bel_finance_expense (finance on the estimates of future cash flows), ra_finance_expense (finance on the risk adjustment) and csm_finance_expense (the CSM interest accreted at the locked-in rate, B72). The three sum to insurance_finance_expense up to floating-point rounding (the aggregate is kept as its own expression, so the parts may differ from it by a rounding step rather than re-deriving it). The split is the structural basis for a later P&L / OCI allocation.

매개변수:
annual()[소스]#

Portfolio totals aggregated to policy years.

Each per-period line item is summed across model points and then across the twelve months of each policy year.

반환 형식:

dict[str, ndarray[tuple[Any, …], dtype[float64]]]

Period-close analysis of change#

fastcashflow.roll_forward(measurement, period_months=12, *, revised=None, revised_at=None, actual_inforce=None, experience_at=None)[소스]#
fastcashflow.roll_forward(measurement, period_months=12, *, revised=None, revised_at=None, actual_inforce=None, experience_at=None)
fastcashflow.roll_forward(measurement, period_months=12, *, revised=None, revised_at=None, actual_inforce=None, experience_at=None)
fastcashflow.roll_forward(measurement, period_months=12, *, revised=None, revised_at=None, actual_inforce=None, experience_at=None)

Slice a measurement into reporting-period movements.

Returns one movement per reporting period of period_months months, reconciling the opening and closing figures; consecutive periods chain and a partial final period is allowed. Dispatches on the measurement type – a new model registers with @roll_forward.register.

For a GMM measurement, an assumption revision is recognised by passing revised (a second measurement of the same book under updated basis) and revised_at (the month it takes effect); in-force experience by actual_inforce (the (n_mp,) in-force remaining at the period end, or a 2-D (n_periods, n_mp) array to roll experience through every period) and experience_at. Either change adjusts the CSM by the resulting change in fulfilment cash flows (floored at zero, any excess falling into the loss component); v1 recognises one or the other, not both in a single call. A PAA or VFA measurement is also accepted – the movement is then the roll of the LRC or of the CSM, to which the revision and experience options do not apply.

매개변수:

period_months (int)

fastcashflow.reconcile(movements)[소스]#

Aggregate period movements into IFRS 17 reconciliation tables.

Each PeriodMovement – per model point – becomes one portfolio-total Reconciliation in the layout of IFRS 17 paragraph 101. Run-off rows are shown negative, so opening plus every row equals closing. A list of PAAPeriodMovement or VFAPeriodMovement is reconciled instead into the PAA liability-for-remaining-coverage or VFA contractual-service-margin tables.

매개변수:

movements (list[PeriodMovement] | list[PAAPeriodMovement] | list[VFAPeriodMovement])

반환 형식:

list[Reconciliation] | list[PAAReconciliation] | list[VFAReconciliation]

class fastcashflow.PeriodMovement(month_start, month_end, bel_opening, bel_assumption_change, bel_experience, bel_interest, bel_release, bel_closing, ra_opening, ra_assumption_change, ra_experience, ra_interest, ra_release, ra_closing, csm_opening, csm_assumption_change, csm_experience, csm_accretion, csm_release, csm_closing, loss_component_recognised)[소스]#

One reporting period’s analysis of change.

The period covers months [month_start, month_end). Every array is (n_mp,), and each block reconciles exactly:

bel_opening + bel_assumption_change + bel_experience
    + bel_interest - bel_release == bel_closing

and likewise for RA and CSM (with csm_accretion in place of *_interest).

*_interest / csm_accretion is the unwind of discount at the locked-in rate; *_release is the expected run-off over the period. *_assumption_change and *_experience are the effect of an assumption revision and of in-force experience – non-zero only in the period the change is recognised. Both relate to future service and so adjust the CSM. loss_component_recognised is the part of an unfavourable change beyond the CSM, which falls into the loss component.

매개변수:
class fastcashflow.Reconciliation(month_start, month_end, bel_opening, bel_future_service, bel_finance, bel_release, bel_closing, ra_opening, ra_future_service, ra_finance, ra_release, ra_closing, csm_opening, csm_future_service, csm_finance, csm_release, csm_closing, loss_component_recognised)[소스]#

An IFRS 17 reconciliation of the insurance contract liability.

Portfolio totals for one reporting period, in the layout of IFRS 17 paragraph 101: the estimates of the present value of future cash flows (bel), the risk adjustment (ra) and the CSM each reconcile from opening to closing. *_future_service is the assumption and experience effect; *_finance is the interest unwind; *_release is the run-off, shown negative – so opening plus every row equals closing.

매개변수:
class fastcashflow.PAAPeriodMovement(month_start, month_end, lrc_opening, premiums, revenue, lrc_closing, loss_component_opening, loss_component_release, loss_component_closing, lic_opening, claims_incurred, claims_paid, lic_closing)[소스]#

One reporting period’s movement of the PAA insurance contract liability.

The period covers months [month_start, month_end). Every array is (n_mp,); the three components each reconcile exactly:

lrc_opening + premiums        - revenue                == lrc_closing
loss_component_opening        - loss_component_release == loss_component_closing
lic_opening + claims_incurred - claims_paid            == lic_closing

The LRC (liability for remaining coverage) is built up by premiums and released by insurance revenue; the loss component runs off over the coverage; the LIC (liability for incurred claims) is built up as claims are incurred and run off as they are paid. All are held undiscounted.

매개변수:
class fastcashflow.PAAReconciliation(month_start, month_end, lrc_opening, premiums, revenue, lrc_closing, loss_component_opening, loss_component_release, loss_component_closing, lic_opening, claims_incurred, claims_paid, lic_closing)[소스]#

An IFRS 17 paragraph-100 reconciliation of the PAA liability.

Portfolio totals for one reporting period, split into the three components – the liability for remaining coverage (excluding the loss component), the loss component, and the liability for incurred claims. Run-off rows are shown negative, so opening plus every row equals closing.

매개변수:
class fastcashflow.VFAPeriodMovement(month_start, month_end, bel_opening, bel_interest, bel_release, bel_closing, ra_opening, ra_interest, ra_release, ra_closing, csm_opening, csm_accretion, csm_release, csm_closing)[소스]#

One reporting period’s movement of the VFA insurance contract liability.

The period covers months [month_start, month_end). Every array is (n_mp,) and each block reconciles exactly:

bel_opening + bel_interest  - bel_release  == bel_closing
ra_opening  + ra_interest   - ra_release   == ra_closing
csm_opening + csm_accretion - csm_release  == csm_closing

*_interest / csm_accretion is the unwind at the underlying-items return; *_release is the expected run-off over the period. Under the VFA the CSM absorbs the variability of the underlying items, so the entity’s profit emerges as the CSM is released.

매개변수:
class fastcashflow.VFAReconciliation(month_start, month_end, bel_opening, bel_finance, bel_release, bel_closing, ra_opening, ra_finance, ra_release, ra_closing, csm_opening, csm_finance, csm_release, csm_closing)[소스]#

An IFRS 17 VFA reconciliation of the insurance contract liability.

Portfolio totals for one reporting period – the BEL, RA and CSM each reconciled from opening to closing. *_finance is the unwind at the underlying-items return; *_release is the run-off, shown negative – so opening plus every row equals closing.

매개변수:

Aggregation and transition#

fastcashflow.group(measurement, by)[소스]#
fastcashflow.group(measurement, by)
fastcashflow.group(measurement, by)
fastcashflow.group(measurement, by)
fastcashflow.group(measurement, by)

Aggregate a per-model-point measurement to any axis.

A general aggregation primitive – not IFRS 17-specific. by is one of:

  • a single axis name (e.g. "product");

  • a list of axis names and/or precomputed (n_mp,) label arrays (e.g. ["product", "issue_year"], or ["product", onerous_array]), joined into one composite label;

  • a single precomputed (n_mp,) array of group labels.

Names are resolved per model point via ModelPoints.axis() against the model points the measure stamped on the result, so no re-passing is needed; a computed axis with no source column (e.g. an onerous flag from loss_component) is passed as an array instead – an np.ndarray, since a Python list is read as a list of axes, not a single label vector.

BEL and RA are summed within each group; the CSM and the loss component are re-derived on the group aggregate, so the max(0, ...) floor nets the contracts within a group but not across groups. The IFRS 17 unit of account (portfolio x annual cohort x profitability) is one choice of axes – group_of_contracts() is the preset for it; management-accounting, profitability and validation views are other choices of by.

Dispatches on the measurement type (GMMMeasurement, VFAMeasurement, ReinsuranceMeasurement, PAAMeasurement). Returns a measurement of the same type whose rows are the groups, in ascending label order – usable in turn by roll_forward(), reconcile() and report(). Its group_labels attribute carries the composite label of each row, so a caller can map a group back to its key (e.g. "|"-split a group_of_contracts() label into portfolio / cohort / profitability) without rebuilding the keys; group_sizes carries the number of model points in each group (model-point rows, not the policy count – they differ when a model point’s count stands for several policies).

fastcashflow.group_of_contracts(measurement, *, portfolio='product', cohort='issue_year', profitability=None)[소스]#
fastcashflow.group_of_contracts(measurement, *, portfolio='product', cohort='issue_year', profitability=None)
fastcashflow.group_of_contracts(measurement, *, portfolio='product', cohort='issue_year', profitability=None)
fastcashflow.group_of_contracts(measurement, *, portfolio='product', cohort='issue_year', profitability=None)
fastcashflow.group_of_contracts(measurement, *, portfolio='product', cohort='issue_year', profitability=None)

Aggregate a measurement to the IFRS 17 group of insurance contracts.

The unit of account (paragraphs 14-24) is a portfolio (14) x annual cohort (22) x profitability (16). This preset builds that grouping from the model points measure() stamped on the measurement and runs group(), so the CSM floor nets within a group but not across.

Dispatches on the measurement type; the profitability axis differs by type (a new measurement registers with @group_of_contracts.register):

  • GMMMeasurement / VFAMeasurement / PAAMeasurement – insurance contracts issued, direct-participating, and short-coverage (PAA) contracts; profitability is the onerous / remaining split (paragraph 16, and 57 for the PAA). The per-type re-derivation differs (VFA accretes the CSM at the underlying-items return; the PAA has no CSM, only the LRC and the onerous loss), handled by group()’s own dispatch.

  • ReinsuranceMeasurement – reinsurance contracts held; profitability is the net-gain split (paragraph 61, csm > 0), and there is no loss component or floor (paragraph 65), so the grouped CSM is the sum of the contract CSMs.

Arguments (keyword-only):

  • portfolio – the column naming the portfolio axis (default "product": paragraph 14’s product line). Pass another column name to group on a different portfolio definition.

  • cohort – the column naming the annual-cohort axis (default "issue_year", derived from issue_date: paragraph 22). Pass another column (e.g. "issue_quarter" carried in the data) for a finer cohort; paragraph 22 caps the span at one year, so a cohort may be finer than annual but not coarser.

  • profitability – the profitability classification. None (default) derives it from the measurement, since it is an output, not a known input (paragraph 16 / 47’s net-outflow test). Pass a precomputed (n_mp,) array for a custom split (e.g. the paragraph-16 three-way split using a CSM-vs-RA threshold), or a column name for a locked classification carried in the data (paragraph 24: the group is fixed at inception).

Requires a full=True measurement.

매개변수:
  • portfolio (str)

  • cohort (str)

반환 형식:

GMMMeasurement

fastcashflow.transition(measurement, fair_value)[소스]#

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 roll_forward(), reconcile() and report().

매개변수:
반환 형식:

GMMMeasurement

State models#

The in-force state machine driving multi-state products (waiver, paid-up, disability income, reincidence, long-term care). A StateModel is a tuple of State objects, each carrying its Transition edges; STATE_MODELS holds the bundled models.

class fastcashflow.StateModel(states, seating=(0,))[소스]#

A product’s in-force state machine, declared as data.

states are the transient states; position fixes the kernel state index, and state 0 is the issue state. seating maps a model point’s input contract state – the ModelPoints.state code (STATE_ACTIVE, STATE_WAIVER, STATE_PAIDUP) – to the index of the state its in-force is seated on at the valuation date: seating[code] is that index. It defaults to seating every model point on state 0.

The occupancy recursion treats every state identically, so an arbitrary StateModel runs on the existing kernels with no per-product code – see the module docstring and compile_state_model().

매개변수:
class fastcashflow.State(name, premium=False, benefit=False, transitions=(), duration_max=0, benefit_max_months=0, mortality_rate='mortality', death_benefit_factor=1.0, exit_after=0)[소스]#

One transient state of the in-force model.

premium flags a premium-paying state – the level and single premium accrue on the occupancy of the states so flagged. benefit flags a benefit-paying state – the ModelPoints.disability_income amount is paid each month its occupancy is held (disability income on a disabled state). transitions are the transitions out of the state, held in application order: the competing-decrement convention (see the module docstring) applies each in turn to the survivors of the previous.

duration_max switches the state to a semi-Markov model. When set to D > 0, the engine tracks D monthly cohorts of in-force in this state (cohort 0 entered this month, cohort 1 entered last month, and cohort D - 1 absorbs everyone who has been here D - 1 months or longer). Transitions with duration_dependent=True then receive a cohort index and may carry different rates per cohort – the natural way to express recovery, reincidence, exclusion (면책) periods, and other duration-since-entry effects. The default 0 keeps the state Markov (a single cohort, identical to the pre-Phase-(c) behaviour).

mortality_rate routes this state’s in-force death decrement to a named rate (default "mortality", the global decrement). A post-diagnosis state can carry an elevated death rate by naming a different rate, supplied via Basis.state_mortality_annual.

benefit_max_months caps how many months a benefit state pays (0 = unbounded); see the field comment in __post_init__.

death_benefit_factor scales the death-coverage benefit paid for the lives residing in this state (default 1.0 = no change). The aggregate death claim is occupancy-weighted: claim = (sum_s occ[s]*factor[s]) * claim_rate. It multiplies the benefit AMOUNT, not the decrement, so the death count is unchanged. A post-diagnosis state paying a richer death benefit (e.g. 2x after a cancer diagnosis) sets death_benefit_factor=2.0. Supported on the full path only (measure(full=True)); the fast path and the VFA path reject a non-default factor.

exit_after removes occupancy from the in-force set once a cohort’s sojourn in this state reaches exit_after months (default 0 = never). Semi-Markov only – it needs sojourn tracking, so the state must set duration_max. Distinct from benefit_max_months (which stops the payment but keeps the lives in force): exit_after ends the cover. A guaranteed-payout state that pays a fixed term and then lapses sets benefit_max_months (pay window) and exit_after (cover end) together.

매개변수:
class fastcashflow.Transition(rate, to=None, lump_sum=False, duration_dependent=False)[소스]#

One transition out of a state.

rate names an assumption rate – "mortality", "lapse", "waiver_incidence" and so on – evaluated by the engine and supplied to compile_state_model(). to is the destination state’s name when the transition moves occupancy to another transient state (waiver inception, recovery, reincidence), or None when it removes occupancy from the in-force set entirely (death, lapse).

lump_sum flags a transition that pays a one-off benefit when it fires – the ModelPoints.disability_benefit amount times the transitioning occupancy. It applies only to a transition with a destination; death and diagnosis lump sums stay on the coverage list.

duration_dependent flags a semi-Markov transition: the rate depends on the sojourn time in the source state (time since entering it), not just on the policy duration. The source state must have duration_max > 0 – the engine tracks per-cohort occupancy there. The rate function for a duration-dependent transition takes a fourth argument state_duration (months in source state).

매개변수:
  • rate (str)

  • to (str | None)

  • lump_sum (bool)

  • duration_dependent (bool)

fastcashflow.STATE_MODELS = mappingproxy({'WAIVER': StateModel(states=(State(name='active', premium=True, benefit=False, transitions=(Transition(rate='mortality', to=None, lump_sum=False, duration_dependent=False), Transition(rate='waiver_incidence', to='waiver', lump_sum=False, duration_dependent=False), Transition(rate='lapse', to=None, lump_sum=False, duration_dependent=False)), duration_max=0, benefit_max_months=0, mortality_rate='mortality', death_benefit_factor=1.0, exit_after=0), State(name='waiver', premium=False, benefit=False, transitions=(Transition(rate='mortality', to=None, lump_sum=False, duration_dependent=False),), duration_max=0, benefit_max_months=0, mortality_rate='mortality', death_benefit_factor=1.0, exit_after=0)), seating=(0, 1, 1)), 'WAIVER_PAIDUP': StateModel(states=(State(name='active', premium=True, benefit=False, transitions=(Transition(rate='mortality', to=None, lump_sum=False, duration_dependent=False), Transition(rate='waiver_incidence', to='waiver', lump_sum=False, duration_dependent=False), Transition(rate='lapse', to=None, lump_sum=False, duration_dependent=False)), duration_max=0, benefit_max_months=0, mortality_rate='mortality', death_benefit_factor=1.0, exit_after=0), State(name='waiver', premium=False, benefit=False, transitions=(Transition(rate='mortality', to=None, lump_sum=False, duration_dependent=False),), duration_max=0, benefit_max_months=0, mortality_rate='mortality', death_benefit_factor=1.0, exit_after=0), State(name='paidup', premium=False, benefit=False, transitions=(Transition(rate='mortality', to=None, lump_sum=False, duration_dependent=False), Transition(rate='lapse_paidup', to=None, lump_sum=False, duration_dependent=False)), duration_max=0, benefit_max_months=0, mortality_rate='mortality', death_benefit_factor=1.0, exit_after=0)), seating=(0, 1, 2))})#
fastcashflow.STATE_ACTIVE = 0#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

fastcashflow.STATE_WAIVER = 1#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

fastcashflow.STATE_PAIDUP = 2#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

Stochastic valuation#

fastcashflow.gmm.stochastic(model_points, basis, rate_scenarios)#

Value a portfolio under each economic scenario – the liability distribution.

rate_scenarios is either

  • a 1-D (n_scenarios,) array – one flat annual discount rate per scenario; or

  • a 2-D (n_scenarios, n_time) array – one discount-rate curve per scenario, an annual rate for each projection month.

The portfolio total of every figure is recorded under each scenario, so the distribution – mean, percentiles – can be read from the result. The projection runs once and a single parallel kernel sweeps the scenario axis (see module docstring); the settlement-pattern and cost-of-capital paths fall back to a per-scenario measure loop (full=False for the confidence-level RA, full=True for cost-of-capital, which the fast path does not compute). Cost-of-capital supports flat (1-D) rate_scenarios only.

매개변수:
반환 형식:

StochasticResult

class fastcashflow.StochasticResult(bel, ra, csm, loss_component)[소스]#

Per-scenario portfolio totals from a stochastic valuation.

Each array is (n_scenarios,) – the portfolio total of that figure under each scenario. Read the distribution off with mean() and percentile(), or from the arrays directly.

매개변수:
mean()[소스]#

The mean of each line across the scenarios.

반환 형식:

dict[str, float]

percentile(q)[소스]#

The q-th percentile of each line across the scenarios.

매개변수:

q (float)

반환 형식:

dict[str, float]

Input and output#

fastcashflow.read_model_points(path, coverages=None, calculation_methods=None)[소스]#

Read model points from a parquet, CSV, Excel or feather file.

Reads the portfolio without any basis – the model points and the actuarial basis are separate inputs. The basis enters only at the engine call (measure), which aligns its coverages to the portfolio’s coverage order.

The portfolio is two frames – a policies frame plus a coverages frame:

  • a policies frame (mp_id, issue_age, term_months, optional sex / count / state / issue_class / issue_date / premium / premium_term_months / premium_frequency_months / annuity_frequency_months / contract_boundary_months / product / channel), one row per policy. Any other column is read as a grouping attribute (portfolio_id, profitability_group, risk_class, region, …) into ModelPoints.attributes, for group() / group_of_contracts();

  • a coverages frame (mp_id, coverage, amount, optional premium / waiting / reduction_end / reduction_factor and the benefit step-up / escalation columns step_month / step_factor (a benefit step at a duration) / escalation_annual / escalation_cap (annual compounding growth, capped – the 체증형 escalating-benefits recipe in the cookbook)), one row per policy x coverage – so per-coverage rules (waiting, reduction and escalation) ride along, which a flat one-row-per-policy file cannot carry.

Pass them as read_model_points(policies, coverages=coverages_path, calculation_methods=...), or as a single .xlsx carrying policies and coverages sheets. The normalised two-frame shape mirrors a policy table joined to a coverage table – the form data arrives in from a policy system. calculation_methods is the company taxonomy file (CSV / parquet / feather / xlsx) – the third side of the split between portfolio (policies + coverages), basis (basis.xlsx) and catalogue (calculation_methods.csv).

The policies frame is the inception-time static spec – issue_age, term, sex, and so on. The in-force closing state (elapsed_months, prior_csm, lock_in_rate) belongs in a separate file read by read_inforce_state(). An elapsed_months column on the policies side is ignored and a UserWarning is emitted; do not encode the as-of date by mixing it into the static spec.

매개변수:
반환 형식:

ModelPoints

fastcashflow.read_vfa_model_points(path, *, calculation_methods=None)[소스]#

Read the account-value base of variable (VFA) contracts from a policies file.

This reads the part measured under the VFA model: the account value and its guarantee floors (GMDB / GMAB), all named policy columns (account_value, minimum_death_benefit, minimum_accumulation_benefit, minimum_crediting_rate). That base carries no coverage-code coverages, so it is a single policies frame. issue_age and term_months are required; the named policy / account columns are read if present.

Protection riders attached to a variable product (death / cancer / hospitalisation 특약) are separate coverages, read and measured on their own – a policies + coverages book through read_model_points() (GMM). So a <coverage>_benefit column is rejected here: a coverage encoded as a column is the lossy wide form, and coverages belong in their own frame which can hold the per-coverage waiting / reduction rules a flat column cannot.

매개변수:
반환 형식:

ModelPoints

fastcashflow.read_basis(path)[소스]#

Read the basis workbook into a per-segment Basis dict.

path is a single basis.xlsx workbook holding both the rate tables and the segment mapping (see the module header for the sheet layout). The segments sheet maps each (product, channel) to which tables it uses plus scalar parameters, with a _DEFAULTS row whose values blank cells inherit; the coverages sheet attaches rate-driven coverages to products.

Returns a SegmentedBasis (a dict subclass) keyed by the segment axes – (product, channel) by default, or whatever non-assumption columns the segments sheet declares (one axis, or three); .segment_axes records the axis names so measure() routes without a segment_by argument.

v1: the discount and inflation tables are read but used flat (their first entry); the per-segment dict is returned for the caller to value segment by segment.

매개변수:

path (Path | str)

반환 형식:

SegmentedBasis

fastcashflow.read_inforce_policies(path, coverages=None, calculation_methods=None)[소스]#

Read a single combined policies + in-force state file.

A self-contained snapshot at a settlement date – one file per valuation date, one row per surviving contract. Columns combine the permanent contract spec (issue_age, sex, term_months, premiums, benefits, …) and the closing state from the prior period (elapsed_months, count, prior_csm, lock_in_rate). This matches the Korean industry “보유계약 마감파일” pattern – one self-contained snapshot per period, no separate state file to keep in sync.

Returns a (ModelPoints, InforceState) tuple. The ModelPoints has the state’s elapsed_months and count already folded in; the InforceState carries prior_csm and lock_in_rate for the in-force valuation call:

mp, state = fcf.read_inforce_policies(
    "inforce_2026Q1.csv",
    coverages="coverages.csv",
    calculation_methods="calculation_methods.csv",
)
val = fcf.gmm.measure_inforce(mp, basis, state, period_months=3)

For the two-file equivalent (separate policies.csv + inforce_state.csv), see read_model_points() + read_inforce_state() + apply_inforce_state(). Both workflows produce valuation-ready inputs that give the same valuation: measure_inforce re-aligns the state by mp_id internally, so the answer does not depend on the state file’s row order. The returned InforceState is itself row-aligned to the model points here; in the two-file path the state object keeps its file order (only the model points are reordered by apply_inforce_state()), so call align_inforce_state() before slicing or reading state.prior_csm directly. Pick the form that fits the company’s extract pipeline.

Required columns: mp_id, elapsed_months, count, prior_csm, lock_in_rate, plus whatever the spec side of read_model_points() needs (issue_age, term_months, optional sex, premiums, <code>_benefit columns for wide form). Variance / movement analysis (roll_forward(), reconcile()) is unaffected – mp_id-based matching across periods works the same regardless of which reader built each snapshot.

매개변수:
반환 형식:

tuple[ModelPoints, InforceState]

fastcashflow.read_inforce_state(path)[소스]#

Read an in-force state file – the per-MP closing state from the prior reporting period.

The file has one row per model point with columns mp_id, elapsed_months, count, prior_csm and lock_in_rate. Reads .parquet, .csv, .xlsx or .feather / .arrow via _read_frame().

Pair with apply_inforce_state() to join the state onto a ModelPoints built from the static policies file, then pass the result to fastcashflow.gmm.measure_inforce() with the returned InforceState.

lock_in_rate is required to be uniform across rows in v1 – the engine takes a scalar locked-in rate. Cohort-aware per-MP rates are a future extension; for now the reader errors out if the column is not constant rather than silently dropping the per-row detail.

매개변수:

path (Path | str)

반환 형식:

InforceState

fastcashflow.apply_inforce_state(model_points, state)[소스]#

Return a ModelPoints with the state’s elapsed_months and count substituted in, joined on mp_id (see align_inforce_state() for the join rules).

Note this substitutes only elapsed_months / count onto the model points; the state’s prior_csm rides on the (separately passed) InforceState. measure_inforce() re-aligns that state by mp_id internally, so prior_csm cannot drift out of order.

매개변수:
반환 형식:

ModelPoints

fastcashflow.align_inforce_state(model_points, state)[소스]#

Return state reordered so its rows line up with model_points.

Every per-MP field of the returned state (elapsed_months, count, prior_csm, mp_id) is row-for-row aligned with the model points. When both carry mp_id the match is by mp_id – reordered when the two files are in different orders, and rejected when their id sets differ – so a misaligned period-close file cannot silently assign one contract’s state (including its prior CSM) to another. When the model points have no mp_id (a hand-built set), the rows are taken positionally after a length check; align them yourself in that case.

매개변수:
반환 형식:

InforceState

class fastcashflow.InforceState(mp_id, elapsed_months, count, prior_csm, lock_in_rate)[소스]#

Per-MP closing state from the prior reporting period.

The input layer for in-force / subsequent-measurement workflows. A fresh inforce_state.csv is produced at each period close from the company’s policy administration system and joined onto the static policies.csv to value the in-force at the next reporting date.

Fields:

  • mp_id – join key, matches the mp_id column on the policies file.

  • elapsed_months – months since each contract’s inception as of the valuation date (= valuation date - inception date).

  • count – in-force at the valuation date (the user has already scaled it down for past lapses); seats the projection.

  • prior_csm – closing CSM at month elapsed_months - period_months, the prior reporting date’s result carried into this period.

  • lock_in_rate – annual locked-in discount rate (Sec. B72(b)). Scalar in v1; per-MP cohort-aware rates are a future extension.

매개변수:
fastcashflow.read_scenarios(path)[소스]#

Read a stochastic scenario set from a file.

The file is a 2-D table – one row per scenario, one column per projection month, every cell a rate or return. Reads .parquet, .csv, .xlsx or .feather / .arrow via _read_frame().

Returns a numpy float64 array of shape (n_scenarios, n_time), or (n_scenarios,) when the file has a single column (flat-rate scenarios). The result is what measure_stochastic() and measure_tvog() accept as their scenarios / return_scenarios input.

Calibration – Hull-White, Vasicek, regime-switching, climate paths, etc. – is left to a separate scenario-generator step; this reader is just the storage / handover layer. For large scenario sets (thousands of paths) prefer .parquet or .feather over .xlsx.

매개변수:

path (Path | str)

반환 형식:

ndarray[tuple[Any, …], dtype[float64]]

fastcashflow.describe_basis(obj, *, file=None)[소스]#

Print the tree structure of a Basis (or read_basis dict).

Groups the fields by role – rates, economic / expense, risk adjustment, coverages / coverage types, state machine, other – so a reader can see what is inside the object without scanning every dataclass field.

Pass a single Basis to see one segment, or pass the dict returned by fastcashflow.io.read_basis() / fastcashflow.io.load_sample_basis() to also see the (product, channel) keys.

반환 형식:

None

fastcashflow.samples.model_points(template='gmm')[소스]#

Bundled sample model points (template="gmm" default, "vfa" for the variable account-value contracts).

매개변수:

template (str)

fastcashflow.samples.basis(template='gmm')[소스]#

Bundled sample basis. template="gmm" (default) returns the per-segment {(product, channel): Basis} dict; template="vfa" returns the single variable-contract Basis.

매개변수:

template (str)

fastcashflow.samples.inforce_state()[소스]#

Bundled sample in-force state (elapsed_months / count / prior_csm / …).

fastcashflow.samples.calculation_methods()[소스]#

Bundled sample coverage-code -> calculation-method taxonomy.

fastcashflow.samples.export(output_dir, template='gmm', format='csv', *, quiet=False)[소스]#

Write a starter set of input template files to output_dir.

template="gmm" writes basis.xlsx plus policies / coverages / calculation_methods / inforce_state and the combined inforce_policies (the period-close one-file form); template="vfa" writes the variable-contract basis.xlsx and policies. Edit them and read back with read_model_points() / read_basis().

format picks the data-file extension – "csv" (default), "parquet", "feather" or "xlsx". The basis is always a multi-sheet .xlsx workbook (it cannot be a flat table), so format applies only to the policies / coverages / state files. Use "parquet" for a portfolio large enough to stream with measure_stream().

Prints a tree of the files written – expanding basis.xlsx into its sheets – so it is clear what landed where. Pass quiet=True to suppress (e.g. in scripts). Returns the destination directory.

매개변수:
반환 형식:

Path

fastcashflow.samples.templates()[소스]#

The available export() / load template names (["gmm", "vfa"]).

반환 형식:

list[str]

fastcashflow.write_measurement(measurement, path, *, ids=None)[소스]#
fastcashflow.write_measurement(measurement, path, *, ids=None)
fastcashflow.write_measurement(measurement, path, *, ids=None)
fastcashflow.write_measurement(measurement, path, *, ids=None)

Write a measurement’s per-model-point headline results to parquet / CSV.

One row per model point, in model-point order. Pass ids for a leading id column so the results join back to policies. Dispatches on the measurement type – GMM writes bel / ra / csm / loss_component, PAA writes lrc / loss_component, VFA adds variable_fee / time_value. A new model registers its columns with @write_measurement.register in the module that defines its measurement type (so io.py stays free of the engine import).

매개변수:
반환 형식:

None

fastcashflow.gmm.measure_stream(input_path, output_dir, basis, *, coverages=None, calculation_methods=None, chunk_size=20000000, backend='cpu', id_column=None, validate_unique_mp_id=True)[소스]#

Stream a valuation through a parquet file one chunk at a time.

Reads the input in chunks of chunk_size model points, values each chunk with the fused fast path (measure(..., full=False)), and writes the results as a parquet dataset – one part-NNNNN.parquet file per chunk – under output_dir. Peak memory is a single chunk, so this scales past what an in-memory run could hold.

The input is a policies + coverages pair, mirroring read_model_points(): input_path is the policies parquet and coverages the coverages parquet. Each chunk of policies pulls its coverage rows by mp_id, so sorting the coverages file by mp_id lets the parquet reader prune row groups. A flat one-row-per-policy (wide) file is not accepted – it cannot carry the per-coverage waiting and reduction rules.

basis may be a single Basis (uniform portfolio) or a {(product, channel): Basis} dict, exactly as measure. With a dict each chunk routes its model points to their segment’s basis, so the policies parquet must carry product / channel columns.

id_column names the policies column written as the result id (so the output parquet joins back to a business key); it defaults to mp_id. The coverages are always joined on mp_id regardless.

validate_unique_mp_id (default True) scans the whole policies file once up front and rejects a duplicate mp_id – the same data error read_model_points() raises, which a chunk-by-chunk read would otherwise miss when the same id falls in different chunks. Set it False to skip the scan when the upstream extract already guarantees uniqueness.

Returns the total number of model points processed.

매개변수:
반환 형식:

int

fastcashflow.sample_data_dir()[소스]#

Return the on-disk path of the bundled sample data directory.

The directory contains sample_basis.xlsx, sample_policies.csv and sample_coverages.csv – the inputs behind load_sample_basis() and load_sample_model_points(). Use this to open the workbook in Excel and see what a complete fastcashflow input looks like before preparing your own.

반환 형식:

Path

fastcashflow.clear_codegen_cache(*, prune_older_than_days=None)[소스]#

Remove generated kernel sources from the on-disk codegen cache.

Each unique state-machine topology persists a fast_kernel_*.py (or fast_kernel_sm_*.py) source file plus its __pycache__ sidecars. Over a session that explores many topologies these accumulate. This helper sweeps them.

매개변수:

prune_older_than_days (float | None) – Only drop files whose mtime is older than this many days. None (the default) drops everything.

반환:

Number of files removed (sources and __pycache__ artefacts).

반환 형식:

int

참고

Disk-only: modules already imported in the current process continue to work via sys.modules. Codegen for a still-needed topology will transparently regenerate on the next call.

Visualisation#

The plotting helpers use matplotlib, which is included in the standard install.

fastcashflow.plot_liability(measurement, *, ax=None, title='Liability components over time')[소스]#

Plot the BEL, RA and CSM trajectories over the contract’s life.

Each line is the portfolio total of that component at each month.

매개변수:
반환 형식:

Axes

fastcashflow.plot_cashflows(measurement, *, period_months=12, ax=None, title='Projected cash flows')[소스]#

Plot projected premium income against claim and expense outgo.

The monthly cash flows are aggregated into buckets of period_months months – a policy year by default. Premiums are drawn upward, claims and expenses downward, and the marked line is the net cash flow each period. Bucketing keeps the front-loaded acquisition expense from dominating the chart while the cash-flow shape stays visible.

매개변수:
반환 형식:

Axes

fastcashflow.plot_csm_runoff(measurement, *, ax=None, title='CSM run-off')[소스]#

Plot the contractual service margin running off to zero.

The CSM is the unearned profit in the contract; its run-off is the profit emerging into the income statement as service is provided.

매개변수:
반환 형식:

Axes

fastcashflow.plot_risk_adjustment(measurement, basis, *, bands=(0.75, 0.85), ax=None, title='The risk adjustment as a confidence level')[소스]#

Plot the risk adjustment as a percentile of the liability distribution.

The confidence-level method models the liability arising from non-financial risk as a normal distribution centred on the best estimate; the risk adjustment is the margin from that mean out to a chosen percentile. This chart draws that normal distribution and shades the margin up to each confidence level in bands. It applies to the confidence-level method only.

매개변수:
반환 형식:

Axes

fastcashflow.plot_analysis_of_change(reconciliation, *, component='csm', ax=None, title=None)[소스]#

Plot one reporting period’s analysis of change as a waterfall.

component selects "bel", "ra" or "csm". The waterfall bridges the opening balance to the closing balance through the future-service, finance and release drivers.

매개변수:
반환 형식:

Axes

fastcashflow.plot_stochastic(result, *, line='bel', ax=None, bins=30, kde=True, title=None)[소스]#

Plot the distribution of a figure across the stochastic scenarios.

line selects "bel", "ra", "csm" or "loss_component". A smooth Gaussian kernel density estimate is drawn over the histogram unless kde is False; the dashed line marks the mean.

매개변수:
반환 형식:

Axes