繁体   English   中英

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

[英]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.

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