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;countis 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 intoBasis.coverages(entryiof that tuple lives at codei). No code is reserved.coverage_amount[k]– the benefit amount of coveragek.coverage_offset–(n_mp+1,); policymp’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) andcoverage_reduction_end/coverage_reduction_factor(a benefit multiplier in force until a cut-off month). Both are CSR arrays aligned withcoverage_indexand default to off – no waiting, full benefit.The coverage list is built one of two ways.
benefitsis the general form: a{cov_idx: amount array}map keyed by coverage code (the index intoBasis.coverages). Or pass the CSR arrayscoverage_index/coverage_amount/coverage_offsetdirectly – 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).
- 매개변수:
benefits (dict[int, ndarray[tuple[Any, ...], dtype[float64]]] | None)
maturity_benefit (ndarray[tuple[Any, ...], dtype[float64]] | None)
annuity_payment (ndarray[tuple[Any, ...], dtype[float64]] | None)
disability_income (ndarray[tuple[Any, ...], dtype[float64]] | None)
disability_benefit (ndarray[tuple[Any, ...], dtype[float64]] | None)
surrender_base_amount (ndarray[tuple[Any, ...], dtype[float64]] | None)
contract_boundary_months (ndarray[tuple[Any, ...], dtype[int64]] | None)
premium_term_months (ndarray[tuple[Any, ...], dtype[int64]] | None)
premium_frequency_months (ndarray[tuple[Any, ...], dtype[int64]] | None)
annuity_frequency_months (ndarray[tuple[Any, ...], dtype[int64]] | None)
account_value (ndarray[tuple[Any, ...], dtype[float64]] | None)
minimum_crediting_rate (ndarray[tuple[Any, ...], dtype[float64]] | None)
minimum_death_benefit (ndarray[tuple[Any, ...], dtype[float64]] | None)
minimum_accumulation_benefit (ndarray[tuple[Any, ...], dtype[float64]] | None)
coverage_index (ndarray[tuple[Any, ...], dtype[int64]] | None)
coverage_amount (ndarray[tuple[Any, ...], dtype[float64]] | None)
coverage_offset (ndarray[tuple[Any, ...], dtype[int64]] | None)
coverage_waiting (ndarray[tuple[Any, ...], dtype[int64]] | None)
coverage_reduction_end (ndarray[tuple[Any, ...], dtype[int64]] | None)
coverage_reduction_factor (ndarray[tuple[Any, ...], dtype[float64]] | None)
coverage_step_month (ndarray[tuple[Any, ...], dtype[int64]] | None)
coverage_step_factor (ndarray[tuple[Any, ...], dtype[float64]] | None)
coverage_escalation_annual (ndarray[tuple[Any, ...], dtype[float64]] | None)
coverage_escalation_cap (ndarray[tuple[Any, ...], dtype[float64]] | None)
elapsed_months (ndarray[tuple[Any, ...], dtype[int64]] | None)
product (ndarray | None)
channel (ndarray | None)
calculation_methods (dict[str, CalculationMethod] | None)
issue_date (ndarray | None)
mp_id (ndarray | None)
- 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 derivedissue_year(calendar year ofissue_date); the named source fieldsproduct/channel/issue_date; then any key inattributes(portfolio_id, profitability_group, risk_class, …). RaisesKeyErrorlisting the available axes when the name is unknown.
- 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.
benefitsis the per-coverage benefit-amount map keyed by coverage code (the index intoBasis.coverages); pass{0: 1_000_000.0}to attach the benefit to the first registered coverage. None means no claim benefits.- 매개변수:
issue_age (float)
premium (float)
term_months (int)
maturity_benefit (float)
annuity_payment (float)
disability_income (float)
disability_benefit (float)
premium_term_months (int | None)
premium_frequency_months (int)
annuity_frequency_months (int)
account_value (float)
minimum_crediting_rate (float)
minimum_death_benefit (float)
minimum_accumulation_benefit (float)
count (float)
sex (int)
state (int)
calculation_methods (dict[str, CalculationMethod] | None)
- 반환 형식:
- subset(indices)[소스]#
Return a new
ModelPointscarrying the rows atindices.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, andcoverage_offsetis reset to the new running cumulative sum. Used byfastcashflow.gmm.measure()to split a portfolio by (product, channel) before per-segment measurement.indicesis 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.- 반환 형식:
- 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 – seeRateFn(infastcashflow._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 (seeannual_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 passesissue_classintof, 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
RateFnshape asmortality_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 viafastcashflow.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), aEXPENSE_BASESdispatch key and a numeric value. The engine projects every row throughderive_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_fixedandlae_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 theinflation_tablessheet (analogous todiscount_annual/discount_tables). Does not apply to the two_initbases (one-time at t=0) or topremium_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 asmortality_annual.Nonemeans no transitions: every model point keeps its input state for the whole projection. The spelling matches the standard actuarial termincidence– 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_vfauses it directly, but the GMMcl_margininmeasuredoes 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; settingexpense_cvon 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 throughmeasure(..., 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.
Nonesettles 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: entryilives at codei, the integer the portfolio’scoverage_indexCSR uses to index this tuple. A contract’s death coverage, if any, is just one entry whoserate_tabletypically 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
StateModeldeclaring the transient states, their transitions and which states pay premium or a benefit.Noneuses the default active / waiver model (WAIVER_MODEL); thewaiver_incidence_annualrate 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.
- 매개변수:
code (str) – The coverage’s code label. The engine works in the integer grid index this factorises to; the label is what the model-point file names a coverage by.
rate (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-rate callable, the same signature as
mortality_annual; the engine converts it to a monthly rate (seeannual_to_monthly()).
참고
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
CalculationMethodtaxonomy (thecalculation_methods.csvfile, surfaced asfastcashflow.modelpoints.ModelPoints.calculation_methods). Those two flags do not live onCoverageRate.
- 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
basisand contributes itsvalueinto the kernel-side expense primitives. Inflation is not a row attribute – it lives onBasis(expense_inflation, matching the waydiscount_annuallives onBasis), 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_traceanddescribe_basisecho 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 intopro_rata(proportional to a base amount) orfixed(per-policy flat).value (float) – Numeric value – a fraction (0..1) for the
_pro_ratabases, an amount per policy for the_fixedbases.
참고
The basis decides whether the global
expense_inflationapplies:gamma_fixedandlae_pro_ratarecur every month and so inflate; the twoalpha_*bases pay once att=0andbeta_pro_ratarides the premium itself, so a second inflation factor would double-count.
- fastcashflow.derive_expense_components(expense_items, n_time, inflation_index=None)[소스]#
Project
expense_itemsonto the five kernel-side primitives.Returns
(alpha_pro_rata, alpha_fixed, beta_pro_rata, gamma_fixed, lae_pro_rata):alpha_pro_rata– sum ofvalueoveralpha_pro_ratarows. Paid att=0on annualized premium.alpha_fixed– sum ofvalueoveralpha_fixedrows. Paid att=0per policy.beta_pro_rata– sum ofvalueoverbeta_pro_ratarows. Charged each premium-paying month on the actual premium.gamma_fixed[t]– per-month per-policy maintenance: eachgamma_fixedrow contributesvalue / 12 * inflation_index[t].lae_pro_rata[t]– LAE (Loss Adjustment Expense) fraction: eachlae_pro_ratarow contributesvalue * inflation_index[t]. Applied to the month’s claim + morbidity + disability total.
inflation_indexis the(n_time,)per-month inflation multiplier produced byfastcashflow.curves.inflation_index(); a scalar economicexpense_inflation = igivesinflation_index[t] = (1+i)^(t/12)and a per-year curve compounds across years. PassNonefor a no-inflation basis (every month equal to 1.0).
- 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)*_pathtrajectories. 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-policyfull=Truerun needs ~100 GB and will OOM on a typical box.full=Falseis the fused, memory-minimal fast path – it fills only the headline (*_pathareNone) at a few hundred bytes per model point, and is the right choice for large-scale valuation; reservefull=Truefor movement analysis or per-segment / chunked runs.basismay be a singleBasis(uniform portfolio) or a{(product, channel): Basis}dict; with a dict each segment is routed to its own basis.segment_bynames the routing axes (resolved viaModelPoints.axis(), so anyattributescolumn works) and the dict keys are tuples of those axes in order. Left asNone(the default) it is taken from the basis: aSegmentedBasisfromread_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; passingsegment_byexplicitly overrides. Cost scales with the number of distinct segments, not the number of axes.backend("cpu"/"gpu") anddiscount_curveapply to the fast path only.
- fastcashflow.gmm.measure_aggregate(model_points, basis, *, chunk_size=200000)[소스]#
Portfolio-aggregate
full=Truemeasurement 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 ofchunk_sizemodel points and accumulates only that(n_time+1,)sum, so peak memory isO(chunk_size x n_time)regardless ofn_mp.Returns an
AggregateMeasurement(scalar totals + aggregatebel_path/ra_path/csm_path). For the per-model-point detail (movement, in-force slicing) usemeasure()on a book small enough to hold every trajectory.basismay be a singleBasisor a per-segment dict, routed per chunk exactly asmeasure()routes it.- 매개변수:
- 반환 형식:
- 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_monthsduration, and the prior period’s closing CSM (state.prior_csm) is carried forward – accreted atstate.lock_in_rateand released over coverage units acrossperiod_months(default 12).The
bel/raare re-based to the valuation date: the projection runs from inception, so the slice is scaled bycount / 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 theamount_per_policy/amount_per_unitsurrender value). The one approximation is thecum_premium_factorsurrender 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. AUserWarningfires only in that mode (basis carries acum_premium_factorsurrender curve and anyelapsed_months > 0); the contractualamount_per_policy/amount_per_unitcurves are linear in the in-force and re-base exactly, so they are the production-grade surrender input and warn-free.stateis theInforceStatereturned byread_inforce_policies()(it carriesprior_csm/lock_in_rate, plus theelapsed_months/countreconciled ontomodel_points).model_pointsandstatemust be reconciled byapply_inforce_state()first –read_inforce_policiesreturns the pair already reconciled; the two-file path (read_model_points+read_inforce_state) calls it explicitly. A model_points whoseelapsed_months/countdisagree withstateis 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=Falsereturns just the headline numbers (faster).Sec. 44 onerous unlocking and experience adjustments are not yet folded in here (
loss_componentis zero in this mode); useroll_forward()with prior and current measurements for the full movement.- 매개변수:
model_points (ModelPoints)
basis (Basis)
state (InforceState)
period_months (int | None)
full (bool)
- 반환 형식:
- 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 areNone.bel_path/ra_path/csm_pathare the(n_mp, n_time+1)trajectories whose column 0 is the inception value (sobel == bel_path[:, 0]when full). The CSM roll-forward decomposes ascsm_path[:, t+1] = csm_path[:, t] + csm_accretion[:, t] - csm_release[:, t].licis the liability for incurred claims – zero unless a claims settlement pattern is set, which also discounts claims to their payment dates in the BEL.- 매개변수:
csm_accretion (ndarray[tuple[Any, ...], dtype[float64]] | None)
csm_release (ndarray[tuple[Any, ...], dtype[float64]] | None)
cashflows (Cashflows | None)
discount_bom (ndarray[tuple[Any, ...], dtype[float64]] | None)
discount_mid (ndarray[tuple[Any, ...], dtype[float64]] | None)
model_points (ModelPoints | None)
group_labels (ndarray | None)
- class fastcashflow.AggregateMeasurement(bel, ra, csm, loss_component, bel_path, ra_path, csm_path)[소스]#
Portfolio-aggregate GMM trajectories – the scalable
full=Trueview.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,)aggregatebel_path/ra_path/csm_path(column 0 is inception, sobel == bel_path[0]). It is whatmeasure_aggregate()returns, computed in bounded memory so it works where a per-model-pointmeasure(full=True)would OOM.
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 returnrfloored at any guaranteed rateg) less the variable feef– fromAV[0]= the model point’saccount_value. A surrender pays the account value; a death exit paysmax(account value, minimum_death_benefit)(GMDB) and the survivors reaching term paymax(account value, minimum_accumulation_benefit)(GMAB), so the excess over the account value is each guarantee’s intrinsic cost. Whenreturn_scenariosis 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, andtime_valuerecords that amount per model point.- 매개변수:
- 반환 형식:
- 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,raandcsmare(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_feeis the present value of the entity’s fee – its share of the underlying items.loss_componentandtime_valueare(n_mp,)inception figures; the time value of the guarantee drives the CSM but is reported separately frombel.- 매개변수:
account_value_path (ndarray[tuple[Any, ...], dtype[float64]] | None)
csm_accretion (ndarray[tuple[Any, ...], dtype[float64]] | None)
csm_release (ndarray[tuple[Any, ...], dtype[float64]] | None)
discount_bom (ndarray[tuple[Any, ...], dtype[float64]] | None)
cashflows (Cashflows | None)
model_points (ModelPoints | None)
group_labels (ndarray | None)
- fastcashflow.vfa.tvog(model_points, basis, return_scenarios)#
Measure the time value of a VFA contract’s minimum guarantee.
return_scenariosis an(n_scenarios, n_time)array of monthly underlying-items returns – one path per scenario,n_timebeing the projection horizon. The model points must carry a non-zerominimum_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).- 매개변수:
- 반환 형식:
- class fastcashflow.TVOGResult(guarantee_cost, intrinsic_value, time_value)[소스]#
The cost of a minimum guarantee, split into intrinsic and time value.
guarantee_costis the(n_scenarios,)present value of the guarantee under each scenario – its distribution.intrinsic_valueis the cost in the central (deterministic) scenario;time_valueis the TVOG, the mean cost in excess of the intrinsic value; andtotal_valueis their sum, the guarantee’s full economic 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 runningmeasure(), so a 1M-row portfolio does not pay for the trace of one contract.basis (Basis | dict) – A single
Basis, or the dict returned byfastcashflow.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.
Nonewrites tosys.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 eachmeasure()so the diff cost stays proportional to one MP.basis_a (Basis | dict) – Two basis to compare. Either a
Basisor the dict fromfastcashflow.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
Basisor the dict fromfastcashflow.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.
Nonewrites tosys.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 att, 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 resultingBEL[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 runningmeasure().basis (Basis | dict) – A
Basisor the dict fromfastcashflow.io.read_basis()(routed by the row’s(product, channel)likeshow_trace()).months (list[int] | None) – Anchor months at which to unroll the recursion.
Noneuses{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_unitsis 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().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]fromcsm[t-1]).Noneuses{1, 12, term//2, term}. Out-of-range entries are ignored.t = 0is the seed and is always printed regardless ofmonths.
- 반환 형식:
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, runsmeasure_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) whenreturn_scenariosis supplied. Use it on direct-participation contracts;show_trace()traces the GMMmeasureand does not cover the account-value mechanic.
- 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 GMMmeasure(BEL / RA / CSM).
Reinsurance#
- fastcashflow.reinsurance.measure(model_points, basis, treaty)#
Measure a reinsurance contract held over a direct portfolio.
treatydescribes 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).- 매개변수:
model_points (ModelPoints)
basis (Basis)
treaty (Treaty)
- 반환 형식:
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,raandcsmare(n_mp,)inception figures –belis the present value of reinsurance premiums less recoveries (a net cost when positive),rais the risk transferred,csmis the inception net cost or gain (may be negative). The trajectory fields are populated only on the full path;csm_pathreconciles ascsm_path[:, t+1] = csm_path[:, t] + csm_accretion[:, t] - csm_release[:, t].- 매개변수:
csm_accretion (ndarray[tuple[Any, ...], dtype[float64]] | None)
csm_release (ndarray[tuple[Any, ...], dtype[float64]] | None)
reinsurance_premium (ndarray[tuple[Any, ...], dtype[float64]] | None)
cashflows (Cashflows | None)
discount_bom (ndarray[tuple[Any, ...], dtype[float64]] | None)
model_points (ModelPoints | None)
group_labels (ndarray | None)
Pricing#
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.10for 10%); must satisfy0 <= margin < 1.csm– an absolute target CSM (profit) per model point.
Every product field of
model_pointsis used as given – onlypremiumis ignored, since it is the unknown being solved for. Returns the solved premium per model point, shape(n_mp,).
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.- 반환 형식:
- 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_componentis(n_mp,)– the onerous loss at inception.insurance_service_resultis revenue less service expense;insurance_finance_expenseis signed (positive an expense). The CSM analysis of change reconciles ascsm_opening + csm_accretion - csm_release = csm_closing(the CSM columns are zero for a PAA measurement, which has no CSM).insurance_finance_expenseis also disaggregated by source (IFRS 17 B130-B136) intobel_finance_expense(finance on the estimates of future cash flows),ra_finance_expense(finance on the risk adjustment) andcsm_finance_expense(the CSM interest accreted at the locked-in rate, B72). The three sum toinsurance_finance_expenseup 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.- 매개변수:
insurance_revenue (ndarray[tuple[Any, ...], dtype[float64]])
insurance_service_expense (ndarray[tuple[Any, ...], dtype[float64]])
insurance_service_result (ndarray[tuple[Any, ...], dtype[float64]])
insurance_finance_expense (ndarray[tuple[Any, ...], dtype[float64]])
bel_finance_expense (ndarray[tuple[Any, ...], dtype[float64]])
ra_finance_expense (ndarray[tuple[Any, ...], dtype[float64]])
csm_finance_expense (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_monthsmonths, 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) andrevised_at(the month it takes effect); in-force experience byactual_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) andexperience_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-totalReconciliationin the layout of IFRS 17 paragraph 101. Run-off rows are shown negative, so opening plus every row equals closing. A list ofPAAPeriodMovementorVFAPeriodMovementis 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_accretionin place of*_interest).*_interest/csm_accretionis the unwind of discount at the locked-in rate;*_releaseis the expected run-off over the period.*_assumption_changeand*_experienceare 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_recognisedis 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_serviceis the assumption and experience effect;*_financeis the interest unwind;*_releaseis the run-off, shown negative – so opening plus every row equals closing.- 매개변수:
month_start (int)
month_end (int)
bel_opening (float)
bel_future_service (float)
bel_finance (float)
bel_release (float)
bel_closing (float)
ra_opening (float)
ra_future_service (float)
ra_finance (float)
ra_release (float)
ra_closing (float)
csm_opening (float)
csm_future_service (float)
csm_finance (float)
csm_release (float)
csm_closing (float)
loss_component_recognised (float)
- 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_accretionis the unwind at the underlying-items return;*_releaseis 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.
*_financeis the unwind at the underlying-items return;*_releaseis 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.
byis 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 fromloss_component) is passed as an array instead – annp.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 ofby.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 byroll_forward(),reconcile()andreport(). Itsgroup_labelsattribute carries the composite label of each row, so a caller can map a group back to its key (e.g."|"-split agroup_of_contracts()label into portfolio / cohort / profitability) without rebuilding the keys;group_sizescarries the number of model points in each group (model-point rows, not the policy count – they differ when a model point’scountstands 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 runsgroup(), 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 bygroup()’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 fromissue_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=Truemeasurement.- 매개변수:
- 반환 형식:
- fastcashflow.transition(measurement, fair_value)[소스]#
Re-set the CSM on the IFRS 17 fair value transition basis.
measurementis a measurement of the in-force book at the transition date – its inception column being that date.fair_valueis the(n_mp,)fair value of each contract or group. The CSM becomesmax(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()andreport().- 매개변수:
measurement (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.
statesare the transient states; position fixes the kernel state index, and state 0 is the issue state.seatingmaps a model point’s input contract state – theModelPoints.statecode (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.
premiumflags a premium-paying state – the level and single premium accrue on the occupancy of the states so flagged.benefitflags a benefit-paying state – theModelPoints.disability_incomeamount is paid each month its occupancy is held (disability income on a disabled state).transitionsare 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_maxswitches the state to a semi-Markov model. When set toD > 0, the engine tracksDmonthly cohorts of in-force in this state (cohort 0 entered this month, cohort 1 entered last month, and cohortD - 1absorbs everyone who has been hereD - 1months or longer). Transitions withduration_dependent=Truethen 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 default0keeps the state Markov (a single cohort, identical to the pre-Phase-(c) behaviour).mortality_rateroutes 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 viaBasis.state_mortality_annual.benefit_max_monthscaps how many months abenefitstate pays (0= unbounded); see the field comment in__post_init__.death_benefit_factorscales the death-coverage benefit paid for the lives residing in this state (default1.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) setsdeath_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_afterremoves occupancy from the in-force set once a cohort’s sojourn in this state reachesexit_aftermonths (default0= never). Semi-Markov only – it needs sojourn tracking, so the state must setduration_max. Distinct frombenefit_max_months(which stops the payment but keeps the lives in force):exit_afterends the cover. A guaranteed-payout state that pays a fixed term and then lapses setsbenefit_max_months(pay window) andexit_after(cover end) together.
- class fastcashflow.Transition(rate, to=None, lump_sum=False, duration_dependent=False)[소스]#
One transition out of a state.
ratenames an assumption rate –"mortality","lapse","waiver_incidence"and so on – evaluated by the engine and supplied tocompile_state_model().tois the destination state’s name when the transition moves occupancy to another transient state (waiver inception, recovery, reincidence), orNonewhen it removes occupancy from the in-force set entirely (death, lapse).lump_sumflags a transition that pays a one-off benefit when it fires – theModelPoints.disability_benefitamount times the transitioning occupancy. It applies only to a transition with a destination; death and diagnosis lump sums stay on the coverage list.duration_dependentflags 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 haveduration_max > 0– the engine tracks per-cohort occupancy there. The rate function for a duration-dependent transition takes a fourth argumentstate_duration(months in source state).
- 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_scenariosis eithera 1-D
(n_scenarios,)array – one flat annual discount rate per scenario; ora 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
measureloop (full=Falsefor the confidence-level RA,full=Truefor cost-of-capital, which the fast path does not compute). Cost-of-capital supports flat (1-D) rate_scenarios only.- 매개변수:
- 반환 형식:
- 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 withmean()andpercentile(), or from the arrays directly.- 매개변수:
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, optionalsex/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, …) intoModelPoints.attributes, forgroup()/group_of_contracts();a coverages frame (
mp_id,coverage,amount, optionalpremium/waiting/reduction_end/reduction_factorand the benefit step-up / escalation columnsstep_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.xlsxcarryingpoliciesandcoveragessheets. The normalised two-frame shape mirrors a policy table joined to a coverage table – the form data arrives in from a policy system.calculation_methodsis 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(). Anelapsed_monthscolumn on the policies side is ignored and aUserWarningis emitted; do not encode the as-of date by mixing it into the static spec.- 매개변수:
- 반환 형식:
- 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_ageandterm_monthsare 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>_benefitcolumn 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.- 매개변수:
- 반환 형식:
- fastcashflow.read_basis(path)[소스]#
Read the basis workbook into a per-segment
Basisdict.pathis a singlebasis.xlsxworkbook holding both the rate tables and the segment mapping (see the module header for the sheet layout). Thesegmentssheet maps each (product, channel) to which tables it uses plus scalar parameters, with a_DEFAULTSrow whose values blank cells inherit; thecoveragessheet attaches rate-driven coverages to products.Returns a
SegmentedBasis(adictsubclass) keyed by the segment axes –(product, channel)by default, or whatever non-assumption columns the segments sheet declares (one axis, or three);.segment_axesrecords the axis names someasure()routes without asegment_byargument.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.
- 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. TheModelPointshas the state’selapsed_monthsandcountalready folded in; theInforceStatecarriesprior_csmandlock_in_ratefor 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), seeread_model_points()+read_inforce_state()+apply_inforce_state(). Both workflows produce valuation-ready inputs that give the same valuation:measure_inforcere-aligns the state by mp_id internally, so the answer does not depend on the state file’s row order. The returnedInforceStateis 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 byapply_inforce_state()), so callalign_inforce_state()before slicing or readingstate.prior_csmdirectly. 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 ofread_model_points()needs (issue_age,term_months, optionalsex, premiums,<code>_benefitcolumns 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.- 매개변수:
- 반환 형식:
- 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_csmandlock_in_rate. Reads.parquet,.csv,.xlsxor.feather/.arrowvia_read_frame().Pair with
apply_inforce_state()to join the state onto aModelPointsbuilt from the static policies file, then pass the result tofastcashflow.gmm.measure_inforce()with the returnedInforceState.lock_in_rateis 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)
- 반환 형식:
- fastcashflow.apply_inforce_state(model_points, state)[소스]#
Return a
ModelPointswith the state’selapsed_monthsandcountsubstituted in, joined onmp_id(seealign_inforce_state()for the join rules).Note this substitutes only
elapsed_months/countonto the model points; the state’sprior_csmrides on the (separately passed)InforceState.measure_inforce()re-aligns that state by mp_id internally, so prior_csm cannot drift out of order.- 매개변수:
model_points (ModelPoints)
state (InforceState)
- 반환 형식:
- fastcashflow.align_inforce_state(model_points, state)[소스]#
Return
statereordered so its rows line up withmodel_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 carrymp_idthe 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 nomp_id(a hand-built set), the rows are taken positionally after a length check; align them yourself in that case.- 매개변수:
model_points (ModelPoints)
state (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.csvis produced at each period close from the company’s policy administration system and joined onto the staticpolicies.csvto value the in-force at the next reporting date.Fields:
mp_id– join key, matches themp_idcolumn 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 monthelapsed_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,.xlsxor.feather/.arrowvia_read_frame().Returns a numpy
float64array of shape(n_scenarios, n_time), or(n_scenarios,)when the file has a single column (flat-rate scenarios). The result is whatmeasure_stochastic()andmeasure_tvog()accept as theirscenarios/return_scenariosinput.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
.parquetor.featherover.xlsx.
- 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
Basisto see one segment, or pass the dict returned byfastcashflow.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-contractBasis.- 매개변수:
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"writesbasis.xlsxpluspolicies/coverages/calculation_methods/inforce_stateand the combinedinforce_policies(the period-close one-file form);template="vfa"writes the variable-contractbasis.xlsxandpolicies. Edit them and read back withread_model_points()/read_basis().formatpicks the data-file extension –"csv"(default),"parquet","feather"or"xlsx". The basis is always a multi-sheet.xlsxworkbook (it cannot be a flat table), soformatapplies only to the policies / coverages / state files. Use"parquet"for a portfolio large enough to stream withmeasure_stream().Prints a tree of the files written – expanding
basis.xlsxinto its sheets – so it is clear what landed where. Passquiet=Trueto suppress (e.g. in scripts). Returns the destination directory.
- fastcashflow.samples.templates()[소스]#
The available
export()/ load template names (["gmm", "vfa"]).
- 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
idsfor a leadingidcolumn so the results join back to policies. Dispatches on the measurement type – GMM writesbel/ra/csm/loss_component, PAA writeslrc/loss_component, VFA addsvariable_fee/time_value. A new model registers its columns with@write_measurement.registerin the module that defines its measurement type (so io.py stays free of the engine import).
- 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_sizemodel points, values each chunk with the fused fast path (measure(..., full=False)), and writes the results as a parquet dataset – onepart-NNNNN.parquetfile per chunk – underoutput_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_pathis the policies parquet andcoveragesthe coverages parquet. Each chunk of policies pulls its coverage rows bymp_id, so sorting the coverages file bymp_idlets 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.basismay be a singleBasis(uniform portfolio) or a{(product, channel): Basis}dict, exactly asmeasure. With a dict each chunk routes its model points to their segment’s basis, so the policies parquet must carryproduct/channelcolumns.id_columnnames the policies column written as the resultid(so the output parquet joins back to a business key); it defaults tomp_id. The coverages are always joined onmp_idregardless.validate_unique_mp_id(defaultTrue) scans the whole policies file once up front and rejects a duplicatemp_id– the same data errorread_model_points()raises, which a chunk-by-chunk read would otherwise miss when the same id falls in different chunks. Set itFalseto skip the scan when the upstream extract already guarantees uniqueness.Returns the total number of model points processed.
- fastcashflow.sample_data_dir()[소스]#
Return the on-disk path of the bundled sample data directory.
The directory contains
sample_basis.xlsx,sample_policies.csvandsample_coverages.csv– the inputs behindload_sample_basis()andload_sample_model_points(). Use this to open the workbook in Excel and see what a complete fastcashflow input looks like before preparing your own.- 반환 형식:
- 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(orfast_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).- 반환 형식:
참고
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.
- 매개변수:
measurement (GMMMeasurement)
ax (Axes | None)
title (str)
- 반환 형식:
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_monthsmonths – 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.- 매개변수:
measurement (GMMMeasurement)
period_months (int)
ax (Axes | None)
title (str)
- 반환 형식:
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.
- 매개변수:
measurement (GMMMeasurement)
ax (Axes | None)
title (str)
- 반환 형식:
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.- 매개변수:
measurement (GMMMeasurement)
basis (Basis)
ax (Axes | None)
title (str)
- 반환 형식:
Axes
- fastcashflow.plot_analysis_of_change(reconciliation, *, component='csm', ax=None, title=None)[소스]#
Plot one reporting period’s analysis of change as a waterfall.
componentselects"bel","ra"or"csm". The waterfall bridges the opening balance to the closing balance through the future-service, finance and release drivers.- 매개변수:
reconciliation (Reconciliation)
component (str)
ax (Axes | None)
title (str | None)
- 반환 형식:
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.
lineselects"bel","ra","csm"or"loss_component". A smooth Gaussian kernel density estimate is drawn over the histogram unlesskdeisFalse; the dashed line marks the mean.- 매개변수:
result (StochasticResult)
line (str)
ax (Axes | None)
bins (int)
kde (bool)
title (str | None)
- 반환 형식:
Axes