VBA: function returns #VALUE - excel

I have a sub that allows me to price an option via a certain model. Then I wanted to build a function that does exactly the same thing in the same way, but I get an error. Some inputs can be vector so I tried the code with and without the brackets. I also switched "Worksheet.function" with "Application", none of that worked.
Public Function TaylorPrice1(S0 As Double, sigma As Double, wgt As Double, rho As Double, T As Double, Kappa As Double, r As Double, num As Double) As Double
Dim ModS() As Double
Dim Z As Double
Dim i, j, L, k As Double
Dim Sum1, Sum2, Sum3, Sum4, Sum5 As Double
Dim U1, U2, U20, U2st, U2nd, U2rd, mz, vz As Double
Dim a1, a2, a3, B1, B2, c1, c2, c3, c4, d1, d2, d3, d4, z1, z2, z3, y, y1, y2 As Double
Dim py, pyst, pynd, Ny1, Ny2 As Double
Dim Modrho() As Double
'ReDim S0(num), sigma(num), wgt(num), rho(num, num) As Double
ReDim ModS(num) As Double
ReDim Modrho(num, num) As Double
Z = 1
Sum1 = 0
Sum2 = 0
Sum3 = 0
Sum4 = 0
Sum5 = 0
U1 = 0
U2 = 0
U20 = 0
U2st = 0
U2nd = 0
U2rd = 0
For i = 0 To num - 1
ModS(i) = wgt(i) * S0(i) * Exp(r * T)
U1 = U1 + ModS(i)
Next i
For i = 0 To num - 1
For j = 0 To num - 1
Modrho(i, j) = rho(i, j) * sigma(i) * sigma(j) * T
U2 = U2 + ModS(i) * ModS(j) * Exp((Z ^ 2) * Modrho(i, j))
Next j
Next i
mz = 2 * Log(U1) - 0.5 * Log(U2)
vz = Log(U2) - 2 * Log(U1)
For i = 0 To num - 1
For j = 0 To num - 1
U20 = U20 + ModS(i) * ModS(j)
U2st = U2st + ModS(i) * ModS(j) * Modrho(i, j)
U2nd = U2nd + ModS(i) * ModS(j) * Modrho(i, j) ^ 2
U2rd = U2rd + ModS(i) * ModS(j) * Modrho(i, j) ^ 3
Next j
Next i
a1 = -(U2st * Z ^ 2) / (2 * U20)
a2 = 2 * a1 ^ 2 - ((U2nd * Z ^ 4) / (2 * U20))
a3 = 6 * a1 * a2 - 4 * a1 ^ 3 - ((U2rd * Z ^ 6) / (2 * U20))
For k = 0 To num - 1
For j = 0 To num - 1
For i = 0 To num - 1
Sum1 = Sum1 + 2 * (ModS(i) * ModS(j) * ModS(k) * Modrho(i, k) * Modrho(j, k))
Next i
Next j
Next k
B1 = (Z ^ 4) / (4 * U1 ^ 3) * Sum1
B2 = a1 ^ 2 - 0.5 * a2
For L = 0 To num - 1
For k = 0 To num - 1
For j = 0 To num - 1
For i = 0 To num - 1
Sum2 = Sum2 + 8 * (ModS(i) * ModS(j) * ModS(k) * ModS(L) * Modrho(i, L) * Modrho(j, k) * Modrho(k, L))
Next i
Next j
Next k
Next L
Sum2 = Sum2 + 2 * U2st * U2nd
For L = 0 To num - 1
For k = 0 To num - 1
For j = 0 To num - 1
For i = 0 To num - 1
Sum3 = Sum3 + 6 * (ModS(i) * ModS(j) * ModS(k) * ModS(L) * Modrho(i, L) * Modrho(j, L) * Modrho(k, L))
Next i
Next j
Next k
Next L
For k = 0 To num - 1
For j = 0 To num - 1
For i = 0 To num - 1
Sum4 = Sum4 + 6 * (ModS(i) * ModS(j) * ModS(k) * Modrho(i, k) * (Modrho(j, k) ^ 2))
Next i
Next j
Next k
For k = 0 To num - 1
For j = 0 To num - 1
For i = 0 To num - 1
Sum5 = Sum5 + 8 * (ModS(i) * ModS(j) * ModS(k) * Modrho(i, j) * Modrho(i, k) * Modrho(j, k))
Next i
Next j
Next k
c1 = -1 * a1 * B1
c2 = (Z ^ 6 / (144 * U1 ^ 4)) * (9 * Sum2 + 4 * Sum3)
c3 = (Z ^ 6 / (48 * U1 ^ 3)) * (4 * Sum4 + Sum5)
c4 = a1 * a2 - 2 / 3 * a1 ^ 3 - a3 / 6
d1 = 0.5 * (6 * a1 ^ 2 + a2 - 4 * B1 + 2 * B2) - 1 / 6 * (120 * a1 ^ 3 - a3 + 6 * (24 * c1 - 6 * c2 + 2 * c3 - c4))
d2 = 0.5 * (10 * a1 ^ 2 + a2 - 6 * B1 + 2 * B2) - (128 * (a1 ^ 3) / 3 - a3 / 6 + 2 * a1 * B1 - a1 * B2 + 50 * c1 - 11 * c2 + 3 * c3 - c4)
d3 = (2 * a1 ^ 2 - B1) - 1 / 3 * (88 * a1 ^ 3 + 3 * a1 * (5 * B1 - 2 * B2) + 3 * (35 * c1 - 6 * c2 + c3))
d4 = (-20 * (a1 ^ 3) / 3 + a1 * (-4 * B1 + B2) - 10 * c1 + c2)
z1 = d2 - d3 + d4
z2 = d3 - d4
z3 = d4
y = Log(Kappa)
y1 = (mz - y) / (Sqr(vz)) + Sqr(vz)
y2 = y1 - Sqr(vz)
Ny1 = Application.Norm_S_Dist(y1, True)
Ny2 = Application.Norm_S_Dist(y2, True)
py = (1 / (Sqr(2 * Application.Pi() * vz))) * Exp((-((y - mz) ^ 2) / (2 * vz)))
pyst = py * 1 / (-vz) * (y - mz)
pynd = mz / vz * pyst + py * (1 / (-vz)) * (1 + y * (-1 / vz) * (y - mz))
TaylorPrice1 = (U1 * Exp(-r * T) * Ny1 - Kappa * Exp(-r * T) * Ny2) + (Exp(-r * T) * Kappa * (z1 * py + z2 * pyst + z3 * pynd))
End Function

You're trying to use some function parameters as arrays but you don't have them initialized as such
For instance
ModS(i) = wgt(i) * S0(i) * Exp(r * T)
You have wgt and SO as
Public Function TaylorPrice1(S0 As Double, sigma As Double, wgt As Double, rho As Double, T As Double, Kappa As Double, r As Double, num As Double) As Double
In your function parameters. The same applies to
Modrho(i, j) = rho(i, j) * sigma(i) * sigma(j) * T
You can drop the As Double from all function parameters that may be arrays and delete your currently commented Redim... line, as un-commenting that would immediately overwrite the parameter values.

Thank you to everyone for your help. I found the problem. The inputs of the function are actually range of cells of an Excel spreadsheet. But VBA didn't recognize them as array, so I had to transform the range in array (rho in the code). Since I also have a multidimensional array, I found that the range variables store the values of the range as mono dimensional row by raw. For example, I have a 14x14 matrix, then the 17th value of the range corresponds to the 2nd row, 3nd column of the matrix. I hope this information can be useful to someone. This is how I solved the main problem
Dim i As Double
Dim j As Double
Dim L As Double
Dim k As Double
Dim S0() As Double
Dim sigma() As Double
Dim wgt() As Double
Dim rho() As Double
Dim Modrho() As Double
Dim ModS() As Double
' transofrmo range nei vettori
Dim cell As Range
Dim num1 As Long, num2 As Long
Dim rhodritto() As Double
num1 = 0
For Each cell In S0Input
num1 = num1 + 1
Next cell
ReDim S0(num1) As Double
ReDim sigma(num1) As Double
ReDim wgt(num1) As Double
ReDim rho(num1, num1) As Double
ReDim Modrho(num1, num1) As Double
ReDim ModS(num1) As Double
i = 1
For Each cell In S0Input
S0(i) = cell.Value
i = i + 1
Next cell
i = 1
For Each cell In sigmaInput
sigma(i) = cell.Value
i = i + 1
Next cell
i = 1
For Each cell In wgtInput
wgt(i) = cell.Value
i = i + 1
Next cell
num2 = 0
For Each cell In rhoInput
num2 = num2 + 1
Next cell
ReDim rhodritto(num2)
i = 1
For Each cell In rhoInput
rhodritto(i) = cell.Value
i = i + 1
Next cell
k = 1
For i = 1 To num1
For j = 1 To num1
rho(i, j) = rhodritto(k)
k = k + 1
Next j
Next i

Related

Creating forumla for sum of products in excel

I need help creating a formula for row 8 that will give me the sum of the products for cost * quantity of that month. The spreadsheet I am working with is 50+ columns and 1100+ rows.
The hand calculation for this is
B8 = (5 * 10) + (1 * 0) + (10 * 0) + (3 * 0) + (6 * 3 ) = 68
C8 = (5 * 0) + (1 * 0) + (10 * 3) + (3 * 8) + (6 * 0) = 54
D8 = (5 * 0) + (1 * 0) + (10 * 0) + (3 * 0) + (6 * 3) = 5
etc
In B8: =$a2*b$2+$a3*b$3+$a4*b$4+$a5*b$5+$a6*b$6
Once entered just drag to right to column F.
Due to order of operations parenthesis are not required but could be included for clarity.
HTH

Making sure user enters a positive number

Having problem in VBA user defined function. How to make sure user enters a positive number and the function asks for another entry
This is the code that I have written. The user has to enter the value of radius, height and liquid length. The value obviously cannot be negative but my code provides answer for absurd values as well. How do i make sure this does not happen
Also, H is assumed to be greater than twice the radius
Option Explicit
Function tank(R As Double, H As Double, d As Double) As Double
Dim v As Double
If R >= 0 And H >= 0 And d >= 0 Then
If d <= R Then
v = (4 * Atn(1) * (2) * (3 * R - d)) / 3
ElseIf d > R And d <= H - R Then
v = (4 * Atn(1) * 2 * R ^ (3)) / 3 + 4 * Atn(1) * R ^ (2) * (d - R)
ElseIf d > H - R And d <= H Then
v = ((4 * Atn(1) * 4 * R ^ (3)) / 3) + (4 * Atn(1) * R ^ (2) * (H - 2 * R)) - ((4 * Atn(1) * (H - d) ^ (2)) * (3 * R - H + d)) / 3
End If
tank = v
End If
End Function
Then, replace this (if I correctly understood your question...):
If R >= 0 And H >= 0 And d >= 0 Then
with (in fact, add the last condition):
If R >= 0 And H >= 0 And d >= 0 And H > R*2 Then
And it would be good telling to the user that something is wrong. I would introduce a Else and a message telling that the input is wrong.

Custom Excel Function using VBA #VALUE error

It's my first time using VBA and I've run into an error. I've got quite a long formula in Excel that I wanted to simplify using VBA. The formula takes the temperature of air (°C) and gives the partial pressure of the water vapour (Pa). The function returns the #VALUE! error.
Function PartialPressureWaterVapor(Temperature)
' Sets temperature from Celcius to Kelvin
TempK = Temperature + 273.15
' Constant values for calculating PartialPressureWaterVapor when temperature is below 0 C
C01 = -5.6745359 * 10 ^ 3
C02 = 6.3925247
C03 = -9.677843 * 10 ^ -3
C04 = 6.2215701 * 10 ^ -7
C05 = 2.0747825 * 10 ^ -9
C06 = -9.484024 * 10 ^ -13
C07 = 4.1635019
' Constant values for calculating PartialPressureWaterVapor when temperature is above 0 C
C08 = -5.8002206 * 10 ^ 3
C09 = 1.3914993
C10 = -4.8640239 * 10 ^ -2
C11 = 4.1764768 * 10 ^ -5
C12 = -1.4452093 * 10 ^ -8
C13 = 6.5459673
If Temperature < 0 Then
PartialPressureWaterVapor = Exp(C01 / TempK + C02 + C03 * TempK + C04 * TempK ^ 2 + C05 * TempK ^ 3 + C06 * TempK ^ 4 + C07 * expression.Ln(TempK))
Else
PartialPressureWaterVapor = Exp(C08 / TempK + C09 + C10 * TempK + C11 * TempK ^ 2 + C12 * TempK ^ 3 + C13 * expression.Ln(TempK))
End If
End Function

Multiple For Loop Iterations (Combination) with filter to achieve highest possible value

I have a set of "Points" & it's "Value".
I want to get highest possible "Value" from combination of "Points".
Example:
My Target Point: 100
Point Value
1 111
2 222
3 333
4 444
5 555
6 666
7 777
8 888
9 999
10 1110
11 1221
12 1332
13 1443
14 1554
15 1665
16 1776
17 1887
18 1998
19 2109
20 2220
There can be TRILLIONS of combination but I need only those combinations upto "My Target Point" yielding Highest "Value".
Possible Answers:
1. (Point 16)*2 + (Point 17)*4 = 100
(Value 1776)*2 + (Value 1887)*4 = 11100
2. (Point 1)*100 = 100
(Value 111)*100 = 11100
& so on.....
So finally I need just one (any) combination with highest value.
amt2 = 0
For i20 = 0 To 5 ' (Max multiple -> 100/20 = 5)
For i19 = 0 To 5 ' (Max multiple -> 100/19 = 5)
For i18 = 0 To 5
For i17 = 0 To 5
For i16 = 0 To 6
For i15 = 0 To 6
For i14 = 0 To 7
For i13 = 0 To 7
For i12 = 0 To 8
For i11 = 0 To 9
For i10 = 0 To 10
For i9 = 0 To 11
For i8 = 0 To 12
For i7 = 0 To 14
For i6 = 0 To 16
For i5 = 0 To 20
For i4 = 0 To 25
For i3 = 0 To 33
For i2 = 0 To 50
For i1 = 0 To 100 ' (Max multiple -> 100/1 = 1)
point1 = (1 * i1) + (2 * i2) + (3 * i3) + (4 * i4) + (5 * i5) + (6 * i6) + (7 * i7) + (8 * i8) + (9 * i9) + (10 * i10) + (11 * i11) + (12 * i12) + (13 * i13) + (14 * i14) + (15 * i15) + (16 * i16) + (17 * i17) + (18 * i18) + (19 * i19) + (20 * i20))
If point1 <= 100 Then
amt1 = (111 * i1) + (222 * i2) + (333 * i3) + (444 * i4) + (555 * i5) + (666 * i6) + (777 * i7) + (888 * i8) + (999 * i9) + (1110 * i1 + (1221 * i11) + (1332 * i12) + (1443 * i13) + (1554 * i14) + (1665 * i15) + (1776 * i16) + (1887 * i17) + (1998 * i18) + (2109 * i19) + (2220 * i20)
If amt2 < amt1 Then
amt2 = amt1
<Save Combination Details>
End If
End If
Next i1
Next i2
Next i3
Next i4
Next i5
Next i6
Next i7
Next i8
Next i9
Next i10
Next i11
Next i12
Next i13
Next i14
Next i15
Next i16
Next i17
Next i18
Next i19
Next i20
Problem with my code is that it iterates through ALL possible combinations which takes lots of time & produce little result.
"Trillions" underestimates how much work your code is trying to do. Your code would pass through the innermost loop 1.94*10^21 times, which at the rate of 10 million passes per second (about the most VBA could give) would take over 6 million years. Instead, just use the Solver add-in to solve what is a fairly straightforward integer programming problem.
Set up your spreadsheet something like this:
Your data is in columns A:B, I added a new column of decision variables, a constraint cell in D2, and an objective function in E2.
The formula in D2 is:
=SUMPRODUCT(A2:A21,C2:C21)
and in E2 it is:
=SUMPRODUCT(B2:B21,C2:C21)
Then I simply ask the solver to find the maximum of cell E2 by changing cells C2:C21 subject to the two constraints that D2 <= 100 and that C2:C21 are integers. I keep the default setting that variables are assumed to be nonnegative, and tell the solver to use the Simplex method (which under the hood will use branch-and-bound for solving this ILP). The optimal solution according to the Solver (found in less than a second as opposed to 6 million years) is 10*Point1 + 6*Point15 with a total value of 11100 -- which happens to be a value that you have already found, showing that this problem has multiple optima.
It is possible but not easy to do this all in VBA, since the solver add-in can be invoked in code. See this for a basic introduction.

Evaluating recursive function in Haskell

I am given this function and asked to manually evaluate g 5. I found the answer to be 25, but this is incorrect. The correct answer is 63. Would anyone help me understand why? Thanks
g :: Int -> Int
g n
| n==0 = 1
| otherwise = 2 * g (n-1) + 1
My answer: (2*4+1) + (2*3+1) + (2*2+1) + (2*1+1) + 1 = 25
You just need to think it out step by step:
(g 5) = 2 * (g 4) + 1
(g 4) = 2 * (g 3) + 1
(g 3) = 2 * (g 2) + 1
(g 2) = 2 * (g 1) + 1
(g 1) = 2 * (g 0) + 1
(g 0) = 1
Then, plug in the values from the bottom-up:
2 * 1 + 1 = 3
2 * 3 + 1 = 7
2 * 7 + 1 = 15
2 * 15 + 1 = 31
2 * 31 + 1 = 63
Your problem is that you were using the raw value of n, instead of what (g n) returned at the end of the recursion.
In your calculation you messed up with the nesting of the terms. They should be nested and not summed up separately.
The way to evaluate such functions is to replace function applications with the body of the function with its parameters replaced by the given arguments. I will do the first few steps and then you can take over:
g 5
if 5 == 0 then 1 else 2 * g (5-1) + 1
2 * g (5-1) + 1
2 * (if (5 - 1) == 0 then 1 else 2 * g ((5-1) - 1) + 1) + 1
2 * (if 4 == 0 then 1 else 2 * g (4-1) + 1) + 1
2 * (2 * g (4-1) + 1) + 1
...
63
#Carcigenicate's answer is of course easier to calculate, but this technique is more universal and more inline with how the code actually works.
Although this isn't your question, it's fairly easy to show by induction that
g n = 2^(n+1)-1
So
g 5 = 2^6 - 1 --> 63
Your parenthesization is wrong. Not doing any reductions (other than expanding g), we get
g 5
= 2 * g 4 + 1
= 2 * (2 * g 3 + 1) + 1
= 2 * (2 * (2 * g 2 + 1) + 1) + 1
= 2 * (2 * (2 * (2 * g 1 + 1) + 1) + 1) + 1
= 2 * (2 * (2 * (2 * (2 * g 0 + 1) + 1) + 1) + 1) + 1
= 2 * (2 * (2 * (2 * (2 * 1 + 1) + 1) + 1) + 1) + 1

Resources