VBA:从每日价值计算月度回报

我有两列,date和每日回报。 我每天有7000左右的回报,我想把它们按每年每个月的复合回报分组。

我创build了一个VBA函数来解决这个问题:

Function MonthlyRet(YearNum, MonthNum, DateData, RetData) As Double Dim nValues As Integer nValues = DateData.Rows.Count MonthlyRet = 1 For i = 2 To nValues If (IsNumeric(RetData(i)) And Year(DateData(i)) = YearNum And Month(DateData(i)) = MonthNum) Then MonthlyRet = MonthlyRet * RetData(i) End If Next i End Function 

我可以在我的数据上运行这个:

 =MonthlyRet(2015,1,Data!$A$1:$A$7000,Data!$AR$1:$AR$7000)-1 

这将在我的数据集中返回2015年1月的复合回报。 这似乎工作,但是,当我从1990年到2015年的所有月复制和粘贴方程,大约300个单元格,需要相当长的时间才能完成一个快速的计算机上的操作。

该algorithm通过7000 if语句循环300次。 对我来说这似乎不是那么多迭代,但是我的计算机将需要一两分钟来计算它们。 在java中,我知道结果将是毫秒,但我是一个VBA新手。

有什么办法可以提高VBA的这个例程的性能吗?

正如我上面写的,当使用VBA查看大范围时,最好将该范围读入数组,然后再遍历数组。 修改你的UDF; 并明确声明所有variables和数据types – 在VBA中总是一件好事,我们结束了:


 Option Explicit Function MonthlyRet(YearNum As Long, MonthNum As Long, DateData As Range, RetData As Range) As Double Dim vDates As Variant, vReturns As Variant Dim I As Long Dim D As Double vDates = DateData vReturns = RetData D = 1 For I = 2 To UBound(vDates, 1) If (IsDate(vDates(I, 1)) And Year(vDates(I, 1)) = YearNum And Month(vDates(I, 1)) = MonthNum) Then D = D * vReturns(I, 1) End If Next I MonthlyRet = D End Function 

不过 ,我build议你看一下Pivot Table 。 在我看来,这将是显示数据的理想select。 例如,您可以将date拖到行区域; 返回数据到列区域; 将值字段设置更改为产品; 然后按月份和年份对这些行进行分组 – 您将得到一个不错的表格,显示相同的结果。

另外,我不确定你的algorithm是否会返回你所期望的值。 不知道如果使用Pivot或UDF,一旦获得sorting后会更容易。

有很多方法来提高性能。 你有什么限制?

选项1:坚持VBA UDF

如果你只是想提高你的UDF的VBA性能,我看不出你能做什么。 这些更改可能会有所帮助:

 Function MonthlyRet(YearNum, MonthNum, DateData, RetData) As Double Dim nValues As Integer, i as Integer:nValues = DateData.Rows.Count:MonthlyRet = 1 For i = 2 To nValues If (IsNumeric(RetData(i)) And Year(DateData(i)) = YearNum And Month(DateData(i)) = MonthNum) Then MonthlyRet = MonthlyRet * RetData(i) Next i End Function 

我在这里写了一篇关于提高VBA性能的文章。

选项2:Excel XLL基于UDF的函数

Excel XLL将为您的UDFfunction启用multithreading。 这里有一个不错的video: https : //www.youtube.com/watch?v=L2ALSgK1LLY

选项3:编写VBAmacros并手动运行而不是使用UDF函数

(a)它会给你更多的控制,当function刷新和防止从而“冻结Excel”和(b)这将比单独的UDFfunction稍快。