如何计算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)
我会重命名您的Year
和Month
variables。 两者都是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)
。