简体   繁体   中英

EXCEL solver, VBA calls unwanted function before launching the solver

I'm writing a code that should calculate the Fair Values of sevaral different financial securities. The securities come from different issuers, so they are grouped by country and then evaluated.

In order to do so, I need to fit 6 parameters for each group/country, unfortunately these parameters aren't fixed, but they will change every day. I need to recalculated them every time I run my model, so I wrote a subroutine to optimize this problem with the Solver.

So far it works most of the time, but sometimes before lunching the solver the vba code steps into other function of the same spreadsheet and changes the starting values ( read as previous day parameters) of my problem. These function are not mentioned in the Solver subroutine, they are not even in the same module or sheet.

Any idea of why this is happening? Any Idea of how to prevent VBA stepping inside unwanted function?

here is my Solver code

Sub NSCoeff()
Dim current_wb As String
current_wb = ThisWorkbook.Name


Workbooks(current_wb).Sheets("Nelson_Siegel").Calculate
Workbooks(current_wb).Sheets("Nelson_Siegel").Activate
SolverReset
SolverOptions Precision:=0.01, Convergence:=0.1, AssumeNonNeg:=False
SolverOk SetCell:="$N$9", MaxMinVal:=2, ValueOf:=0, ByChange:="$N$4:$S$4", _
    Engine:=1, EngineDesc:="GRG Nonlinear"
SolverAdd CellRef:="$N$4", Relation:=3, FormulaText:="0.001"
SolverAdd CellRef:="$S$4", Relation:=3, FormulaText:="0.001"
SolverOk SetCell:="$N$9", MaxMinVal:=2, ValueOf:=0, ByChange:="$N$4:$S$4", _
    Engine:=1, EngineDesc:="GRG Nonlinear"
SolverOk SetCell:="$N$9", MaxMinVal:=2, ValueOf:=0, ByChange:="$N$4:$S$4", _
    Engine:=1, EngineDesc:="GRG Nonlinear"
SolverSolve userFinish:=True

End Sub

Immediately after the last line the code steps into this function

Function Discount_Quartic(a As Double, b As Double, c As Double, d As Double, t As Double) As Double
Dim dr, r As Double
Application.Volatile

r = Worksheets("ImpBond").Cells(4, 26).Value
dr = Worksheets("ImpBond").Cells(4, 27).Value
Discount_Quartic = a * Exp(-r * t) + b * Exp(-r * t * dr) + c * Exp(-r * t * dr ^ 2) + d * Exp(-r * t * dr ^ 3) + (1 - a - b - c - d) * Exp(-r * dr ^ 4 * t)
End Function

Thanks for the help!

It depends on this:

Application.Volatile

This method tells the application that the function is Volatile . In other words, every time something changes into the spreadsheet, the function must be recalculated.

Hence:

  • You modify the spreadsheet through your sub NSCoeff ;
  • The Application sees what was Volatile and recalculates everything it was so. In your case, Discount_Quartic . Voilà voilà

Find more about the Application.Volatile method here .

And as for Any Idea of how to prevent VBA stepping inside unwanted function? , you have two solutions (probably more, but these are the ones coming to my mind now):

  • Remove the Application.Volatile from the Function. This will, though, not prompt the recalculation of the function anymore (unless you don't explicitly recalculate it).
  • Doing a small trick that I will show you with a simple example:

     Dim dontCall As Boolean '<-- default: False Sub dontCallTheFunction() Range("A1") = 1 '<-- recalculation prompted, we will get into the function dontCall= True'<-- we don't want the function to be recalculated End Sub Function myFunction() Application.Volatile If dontCall= False Then myFunction = 3 Else dontCall = False '<-- reset the value to False, so next time we'll calculate it normally End If End Function 

If the parameters for Solver are meant to be static values based on yesterday's data then you should make a static copy of the values for using with Solver. I suspect that your parameters are the results of calculations which include dates, etc for discounting (and rates, coupons). So when you open the workbook these calcs get updated (your function above was marked as volatile as explained by @ Matteo NNZ) and so Solver starts using the new values.

From your code, Solver is trying to minimise cell N9 by changing cells N4:S4 but keeping both N4 and S4 >= 0.001.

I had exactly the same problem of you and found your ask trying to answer mine. I agreed with ChipsLetten then I took a look on my spreadsheet and discovery that I have cells with the function. So, check if your spreadsheet isn't using the Discount_Quadratic in some cells

(like cell A1 with the formula "=Discount_Quadratic(a,b,c,d,t)")

If you have this function in cells of your spreadsheet, Excel will run this function equal to no cells with this function there is. So, when Excel update the formulas of all the spreadsheet, at any time your code will be interrupted by this update and running the code inside this function, even without you really had called it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM