-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathifrs.py
More file actions
297 lines (215 loc) · 7.47 KB
/
ifrs.py
File metadata and controls
297 lines (215 loc) · 7.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
"""Source module for IFRS17 CSM amortization simulation
This module contains formulas to simulate amortization of
contract service margin (CSM) defined in IFRS17.
This module is a mix-in module to projection module in nestedlife project.
"""
def AccumCF(t):
"""Accumulated cashflows"""
return -NetInsurAssets(t)
def ActualNetCF(t):
"""Acutal net cashflow"""
return NetInsurCF(t) + IntAccumCF(t)
#%% The statement of Financial Posisition
def NetBalance(t):
"""Net insurance assets plus accumulated cashflows."""
return NetInsurAssets(t) + AccumCF(t)
def NetInsurAssets(t):
"""Net Insurance Assets or Liabilities
Warnings:
The liabilities for incurred claims are not implemented.
"""
return (PV_FutureCF(t)
- RiskAdjustment(t)
- CSM(t))
def PV_FutureCF(t):
"""Present value of future cashflows"""
return PV_Cashflow(t, t, t)
def RiskAdjustment(t):
"""Risk Adjustment
Warnings:
To be implemented
"""
return 0
#%% CSM Calculations
def CSM_Unfloored(t):
"""Unfloored CSM (38, 44)"""
if t == 0:
# Initial recognition (38)
return PV_FutureCF(t) - RiskAdjustment(t)
else:
# Subsequent recognition (44)
return (CSM_Unfloored(t-1)
+ IntAccrCSM(t-1)
+ AdjCSM_FlufCF(t-1)
- TransServices(t-1))
def CSM(t):
"""floored CSM (38, 44)"""
if t == 0:
# Initial recognition (38)
return max(0, PV_FutureCF(t) - RiskAdjustment(t))
else:
# Subsequent recognition (44)
return max(0, (CSM(t - 1)
+ IntAccrCSM(t - 1)
+ AdjCSM_FlufCF(t - 1)
- TransServices(t - 1)))
def LossComp(t):
"""Loss Component"""
if t == 0:
# Initial recognition
return - min(0, PV_FutureCF(t) - RiskAdjustment(t))
else:
# Subsequent recognition
return max(0, LossComp(t - 1) - AdjLCO_FulfCF(t - 1))
def Incr_LossComp(t):
"""Increase in Loss Component"""
if t == 0:
return LossComp(t)
else:
return max(0, LossComp(t) - LossComp(t - 1))
def AdjLCO_FulfCF(t):
"""Adjustment to Loss Component for changes in fulfilment cashflows"""
if LossComp(t) > 0:
return min(LossComp(t), EstClaim(t) + EstExps(t) + RelsRiskAdj(t))
else:
return 0
def IntAccrCSM(t):
"""Interest accreted on CSM (44(b))"""
return CSM(t) * DiscRate(t, 0)
def AdjCSM_FlufCF(t):
"""Adjustment to CSM for changes in fulfilment cashflows (44(c)->B96-B100)
Warnings:
Only B96(b) changes in PV of the future cashflows are implemented.
TODO: Risk Adjustment is yet to be implemented. At the momement
this adjustment only considers present value of future cashflows.
TODO: Loss component for onerous contracts are yet to be implemented.
At the momemnt this adjustment allows negative CSM.
"""
return PV_Cashflow(t + 1, t + 1, 0) - PV_Cashflow(t, t + 1, 0)
def PV_Cashflow(t, t_at, t_rate):
"""Present value of future cashflows
This formula takes 3 time parameters.
The projection starts from `t`, and the projected cashflows are
discounted back to `t_at`.
The discount rates applied are the ones at `t_rate`.
Args:
t: Time from which the projection
t_at: Time discount rates at which are used.
t_rate: Time to which the cashflows are discounted.
"""
return InnerProj(t).PresentValue(t_rate).PV_NetCashflow(t_at)
def TransServices(t):
"""Transfer of services (44(e)->B119)
"""
csm_pre_rel = (CSM(t)
+ IntAccrCSM(t)
+ AdjCSM_FlufCF(t))
diff_covunits = CovUnitsBeg1(t) * (1 + InnerProj(0).scen.DiscRate(t))
pv_sumcovunits_end = PV_SumCovUnits(t + 1, 0)
return csm_pre_rel * diff_covunits / (diff_covunits + pv_sumcovunits_end)
def CovUnitsBeg1(t):
"""The number of coverage units at `t` after new business"""
return InsurIF_Beg1(t)
def CovUnitsEnd(t):
"""The number of coverage units at `t`"""
return InsurIF_End(t)
def PV_SumCovUnits(t, t_rate):
"""Present value of cumulatvie coverage units
The non-economic assumptions used for future estimation are the
current estimate at time `t`.
The discount rates used are the ones at time `t_rate`.
"""
return InnerProj(t).PresentValue(t_rate).PV_SumInsurIF(t)
#%% The statement of Financial Performance
def ProfitBefTax(t):
"""IFRS Profit before tax"""
return InsServiceResult(t) + InsurFinIncomeExps(t)
def InsServiceResult(t):
"""Insurance Service Result (80(a), 83-86)"""
return InsurRevenue(t) - InsurServiceExps(t)
def InsurFinIncomeExps(t):
"""Insurance Finance Income or Expenses (80(b), 87-92, B128-B136)
Warning:
Accounting Policy Choice 88(b) not implemented.
"""
chg_discrate = (PV_Cashflow(t + 1, t + 1, t + 1)
- PV_Cashflow(t + 1, t + 1, t))
return (EstIntOnCF(t) + chg_discrate
- IntAccrCSM(t) + IntAccumCF(t))
def InsurRevenue(t):
"""Insurance Revenue (82-85, B120-B125)"""
return (EstClaim(t)
+ EstExps(t)
+ RelsRiskAdj(t)
+ TransServices(t)
+ AmortAcqCashflow(t)
- AdjLCO_FulfCF(t))
def EstPremIncome(t):
"""Expected Premium Income"""
return InnerProj(t).PremIncome(t)
def EstAcqCashflow(t):
"""Expected Acquisition Cashflow"""
est = InnerProj(t)
return (est.ExpsCommInit(t)
+ est.ExpsCommRen(t)
+ est.ExpsAcq(t))
def EstIntOnCF(t):
"""Expected Interest on future cashflows"""
return InnerProj(t).PresentValue(t).InterestNetCF(t)
def EstClaim(t):
"""Expected Claims
Warning:
Using actuarl invest componets as proxy.
"""
est = InnerProj(t)
return est.BenefitTotal(t) - InvstComponent(t)
def EstExps(t):
"""Expected Expenses"""
est = InnerProj(t)
return (est.ExpsTotal(t)
- est.ExpsCommInit(t)
- est.ExpsCommRen(t)
- est.ExpsAcq(t))
def AsmpChangeImpact(t):
"""Non-financial assumption changes"""
return PV_Cashflow(t + 1, t + 1, 0) - PV_Cashflow(t, t + 1, 0)
def RelsRiskAdj(t):
"""Release of Risk Adjustment to Revenue
Warning:
To be implemented.
"""
return 0
def InsurServiceExps(t):
"""Insurance Service Expense (103(b))"""
return (IncurClaim(t)
+ IncurExps(t)
+ AmortAcqCashflow(t)
+ Incr_LossComp(t)
- AdjLCO_FulfCF(t))
def IncurClaim(t):
"""Incurred Claims"""
return BenefitTotal(t) - InvstComponent(t)
def InvstComponent(t):
"""Investment Components in Incur Claims
Warning:
To be implemented.
"""
return 0
def IncurExps(t):
"""Incurred Expenses"""
return (ExpsTotal(t) - ExpsCommTotal(t) - ExpsAcq(t))
#%% Acquisition Cashflow Amortization
def AcqPremRatio():
"""Ratio of PV Acquisiton Cashflows to PV Premiums.
The ratio is determined by the expectation at issue.
"""
pvs = InnerProj(0).PresentValue(0)
return ((pvs.PV_ExpsCommTotal(0) + pvs.PV_ExpsAcq(0))
/ pvs.PV_PremIncome(0))
def AmortAcqCashflow(t):
"""Amortization of Acquisition Cash Flows
Warning:
Implemented as a constant percentage of actual premiums,
thus not totalling the original amount if actual != expected.
"""
return -AcqPremRatio * PremIncome(t)