[英]EXCEL solver, VBA calls unwanted function before launching the solver
我正在编写一个代码,该代码应计算各种不同金融证券的公允价值。 这些证券来自不同的发行人,因此将它们按国家分组,然后进行评估。
为此,我需要为每个组/国家/地区设置6个参数,不幸的是这些参数不是固定的,但每天都会更改。 每次运行模型时,我都需要重新计算它们,因此我编写了一个子例程来优化求解器的此问题。
到目前为止,它在大多数时间都有效,但是有时在午餐前,vba代码进入了同一电子表格的其他功能,并更改了问题的起始值(作为前一天的参数读取)。 Solver子例程中未提及这些功能,甚至在同一模块或工作表中也未提及。
知道为什么会这样吗? 关于如何防止VBA跨入有害功能的任何想法?
这是我的求解器代码
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
最后一行之后,代码立即进入此函数
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
谢谢您的帮助!
这取决于:
Application.Volatile
该方法告诉应用程序该函数是Volatile
。 换句话说, 每次对电子表格进行更改时 , 都必须重新计算该函数。
因此:
NSCoeff
修改电子表格; Application
看到什么是Volatile
然后重新计算所有内容。 您的情况是Discount_Quartic
。 Voilàvoilà 在此处找到有关Application.Volatile
方法的更多信息。
至于关于如何防止VBA跨入有害功能的任何想法? ,您有两种解决方案(可能更多,但是现在我想到了这些):
Application.Volatile
。 但是,这将不再提示重新计算该函数(除非您没有明确地重新计算它)。 做一个小技巧,我将通过一个简单的示例向您展示:
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
如果根据昨天的数据来确定Solver的参数为静态值,则应为这些值制作一个静态副本以用于Solver。 我怀疑您的参数是计算的结果,其中包括折扣的日期等(以及费率,优惠券)。 因此,当您打开工作簿时,这些计算将得到更新(如@ Matteo NNZ所述,上面的函数被标记为volatile),因此Solver开始使用新值。
根据您的代码,Solver尝试通过更改单元格N4:S4来使单元格N9最小化,但同时使N4和S4均≥0.001。
我遇到了与您完全相同的问题,发现您想回答我的问题。 我同意ChipsLetten的意见,然后看了一下电子表格,发现我具有该功能的单元格。 因此,请检查您的电子表格是否在某些单元格中未使用Discount_Quadratic
(如具有公式“ = Discount_Quadratic(a,b,c,d,t)”的单元格A1)
如果您在电子表格的单元格中具有此功能,则Excel将运行此功能,等于没有此功能的任何单元格。 因此,当Excel更新所有电子表格的公式时,即使您没有真正调用它,在任何时候您的代码都会被此更新中断并在此函数内运行代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.