1

'H' 列是年份数据列,'I' 列是月份数据列,'D' 列是我们要计算每月波动率的 10 年期债券收益率。这是此问题的另一个改进代码,请帮助我。返回仍然是#NAME。感谢@Comintern 的回答。根据@Comintern 的建议,我已经修改了代码。名称管理器中,“Yr”指的是当年的列(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
4

1 回答 1

0

此代码有多个问题。至于#NAME错误,您可能只需要将函数移动到模块中。我还建议将其明确公开:

Public Function Volatility(n As Variant) As Variant

我也会删除Option Base 0- 它是默认基础。您正在使用的唯一数组是由 Excel 生成的(因此它们总是以 1 为基数)和TempSave,您在此处明确声明其下限为 1:

ReDim Preserve TempSave(1 To dnum)

我会重命名你的YearMonth变量。两者都是 VBA 函数的名称,而您的局部变量隐藏了它们。

这段代码...

dnum = 0
mnum = 0

...不做任何事情 - 变量总是被初始化为其默认值。尽管在这种情况下,默认值为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为一维数组,但尝试使用二维对其进行索引。请注意,您只能ReDim Preserve使用最高维度,因此如果您需要创建具有动态边界的列,您需要从源数组计算长度或转置它。Bond也将是一个二维数组(假设ActiveWorkbook.Names("C_10")不止一个单元格)。

如果您的任何范围1 个单元格,则这些分配将为您提供类型不匹配:

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).

于 2016-10-25T14:36:05.277 回答