A Comprehensive Monte Carlo Valuation of Variable Annuities

Hengxin Li, Mingbin Feng, Mingyi Jiang

2020-01-19

Package Info

This package uses Monte Carlo simulation to estimate the fair market value of a large portfolio of synthetic variable annuities. The portfolio of variable annuities under consideration is generated based on realistic features of common types of guarantee riders in North America. The Monte Carlo simulation engine generates sample paths of asset prices based on Black-Scholes model. In this vignette, we will demonstrate the functionalities provided in this package.

For illustrative purposes, we will use few scenarios to valuate a pool of two variable annuities. Users may obtain a more robust valuation result by increasing the amount of risk-neutral scenarios.

Yield Curve Generation

In this step, we exploit Newton’s method to calculate discount factors and forward rates at different tenor based on given swap rates using buildCurve().

# Initialize required inputs to boostrap a curve
swap <- c(0.69, 0.77, 0.88, 1.01, 1.14, 1.38, 1.66, 2.15)*0.01
tenor <- c(1, 2, 3, 4, 5, 7, 10, 30)
fixFreq <- 6
fixDCC <- "Thirty360"
fltFreq <- 6
fltDCC <- "ACT360"
calendar <- "NY"
bdc <- "Modified_Foll"
curveDate <- "2016-02-08"
numSetDay <- 2
yieldCurveDCC <- "Thirty360"
# Bootstrap a forward curve 
buildCurve(swap, tenor, fixFreq, fixDCC, fltFreq, fltDCC, calendar, bdc,
            curveDate, numSetDay, yieldCurveDCC)
#>      obsDate discountFac    zeroRate forwardCurve  dayCount
#> 1 2016-02-08   1.0000000 0.000000000  0.006912035  0.000000
#> 2 2017-02-10   0.9930975 0.006888125  0.008520036  1.005556
#> 3 2018-02-10   0.9847078 0.007683825  0.011060713  2.005556
#> 4 2019-02-10   0.9739354 0.008787170  0.014146403  3.005556
#> 5 2020-02-10   0.9603499 0.010100373  0.016846310  4.005556
#> 6 2021-02-10   0.9444396 0.011420029  0.020451281  5.005556
#> 7 2023-02-10   0.9073275 0.013882093  0.024514485  7.005556
#> 8 2026-02-10   0.8451708 0.016812319  0.032098279 10.005556
#> 9 2046-02-10   0.5147311 0.022132923  0.032098279 30.005556

Generate index scenarios and fund scenarios

In the following example, we first simulate the index movements using genIndexScen(). Three of the inputs to genIndexScen() are stored as default data under variable names “mCov”, “indexNames”, and “cForwardCurve” respectively. For illustration purposes, we will simulate 100 scenarios for 360 steps with a step length dT = 1/12 and seed = 1.

The underlying model utilizes the multivariate Black-Scholes model. All the simulated index movements are stored in a 3D-array with dimensions [number of Scenarios, number of Steps, number of Indices]

Default covariance matrix

US SMALL INT FIXED MONEY
0.15 0.0 0.00 0.000 0.0000
0.00 0.2 0.00 0.000 0.0000
0.00 0.0 0.17 0.000 0.0000
0.00 0.0 0.00 0.029 0.0000
0.00 0.0 0.00 0.000 0.0061

Default index names

Index Names
US
SMALL
INT
FIXED
MONEY

Risk-neutral path simulation for 5 indices

# We will show the index simulated path for five months of the first scenario 
indexScen <- genIndexScen(mCov, 100, 360, indexNames, 1 / 12, cForwardCurve, 1)
indexScen[1, 1:5, ]
#>           [,1]      [,2]      [,3]      [,4]      [,5]
#> [1,] 0.9280933 0.7108209 1.0542468 1.0391611 1.0050411
#> [2,] 1.0160765 1.1770017 0.9065351 0.9935556 0.9305910
#> [3,] 0.9066403 0.9151064 1.2239807 1.0199796 0.9939919
#> [4,] 1.1897872 0.9397168 0.9853616 1.0115470 1.0117871
#> [5,] 1.0327826 0.9718774 0.8855638 1.0016170 0.9723979

Then we use genFundScen() to map the index movements to funds according to different allocations of capital using a fund map (stored as default data under variable “fundMap”). The fund movements are also stored in a 3D-array with dimension [number of Scenarios, number of Steps, number of Funds]

Risk-neutral path simulation for 10 funds

# Again, we show the fund simulated path for five months of the first scenario 
fundScen <- genFundScen(fundMap, indexScen)
fundScen[1, 1:5, ]
#>           [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]
#> [1,] 0.9280933 0.7108209 1.0542468 1.0391611 1.0050411 0.8411844 0.9911700
#> [2,] 1.0160765 1.1770017 0.9065351 0.9935556 0.9305910 1.0804466 0.9613058
#> [3,] 0.9066403 0.9151064 1.2239807 1.0199796 0.9939919 0.9100268 1.0653105
#> [4,] 1.1897872 0.9397168 0.9853616 1.0115470 1.0117871 1.0897591 1.0875744
#> [5,] 1.0327826 0.9718774 0.8855638 1.0016170 0.9723979 1.0084206 0.9591732
#>           [,8]      [,9]     [,10]
#> [1,] 0.9836272 0.9512190 0.9474726
#> [2,] 1.0048160 0.9876751 1.0047520
#> [3,] 0.9633100 1.1313184 1.0119398
#> [4,] 1.1006671 0.9716682 1.0276399
#> [5,] 1.0171998 0.9114579 0.9728478

Generate a synthetic portfolio of variable annuities

Perhaps the most value-added step in this package is the generation of synthetic portfolio of variable annuities that has realistic charateristic features. Using the fuction genPortInception(), users can generate a synthetic variable annuity portfolio of desirable size. The function genPortInception() has certain predetermined default values based on the research in the package reference. We recommend users to change these default values, such as maturity and issue range, to match their portfolio characteristics. In the current version, there are a few constraints for the portfolio being generated: The issue range must be later than the first date of historical scenario; The maturity range should also be set after the valuation date to be meaningful.

# For illustration purposes, we will only simulate one guarantee contract for each of the 19 guarantee types. Please note that due to randomness the generated portfolio under this code block may not align with the default VAPort under lazy data.
if(capabilities("long.double")) {
genPortInception(issueRng = c("2001-08-01", "2014-01-01"), numPolicy =  1)
}
#>      recordID survivorShip gender productType  issueDate    matDate  birthDate
#> DBRP        1            1      F        DBRP 2013-11-01 2031-11-01 1954-02-01
#> DBRU        2            1      F        DBRU 2009-09-01 2029-09-01 1957-06-01
#> DBSU        3            1      F        DBSU 2010-08-01 2030-08-01 1978-08-01
#> ABRP        4            1      M        ABRP 2007-07-01 2022-07-01 1969-05-01
#> ABRU        5            1      M        ABRU 2008-07-01 2025-07-01 1960-07-01
#> ABSU        6            1      M        ABSU 2011-05-01 2030-05-01 1966-05-01
#> IBRP        7            1      F        IBRP 2001-11-01 2024-11-01 1978-03-01
#> IBRU        8            1      F        IBRU 2002-07-01 2026-07-01 1968-11-01
#> IBSU        9            1      M        IBSU 2013-07-01 2039-07-01 1964-07-01
#> MBRP       10            1      M        MBRP 2009-08-01 2026-08-01 1964-11-01
#> MBRU       11            1      M        MBRU 2009-03-01 2033-03-01 1975-04-01
#> MBSU       12            1      M        MBSU 2013-12-01 2041-12-01 1953-05-01
#> WBRP       13            1      F        WBRP 2008-10-01 2027-10-01 1972-09-01
#> WBRU       14            1      F        WBRU 2008-12-01 2026-12-01 1968-06-01
#> WBSU       15            1      M        WBSU 2004-10-01 2031-10-01 1950-02-01
#> DBAB       16            1      F        DBAB 2007-12-01 2034-12-01 1971-05-01
#> DBIB       17            1      F        DBIB 2012-05-01 2028-05-01 1951-10-01
#> DBMB       18            1      F        DBMB 2007-09-01 2033-09-01 1956-09-01
#> DBWB       19            1      F        DBWB 2004-04-01 2033-04-01 1963-07-01
#>      currentDate baseFee riderFee rollUpRate gbAmt gmwbBalance wbWithdrawalRate
#> DBRP  2013-11-01    0.02   0.0025      5e-04     0           0            5e-04
#> DBRU  2009-09-01    0.02   0.0035      5e-04     0           0            5e-04
#> DBSU  2010-08-01    0.02   0.0035      5e-04     0           0            5e-04
#> ABRP  2007-07-01    0.02   0.0050      5e-04     0           0            5e-04
#> ABRU  2008-07-01    0.02   0.0060      5e-04     0           0            5e-04
#> ABSU  2011-05-01    0.02   0.0060      5e-04     0           0            5e-04
#> IBRP  2001-11-01    0.02   0.0060      5e-04     0           0            5e-04
#> IBRU  2002-07-01    0.02   0.0070      5e-04     0           0            5e-04
#> IBSU  2013-07-01    0.02   0.0070      5e-04     0           0            5e-04
#> MBRP  2009-08-01    0.02   0.0050      5e-04     0           0            5e-04
#> MBRU  2009-03-01    0.02   0.0060      5e-04     0           0            5e-04
#> MBSU  2013-12-01    0.02   0.0060      5e-04     0           0            5e-04
#> WBRP  2008-10-01    0.02   0.0065      5e-04     0           0            5e-04
#> WBRU  2008-12-01    0.02   0.0075      5e-04     0           0            5e-04
#> WBSU  2004-10-01    0.02   0.0075      5e-04     0           0            5e-04
#> DBAB  2007-12-01    0.02   0.0075      5e-04     0           0            5e-04
#> DBIB  2012-05-01    0.02   0.0085      5e-04     0           0            5e-04
#> DBMB  2007-09-01    0.02   0.0075      5e-04     0           0            5e-04
#> DBWB  2004-04-01    0.02   0.0090      5e-04     0           0            5e-04
#>      withdrawal fundNum1 fundNum2 fundNum3 fundNum4 fundNum5 fundNum6 fundNum7
#> DBRP          0        1        2        3        4        5        6        7
#> DBRU          0        1        2        3        4        5        6        7
#> DBSU          0        1        2        3        4        5        6        7
#> ABRP          0        1        2        3        4        5        6        7
#> ABRU          0        1        2        3        4        5        6        7
#> ABSU          0        1        2        3        4        5        6        7
#> IBRP          0        1        2        3        4        5        6        7
#> IBRU          0        1        2        3        4        5        6        7
#> IBSU          0        1        2        3        4        5        6        7
#> MBRP          0        1        2        3        4        5        6        7
#> MBRU          0        1        2        3        4        5        6        7
#> MBSU          0        1        2        3        4        5        6        7
#> WBRP          0        1        2        3        4        5        6        7
#> WBRU          0        1        2        3        4        5        6        7
#> WBSU          0        1        2        3        4        5        6        7
#> DBAB          0        1        2        3        4        5        6        7
#> DBIB          0        1        2        3        4        5        6        7
#> DBMB          0        1        2        3        4        5        6        7
#> DBWB          0        1        2        3        4        5        6        7
#>      fundNum8 fundNum9 fundNum10 fundValue1 fundValue2 fundValue3 fundValue4
#> DBRP        8        9        10      0.000       0.00      0.000 105809.638
#> DBRU        8        9        10      0.000   31553.25  31553.248  31553.248
#> DBSU        8        9        10  27721.639   27721.64  27721.639  27721.639
#> ABRP        8        9        10      0.000       0.00  71421.693  71421.693
#> ABRU        8        9        10  22052.253   22052.25  22052.253  22052.253
#> ABSU        8        9        10      0.000   21364.51  21364.506  21364.506
#> IBRP        8        9        10      0.000       0.00 205836.574      0.000
#> IBRU        8        9        10      0.000       0.00      0.000      0.000
#> IBSU        8        9        10  48171.917   48171.92  48171.917  48171.917
#> MBRP        8        9        10      0.000       0.00  52395.296  52395.296
#> MBRU        8        9        10  38515.487   38515.49  38515.487  38515.487
#> MBSU        8        9        10   9882.453       0.00   9882.453   9882.453
#> WBRP        8        9        10      0.000   55944.97  55944.968  55944.968
#> WBRU        8        9        10   6677.476       0.00   6677.476      0.000
#> WBSU        8        9        10  50324.322       0.00  50324.322      0.000
#> DBAB        8        9        10  57902.770   57902.77      0.000      0.000
#> DBIB        8        9        10  66714.406   66714.41  66714.406  66714.406
#> DBMB        8        9        10      0.000       0.00      0.000      0.000
#> DBWB        8        9        10  70521.621       0.00      0.000  70521.621
#>      fundValue5 fundValue6 fundValue7 fundValue8 fundValue9 fundValue10
#> DBRP      0.000      0.000      0.000      0.000 105809.638       0.000
#> DBRU  31553.248  31553.248  31553.248  31553.248  31553.248   31553.248
#> DBSU  27721.639  27721.639  27721.639  27721.639      0.000   27721.639
#> ABRP  71421.693  71421.693  71421.693  71421.693      0.000       0.000
#> ABRU  22052.253  22052.253  22052.253  22052.253  22052.253       0.000
#> ABSU  21364.506  21364.506      0.000      0.000      0.000   21364.506
#> IBRP      0.000      0.000      0.000      0.000 205836.574       0.000
#> IBRU      0.000 131955.783      0.000      0.000 131955.783       0.000
#> IBSU  48171.917  48171.917  48171.917  48171.917  48171.917   48171.917
#> MBRP      0.000      0.000  52395.296  52395.296      0.000   52395.296
#> MBRU  38515.487  38515.487  38515.487  38515.487  38515.487   38515.487
#> MBSU   9882.453   9882.453   9882.453   9882.453   9882.453    9882.453
#> WBRP  55944.968  55944.968  55944.968      0.000      0.000   55944.968
#> WBRU   6677.476   6677.476   6677.476   6677.476   6677.476    6677.476
#> WBSU  50324.322  50324.322      0.000  50324.322      0.000   50324.322
#> DBAB      0.000      0.000      0.000      0.000      0.000       0.000
#> DBIB      0.000      0.000      0.000  66714.406  66714.406       0.000
#> DBMB      0.000  91520.653  91520.653  91520.653      0.000   91520.653
#> DBWB  70521.621      0.000  70521.621  70521.621  70521.621       0.000
#>      fundFee1 fundFee2 fundFee3 fundFee4 fundFee5 fundFee6 fundFee7 fundFee8
#> DBRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBRU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBSU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> ABRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> ABRU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> ABSU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> IBRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> IBRU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> IBSU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> MBRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> MBRU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> MBSU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> WBRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> WBRU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> WBSU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBAB    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBIB    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBMB    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBWB    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#>      fundFee9 fundFee10
#> DBRP   0.0047    0.0046
#> DBRU   0.0047    0.0046
#> DBSU   0.0047    0.0046
#> ABRP   0.0047    0.0046
#> ABRU   0.0047    0.0046
#> ABSU   0.0047    0.0046
#> IBRP   0.0047    0.0046
#> IBRU   0.0047    0.0046
#> IBSU   0.0047    0.0046
#> MBRP   0.0047    0.0046
#> MBRU   0.0047    0.0046
#> MBSU   0.0047    0.0046
#> WBRP   0.0047    0.0046
#> WBRU   0.0047    0.0046
#> WBSU   0.0047    0.0046
#> DBAB   0.0047    0.0046
#> DBIB   0.0047    0.0046
#> DBMB   0.0047    0.0046
#> DBWB   0.0047    0.0046

Monte Carlo Valuation

After generating the above required elements for Monte Carlo valuation, we can now proceed to calculate the fair market price of the portfolio by calling the function valuatePortfolio(). Under the current version of the package, all the annuity contracts in the portfolio are assumed to be valuated on the same date, i.e. the first date of our simulated fund scenario. Users can either use the default mortality table by calling “mortTable”, or input a mortality table to project liability cash flows.

# In this vignette, we will arbitrarily use the first two scenarios from fundSen to valuate a portfolio of two guarantees to speed up the execution of the example.
# The input cForwardCurve is a vector of 0.02 with dimension 360. It could also be a forward curve calculated using the buildCurve() function.
valuatePortfolio(VAPort[1:2, ], mortTable, fundScen[1, , ], 1 / 12, cForwardCurve)
#> $portVal
#> [1] 0
#> 
#> $portRC
#> [1] 597.3302
#> 
#> $vecVal
#> [1] 0 0
#> 
#> $vecRC
#> [1] 347.5886 249.7416

Note that users can also “age” the portfolio, calling the function agePortfolio(), to a particular valuatioon date by incorporating the historical fund movements prior to that date.

# Again, we will arbitrarily age a portfolio of two guarantees to speed up the execution.
targetDate <- "2016-01-01"
# Here we generate historical fund scenarios using default index data stored under "histIdxScen"
histFundScen <- genFundScen(fundMap, histIdxScen)
# Perform aging
agePortfolio(VAPort[1:2, ], mortTable, histFundScen, histDates, dT = 1 / 12, targetDate, cForwardCurve)
#>      recordID survivorShip gender productType  issueDate    matDate  birthDate
#> DBRP        1            1      M        DBRP 2010-11-01 2036-11-01 1965-07-01
#> DBRU        2            1      M        DBRU 2013-02-01 2034-02-01 1969-11-01
#>      currentDate baseFee riderFee rollUpRate gbAmt gmwbBalance wbWithdrawalRate
#> DBRP  2016-01-01    0.02   0.0025      5e-04     0           0            5e-04
#> DBRU  2016-01-01    0.02   0.0035      5e-04     0           0            5e-04
#>      withdrawal fundNum1 fundNum2 fundNum3 fundNum4 fundNum5 fundNum6 fundNum7
#> DBRP          0        1        2        3        4        5        6        7
#> DBRU          0        1        2        3        4        5        6        7
#>      fundNum8 fundNum9 fundNum10 fundValue1 fundValue2 fundValue3 fundValue4
#> DBRP        8        9        10   120788.3  135115.39   90082.35   56505.24
#> DBRU        8        9        10        0.0   54975.59       0.00   44099.64
#>      fundValue5 fundValue6 fundValue7 fundValue8 fundValue9 fundValue10
#> DBRP   47943.95   126814.8       0.00       0.00   103083.3    85152.89
#> DBRU   42005.60        0.0   51996.72   51055.69        0.0        0.00
#>      fundFee1 fundFee2 fundFee3 fundFee4 fundFee5 fundFee6 fundFee7 fundFee8
#> DBRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#> DBRU    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#>      fundFee9 fundFee10
#> DBRP   0.0047    0.0046
#> DBRU   0.0047    0.0046

Closing Remarks

Though the primary purpose of this package is to valuate a portfolio of variable annuities, users can also use the valuateOnePolicy() and the ageOnePolicy() functions to perform fair market valuation on a single variable annuity as demonstrated below.

Valuation of one variable annuity

exPolicy <- VAPort[1, ]
valuateOnePolicy(exPolicy, mortTable, fundScen[1:2, , ], 1 / 12, cForwardCurve)
#> $policyValue
#> [1] 0
#> 
#> $riskCharge
#> [1] 454.1419

Aging of one variable annuity

# Similarly, users can age this single policy before pricing it. We use the same target date and historical fund scenario as generated before
exPolicy <- VAPort[1, ]
ageOnePolicy(exPolicy, mortTable, histFundScen, histDates, dT = 1 / 12, targetDate, cForwardCurve)
#>      recordID survivorShip gender productType  issueDate    matDate  birthDate
#> DBRP        1            1      M        DBRP 2010-11-01 2036-11-01 1965-07-01
#>      currentDate baseFee riderFee rollUpRate gbAmt gmwbBalance wbWithdrawalRate
#> DBRP  2016-01-01    0.02   0.0025      5e-04     0           0            5e-04
#>      withdrawal fundNum1 fundNum2 fundNum3 fundNum4 fundNum5 fundNum6 fundNum7
#> DBRP          0        1        2        3        4        5        6        7
#>      fundNum8 fundNum9 fundNum10 fundValue1 fundValue2 fundValue3 fundValue4
#> DBRP        8        9        10   120788.3   135115.4   90082.35   56505.24
#>      fundValue5 fundValue6 fundValue7 fundValue8 fundValue9 fundValue10
#> DBRP   47943.95   126814.8          0          0   103083.3    85152.89
#>      fundFee1 fundFee2 fundFee3 fundFee4 fundFee5 fundFee6 fundFee7 fundFee8
#> DBRP    0.003    0.005    0.006    0.008    0.001   0.0038   0.0045   0.0055
#>      fundFee9 fundFee10
#> DBRP   0.0047    0.0046