2016-06-13 113 views
0

我正在重新访问Excel VBA中的一些旧代码并尝试将其转换为Access VBA。调整Excel VBA函数以访问VBA

此代码需要一系列数字(“零”)并计算“Lambda”权重的简单加权平均值。此计算和此代码工作正常,并已验证为正确。

Excel代码如下。

Option Explicit 


Function EWMA(Zeros As Range, Lambda As Double, MarkDate As Date, MaturityDate As Date) As Double 

    Dim vZeros() As Variant 
    Dim Price1 As Double, Price2 As Double 
    Dim SumWtdRtn As Double 
    Dim I As Long 
    Dim m As Double 

    Dim LogRtn As Double, RtnSQ As Double, WT As Double, WtdRtn As Double 

vZeros = Zeros 

m = Month(MaturityDate) - Month(MarkDate) 

For I = 2 To UBound(vZeros, 1) 

    Price1 = 1/((1 + vZeros(I - 1, 1))^(m/12)) 
    Price2 = 1/((1 + vZeros(I, 1))^(m/12)) 


    LogRtn = Log(Price1/Price2) 

    RtnSQ = LogRtn^2 

    WT = (1 - Lambda) * Lambda^(I - 2) 

    WtdRtn = WT * RtnSQ 

    SumWtdRtn = SumWtdRtn + WtdRtn 

Next I 

EWMA = SumWtdRtn^(1/2) 

End Function 

现在我试图在Access VBA中重现这个相同的功能。此代码引用一个表格(“HolderTable”),它由与上述Excel代码中的“零”范围完全相同的数字组成。在Access中,这些被标记为“InterpRate”。然后,它应用与Excel代码中完全相同的计算,但适用于Access语法。

接入码如下:

Function EWMA(Lambda As Double) As Double 

Dim Price1 As Double, Price2 As Double 
Dim vInterpRate() As Variant 
Dim SumWtdRtn As Double 
Dim I As Long 
Dim m As Double 
Dim rec As Recordset 


Dim LogRtn As Double, RtnSQ As Double, WT As Double, WtdRtn As Double 

m = 3 

Dim x As Integer 

Set rec = CurrentDb.OpenRecordset("SELECT InterpRate FROM HolderTable") 

x = 1 

Do While rec.EOF = False 

ReDim Preserve vInterpRate(x + 1) 

vInterpRate(x) = rec("InterpRate") 

x = x + 1 

rec.MoveNext 

Loop 

For I = 1 To x 

Price1 = 1/((1 + vInterpRate(I - 1))^(m/12)) 

Price2 = 1/((1 + vInterpRate(I))^(m/12)) 


    LogRtn = Log(Price2/Price1) 

    RtnSQ = LogRtn^2 

    WT = (1 - Lambda) * Lambda^(I - 2) 

    WtdRtn = WT * RtnSQ 

    SumWtdRtn = SumWtdRtn + WtdRtn 

Next I 

EWMA = SumWtdRtn^(1/2) 

End Function 

理想的情况下,这些应该产生完全相同的数字。 “零”范围和“interpRate”数字是相同的。我怀疑问题出在我如何在Access中定义我的数组,但我似乎无法修复它。两个守则之间是否有不一致?

作为参考,我附上了Excel电子表格,附有VBA代码。 http://www.filedropper.com/soewma_1

+1

难道只是x在您的访问版本中增加了1倍太多? –

+0

我认为这可能是可能的,我怎么能改变它来解决这个问题? – beeba

+1

最简单的方法是在你的Do ... While循环中添加“x = x - 1” –

回答

1

的恕我直言最好的易读的方式是先从X = 0,并把X = X + 1在每个循环的开始:

Set rec = CurrentDb.OpenRecordset("SELECT InterpRate FROM HolderTable") 
x = 0 
Do While rec.EOF = False 
    x = x + 1 
    ReDim Preserve vInterpRate(x) 
    vInterpRate(x) = rec("InterpRate") 
    rec.MoveNext 
Loop 

而且因为你访问vInterpRate(I - 1),你的第二个循环必须be

For I = 2 To x 

而不是For I = 1 To x

+0

非常感谢你,完全解决它。 – beeba

+0

你能否为我澄清一点? vInterpRate(0)给出数组的第一个元素,vInterpRate(1)给出第二个元素。如果我设置I = 2,是不是我跳过一个元素? – beeba

+0

例如“debug.Print vInterpRate(0)”给出了“0.38”,我可以确认它是数组的第一个元素 – beeba