简体   繁体   English

EXCEL解算器,VBA在启动解算器之前会调用不需要的函数

[英]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. 为此,我需要为每个组/国家/地区设置6个参数,不幸的是这些参数不是固定的,但每天都会更改。 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. 到目前为止,它在大多数时间都有效,但是有时在午餐前,vba代码进入了同一电子表格的其他功能,并更改了问题的起始值(作为前一天的参数读取)。 These function are not mentioned in the Solver subroutine, they are not even in the same module or sheet. Solver子例程中未提及这些功能,甚至在同一模块或工作表中也未提及。

Any idea of why this is happening? 知道为什么会这样吗? Any Idea of how to prevent VBA stepping inside unwanted function? 关于如何防止VBA跨入有害功能的任何想法?

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 . 该方法告诉应用程序该函数是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 ; 您可以通过子NSCoeff修改电子表格;
  • The Application sees what was Volatile and recalculates everything it was so. Application看到什么是Volatile然后重新计算所有内容。 In your case, Discount_Quartic . 您的情况是Discount_Quartic Voilà voilà Voilàvoilà

Find more about the Application.Volatile method here . 在此处找到有关Application.Volatile方法的更多信息。

And as for Any Idea of how to prevent VBA stepping inside unwanted function? 至于关于如何防止VBA跨入有害功能的任何想法? , you have two solutions (probably more, but these are the ones coming to my mind now): ,您有两种解决方案(可能更多,但是现在我想到了这些):

  • Remove the Application.Volatile from the Function. 从功能中删除Application.Volatile 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. 如果根据昨天的数据来确定Solver的参数为静态值,则应为这些值制作一个静态副本以用于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. 因此,当您打开工作簿时,这些计算将得到更新(如@ Matteo NNZ所述,上面的函数被标记为volatile),因此Solver开始使用新值。

From your code, Solver is trying to minimise cell N9 by changing cells N4:S4 but keeping both N4 and S4 >= 0.001. 根据您的代码,Solver尝试通过更改单元格N4:S4来使单元格N9最小化,但同时使N4和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. 我同意ChipsLetten的意见,然后看了一下电子表格,发现我具有该功能的单元格。 So, check if your spreadsheet isn't using the Discount_Quadratic in some cells 因此,请检查您的电子表格是否在某些单元格中未使用Discount_Quadratic

(like cell A1 with the formula "=Discount_Quadratic(a,b,c,d,t)") (如具有公式“ = Discount_Quadratic(a,b,c,d,t)”的单元格A1)

If you have this function in cells of your spreadsheet, Excel will run this function equal to no cells with this function there is. 如果您在电子表格的单元格中具有此功能,则Excel将运行此功能,等于没有此功能的任何单元格。 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. 因此,当Excel更新所有电子表格的公式时,即使您没有真正调用它,在任何时候您的代码都会被此更新中断并在此函数内运行代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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