This is the formula in Excel that I'm trying to convert to VBA code:
=IFERROR(IF(effDate>curDate,0,IF((curDate-effDate+1)>nDays,nDays*(nSpend/365),((nSpend/365)*(curDate-effDate+1))-IF((curDate-effDate+1)-nDays>0,nSpend/365,0))),0)
For checking working purposes here are the values for each variable:
effDate: 1/1/17 (dimmed as value)
curDate: 3/31/17 (dimmed as value)
nDays: 60
nSpend: 1600
Correct answer: 263
I tried to make it work for two days now and I retyped in about a hundred different way and none of them work. The code may work for one cell but it doesn't calculate correctly for the others. Or it doesn't work at all. Here is one of the examples of what I made earlier (name of the function is APFcst):
If effDate > curDate then
APFcst = 0
Exit Function
End if
If (curDate - effDate + 1) > nDays then
APFcst = nDays * (nSpend / 365)
Else
val1 = (nSpend / 365) * (curDate - effDatea + 1)
end if
if (curDate - effDate + 1) - nDays > 0 then
val2 = nSpend / 365
else
val2 = 0
end if
APFcst = val1 - val2
Exit Function
End if
NOTE: everything is dimmed properly, the issue that I'm having is just translating the actual formula so it'll give me the correct answer.
Please help! I've been staring at this for so long that I might not see an obvious solution.
After noticing that the last IF check in your formula is redundant, here's a simplification of your equation:
Function xAPFcst(effDate, curDate, nSpend, nDays) As double
xAPFcst = IIf(effDate > curDate, 0, (nSpend / 365) * Application.Min(nDays, curDate - effDate + 1))
End function
Something like this, maybe possible to shorten it a touch using IIF's and perhaps, looking at using (nSpend / 365) a bit more effectively, i'll take a look again later. I've not properly tested as yet.
Function formula_test(dtCurrentDate As Date, dtEffectiveDate As Date, nDays As Long, nSpend As Double) As Double
On Error GoTo eHandle
If dtEffectiveDate > dtCurrentDate Then
formula_test = 0
Else
If ((dtCurrentDate - dtEffectiveDate) + 1) > nDays Then
formula_test = nDays * (nSpend / 365)
Else
formula_test = ((nSpend / 365) * (dtCurrentDate - dtEffectiveDate + 1))
If (dtCurrentDate - dtCurrentDate + 1) - nDays > 0 Then
formula_test = formula_test - nSpend / 365
End If
End If
End If
Exit Function
eHandle:
formula_test = 0
End Function
Related
I'm looping through a list of decimals and I use an if statement to catch any junk data and not chart it if any appears in the list, though the if statement doesn't seem to be catching this and the junk data gets charted anyways. I've tried Continue For and exiting the sub altogether, but it rarely seems to be caught. My code below:
For i = 1 To 8
If hotTemps(i - 1) > 3000 Or hotTemps(i - 1) < -400 Then
Continue For
End If
If celsius.Checked And sysTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(TimeOfDay.ToString("HH:mm:ss"), CDec(hotTemps(i - 1)))
ElseIf fahrenheit.Checked And sysTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(TimeOfDay.ToString("HH:mm:ss"), CDec((hotTemps(i - 1))) * 1.8 + 32)
ElseIf celsius.Checked And elapsedTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(elapsed, CDec(hotTemps(i - 1)))
ElseIf fahrenheit.Checked And elapsedTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(elapsed, CDec((hotTemps(i - 1))) * 1.8 + 32)
End If
Next
Simplify your loop to check your logic.
Dim lst As New List(Of Integer)
For a = 0 To 7
If a > 6 Or a < 3 Then
Continue For
End If
lst.Add(a)
Next
For Each i In lst
Debug.Print(i.ToString)
Next
This produces
3
4
5
6
Is this the expected result?
=IF((effDate)-curDate>0,0,IF(curDate-(effDate)+1>nDays,0,nSpend/4))+IF((effDate+365/4*1)-curDate>0,0,IF(curDate-(effDate+365/$4*1)+1>nDays,0,nSpend/4))+IF((effDate+365/4*2)-curDate>0,0,IF(curDate-(effDate+365/4*2)+1>nDays,0,nSpend/4))+IF((effDate+365/4*3)-curDate>0,0,IF(curDate-(effDate+365/4*3)+1>nDays,0,nSpend/4))
effDate: 1/1/2017 (as value)
curDate: 1/31/2017 (as value)
nSpend: 1600
nDays: 60
Correct answer: 400
Above is a long formula I'm trying to covert to VBA code. The way I've been trying to do it is long and I tried breaking it up into smaller functions, but it's not giving me the right answer. My VBA skills are very beginner so I'm not sure what else to try. I keep getting the wrong answer or no answer at all.
This is what I've been trying:
If effdate - curdate > 0 Then
val1 = 0
Exit Function
End If
If curdate - effDate + 1 > nDays Then
val1 = 0
Else
val1 = nSpend / 4
End If
If (effDate + (365 / 4)) - curdate > 0 Then
val2 = 0
Exit Function
End If
If curdate - (effDate + (365 / 4)) + 1 > nDays Then
val2 = 0
Else
val2 = nSpend / 4
End If
If effDate + (365 / (4 * 2)) - curdate > 0 Then
val3 = 0
Exit Function
End If
If curdate - (effDate + (365 / (4 * 2))) + 1 > nDays Then
val3 = 0
Else
val3 = nSpend / 4
End If
If effDate + (365 / (4 * 3)) - curdate > 0 Then
val4 = 0
Exit Function
End If
If curdate - (effDate + (365 / (4 * 3))) + 1 > nDays Then
val4 = 0
Else
val4 = nSpend / 4
End If
End If
APFcst = val1 + val2 + val3 + val4
End Function
I dimmed everything correctly, it's the actual conversion that I have problems with.
I would appreciate the help! This is also a huge learning stretch for me since I just started learning VBA coding.
Thank you!
If you know the formula then you can use Evaluate() to achieve what you want.
Sub Sample()
Dim f1, f2, f3, f4
f1 = "=IF((effDate)-curDate>0,0,IF(curDate-(effDate)+1>nDays,0,nSpend/4))"
f2 = "=IF((effDate+365/4*1)-curDate>0,0,IF(curDate-(effDate+365/4*1)+1>nDays,0,nSpend/4))"
f3 = "=IF((effDate+365/4*2)-curDate>0,0,IF(curDate-(effDate+365/4*2)+1>nDays,0,nSpend/4))"
f4 = "=IF((effDate+365/4*3)-curDate>0,0,IF(curDate-(effDate+365/4*3)+1>nDays,0,nSpend/4))"
'~~> Change Sheet1 to the relevant sheet code name
Debug.Print Sheet1.Evaluate(f1) + Sheet1.Evaluate(f2) + Sheet1.Evaluate(f3) + Sheet1.Evaluate(f4)
End Sub
DateAdd ( interval, number, date )
You should investigate this and apply it towards what youre trying to do :)
https://www.techonthenet.com/excel/formulas/dateadd.php
I was intrigued by this to see why it wasn't working, I've rewrote the if > else > else logic to an if or > else but it achieves the same thing. Like Doug Coats' answer says, you can use DateAdd to work with subtraction/adding dates together. I've just converted the date strings to double:
Private Sub CommandButton1_Click()
Dim x As Date: Dim y As Date
Dim effDate As Double
Dim curDate As Double
Dim nSpend As Double
Dim nDays As Double
x = "1/1/17"
y = "31/1/17"
effDate = CDbl(x)
curDate = CDbl(y)
nSpend = 1600
nDays = 60
If (effDate - curDate > 0) Or (curDate - effDate + 1 > nDays) Then
val1 = 0
Else
val1 = nSpend / 4
End If
If ((effDate + (365 / 4)) - curDate > 0) Or (curDate - (effDate + (365 / 4)) + 1 > nDays) Then
val2 = 0
Else
val2 = nSpend / 4
End If
If (effDate + (365 / (4 * 2)) - curDate > 0) Or (curDate - (effDate + (365 / (4 * 2))) + 1 > nDays) Then
val3 = 0
Else
val3 = nSpend / 4
End If
If (effDate + (365 / (4 * 3)) - curDate > 0) Or (curDate - (effDate + (365 / (4 * 3))) + 1 > nDays) Then
val4 = 0
Else
val4 = nSpend / 4
End If
MsgBox (val1 + val2 + val3 + val4)
End Sub
This code doesn't find the correct output
for say n= 1 (although it gives the correct output for say n= 2,3,4..etc.)
if we put n= 1 to find x then the i loop will continue from 1 to 0, hence the first term in x should vanish and leftover should be the second term 5; but it gives 0 ?
Is there any limitation on the input n to run the for loop ?I would appreciate any help.
Function math(n As Integer) As Double
Dim i As Integer
Dim x As Double
For i = 1 To n - 1
x = (n - 1) * 2 + 5
sum = sum + x
Next i
math = sum
End Function
Why not simply:
Function math(n As Integer) As Double
Math = ((n - 1) * 2 + 5) * Abs((n - 1) - (n = 1))
End Function
???
if the answer is correct then Math = (n * 2 + 3) * Abs((n - 1) - (n = 1)) would be easier to understand and make much more sense
In the for loop, if you don't precise the Step, the variable will only increment by 1.
And here, you start at 1 to go to 0, so the loop won't execute, you need to test n to cover both cases :
Function math(n As Integer) As Double
If n < 0 Then Exit Function
Dim i As Integer
Dim x As Double
Dim Summ As Double
Select Case n
Case Is > 1
For i = 1 To n - 1
x = (i - 1) * 2 + 5
Summ = Summ + x
Next i
Case Is = 1
Summ = (n - 1) * 2 + 5
Case Is = 0
Summ = 5
Case Else
MsgBox "This case is not supported", vbInformation + vbOKOnly
Exit Function
End Select
math = Summ
End Function
If n = 1, you end up with For i = 1 To 0 which is incorrect and
should be expressed For i = 1 To 0 STEP -1.
So I suggest you add the STEP BYand make sure it is either 1 to -1 depending on N.
I have a method I wrote in a VBA module
Public Function calcAscentTime()
IDepth = CInt(Sheets("Fundies").Range("B47"))
T = 0
T = T + 1 ' Add 1 minute for emergency
D = Math.Round((IDepth / 10) * 10) 'Round to Ceiling of nearest 10
half_depth = Math.Round(((D / 2) / 10) * 10, 0) 'Get where our first stop is
T = T + Math.Round((((D - half_depth) / 30) / 2) * 2) ' Ascend to first stop at 30ft/min
T = T + (half_depth / 10) ' 1 minute for every stop thereafter
What this does is take a value from Cell B47 on the "Fundies" worksheet and should return a value based on the calculations. I enter =calcAscentTime() into cell B48, expecting to get a value of 8(B47's value is 100), but get a return value of 0. What am I doing wrong?
ou're function isn't returning anything. Assigning the function name to the calculated variable should return the expected result (assuming you have everything else right). Something like:
Public Function calcAscentTime()
IDepth = CInt(Sheets("Fundies").Range("B47"))
T = 0
T = T + 1 ' Add 1 minute for emergency
D = Math.Round((IDepth / 10) * 10) 'Round to Ceiling of nearest 10
half_depth = Math.Round(((D / 2) / 10) * 10, 0) 'Get where our first stop is
T = T + Math.Round((((D - half_depth) / 30) / 2) * 2) ' Ascend to first stop at 30ft/min
T = T + (half_depth / 10) ' 1 minute for every stop thereafter
calcAscentTime = T
End Function
Keep in mind, you should probably Dim your variables to the proper type to avoid any kind of confusion / miss-casting by the compiler.
EDIT: I fixed it, the ReDim and all starts at 0 and not 1 so I had a cell that was empty which wasn't supposed to be there!
It now works, thanks for the help!
I'm trying to take a matrix and invert it, but for some reason I get this error:
Unable to get the MInverse property of the WorksheetFunction class.
My (relevant) code is as following:
Dim covar() As Variant
ReDim covar(UBound(assetNames), UBound(assetNames))
Dim corr() As Double
ReDim corr(UBound(assetNames), UBound(assetNames))
Dim covarTmp As Double
For i = 0 To UBound(assetNames) - 1
For j = 0 To UBound(assetNames) - 1
covarTmp = 0
For t = 1 To wantedT
covarTmp = covarTmp + (Log((prices(histAmount + 1 - t, i + 1)) / (prices(histAmount - t, i + 1))) - mu(i) * dt) * (Log((prices(histAmount + 1 - t, j + 1)) / (prices(histAmount - t, j + 1))) - mu(j) * dt)
Next t
covar(i, j) = covarTmp * (1 / ((wantedT - 1) * dt))
corr(i, j) = covar(i, j) / (sigma(i) * sigma(j))
Next j
Next i
Dim covarInv() As Variant
ReDim covarInv(UBound(assetNames), UBound(assetNames))
'ReDim covar(1 To UBound(assetNames), 1 To UBound(assetNames))
covarInv = Application.WorksheetFunction.MInverse(covar)
This last row is where the error occurs.
I've tried many things, having covar and covarInv dim as double, variant etc. Different ReDims on covar and covarInv.
You don't say what version of Excel you are using, but with Excel 2010 there seems to be a Minverse maximum limit of 200 * 200 (for Excel 2003 its probably around 80 * 80): How many asset names do you have?