[Returnanalytics-commits] r3290 - in pkg/PortfolioAnalytics: demo sandbox/benchmarking

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Wed Dec 18 06:07:59 CET 2013


Author: rossbennett34
Date: 2013-12-18 06:07:59 +0100 (Wed, 18 Dec 2013)
New Revision: 3290

Added:
   pkg/PortfolioAnalytics/sandbox/benchmarking/performance_considerations.txt
Modified:
   pkg/PortfolioAnalytics/demo/constrained_optim.R
Log:
Adding file to describe potential bottlenecks for performance considerations

Modified: pkg/PortfolioAnalytics/demo/constrained_optim.R
===================================================================
--- pkg/PortfolioAnalytics/demo/constrained_optim.R	2013-12-17 21:06:07 UTC (rev 3289)
+++ pkg/PortfolioAnalytics/demo/constrained_optim.R	2013-12-18 05:07:59 UTC (rev 3290)
@@ -1,41 +1,62 @@
-require("PerformanceAnalytics")
-require("PortfolioAnalytics")
-require("DEoptim")
 
+library(PortfolioAnalytics)
+require(DEoptim)
+
 # Load the data
 data(edhec)
 
 #constraints
-constraints <- constraint(assets = colnames(edhec[, 1:10]), min = 0.01, max = 0.4, min_sum=1, max_sum=1, weight_seq = generatesequence())
-# note that if you wanted to do a random portfolio optimization, mun_sum of .99 and max_sum of 1.01 might be more appropriate
-constraints <- add.objective(constraints=constraints, type="return", name="mean", arguments=list(), enabled=TRUE)
-constraints <- add.objective(constraints=constraints, type="risk_budget", name="ES", arguments=list(), enabled=TRUE, p=.95, min_prisk=.05, max_prisk=.15)
+constraints <- constraint(assets = colnames(edhec[, 1:10]), min = 0.01, 
+                          max = 0.4, min_sum=0.99, max_sum=1.01, 
+                          weight_seq = generatesequence())
 
-#now set some additional bits
-# I should have set the multiplier for returns to negative
-constraints$objectives[[1]]$multiplier=-1
-# and let's set a portfolio risk target in the risk budget objective too
-constraints$objectives[[2]]$target=.05
-# and clean the returns
-constraints$objectives[[2]]$clean="boudt"
+constraints <- add.objective(constraints=constraints, 
+                             type="return", 
+                             name="mean")
 
-print("We'll use a search_size parameter of 1000 for this demo, but realistic portfolios will likely require search_size parameters much larger, the default is 20000 which is almost always large enough for any realistic portfolio and constraints, but will take substantially longer to run.")
+constraints <- add.objective(constraints=constraints, 
+                             type="risk_budget", 
+                             name="ES", arguments=list(clean="boudt", p=0.95),
+                             min_prisk=.05, 
+                             max_prisk=.15,
+                             target=0.05)
+
+print("We'll use a search_size parameter of 1000 for this demo, but realistic 
+      portfolios will likely require search_size parameters much larger, the 
+      default is 20000 which is almost always large enough for any realistic 
+      portfolio and constraints, but will take substantially longer to run.")
+
 # look for a solution using both DEoptim and random portfolios
-opt_out <- optimize.portfolio(R=edhec[,1:10], constraints=constraints, optimize_method="DEoptim", search_size=1000, trace=TRUE)
+opt_out <- optimize.portfolio(R=edhec[,1:10], 
+                              constraints=constraints, 
+                              optimize_method="DEoptim", 
+                              search_size=1000, 
+                              trace=TRUE)
 
-#we need a little more wiggle in min/max sum for random portfolios or it takes too long to converge
-constraints$min_sum <- 0.99
-constraints$max_sum <- 1.01
-opt_out_random <- optimize.portfolio(R=edhec[,1:10], constraints=constraints, optimize_method="random", search_size=1000, trace=TRUE)
+opt_out_random <- optimize.portfolio(R=edhec[,1:10], 
+                                     constraints=constraints, 
+                                     optimize_method="random", 
+                                     search_size=1000, 
+                                     trace=TRUE)
 
-# now lets try a portfolio that rebalances quarterly
-opt_out_rebalancing <- optimize.portfolio.rebalancing_v1(R=edhec[,1:10], constraints=constraints, optimize_method="DEoptim", search_size=1000, trace=FALSE,rebalance_on='quarters')
-rebalancing_weights <- matrix(nrow=length(opt_out_rebalancing),ncol=length(opt_out_rebalancing[[1]]]$weights))
-rownames(rebalancing_weights) <- names(opt_out_rebalancing)
-colnames(rebalancing_weights) <- names(opt_out_rebalancing[[1]]$weights)
-for(period in 1:length(opt_out_rebalancing)) rebalancing_weights[period,] <- opt_out_rebalancing[[period]]$weights
+# Optimize a portfolio that rebalances quarterly
+opt_out_rebalancing <- optimize.portfolio.rebalancing(R=edhec[,1:10], 
+                                                      constraints=constraints, 
+                                                      optimize_method="random", 
+                                                      search_size=1000, 
+                                                      trace=FALSE, 
+                                                      rebalance_on='quarters')
+
+rebalancing_weights <- extractWeights(opt_out_rebalancing)
 rebalancing_returns <- Return.rebalancing(R=edhec,weights=rebalancing_weights)
 charts.PerformanceSummary(rebalancing_returns)
 
-# and now lets rebalance quarterly with 48 mo trailing
-opt_out_trailing<-optimize.portfolio.rebalancing(R=edhec[,1:10], constraints=constraints, optimize_method="DEoptim", search_size=1000, trace=FALSE,rebalance_on='quarters',trailing_periods=48,training_period=48)
+# Optimize a portfolio that rebalances quarterly with 48 mo trailing
+opt_out_trailing <- optimize.portfolio.rebalancing(R=edhec[,1:10], 
+                                                 constraints=constraints, 
+                                                   optimize_method="random", 
+                                                   search_size=1000, 
+                                                   trace=FALSE,
+                                                   rebalance_on='quarters',
+                                                   trailing_periods=48,
+                                                   training_period=48)

Added: pkg/PortfolioAnalytics/sandbox/benchmarking/performance_considerations.txt
===================================================================
--- pkg/PortfolioAnalytics/sandbox/benchmarking/performance_considerations.txt	                        (rev 0)
+++ pkg/PortfolioAnalytics/sandbox/benchmarking/performance_considerations.txt	2013-12-18 05:07:59 UTC (rev 3290)
@@ -0,0 +1,13 @@
+Version: 0.8.3
+12/17/2013 
+
+The functions described in the paragraphs below should be monitored and considered for any degradation in performance.
+
+optimize.portfolio() is the main function for portfolio optimization. The default function to calculate the portfolio moments is set.portfolio.moments(). The set.portfolio.moments() function should calculate the moments once in optimize.portfolio() and then pass the moments to constrained_objective(). constrained_objective() is the objective function for DEoptim, random portfolios, pso, and GenSA. There is a check in constrained_objective() that will calculate the moments if they are not set correctly in optimize.portfolio(). This can be very expensive in terms of performance because constrained_objective() is potentially called thousands or tens of thousands of times.
+
+random_portfolios() calculates a number of portfolios that satisfy weight_sum, box, group, and position limit constraints. There are 3 methods to calculate a random set of weights:
+1) sample, 2) uniform, and 3) grid. The uniform and grid methods are relatively fast and the sample method has the potential to be slower.
+
+Generating random portfolios with the sample method is a “brute force search” method to generate a random set of weights and can potentially be slow depending on the number of assets and combination of constraints. The sample method to generate a random set of weights is relatively fast for sum of weights, box, and position limit constraints. Including group constraints or making the constraints restrictive will increase runtime of the function. rp_sample() only handles weight_sum and box constraints. Group and position limit constraints are handled in rp_transform(), which is called in randomize_portfolio. rp_transform() uses logic from random portfolios so any improvement should be implemented in both functions. fn_map() is a wrapper for rp_transform and is used in the mapping function for DEoptim so any improvement here could be a performance gain for optimization with DEoptim.
+
+For optimize_method=”DEoptim”, the initial population is calculated with random_portfolios(). A set of random portfolios can be passed in by the user with the “rp” argument. If “rp” is not passed in, then we generate random portfolios in optimize.portfolio() used for the initial population. For a single period optimization with optimize.portfolio(), the random portfolios are only generated once. However, optimize.portfolio.rebalancing() is a wrapper for optimize.portfolio() to manage the time index to pass the returns to optimize.portfolio() for out of sample portfolio optimization with rebalancing . This results in multiple calls to optimize.portfolio(). For optimize_method=”random” and optimize_method=”DEoptim”, the random portfolios should only be generated once. Generating random portfolios at each call to optimize.portfolio() is redundant and negatively impacts performance.
\ No newline at end of file



More information about the Returnanalytics-commits mailing list