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

时间:2015-06-05 11:43:54

标签: excel vba excel-vba

我正在编写一个代码来计算不同金融证券的公允价值。证券来自不同的发行人,因此按国家分组,然后进行评估。

为了做到这一点,我需要为每个组/国家拟合6个参数,遗憾的是这些参数不是固定的,但它们每天都会改变。每次运行模型时我都需要重新计算它们,所以我编写了一个子程序来用Solver优化这个问题。

到目前为止,它大部分时间都可以工作,但有时在解析求解器之前,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

感谢您的帮助!

3 个答案:

答案 0 :(得分:0)

这取决于:

Application.Volatile

此方法告诉应用程序该函数是Volatile。换句话说,每当某些内容更改为电子表格时,都必须重新计算该函数。

因此:

  • 您可以通过子NSCoeff;
  • 修改电子表格
  • Application看到Volatile的内容并重新计算其中的所有内容。在您的情况下,Discount_Quartic。 Voilàvoilà

详细了解Application.Volatile方法here

至于如何防止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
    

答案 1 :(得分:0)

如果Solver的参数是基于昨天数据的静态值,那么您应该使用Solver制作值的静态副本。我怀疑你的参数是计算的结果,包括折扣的日期等(以及费率,优惠券)。因此,当您打开工作簿时,这些计算得到更新(上面的函数被标记为易失性,如@ Matteo NNZ所解释的那样),因此Solver开始使用新值。

从您的代码中,Solver尝试通过更改单元格N4:S4来最小化单元格N9,但保持N4和S4> = 0.001。

答案 2 :(得分:0)

我遇到了与你完全相同的问题,发现你的问题试图回答我的问题。我同意ChipsLetten然后我看了一下我的电子表格并发现我有这个功能的单元格。 因此,请检查您的电子表格是否在某些单元格中使用 Discount_Quadratic

  

(类似于公式&#34的单元格A1; = Discount_Quadratic(a,b,c,d,t)&#34;)

如果您在电子表格的单元格中使用此功能,Excel将运行此功能,等于没有具有此功能的单元格。因此,当Excel更新所有电子表格的公式时,您的代码将随时被此更新中断并运行此函数内的代码,即使您没有真正调用它。