如何在列时间序列

时间:2016-10-25 05:53:14

标签: excel vba excel-vba volatility

'H' Column is the year data column, 'I' Column is the month data column, 'D' Column is the 10-year bond yield we want to calculate the monthly volatility.这是此问题的另一个改进代码,请帮帮我。返回仍然是#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

1 个答案:

答案 0 :(得分: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声明为一维数组,但尝试使用2维对其进行索引。请注意,您只能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)