用 Excel VBA 中的类模块 Class module 计算精算现值。
本文背景:类模块 (Class module)的普及是未来VBA编程的发展趋势。它具有能够简洁化代码,增强代码可读性的特点。但同时,它会加大代码维护的难度。类模块 (Class module)相对门槛较高,比普通模块更难理解。考虑到做精算同事的背景,可能要两者权衡取舍。
不积跬步无以至千里,本文用了一个简单的类模块 (Class module)例子,帮助大家入门。本文设计了一个精算背景,目标读者为类模块初级学习者。欢迎大家指出不足之处。
我有一个朋友,她叫做小珂珂。
小珂珂是 ActuaryGarden 公司的精算实习生,这天,她在做精算表写VBA的时候遇到了一个问题:她手上目前有两套精算假设,想利用这两套假设计算年金现值a,还有定期寿险现值A。
因为不想重复工作,她想到,每一套假设都可以看作一个对象(Object)呀!可以利用类模块(Class model)来避免重复工作。 可以把利息率和死亡率设置成类模块(Class model)的属性,计算A和a设置成类模块(Class model)的方法~
如何定义Class module
首先,小珂珂创建了一个新的类模块(Class module)。
并把它的名字在属性窗口中改成了:factor
注意,这个名字十分重要,它决定了我们要如何在普通模块中创建对象。
这里要解释一下没有用中文写属性名称的原因:因为在VBA编辑器中较难设定中文编码,在分发Excel文件的时候容易出现乱码问题。当然,如果您有更好的解决方案,欢迎留言。
如何创建属性
小珂珂想要创建两个属性,一个是死亡率,一个是利息率。 这样的话,对于任何一个假设,都都可以轻易获得这些数据。 所以她打开了名为factor的类模块(Class model),开始写属性啦~
定义变量。getmordata 是死亡数据表,getinsrate是利率。 好的编程习惯是一定要把Option Explicit加上哦,这样可以让代码更不容易出错,跑的更快。 1
2
3Option Explicit
Private getmordata As Variant
Private getinsrate As Single
注意,这里面的变量getmordata,getinsrate 是这个类模块(Class model)里面的局域变量(private variable),我们在调取属性的时候,并不需要用它们。
这个属性要通过下面定义的mortable()来获取。赋值在VBA中使用Let来表示的,代码如下: 1
2
3
4
5Property Let mortable(rData As Variant)
'这里可以定义一下如何验证属性rData的值
'比如死亡率是否在0和1之间
getmordata = rData
End Property
假设小珂珂把mortable赋好值啦,那么该如何获取这个值呢? 那么就涉及到Get啦~ 1
2
3Property Get mortable() As Variant
mortable = getmordata
End Property
利率的属性也是通过相同方法得到的,大家可以自己试一试哦。
- 这里最容易迷惑的点在于getmordata和mortable到底有什么区别?他俩看起来很相似呀,为什么要一个等于另一个呢?
可以这么想:getmordata是在类模块(Class model)中用来称呼死亡率表的名字,它不能在这个类模块(Class model)之外使用,而mortable是用来在类模块(Class model)外部称呼这个属性的。
如何创建方法
接下来,小珂珂就要定义方法啦。方法就太简单啦。方法就是函数而已,不同之处在于,它可以直接调用一些定义好的属性。 下面的代码就是小珂珂计算A的过程 1
2
3
4
5
6
7Function bigavalue(lowerlimit As Integer, duration As Integer):
bigavalue = 0
Dim i As Integer
For i = lowerlimit To duration + lowerlimit
bigavalue = bigavalue + getmordata(lowerlimit, 2) / (1 + insrate) ^ (0.05 + i - lowerlimit)
Next i
End Function
调用类模块(Class model)
大家还记得小珂珂把定义好的类模块(Class model)叫做factor了吗?想要定义新的对象,她是这样做滴: 1
2
3
4
5
6'Declare class variable
Dim factorA As factor
Dim factorB As factor
Set factorA = New factor
Set factorB = New factor1
2
3'Declare class variable
Dim factorA As new factor
Dim factorB As new factor
factorA和factorB都是新的factor,小珂珂不禁觉得,太简单啦。 然后小珂珂把这种假设的属性设置好。 - Atable和Btable都是事先读取了Table1和Table2值的array数组。 - rateA和rateB是两种假设下的利率。 - bigavalue是用来计算A的方法。
注意Debug.Print的内容可以在即时窗口(immediate window)中显示出来。调用即时窗口(immediate window)的快捷键是Ctrl + G 1
2
3
4
5
6
7
8
9
10
11 factorA.mortable = Atable
factorB.mortable = Btable
factorA.insrate = Range("rateA").Value
factorB.insrate = Range("rateB").Value
'Calculations
Debug.Print (factorA.bigavalue(10, 10))
Debug.Print (factorA.smlavalue(10, 10))
Debug.Print (factorB.bigavalue(10, 10))
Debug.Print (factorB.smlavalue(10, 10))
这个时候就要用到一个叫做集合(Collections)的东西。
像这样可以定义一个叫做Assumptions的集合: 1
2Dim Assumptions As Collection
Set Assumptions = New Collection1
2Assumptions.Add factorA
Assumptions.Add factorB1
2
3For Each fac In Assumptions
Debug.Print fac.insrate
Next fac
本文完整代码点击阅读原文进入精算后花园论坛下载。
正在检查 Disqus 能否访问...