使用Cholesky分解进行投资组合模拟

时间:2015-07-28 08:29:06

标签: r montecarlo

我对具有4种资产(债券,股票,股票,现金市场)的投资组合进行MC模拟 我使用每月步骤,我的模拟范围是10年,即120步。我的最终目标是计算年度预期缺口,即获得投资组合回报中最差的5%。

模拟似乎没问题 - 乍一看。然而,我的印象是随着时间的推移漂移在这个过程中占主导地位,所以我的预期缺口甚至是长期的积极因素。当我增加权益权重时,预期的差额最终会减少。当我将每个资产的预期回报设置为零时也是如此,因此增加的风险应该会拖累预期的亏损。 我希望我的代码中有一个错误,但看不到它。任何建议高度赞赏!

#maturity in years
maturity <- 10
#Using monthly steps
nsteps <- maturity*12
dt <-  maturity / nsteps
#number of assets
nAssets = 4
#number of simulations
nTrails = 10000

#expected return p.a. for each asset, stored in vector BM.mu
BM.mu <- rep(NA,nAssets)
BM.mu[1] <- 0.0072
BM.mu[2] <- 0.0365
BM.mu[3] <- 0.04702
BM.mu[4] <- 0.0005

#defining variable size
simulated.Returns   <- array(NA,    dim = c(nsteps+1, nTrails, nAssets))
cumulative.PortReturns  <- matrix(rep(NA,nsteps*nTrails), nrow = nsteps, ncol = nTrails)
ES  <- rep(NA, maturity)

#defining my monthly correlation and covariance matrix
corr_matrix <- matrix(c(1.000000000, -0.05081574, -0.07697585,  0.0051,
            -0.050815743,  1.00000000,  0.80997805, -0.3540,
            -0.076975850,  0.80997805,  1.00000000, -0.3130,
            0.005095699, -0.35365332, -0.31278506,  1.0000), nrow = 4, ncol = 4)

cov_matrix <- matrix(c(1.44e-04, -2.20e-05, -3.86e-05,  8.44e-08,
            -2.20e-05,  1.30e-03,  1.22e-03, -1.76e-05,
            -3.86e-05,  1.22e-03,  1.75e-03, -1.81e-05,
            8.44e-08, -1.76e-05, -1.81e-05,  1.90e-06), nrow = 4, ncol = 4)

#defining my portfolio weights
port.weights <- c(0.72, 0.07, 0.07, 0.14)

#performing cholesky decomposition
R <- (chol(corr_matrix))

#generating standard-normal, random variables
x <- array(rnorm(nsteps*nTrails*nAssets), c(nsteps*nTrails,nAssets))

#generating correlated standard-normal, random variables
ep <- x %*% R

#defining the drift 
drift <- BM.mu - 0.5 * diag(cov_matrix) 

#generating asset paths
temp = array(exp(as.vector(drift %*% t(dt)) + t(ep *sqrt(diag(cov_matrix)))), c(nAssets,nsteps,nTrails))

for(i in 2:nsteps) temp[,i,] = temp[,i,] * temp[,(i-1),] 

#changing dimension of the array temp from dim(nAssets, nsteps, nTrails) to dim(nsteps, nAssets, nTrails)
simulated.Returns <- aperm(temp,c(2,1,3))

#computing portfolio returns for each simulation (nTrails). To do this, each step is weighted with "port.weights"
#Since I generate continuous returns, I first transform them into discrete, multiply with weights and then transform back into continuous.
for (z in 1:nTrails) {
for (i in 1:nsteps) cumulative.PortReturns[i,z] = log(1+((exp(simulated.Returns[i,,z]-1)-1) %*% port.weights))
}

#Finally I compute the monthly expected shortfall (5%-level) by taking the average of the 5% worst portfolio yields
#I do steps of 12 as I calculate the ES at the end of each year
z = 0
for (i in seq(12, nsteps, by = 12 )) {
z = z + 1 
ES[z]   <- mean(sort(cumulative.PortReturns[i,]) [1:(0.05*nTrails)])
}

#plotting a sample of simulated portfolio returns
#library(QRM)
plot(as.timeSeries(cumulative.PortReturns[,1:100]), plot.type = 'single')

1 个答案:

答案 0 :(得分:1)

根据您的评论,您已将BM.mu定义为每项资产的年度预期回报。但是,您使用每月而非年度步骤模拟每个样本路径。然后,需要将drift变量合并到BM.mu变量中,相应地将#defining the drift drift <- BM.mu/12 - 0.5 * diag(cov_matrix) 缩放到预期的每月回报:

drift

如果没有这个,您将使用年度预期回报值和月度协方差矩阵计算class unwellBasic: UIViewController, UITextViewDelegate, UIScrollViewDelegate, UITextFieldDelegate { @IBOutlet var scrollView: UIScrollView! weak var activeTextView : UITextView? weak var activeTextField : UITextField? @IBOutlet var main: UITextView! @IBOutlet var initials: UITextField! @IBOutlet var maleButton: UIButton! @IBOutlet var femaleButton: UIButton! @IBOutlet var age: UITextField! @IBOutlet var test: UITextField! func registerForKeyboardNotifications() { let notificationCenter = NSNotificationCenter.defaultCenter() notificationCenter.addObserver(self, selector: "keyboardWillBeShown:", name: UIKeyboardWillShowNotification, object: nil) notificationCenter.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil) } @IBAction func back(sender: AnyObject) { self.navigationController?.popViewControllerAnimated(true) } @IBAction func next(sender: AnyObject) { self.performSegueWithIdentifier("bodySegue", sender: self) } func tapped() { initials.resignFirstResponder() main.resignFirstResponder() age.resignFirstResponder() test.resignFirstResponder() self.activeTextView = nil } // Called when the UIKeyboardDidShowNotification is sent. func keyboardWillBeShown(sender: NSNotification) { let info: NSDictionary = sender.userInfo! let value: NSValue = info.valueForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue let keyboardSize: CGSize = value.CGRectValue().size let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0) scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets // If active text field is hidden by keyboard, scroll it so it's visible if self.activeTextView != nil { var aRect: CGRect = self.view.frame aRect.size.height -= keyboardSize.height let activeTextViewRect: CGRect? = self.activeTextView!.frame let activeTextViewOrigin: CGPoint? = activeTextViewRect?.origin if (!CGRectContainsPoint(aRect, activeTextViewOrigin!)) { scrollView.scrollRectToVisible(activeTextViewRect!, animated:true) } } if self.activeTextField != nil { var aRect: CGRect = self.view.frame aRect.size.height -= keyboardSize.height let activeTextViewRect: CGRect? = self.activeTextField!.frame let activeTextViewOrigin: CGPoint? = activeTextViewRect?.origin if (!CGRectContainsPoint(aRect, activeTextViewOrigin!)) { scrollView.scrollRectToVisible(activeTextViewRect!, animated:true) } } } // Called when the UIKeyboardWillHideNotification is sent func keyboardWillBeHidden(sender: NSNotification) { let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0) scrollView.contentInset = contentInsets self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true) self .viewDidLayoutSubviews() self.activeTextView = nil } func textViewDidBeginEditing(textView: UITextView) { self.activeTextView = textView scrollView.scrollEnabled = true } func textViewDidEndEditing(textView: UITextView) { self.activeTextView = nil scrollView.scrollEnabled = false self.scrollView .setContentOffset(CGPointMake(0, 0), animated: true) self .viewDidLayoutSubviews() } func textFieldDidBeginEditing(textField: UITextField) { activeTextField = textField scrollView.scrollEnabled = true } func textFieldDidEndEditing(textField: UITextField) { activeTextField = nil scrollView.scrollEnabled = false } func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore. { textField.resignFirstResponder() return true; } override func viewDidLoad() { super.viewDidLoad() var tap = UITapGestureRecognizer (target: self, action: ("tapped")) self.view.addGestureRecognizer(tap) self.main.delegate = self self.initials.delegate = self self.age.delegate = self self.registerForKeyboardNotifications() } 值。这导致比您预期的更大的漂移,这将影响您所看到的结果。