Rearrange equation to solve for a different variable - excel

I am looking at VBA code (function) written by someone else.
Here is the code:
Function EuropeanDelta(StrikePrice, MarketPrice, Volatility, InterestRate As Double, PC As String, ValueDate, ExpiryDate As Date, Optional PriceOrYield As String = "P") As Double
Rem Declare our working variables
Dim r As Double
Dim d1 As Double
Dim d2 As Double
Dim t As Double
Dim SqT As Double
Rem End of variable declaration
If PriceOrYield = "Y" Then
MarketPrice = 100 - MarketPrice
StrikePrice = 100 - StrikePrice
If PC = "C" Then
PC = "P"
Else
PC = "C"
End If
End If
Rem Initiase our working variables
t = (ExpiryDate - ValueDate) / 365
SqT = Sqr(t)
r = Application.WorksheetFunction.Ln(1 + InterestRate)
d1 = (Application.WorksheetFunction.Ln(MarketPrice / StrikePrice) + (Volatility * Volatility * 0.5) * t) / (Volatility * SqT)
Rem Quick logic to deal with Calls or Puts
If PC = "C" Then
EuropeanDelta = Exp(-r * t) * Application.WorksheetFunction.NormSDist(d1)
Else
EuropeanDelta = -Exp(-r * t) * Application.WorksheetFunction.NormSDist(-d1)
End If
If PriceOrYield = "Y" Then
EuropeanDelta = EuropeanDelta * -1
End If
End Function
The whole problem is based around the line for "d1". I would like to re-organise to solve for "StrikePrice". I have tried writing it out mathematically and then re-arranging, then swapping back to VBA.

#duffymo is correct, but am giving the answer directly in terms of VBA code
' d1 = (Log(MarketPrice / StrikePrice) + (Volatility * Volatility * 0.5) * t) / (Volatility * Sqr(t))
'
' Volatility * Sqr(t) * d1 = Log(MarketPrice / StrikePrice) + Volatility^2 * t/2
'
' Log(MarketPrice / StrikePrice) = Volatility * Sqr(t) * d1 - Volatility^2 * t/2
'
' MarketPrice / StrikePrice = Exp(Volatility * Sqr(t) * d1 - Volatility^2 * t/2)
'
StrikePrice = MarketPrice / Exp(Volatility * Sqr(t) * d1 - Volatility^2 * t/2)
Other Notes :
For brevity replace Application.WorksheetFunction.Ln() with Log()
There is no need cache SqT = Sqr(t) since it is only used once.
For clarity replace Volatility*Volatility with Volatility^2 as internally it does the same thing.

This is just algebra - high school math.
Take it in steps. Make sure you do the same operation to both sides to make sure that equality still holds.
Here's your starting equation:
d = {ln(m/s) + v*v*t/2}/(v*sqrt(t))
Multiply both sides by the denominator of the RHS:
d*v*sqrt(t) = ln(m/s) + v*v*t/2
Subtract v*v*t/2 from both sides:
(d*v*sqrt(t) - v*v*t/2) = ln(m/s)
Apply the exponential function to both sides, noting that exp(ln(x)) = x:
exp(d*v*sqrt(t) - v*v*t/2) = m/s
Multiply both sides by s:
s*exp(d*v*sqrt(t) - v*v*t/2) = m
Divide both sides by exp(d*v*sqrt(t) - v*v*t/2) to get the desired result:
s = m/exp(d*v*sqrt(t) - v*v*t/2)
Let's see if this function makes sense.
At t = 0 the denominator exp(0) = 1, so the strike price is equal to the market price.
As t -> infinity, we hope that the denominator gets large so s -> zero. L'Hospital's Rule will help here.

Related

#value! error in UDF when doing simple division

When doing a simple division problem with some defined variables I am getting the #value error in a UDF. The variables are all defined as doubles.
Apologies in advance as I am a mechanical engineer by trade so my coding is very amateur. I have a design book I use in excel that can end up being many columns long so to avoid this I am trying to code some UDFs to eliminate the all the cells just doing calculations for other cells. With that, I have run into an issue that I have in my calculations as soon as I start to try to divide variables.
In the code, I am not getting an issue until the Cx dim. I noted out everything starting at SFA_Radians and set the function to output each variable. All is good and expected values until reaching Cx. No matter what I do it seems if I am dividing by a variable I get the #VALUE error. Any help is much appreciated.
Function RADEFFECTSF(SFA As Range, FacetAngle As Range, FacetRadius As Range) As Variant
Dim Slope1 As Double
Dim Slope2 As Double
Dim X1 As Double
Dim Y1 As Double
Dim X2 As Double
Dim Y2 As Double
Dim b1 As Double
Dim b2 As Double
Dim SFA_Radians As Double
Dim FacetAngle_Radians As Double
Dim Pi As Double
Dim Cx As Double
Dim Cy As Double
Dim CalcArray() As Double
Dim i As Long
Pi = Application.WorksheetFunction.Pi()
ReDim CalcArray(1 To SFA.Cells.Count)
For i = 1 To SFA.Cells.Count
SFA_Radians = SFA(i) * Pi / 180
FacetAngle_Radians = FacetAngle(i) * Pi / 180
Slope1 = -Tan(SFA_Radians)
Slope2 = Tan(FacetAngle_Radians)
X1 = FacetRadius(i) * Sin(SFA_Radians)
Y1 = FacetRadius(i) * Cos(SFA_Radians)
b1 = Y1 - (Slope1 * X1)
X2 = -FacetRadius(i) * Sin(FacetAngle_Radians)
Y2 = FacetRadius(i) * Cos(FacetAngle_Radians)
b2 = Y2 - (Slope2 * X2)
Cx = (b2 - b1) / (Slope1 - Slope2)
Cy = (Slope1 * (Cx / (b1))) + b1
CalcArray(i) = Cy - (FacetRadius(i) * Cos(SFA_Radians))
Next i
RADEFFECTSF = CalcArray()
End Function
I already try your code on some sample data and it works:
SAMPLE
From my experience (I am engineer too), most probably some of the data you are importing on the range aren´t numbers. Check it.
The Slope1 - Slope2 value, you can get 0 so place a condition. Same comment for b1.
Check line by line writing the values you are getting in a additional range to see exactly where it is failing, just keeping remaining code as a comment.F.e.
Function RADEFFECTSF(SFA As Range, FacetAngle As Range, FacetRadius As Range) As Variant
...
Pi = 4 * Atn(1)
ReDim CalcArray(1 To SFA.Cells.Count)
For i = 1 To SFA.Cells.Count
SFA_Radians = SFA(i) * Pi / 180
FacetAngle_Radians = FacetAngle(i) * Pi / 180
Slope1 = -Tan(SFA_Radians)
Slope2 = Tan(FacetAngle_Radians)
X1 = FacetRadius(i) * Sin(SFA_Radians)
CalcArray(i) = X1 'This line is just to return the data X1
'Y1 = FacetRadius(i) * Cos(SFA_Radians)
'b1 = Y1 - (Slope1 * X1)
'X2 = -FacetRadius(i) * Sin(FacetAngle_Radians)
'Y2 = FacetRadius(i) * Cos(FacetAngle_Radians)
'b2 = Y2 - (Slope2 * X2)
'If Slope1 <> Slope2 then
'Cx = (b2 - b1) / (Slope1 - Slope2)
'Else
'Place what it is expected when Slope1=Slope2
'End If
'Cy = (Slope1 * (Cx / (b1))) + b1
'CalcArray(i) = Cy - (FacetRadius(i) * Cos(SFA_Radians))
Next i
RADEFFECTSF = CalcArray()
End Function
Check that X1 is the one expected... and so on. Then you can find which one is the code line introducing the unexpected value.
Sorry to give that one as reply, but still I can´t make comments.

VBA : For loop exiting without returning the value

I have the following piece for code to simulate stock prices using stochastic process
Function varswap1(s0, r0, sigma0, t) As Double
Rnd (-10)
Randomize (999)
Dim i As Integer, j As Integer, r As Double
Dim stock() As Double, dt As Double
Dim per As Integer
per = WorksheetFunction.Round(t * 252, 0)
ReDim stock(per)
stock(1) = s0
dt = 1 / 252
For i = 1 To per
stock(i + 1) = stock(i) * Exp((r0 - 0.5 * sigma0 ^ 2) * dt + sigma0 * Sqr(dt) * WorksheetFunction.NormSInv(Rnd()))
Next
varswap1 = WorksheetFunction.Average(stock)
End Function
In this code, I ran debugging by placing a break point at Next and the entire For loop is working absolutely fine. The problem is after completing the loop the function exits and #VALUE! error is displayed in the cell.
I am not able to figure out what is wrong with this code.
Will be thankful if anyone can help me with it.
Try this:
Const n As Integer = 252
Function varswap1(s0, r0, sigma0, t) As Double
Rnd (-10)
Randomize (999)
Dim i As Integer, j As Integer, r As Double
Dim stock() As Double, dt As Double
Dim per As Integer
per = WorksheetFunction.Round(t * n, 0)
ReDim stock(per)
stock(0) = s0 ' First item in the array has index 0
dt = 1# / n ' Avoid integer division, 1/252 = 0
For i = 1 To per
'Each stock depends on the previous stock value:
stock(i) = stock(i - 1) * Exp((r0 - 0.5 * sigma0 ^ 2) * dt + sigma0 * Sqr(dt) * WorksheetFunction.NormSInv(Rnd()))
Next
varswap1 = WorksheetFunction.Average(stock)
End Function
I saw two issues and one suggestion.
One is the array stock goes from 0..252 but you assign values to 1..253 so it crashes.
Also there is a possible integer division resulting in dt=0.0. I updated the definition to make the intent clear that the division is to be done after the conversion from integer to double. Lastly, I moved the magic number 252 to a constant.

How to return value in Excel UDF Function?

I got some code written in a function in VBA, but I'm stuck on how to return the output values areaAnswer1 & areaAnswer2 inside the if - else statments. I'm still new to this. Any help & suggestions are very much appreciated.
Function dateArea(inputDate1 As Date, t1 As Date, t2 As Date, duration As Integer, output As Integer) As Integer
endOfYear = Workbook.Date(Year(inputDate1), 12, 31)
inputDate2 = Workbook.Date(Year(inputDate1) + 1, Month(inputDate1), Day(inputDate1))
endOfDate1 = Workbook.Date(Year(inputDate1) + duration, Month(inputDate1), Day(inputDate1))
endOfDate2 = Workbook.Date(Year(inputDate2) + duration, Month(inputDate2), Day(inputDate2))
areaBase1 = endOfYear - inputDate1
areaBase2 = inputDate2 - endOfYear
totalArea1 = areaBase1 * 365
totalArea2 = areaBase2 * 365
triangleBase1 = endOfDate1 - inputDate1
triangleHypo1 = Workbook.Sqrt((365 * 365) + (triangleBase1 * triangleBase1))
triangleBase2 = t1 - inputDate2
triangleHypo2 = triangleHypo1 * triangleBase2 / triangleBase1
triangleHeight2 = Workbook.Sqrt((triangleHypo2 * triangleHypo2) - (triangleBase2 * triangleBase2))
triangleArea2 = (triangleBase2 * triangleHeight2) / 2
triangleBase3 = (inputDate2 - endOfYear) + (t1 - inputDate2)
triangleHypo3 = triangleBase3 * triangleHypo2 / (t1 - inputDate2)
triangleHeight3 = Workbook.Sqrt((triangleHypo3 * triangleHypo3) - (triangleBase3 * triangleBase3))
triangleArea3 = (triangleBase3 * triangleBaseHeight3) / 2
areaDiffBot2 = triangleArea3 - triangleArea2
triangleBase4 = 365 + (t1 - inputDate2)
triangleHypo4 = triangleBase4 * triangleHeight2 / (t1 - inputDate2)
triangleHeight4 = Workbook.Sqrt((triangleHypo4 * triangleHypo4) - (triangleBase4 * triangleBase4))
triangleArea4 = (triangleBase4 * triangleHeight4) / 2
areaDiffBot1 = triangleArea4 - triangleArea3
triangleHeight5 = 365 * (endOfDate1 - t2) / triangleBase1
triangleHypo5 = Workbook.Sqrt((triangleHeight5 * triangleHeight5) + ((endOfDate1 - t2) * (endOfDate1 - t2)))
triangleArea5 = (endOfDate1 - t2) * triangleHeight5 / 2
triangleBase6 = (endOfDate1 - t2) + areaBase1
triangleHeight6 = (triangleBase6) * 365 / (endOfDate1 - t2)
triangleHypo6 = Workbook.Sqrt((triangleBase6 * triangleBase6) + (triangleHeight6 * triangleHeight6))
triangleArea6 = (triangleBase6 * triangleHeight6) / 2
areaDiffTop1 = triangleArea6 - triangleArea5
triangleBase7 = triangleBase6 + areaBase2
triangleHeight7 = triangleBase7 * triangleHeight6 / triangleBase6
triangleHypo7 = Workbook.Sqrt((triangleBase7 * triangleBase7) + (triangleHeight7 * triangleHeight7))
triangleArea7 = (triangleBase7 * triangleHeight7) / 2
areaDiffTop2 = triangleArea7 - triangleArea6
totalUsedArea1 = areaDiffTop1 + areaDiffBot1
totalUsedArea2 = areaDiffTop2 + areaDiffBot2
areaAnswer1 = totalArea1 - totalUsedArea1
areaAnswer2 = totalArea2 - totalUsedArea2
If output = 1 Then
ElseIf output = 2 Then
ElseIf output = 3 Then
Else
End If
End Function
In VBA you set the return value by assigning it to the function like this:
areaAnswer1 = totalArea1 - totalUsedArea1
areaAnswer2 = totalArea2 - totalUsedArea2
If output = 1 Then
dateArea = areaAnswer1
ElseIf output = 2 Then
dateArea = areaAnswer2
ElseIf output = 3 Then
' ...etc
Note that the assignment to the function does not exit the function. In this case you don't need that immediate exit, as you are already at the end of it. But in some cases you'll want to exit the function as soon as you have assigned the return value:
Exit Function
Just have the function equal a typed value or one of the variables at the end.
select case output
case 1
dateArea = totalUsedArea1
case 2
dateArea = totalUsedArea2
case 3
dateArea = totalUsedArea3
case else
'do something or nothing
end select
Note that you have specified returning an integer which cannot contain a decimal and must be smaller than 32667 (or there abouts).

Excel (2007) function does not calculate when I open the file (Automatic calculation)

I have created a function via vba and I have used this function to make an iterative table. I have set the workbook calculation to automatic and it all works fine but when I open the excel file, the cells that contain the mentioned function, give me #name error and everytime I need to recalculate. Is there a way to fix this?
Public Function FrictionFactor(relativeroughness, reynoldsnumber)
'Dim relativeroughness, reynoldsnumber As Double
fNext = 0.005 ' initial value for f
fIncrement = 0.005 ' initial step size
Convergence = 0.000001 ' sets the decimal place accuracy of the result
Do
fStart = fNext
LHSColebrookStart = 1 / (fStart ^ 0.5)
RHSColebrookStart = -2 * (Log((relativeroughness / 3.7) + (2.51 / (reynoldsnumber * (fStart ^ 0.5)))) / Log(10))
DifferenceStart = LHSColebrookStart - RHSColebrookStart
fNext = fStart + fIncrement
LHSColebrookNext = 1 / (fNext ^ 0.5)
RHSColebrookNext = -2 * (Log((relativeroughness / 3.7) + (2.51 / (reynoldsnumber * (fNext ^ 0.5)))) / Log(10))
DifferenceNext = LHSColebrookNext - RHSColebrookNext
If DifferenceStart * DifferenceNext < 0 Then ' march f in opposite direction and more slowly
fIncrement = fIncrement / -10
ElseIf DifferenceStart * DifferenceNext = 0 Then ' done
fIncrement = 0
End If ' keep marching f in same direction and at same rate
Loop While Abs(fStart - fNext) > Convergence
FrictionFactor = fStart
End Function
The usual reason this happens is that macros are not enabled when the workbook is opened. Check your Security settings.

Set VBA macro for Excel to run a series of Linear Equations by taking variable from several rows?

I've got a set of equations which I'd like to be repeated taking variables from the next row down for each of the columns at which each variable is located. I am a beginner, so my coding is probably not to scratch:
Sub Iteration()
Dim al, ab, ae As Double
Dim as1, as2 As Double
'etc
as1 = Range("CG7")
as2 = Range("CG8")
aA1 = Range("BQ7")
'etc
intCounter = 0
For intCounter = 1 To 10000
Let x = ((aN1 * 1000) - (as1 * aA1) + (as2 * aA2)) / (al * fc * ae * ab)
Let x2 = ((aN12 * 1000) - (as12 * aA12) + (as22 * aA22)) / (al2 * fc2 * ae2 * ab2)
Next
Sheets("Sheet1").Range("CJ7").Value = x
End Sub
I've done this for several variables which I've set as the range relative to each variable value. And then for the next row I've had to redo the whole equation and set the variables again for the next row down. Is there any way to set the variables (possibly with a relative cell reference?) which will skip to the cell in the next row for the next calculation? Consider also that there are 36 rows for calculation and about 9 variables!
If I understand you correctly, how about something like this:
Sub Iteration()
Dim al, ab, ae As Double
Dim as1, as2 As Double
'etc
intCounter = 0
For intCounter = 0 To 10000
as1 = Range("CG7").Offset(intCounter)
as2 = Range("CG8").Offset(intCounter)
aA1 = Range("BQ7").Offset(intCounter)
'etc
Let x = ((aN1 * 1000) - (as1 * aA1) + (as2 * aA2)) / (al * fc * ae * ab)
Let x2 = ((aN12 * 1000) - (as12 * aA12) + (as22 * aA22)) / (al2 * fc2 * ae2 * ab2)
Next
Sheets("Sheet1").Range("CJ7").Value = x
End Sub

Resources