如何计算Excel VBA在列时间序列下的每月波动率

'H'栏是年份数据栏,'I'栏是月份数据栏,'D'栏是我们要计算10年期国债收益率的月度波动率。 这是这个问题的另一个改进的代码,请帮助我。 返回仍然是#NAME。 感谢@Comintern的回答。 根据@Comintern的build议,我修改了代码。 在名称pipe理器中,“年”是指年份(H3:H3696),“M”是指月份的列(I3:I3696),“C_10”是指中国10年的原始收益数据国债。

现在,我想要得到收益率的每月波动。

Function Volatility(n As Variant) As Variant 'this function uses to calculate volatility of a bond yield '"n" is the number of data/date we need to calculate 'please manage the data name in the name manager of formulas Dim i As Integer, dnum As Integer, mnum As Integer, vectornum As Integer 'dnum count day number, mnum count month number Dim Result(), TempSave() As Variant Dim Yr, M As Range vectornum = Int(n / 20) + 1 ReDim Result(vectornum) As Variant Yr = ActiveWorkbook.Names("Yr").Value M = ActiveWorkbook.Names("M").Value Bond = ActiveWorkbook.Names("C_10").Value For i = 1 To n If Yr(i) = Yr(i + 1) And M(i) = M(i + 1) Then dnum = dnum + 1 ReDim Preserve TempSave(1 To dnum) TempSave(dnum) = Bond(i) 'this is the temporary data container for the same month bond yield Else TempSave(dnum + 1) = Bond(i) 'because there is a gap between two month, so, we add the last 'same month bond yield' back dnum = 0 mnum = mnum + 1 Result(mnum) = Application.WorksheetFunction.StDev_S(TempSave) End If Next i Volatility = Result End Function 

此代码有多个问题。 至于#NAME错误,您可能只需要将该function移动到一个模块。 我也build议明确公开:

 Public Function Volatility(n As Variant) As Variant 

我也会删除Option Base 0 – 这是默认的基础。 你正在使用的唯一数组是由Excel生成的(所以它们总是以1为基数)和TempSave ,你在这里显式声明一个下限为1的TempSave

 ReDim Preserve TempSave(1 To dnum) 

我会重命名您的YearMonthvariables。 两者都是VBA函数的名字,而你的局部variables隐藏了它们。

这个代码…

 dnum = 0 mnum = 0 

…什么都不做 – variables总是被初始化为默认值。 虽然在这种情况下,默认值是Empty (它将隐式地强制转换为0),因为你(可能是偶然)在这里声明它们为Variant

 Dim i, j, dnum, mnum, vectornum As Integer 

如果它们都是Integer ,那么你需要明确地声明:

 Dim i As Integer, j As Integer, dnum As Integer, mnum As Integer, vectornum As Integer 

您可以从循环计数中删除Step 1 – 这是默认值,但也需要从1开始,而不是从0开始(再次,Excel的数组是基数为1):

 For i = 0 To n Step 1 

这条线…

 If Year(i) = Year(i + 1) And Month(i) = Month(i + 1) Then 

…将给出一个“下标超出范围”的错误,因为如果Range.Value引用多个单元格,则会得到一个二维数组。 这意味着你需要提供两个索引。 我假设这些都在同一列,所以它应该是:

 If Year(I, 1) = Year(i + 1, 1) And Month(I, 1) = Month(i + 1, 1) Then 

你在这里有相反的问题:

  ReDim Preserve TempSave(1 To dnum) TempSave(i, 1) = Bond(i) 

您将TempSave声明为一维数组,但试图用2维索引它。 请注意,您只能使用ReDim Preserve最高维度,所以如果您需要创build具有dynamic边界的列,则需要从源数组计算长度或转置它。 Bond也将是一个二维数组(假设ActiveWorkbook.Names("C_10")是多个单元格)。

如果你的任何范围 1单元格,这些分配将给你一个types不匹配:

 Year = ActiveWorkbook.Names("Year").Value Month = ActiveWorkbook.Names("Month").Value Bond = ActiveWorkbook.Names("C_10").Value 

最后, Volatility = Result可能不是返回它应该,因为你有它声明:

 ReDim Result(vectornum, 1) As Variant 

从UDF返回Variant数组时,只会得到数组中的第一个值 – 在本例中为Result(1, 1)