2016-06-13 7 views
0

Я пересматриваю старый код в Excel VBA и пытаюсь преобразовать его в Access VBA.Адаптация функции Excel VBA для доступа к VBA

Этот код принимает ряд чисел («нули») и вычисляет простое взвешенное среднее значение с весом «Лямбда». Этот расчет и этот код отлично работают и были проверены как правильные.

Код 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»), которая состоит из тех же чисел, что и диапазон «Zeros» в вышеуказанном коде 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 

В идеале, они должны производить ту же цифру. Диапазон «Zeros» и номера «interpRate» идентичны. Я подозреваю, что проблема связана с тем, как я определил свой массив в Access, однако я не могу его исправить. Существуют ли какие-либо несоответствия между этими двумя кодами?

Для справки, я прилагаю таблицу Excel с кодом VBA. http://www.filedropper.com/soewma_1

+1

Это просто, что x увеличивается в 1 раз слишком много в вашей версии доступа? –

+0

Я думаю, что это возможно, как я могу изменить его, чтобы исправить это? – beeba

+1

Простейшим способом было бы добавить «x = x - 1» после вашего Do ... While loop –

ответ

1

ИМХО лучше читаемым способ начать с х = 0 и положить х = х + 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