Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/optimizer.R
1433 views
1
# Optimizer Functions
2
3
################################################################################
4
# FUNCTIONS:
5
#
6
# BruteForcePortfolios (R,weightgrid,yeargrid)
7
# BacktestData ()
8
# Backtest (R,portfolioreturns, yeargrid, cutat=1000000, methods, p, ... )
9
# weight.grid (columnnames, seqstart=.05, seqend=.25, seqstep=.05)
10
# maxdrawdown (R)
11
# cut.returns (R, cutrow, startrow=1)
12
# weighttest (weightgrid, test=1)
13
# WeightedPortfolioUtility (R, weightgrid, from, to, methods, p, ...)
14
# backtestDisplay (R, portfolioreturns, yeargrid, backtestresults, show="Cumulative.Return" )
15
# MonthlyBacktestResults (R, weightgrid, yeargrid, backtestweights)
16
#
17
################################################################################
18
19
# Check to see if the required libraries are loaded
20
if(!require("PerformanceAnalytics", quietly=TRUE)) {
21
stop("package", sQuote("PerformanceAnalytics"), "is needed. Stopping")
22
}
23
#source("optim_functions.R")
24
25
# ------------------------------------------------------------------------------
26
cut.returns =
27
function (R, cutrow, startrow=1)
28
{ # @author Brian G. Peterson
29
30
# Description:
31
32
# FUNCTION:
33
result = R[startrow:cutrow,]
34
35
# Return Value:
36
result
37
}
38
39
# ------------------------------------------------------------------------------
40
weighttest =
41
function (weightgrid, test=1)
42
{
43
rows=nrow(weightgrid)
44
45
result=NA
46
47
for(row in 1:rows) {
48
r = as.vector(weightgrid[row,])
49
#if (!is.numeric(r)) stop("The selected row is not numeric")
50
51
if (sum(r) == test) {
52
#if (result=NA) {
53
#create data.frame
54
# result=data.frame(r=r)
55
#} else {
56
r=data.frame(r=r)
57
result=cbind(result,r)
58
#}
59
}
60
} #end rows loop
61
62
# Return Value:
63
result
64
65
}
66
67
# ------------------------------------------------------------------------------
68
# @todo: use zoo rollapply in BruteForcePortfolios() fn
69
#WeightedPortfolioUtility =
70
WeightedPortfolioUtility =
71
function (R, weightgrid, from, to,
72
methods=c( "PeriodGVaR", "ThreeYrGVaR", "InceptionGVaR", "PeriodmodVaR", "ThreeYrmodVaR", "InceptionmodVaR",
73
"PeriodGES", "ThreeYrGES", "InceptionGES", "PeriodmodES", "ThreeYrmodES", "InceptionmodES",
74
"PeriodStdDev", "ThreeYrStdDev", "InceptionStdDev",
75
"PeriodReturn", "maxdd", "omega" )
76
, p=0.95, ... )
77
{ # @author Brian G. Peterson and Kris Boudt
78
79
# Description:
80
# This is the workhorse of the backtest architecture.
81
# Any optimization backtesting model must
82
# - create portfolios,
83
# - analyze their returns,
84
# - and allow you to use some metric, function, or algorithm
85
# to analyze the results
86
#
87
# function takes a set of returns, a set of portfolio weights,
88
# and a timeframe to operate within, and generates a set of statistics
89
# for every possible weight.
90
#
91
# When you calculate statistics for all possible weights generated by
92
# a brute force method, an estimation method, some function,
93
# a regression, etc., you can then run tests against the results "in-sample"
94
# to determine which weighting vector you want to use "out-of-sample"
95
# in the next rolling period.
96
#
97
# This function is extremely computationally intensive, because it is doing
98
# a lot of things with every single possible weighting vector, so you want
99
# to be able to run it and store the results for later analysis.
100
# It is best to strike a balance between placing functions in here that
101
# you will need to help choose the optimal weighting vector, and be
102
# parsimonious, as these calculations may be run tens of thousands of times
103
# in any given backtest. Remember that once you have chosen an optimal
104
# portfolio or a sub-set of possible optimal portfolios, you can run more
105
# exhaustive analytics on each of your candidates later, rather than on the
106
# entire set of all possible portfolios.
107
#
108
# R data structure of historical returns
109
# weightgrid each row contains one weighting vector, same number of columns as your returns
110
# from where to cut the beginning of the return stream
111
# to where to cut the end of the return stream
112
#
113
# @returns data frame where each row has the same index number as a weighting vector,
114
# and each column is one of your metrics from inside this function
115
#
116
# @todo don't recalculate if Period and ThreeYr or Inception and ThreeYr are the same
117
118
# Setup:
119
# there's a risk here is sampling from weightgrid that
120
# your row names and numbers won;t match, need to be careful
121
122
# data type conditionals
123
# cut the return series for from:to
124
if (class(R) == "timeSeries") {
125
R = R@Data
126
}
127
128
if (from < 1) from = 1
129
if (to > nrow(R)) to = nrow(R)
130
131
132
if (ncol(weightgrid) != ncol(R)) stop ("The Weighting Vector and Return Collection do not have the same number of Columns.")
133
134
# Compute multivariate moments
135
# should probably change this part to use zoo's rollapply to create the various groupings
136
137
threeyrfrom = to - 35; #for monthly data 36-35=1 for three year period
138
if (threeyrfrom < 1 ) threeyrfrom = 1
139
140
R.inception = R[1:to , ];
141
mu.inception = apply(R.inception,2,'mean');
142
sigma.inception = cov(R.inception);
143
M3.inception = M3.MM(R.inception);
144
M4.inception = M4.MM(R.inception);
145
146
R.period = R[from:to, ];
147
mu.period = apply(R.period,2,'mean');
148
sigma.period = cov(R.period);
149
M3.period = M3.MM(R.period);
150
M4.period = M4.MM(R.period);
151
152
R.3yr = R[ threeyrfrom:to, ];
153
mu.3yr = apply(R.3yr,2,'mean');
154
sigma.3yr = cov(R.3yr);
155
M3.3yr = M3.MM(R.3yr);
156
M4.3yr = M4.MM(R.3yr);
157
158
rows=nrow(weightgrid)
159
# Function:
160
# this outer loop makes me very angry.
161
# R seems to hang and never return on very large matrices or data.frame's
162
# to get around this, we subset the data into chunks that R can handle,
163
# we then run the inner for loop against these, and reassemble the list
164
# into a single structure at the end.
165
#
166
# if we *must* do this to work around limitations in R, perhaps we can
167
# figure out how to examine the length of weightgrid and subset it automatically
168
subsetrows= matrix(c(1,31000,31001,62000,62001,rows), nrow=3,byrow=TRUE)
169
# subsetrows= matrix(c(1,10,11,20,21,30), nrow=3,byrow=TRUE)
170
resultlist=vector("list", 3)
171
weightgridsave=weightgrid
172
for (srow in 1:3) {
173
weightgrid=weightgrid[subsetrows[srow,1]:subsetrows[srow,2],,drop=FALSE]
174
result=NULL
175
176
for(row in rownames(weightgrid)) {
177
# at some point consider parallelizing this by using a clustered apply
178
# to call a sub-function so that this could get distributed
179
# to multiple processor cores or threads
180
181
# construct a data structure that holds each result for this row
182
resultrow=data.frame(row.names = row)
183
184
w = as.numeric(weightgrid[row,])
185
# test each row in the weighting vectors against the right dates in the return collection
186
187
# problem of NAs? Not solved yet !!!!
188
# should really solve this by calling checkData in ButeForcePortfolios
189
#if (any(is.na(R))) {
190
# print( paste("NA\'s in returns: ",row, " ",w," from ", from) )
191
# #browser()
192
#}
193
194
mean.inception = mean.MM( w , mu.inception );
195
mean.period = mean.MM( w , mu.period) ;
196
mean.3yr = mean.MM( w , mu.3yr ) ;
197
198
for (method in methods) {
199
switch(method,
200
PeriodStdDev = {
201
# Standard Deviation
202
PeriodStdDev = StdDev.MM(w,sigma=sigma.period)
203
PeriodSRStdDev = mean.period/ PeriodStdDev
204
colnames(PeriodStdDev) = "StdDev.period"
205
colnames(PeriodSRStdDev)="SR.StdDev.period"
206
resultrow= cbind(resultrow,PeriodStdDev,PeriodSRStdDev)
207
},
208
ThreeYrStdDev = {
209
# Standard Deviation
210
ThreeYrStdDev = StdDev.MM(w,sigma=sigma.3yr)
211
ThreeYrSRStdDev = mean.3yr/ThreeYrStdDev;
212
colnames(ThreeYrStdDev) = "StdDev.3yr"
213
colnames(ThreeYrStdDev) = "SR.StdDev.3yr"
214
resultrow= cbind(resultrow,ThreeYrStdDev,ThreeYrSRStdDev)
215
},
216
InceptionStdDev = {
217
# Standard Deviation
218
InceptionStdDev = StdDev.MM(w,sigma=sigma.inception)
219
InceptionSRStdDev = mean.inception/InceptionStdDev
220
colnames(InceptionStdDev) = "StdDev.inception"
221
colnames(InceptionSRStdDev) = "SR.StdDev.inception"
222
resultrow= cbind(resultrow,InceptionStdDev, InceptionSRStdDev)
223
},
224
PeriodGVaR = {
225
PeriodGVaR = GVaR.MM(w=w, mu=mu.period, sigma = sigma.period, p=p )
226
PeriodSRGVaR = mean.period/PeriodGVaR
227
colnames(PeriodGVaR)="GVaR.period"
228
colnames(PeriodSRGVaR)="SR.GVaR.period"
229
resultrow= cbind(resultrow,PeriodGVaR,PeriodSRGVaR)
230
},
231
ThreeYrGVaR = {
232
ThreeYrGVaR = GVaR.MM(w=w, mu=mu.3yr, sigma = sigma.3yr, p=p )
233
ThreeYrSRGVaR = mean.3yr/ThreeYrGVaR
234
colnames(ThreeYrGVaR)="GVaR.3yr"
235
colnames(ThreeYrSRGVaR)="SR.GVaR.3yr"
236
resultrow= cbind(resultrow,ThreeYrGVaR,ThreeYrSRGVaR)
237
},
238
InceptionGVaR = {
239
InceptionGVaR = GVaR.MM(w=w, mu=mu.inception, sigma = sigma.inception, p=p )
240
InceptionSRGVaR = mean.inception/InceptionGVaR
241
colnames(InceptionGVaR)="GVaR.inception"
242
colnames(InceptionSRGVaR)="SR.GVaR.inception"
243
resultrow= cbind(resultrow,InceptionGVaR,InceptionSRGVaR)
244
},
245
PeriodmodVaR = {
246
PeriodmodVaR = mVaR.MM(w=w, mu=mu.period, sigma = sigma.period, M3=M3.period , M4 =M4.period , p=p )
247
PeriodSRmodVaR = mean.period/PeriodmodVaR
248
colnames(PeriodmodVaR)="modVaR.period"
249
colnames(PeriodSRmodVaR)="SR.modVaR.period"
250
resultrow= cbind(resultrow,PeriodmodVaR,PeriodSRmodVaR)
251
},
252
InceptionmodVaR = {
253
InceptionmodVaR = mVaR.MM(w=w, mu=mu.inception, sigma = sigma.inception, M3=M3.inception , M4 =M4.inception , p=p )
254
InceptionSRmodVaR = mean.inception/InceptionmodVaR
255
colnames(InceptionmodVaR)="modVaR.inception"
256
colnames(InceptionSRmodVaR)="SR.modVaR.inception"
257
resultrow= cbind(resultrow,InceptionmodVaR,InceptionSRmodVaR)
258
},
259
ThreeYrmodVaR = {
260
ThreeYrmodVaR = mVaR.MM(w=w, mu=mu.3yr, sigma = sigma.3yr, M3=M3.3yr , M4 =M4.3yr, p=p )
261
ThreeYrSRmodVaR = mean.3yr/ThreeYrmodVaR
262
colnames(ThreeYrmodVaR)="modVaR.3yr"
263
colnames(ThreeYrSRmodVaR)="SR.modVaR.3yr"
264
resultrow= cbind(resultrow,ThreeYrmodVaR,ThreeYrSRmodVaR)
265
},
266
InceptionGES = {
267
InceptionGES = GES.MM(w=w, mu=mu.inception, sigma = sigma.inception, p=p )
268
InceptionSRGES = mean.inception/InceptionGES
269
colnames(InceptionGES)="GES.inception"
270
colnames(InceptionSRGES)="SR.GES.inception"
271
resultrow= cbind(resultrow,InceptionGES,InceptionSRGES)
272
},
273
PeriodGES = {
274
PeriodGES = GES.MM(w=w, mu=mu.period, sigma = sigma.period, p=p )
275
PeriodSRGES = mean.period/PeriodGES
276
colnames(PeriodGES)="GES.period"
277
colnames(PeriodSRGES)="SR.GES.period"
278
resultrow= cbind(resultrow,PeriodGES,PeriodSRGES)
279
},
280
ThreeYrGES = {
281
ThreeYrGES = GES.MM(w=w, mu=mu.3yr, sigma = sigma.3yr, p=p )
282
ThreeYrSRGES = mean.3yr/ThreeYrGES
283
colnames(ThreeYrGES)="GES.3yr"
284
colnames(ThreeYrSRGES)="SR.GES.3yr"
285
resultrow= cbind(resultrow,ThreeYrGES,ThreeYrSRGES)
286
},
287
PeriodmodES = {
288
PeriodmodES = mES.MM(w=w, mu=mu.period, sigma = sigma.period, M3=M3.period , M4 =M4.period , p=p )
289
PeriodSRmodES = mean.period/PeriodmodES
290
colnames(PeriodmodES)="modES.period"
291
colnames(PeriodSRmodES)="SR.modES.period"
292
resultrow= cbind(resultrow,PeriodmodES,PeriodSRmodES)
293
},
294
ThreeYrmodES = {
295
ThreeYrmodES = mES.MM(w=w, mu=mu.3yr, sigma = sigma.3yr, M3=M3.3yr , M4 =M4.3yr , p=p )
296
ThreeYrSRmodES = mean.3yr/ThreeYrmodES
297
colnames(ThreeYrmodES)="modES.3yr"
298
colnames(ThreeYrSRmodES)="SR.modES.3yr"
299
resultrow= cbind(resultrow,ThreeYrmodES,ThreeYrSRmodES)
300
},
301
InceptionmodES = {
302
InceptionmodES = mES.MM(w=w, mu=mu.inception, sigma = sigma.inception, M3=M3.inception , M4 =M4.inception, p=p )
303
InceptionSRmodES = mean.inception/InceptionmodES
304
colnames(InceptionmodES)="modES.inception"
305
colnames(InceptionSRmodES)="SR.modES.inception"
306
resultrow= cbind(resultrow,InceptionmodES,InceptionSRmodES)
307
}
308
# @todo put Return.portfolio, maxdrawdown, omega back, think about others
309
)#end switch function
310
}# end loop over methods
311
312
if (is.null(result)){
313
result=matrix(nrow=nrow(weightgrid),ncol=ncol(resultrow),byrow=TRUE)
314
rownames(result)=rownames(weightgrid)
315
colnames(result)=colnames(resultrow)
316
}
317
318
# print( paste("Completed row: ",rownames(resultrow),":",date()) )
319
# then rbind the rows
320
# result = rbind(result,resultrow)
321
result[as.character(row),]=as.matrix(resultrow)
322
323
} #end rows loop
324
resultlist[[srow]] <- result
325
weightgrid=weightgridsave
326
print(paste("Row ",subsetrows[srow,2]," completed ",date()))
327
} #end subset loop
328
329
result=rbind(resultlist[[1]],resultlist[[2]],resultlist[[3]])
330
331
# Return Value:
332
result
333
334
}
335
336
337
# ------------------------------------------------------------------------------
338
# @todo: use zoo rollapply in BruteForcePortfolios() fn
339
BruteForcePortfolios =
340
function(R,weightgrid,yeargrid,
341
methods=c( "PeriodGVaR", "ThreeYrGVaR", "InceptionGVaR", "PeriodmodVaR", "ThreeYrmodVaR", "InceptionmodVaR",
342
"PeriodGES", "ThreeYrGES", "InceptionGES", "PeriodmodES", "ThreeYrmodES", "InceptionmodES",
343
"maxdd", "omega", "PeriodStdDev", "ThreeYrStdDev", "InceptionStdDev" )
344
, p=0.95, ...
345
)
346
{ # @author Brian G. Peterson
347
348
# Description:
349
#
350
# Performs the looping and storage of the base analytics for your series
351
# of possible portfolios. I've titled the third parameter 'yeargrid',
352
# but it is really a 'rolling window grid', although these will often be years.
353
# We slice the computation into these years or rolling periods,
354
# and store the results separately, because each of these rolling periods will
355
# have one solution for each possible weighting vector. By generating them and
356
# storing them for all weighting vectors in every period, you can do all the hard
357
# computational work in one pass, and then reuse the data set over and over again
358
# in multiple analytic tests, methods, or hypotheses for choosing in-sample results
359
# to use as out-of-sample weights.
360
#
361
# @todo add optional subdirectory tp keep different backtests apart
362
#
363
# R data frame of historical returns
364
#
365
# weightgrid each row contains one weighting vector, same number of columns as your returns
366
#
367
# yeargrid list of from/to vectors for the periods we want to backtest over
368
#
369
# Return:
370
# portfolioreturns list of data frames of set of returns for all possible portfolios
371
# (output of BruteForcePortfolios function)
372
373
# Setup:
374
rows=nrow(yeargrid)
375
376
# Function:
377
print( paste("Started:",date()) )
378
for (rnum in 1:rows) {
379
row = yeargrid[rnum,]
380
yearname=rownames(row)
381
from = row [,1]
382
to = row [,2]
383
384
if ( 1 > from ) from = 1
385
if ( rows > to ) to = rows
386
387
# construct a data structure that holds each result for this year
388
resultarray = WeightedPortfolioUtility(R, weightgrid, from, to, methods=methods, p=p, ...=...)
389
# at some point parallelize the call to WeightedPortfolioUtility by using a clustered apply
390
# to call WeightedPortfolioUtility so that this could get distributed
391
# to multiple processor cores or threads
392
393
# then write a CSV
394
write.table(resultarray, file = paste(yearname,".csv",sep=""),
395
append = FALSE, quote = TRUE, sep = ",",
396
eol = "\n", na = "NA", dec = ".", row.names = TRUE,
397
col.names = TRUE, qmethod = "escape")
398
399
print( paste("Completed",yearname,":",date()) )
400
# print(resultarray)
401
} # end row loop
402
}
403
404
# ------------------------------------------------------------------------------
405
BacktestData =
406
function(yeargrid)
407
{ # @author Brian G. Peterson
408
409
# Description:
410
#
411
# load the data into a list suitable for use by Backtest and BacktestDisplay functions
412
# use the yeargrid used by BruteForcePortfolios to figure out which files to load
413
#
414
# @todo add optional subdirectory to keep different backtests apart
415
#
416
# yeargrid list of from/to vectors for the periods we've run the backtest over
417
# yeargrid will have one row for the last out of sample year,
418
# which is not calculated by BruteForcePortfolios
419
420
# Function:
421
rows=nrow(yeargrid)-1 # take out the out of sample year, for which there is no data
422
423
for (rnum in 1:rows) {
424
row = yeargrid[rnum,]
425
yearname=rownames(row)
426
# print(yearname)
427
currentyeardata = read.table(paste(yearname,".csv",sep=""),header=TRUE, row.names = 1,sep = ",")
428
if (rnum==1) {
429
#create e,ty list, as c() doesn't work the way you would expect with a list
430
result=vector("list")
431
}
432
433
#assign each year into the list using the yearname as the index
434
result[[yearname]]=currentyeardata
435
436
}
437
names(result) = t(rownames(yeargrid[1:rows,]))
438
439
#Return:
440
result
441
}
442
443
# ------------------------------------------------------------------------------
444
Backtest =
445
function(R,bfresults, yeargrid, cutat=1000000, benchmarkreturns )
446
{
447
# Description:
448
#
449
# complete brute force hackjob to get out of sample results
450
#
451
# Given a set of historical returns R, and a set of portfolio returns calculated from
452
# the BruteForcePortfolios function, we can now apply several utility functions to
453
# find the best portfolio out of the universe of all sample portfolios.
454
#
455
# Basically, we find an in-sample solution to each utility function, and store the
456
# weighting vector for that portfolio as our strategic weight for use out of sample.
457
# by testing several utility functions, we can examine the models for bias, and determine
458
# which utility function produces the most acceptable out of sample results.
459
#
460
# R data frame of historical returns
461
#
462
# bfresults list of data frames of set of utility fn results for all possible portfolios
463
# (output of BruteForcePortfolios function)
464
#
465
# yeargrid list of from/to vectors for the periods we want to backtest over
466
#
467
# cutat numerical index to stop comparing the portfolioreturns at.
468
# used to slice the weighted returns at particular weight
469
#
470
# benchmarkreturns return vector for benchmark, should match the dates on
471
# the in-sample portfolio returns
472
473
474
# Setup:
475
rows=nrow(yeargrid-1)
476
477
benchmarkreturns = as.vector(benchmarkreturns)
478
479
# construct a matrix for the results that's the same size and labels as the input lists
480
result=matrix(nrow=nrow(yeargrid[-1,]),ncol=ncol(bfresults[[1]]))
481
rownames(result)=rownames(yeargrid[-1,])
482
colnames(result)=colnames(bfresults[[1]])
483
colns= colnames(bfresults[[1]])
484
portfoliorows=nrow(bfresults[[1]])
485
if (cutat<portfoliorows) {
486
portfoliorows=cutat
487
}
488
489
# Function:
490
for (rnum in 1:(rows-1)) {
491
insample = yeargrid[rnum,]
492
outofsample = yeargrid[rnum+1,]
493
yearname = rownames(insample)
494
outname = rownames(outofsample)
495
inresults = bfresults[[yearname]][1:portfoliorows,]
496
497
#Check Utility fn for insample , and apply to out of sample row
498
print(paste("Starting",yearname,date()))
499
for (coln in colns) {
500
##################################
501
# Risk/Reward maximization utility functions
502
# for utility function
503
# w' = max(meanreturn/riskmeasure)
504
#
505
# These are the Sharpe Ratio and modified Sharpe Ratio methods
506
#
507
# These utility functions are called "Constant Relative Risk Aversion (CRRA)" (verify this!)
508
##################################
509
for (maxmethod in c("SR.StdDev.period", "SR.StdDev.3yr", "SR.StdDev.inception",
510
"SR.GVaR.period", "SR.GVaR.3yr", "SR.GVaR.inception",
511
"SR.modVaR.period", "SR.modVaR.inception", "SR.modVaR.3yr",
512
"SR.GES.inception", "SR.GES.period", "SR.GES.3yr",
513
"SR.modES.period", "SR.modES.3yr", "SR.modES.inception")){
514
if (maxmethod==coln){
515
# return the max of the BF in-sample results for that column
516
result[outname,coln]= rownames(inresults[which.max(inresults[1:portfoliorows,coln]),])
517
}
518
} #end maxmethod
519
520
##################################
521
# Risk Reduction utility functions
522
# for utility function
523
# w' = min(riskmeasure)
524
#
525
# These utility functions are called "Constant Absolute Risk Aversion (CARA)"
526
##################################
527
for (minmethod in c("StdDev.period", "StdDev.3yr", "StdDev.inception",
528
"GVaR.period", "GVaR.3yr", "GVaR.inception",
529
"modVaR.period", "modVaR.inception", "modVaR.3yr",
530
"GES.inception", "GES.period", "GES.3yr",
531
"modES.period", "modES.3yr", "modES.inception")){
532
if (minmethod==coln){
533
# return the min of the BF in-sample results for that column
534
result[outname,coln]= rownames(inresults[which.min(inresults[1:portfoliorows,coln]),])
535
}
536
} #end minmethod
537
} # end columns loop
538
539
print(paste("Completed",yearname,date()))
540
541
# add Equalweighted
542
# EqualWeighted = 1
543
544
# ##################################
545
# # Risk Reduction utility functions
546
# # for utility function
547
# # w' = min(VaR.CornishFisher(p=0.95))
548
# minmodVaR = which.min(portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.period"])
549
# #minmodVaRi = which.min(portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.inception"])
550
# minmodVaR3yr = which.min(portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.3yr"])
551
#
552
# # for utility function
553
# # w' = max(return/VaR.CornishFisher) for both VaR.CornishFisher.period and VaR.CornishFisher.inception
554
# #SharpeRatio.modified = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"]/portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.period"])
555
# SharpeRatio.modified3yr = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"]/portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.3yr"])
556
# #SharpeRatio.modifiedi = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"]/portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.inception"])
557
#
558
# # for utility function
559
# # w' = max(return/Max.Drawdown)
560
# ReturnOverDrawdown = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"]/portfolioreturns[[yearname]][1:portfoliorows,"Max.Drawdown"])
561
#
562
# # for utility function
563
# # w' = max(return)
564
# maxReturn = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"])
565
#
566
# # for utility function
567
# # w' = min(VaR.CornishFisher(p=0.95)) such that return is greater than the benchmark
568
# minVaRretoverBM = which.min(portfolioreturns[[yearname]][which(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"]>=Return.cumulative(benchmarkreturns[infrom:into])),"VaR.CornishFisher.period"])
569
# if (length(minVaRretoverBM)==0) { minVaRretoverBM = maxReturn }
570
#
571
# #for utility function
572
# #w' = max(return) such that VaR.CornishFisher is less than VaR.CornishFisher(benchmark)
573
# maxmodVaRltBM=which.max(portfolioreturns[[yearname]][which(portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.period"]<VaR.CornishFisher(benchmarkreturns[infrom:into],p=0.95)),"Cumulative.Return"])
574
# if (length(maxmodVaRltBM)==0) { maxmodVaRltBM = 1 }
575
#
576
# #add utility functions tor Equal weighted portfolio
577
# # for utility function
578
# # w' = min(VaR.CornishFisher(p=0.95)) such that return is greater than equal weighted portfolio
579
# minVaRretoverEW = which.min(portfolioreturns[[yearname]][which(portfolioreturns[[yearname]][1:portfoliorows,"Cumulative.Return"]>=portfolioreturns[[yearname]][1,"Cumulative.Return"]),"VaR.CornishFisher.period"])
580
# if (length(minVaRretoverEW)==0) { minVaRretoverEW = 1 }
581
#
582
# #for utility function
583
# #w' = max(return) such that VaR.CornishFisher is less than VaR.CornishFisher(equal weighted)
584
# maxmodVaRltEW=which.max(portfolioreturns[[yearname]][which(portfolioreturns[[yearname]][1:portfoliorows,"VaR.CornishFisher.period"]<portfolioreturns[[yearname]][1,"Cumulative.Return"]),"Cumulative.Return"])
585
# if (length(maxmodVaRltEW)==0) { maxmodVaRltEW = NA }
586
#
587
# #for utility function
588
# #w' = max(omega)
589
# maxOmega = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Omega"])
590
#
591
# #for utility function
592
# #w' = max(Sharpe.period)
593
# maxPeriodSharpe = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Sharpe.period"])
594
#
595
# #for utility function
596
# #w' = max(Sharpe.3.yr)
597
# max3yrSharpe = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Sharpe.3.yr"])
598
#
599
# #for utility function
600
# #w' = max(Sharpe.inception)
601
# #maxInceptionSharpe = which.max(portfolioreturns[[yearname]][1:portfoliorows,"Sharpe.inception"])
602
#
603
#
604
# ########## end of utility functions ##########
605
# # construct a data structure that holds each result for this row
606
# if (rnum==2) {
607
# #create data.frame
608
# result=data.frame()
609
# resultrow=data.frame()
610
# }
611
# # first cbind the columns
612
# resultrow = cbind(EqualWeighted, minmodVaR, minmodVaR3yr, SharpeRatio.modified3yr, ReturnOverDrawdown, maxReturn,
613
# minVaRretoverBM, maxmodVaRltBM, minVaRretoverEW, maxmodVaRltEW,
614
# maxPeriodSharpe, max3yrSharpe, maxOmega )
615
#
616
# rownames(resultrow) = outname
617
#
618
# # then rbind the rows
619
# result = rbind(result,resultrow)
620
# # print(resultarray)
621
622
} # end row loop
623
624
# Result:
625
result
626
}
627
628
# ------------------------------------------------------------------------------
629
BacktestDisplay =
630
function (R, bfresults, yeargrid, backtestresults, benchmarkreturns )
631
{ # a function by Brian G. Peterson
632
633
# Description:
634
# This function lets us use the output of the Backtest() function to do some
635
# comparative analysis of how each utility function performed out of sample.
636
# It takes as input all the component parts, and shows a single summary statistic
637
# for each out of sample period for each utility function. Periods are rows,
638
# utility functions are columns in the output.
639
# Eventually, we'll want to make this more sophisticated, and return a
640
# data structure with *all* the summary statistics for each out-of-sample portfolio,
641
# but this works for now.
642
#
643
# R data frame of historical returns
644
#
645
# bfresults list of data frames of set of returns for all possible portfolios
646
# (output of BruteForcePortfolios function)
647
#
648
# yeargrid list of from/to vectors for the periods we've run the backtest over
649
# yeargrid will have one row for the last out of sample year,
650
# which is not calculated by BruteForcePortfolios
651
#
652
# weightgrid each row contains one weighting vector, same number of columns as your returns
653
#
654
# backtestresults data frame of set of weighting vectors for each
655
# utility function in each year/period
656
# (output of Backtest function)
657
#
658
# benchmarkreturns return vector for benchmark, should match the dates on
659
# the in-sample portfolio returns
660
661
662
cols = ncol(backtestresults) # get the number of utility functions
663
664
# add column for equal weighted portfolio in backtestresults
665
# probably rep 1 for number of rows, and cbind
666
equalcol= t(t(rep(1,nrow(backtestresults))))
667
colnames(equalcol)="Equal.Weighted"
668
backtestresults=cbind(backtestresults,as.matrix(equalcol))
669
670
result=vector("list")
671
672
# Function:
673
674
for (row in 1:(nrow(backtestresults)-1)){
675
yearrow = backtestresults[row,,drop=FALSE]
676
from = yeargrid [row,1]
677
to = yeargrid [row,2]
678
yearname = rownames(backtestresults[row,,drop=F])
679
680
# print(rownames(backtestresults[row,,drop=FALSE]))
681
682
resultcols = ncol(backtestresults)+2
683
resultmatrix=matrix(nrow=ncol(backtestresults),ncol=resultcols,byrow=TRUE )
684
colnames(resultmatrix)=c("Return.Portfolio","skewness","kurtosis",colnames(backtestresults)[-(resultcols-2)])
685
rownames(resultmatrix)=colnames(backtestresults)
686
687
for (col in 1:ncol(backtestresults)){
688
tcols=resultcols-3
689
targetportfolio= backtestresults[row,col]
690
resultmatrix[col,4:resultcols]=as.matrix(bfresults[[yearname]][targetportfolio,1:(resultcols-3)])
691
# calc Return of the portfolio using Portfolio.Return function
692
pwealth=Return.portfolio(R[from:to,], weights=weightgrid[targetportfolio,], wealth.index = TRUE)
693
totalreturn=pwealth[length(pwealth)]-1
694
pwealth=rbind(1,pwealth)
695
preturn=t(diff(log(pwealth)))
696
# calc skewness
697
pskew=skewness(as.vector(preturn))[1]
698
# calc kurtosis
699
pkurt=kurtosis(as.vector(preturn))[1]
700
resultmatrix[col,1]=totalreturn
701
resultmatrix[col,2]=pskew
702
resultmatrix[col,3]=pkurt
703
}
704
705
# @todo add row for benchmark portfolios
706
# Call WeightedPortfolioUtility with weight of 1?
707
708
#browser()
709
result[[yearname]]=resultmatrix
710
}
711
712
#Return:
713
result
714
715
}
716
717
# ------------------------------------------------------------------------------
718
BacktestWeightDisplay =
719
function(backtestresults, weightgrid)
720
{ # @author Brian G. Peterson
721
722
# Description:
723
# Display the weights chosen for each year/period for each utility function.
724
#
725
# backtestresults data frame of set of weighting vectors for each
726
# utility function in each year/period
727
# (output of Backtest function)
728
#
729
# weightgrid each row contains one weighting vector,
730
# same number of columns as your returns
731
# you probably want to have the column names of the weightgrid match your asset names
732
#
733
# yeargrid list of from/to vectors for the periods we've run the backtest over
734
# yeargrid will have one row for the last out of sample year,
735
# which is not calculated by BruteForcePortfolios
736
#
737
# Return:
738
# list of years/periods with each period containing a data frame of weights by utiltiy function
739
740
# Setup:
741
742
cols = ncol(backtestresults) # get the number of utility functions
743
744
result=vector("list")
745
746
# Function:
747
748
for (col in 1:ncol(backtestresults)){
749
# we're looping on each column in the backtest results (objective functions)
750
resultmatrix=matrix(nrow=ncol(weightgrid),ncol=nrow(backtestresults),byrow=TRUE )
751
colnames(resultmatrix)=rownames(backtestresults) # years
752
rownames(resultmatrix)=colnames(weightgrid) # instruments
753
for (row in 1:nrow(backtestresults)){
754
# now loop on years
755
resultmatrix[1:ncol(weightgrid),row]=t(weightgrid[backtestresults[row,col],])
756
}
757
objname=colnames(backtestresults[,col,drop=F])
758
#browser()
759
result[[objname]]=resultmatrix
760
}
761
762
# @todo put a method in here or something to let the user decide how to arrange
763
# arrange list by years with rows as objective functions and columns as instruments
764
# for (row in 1:nrow(backtestresults)){
765
# # print(rownames(backtestresults[row,,drop=FALSE]))
766
# resultmatrix=matrix(nrow=ncol(backtestresults),ncol=ncol(weightgrid),byrow=TRUE )
767
# colnames(resultmatrix)=colnames(weightgrid)
768
# rownames(resultmatrix)=colnames(backtestresults)
769
# for (col in 1:ncol(backtestresults)){
770
# resultmatrix[col,1:ncol(weightgrid)]=t(weightgrid[backtestresults[row,col],])
771
# }
772
# yearname=rownames(backtestresults[row,,drop=F])
773
# # browser()
774
# result[[yearname]]=resultmatrix
775
# }
776
777
#Return:
778
result
779
}
780
781
782
# ------------------------------------------------------------------------------
783
#MonthlyBacktestResults =
784
# use pfolioReturn(returnarray,weightingvector) from fPortfolio
785
MonthlyBacktestResults =
786
function (R, weightgrid, yeargrid, backtestresults)
787
{ # @author Brian G. Peterson
788
789
# R data structure of component returns
790
#
791
# weightgrid each row contains one weighting vector, same number of columns as your returns
792
#
793
# yeargrid list of from/to vectors for the periods we want to backtest over
794
#
795
# backtestresults data frame of set of weighting vectors for each
796
# utility function in each year/period
797
# (output of Backtest function)
798
799
# Setup:
800
result=NULL
801
resultcols=NULL
802
803
# data type conditionals
804
# cut the return series for from:to
805
if (class(R) == "timeSeries") {
806
R = R@Data
807
} else {
808
R = R
809
}
810
811
if (ncol(weightgrid) != ncol(R)) stop ("The Weighting Vector and Return Collection do not have the same number of Columns.")
812
813
# add column for equal weighted portfolio in backtestresults
814
# probably rep 1 for number of rows, and cbind
815
equalcol= t(t(rep(1,nrow(backtestresults))))
816
colnames(equalcol)="Equal.Weighted"
817
backtestresults=cbind(backtestresults,as.matrix(equalcol))
818
819
result=data.frame()
820
for (row in 1:(nrow(backtestresults)-1)){
821
# ok, we're looping on year.
822
# for each year, we need to apply the weights in our backtest results to the portfolio and get a monthly return
823
yearrow = backtestresults[row,,drop=FALSE]
824
yearname = rownames(backtestresults[row,,drop=F])
825
from = yeargrid [yearname,1]
826
to = yeargrid [yearname,2]
827
print(paste("Starting",yearname,date()))
828
resultcols=NULL
829
830
for (col in 1:ncol(backtestresults)){
831
# look up the weighting vector of the target portfolio
832
targetportfolio= backtestresults[row,col]
833
# calc Return of the portfolio using Portfolio.Return function
834
preturn=Return.portfolio(R[from:to,], weights=weightgrid[targetportfolio,], wealth.index = FALSE,method="compound")
835
if (col==1) {
836
#create data.frame
837
resultcols=preturn
838
} else {
839
resultcols=cbind(resultcols,preturn)
840
}
841
# @todo add col for benchmark portfolios
842
}
843
if (row==1) {
844
#create data.frame
845
result=resultcols
846
} else {
847
result=rbind(result,resultcols)
848
}
849
print(paste("Ending",yearname,date()))
850
}
851
852
colnames(result)=colnames(backtestresults)
853
854
# Return Value:
855
result
856
857
}
858
859
# Return.portfolio.multiweight <- function (R, weights, yeargrid, ...){
860
# result=data.frame()
861
#
862
# weights=checkData(weights,method="matrix")
863
#
864
# # take only the first method
865
# # method = method[1]
866
#
867
# # then loop:
868
# for (row in 1:nrow(yeargrid)){
869
# from =yeargrid[row,1]
870
# to = yeargrid[row,2]
871
# if(row==1){ startingwealth=1 }
872
# resultreturns=Return.portfolio(R[from:to,],weights=t(weights[row,]), startingwealth=startingwealth, ...=...)
873
# startingwealth=resultreturns[nrow(resultreturns),"portfolio.wealthindex"]
874
# # the [,-1] takes out the weighted returns, which you don't care
875
# # about for contribution, although you may care about it for
876
# # graphing, and want to pull it into another var
877
#
878
# result=rbind(result,resultreturns)
879
# }
880
# result
881
# }
882
# # ------------------------------------------------------------------------------
883
# # Return.portfolio - replaces RMetrics pfolioReturn fn
884
# # move this function and the pfolioReturn wrapper into Performanceanalytics and remove from this file
885
#
886
# Return.portfolio <- function (R, weights=NULL, wealth.index = FALSE, contribution=FALSE, method = c("compound","simple"), startingwealth=1)
887
# { # @author Brian G. Peterson
888
#
889
# # Function to calculate weighted portfolio returns
890
# #
891
# # R data structure of component returns
892
# #
893
# # weights usually a numeric vector which has the length of the number
894
# # of assets. The weights measures the normalized weights of
895
# # the individual assets. By default 'NULL', then an equally
896
# # weighted set of assets is assumed.
897
# #
898
# # method: "simple", "compound"
899
# #
900
# # wealth.index if wealth.index is TRUE, return a wealth index, if false, return a return vector for each period
901
# #
902
# # contribution if contribution is TRUE, add the weighted return contributed by the asset in this period
903
# #
904
# # @todo method param doesn't really do anything right now. the calculation of the price series would be different for simple than compound
905
# # @todo add contribution
906
#
907
# # Setup:
908
# R=checkData(R,method="zoo")
909
#
910
# # take only the first method
911
# method = method[1]
912
#
913
# if (is.null(weights)){
914
# # set up an equal weighted portfolio
915
# weights = t(rep(1/ncol(R), ncol(R)))
916
# }
917
#
918
# if (ncol(weights) != ncol(R)) stop ("The Weighting Vector and Return Collection do not have the same number of Columns.")
919
#
920
# #Function:
921
#
922
#
923
# # if(method=="compound") {
924
# # construct the wealth index of unweighted assets
925
# wealthindex.assets=cumprod(startingwealth+R)
926
#
927
# # I don't currently think that the weighted wealth index is the correct route
928
# # I'll uncomment this and leave it in here so that we can compare
929
# # build a structure for our weighted results
930
# wealthindex.weighted = matrix(nrow=nrow(R),ncol=ncol(R))
931
# colnames(wealthindex.weighted)=colnames(wealthindex.assets)
932
# rownames(wealthindex.weighted)=rownames(wealthindex.assets)
933
#
934
# # weight the results
935
# for (col in 1:ncol(weights)){
936
# wealthindex.weighted[,col]=weights[,col]*wealthindex.assets[,col]
937
# }
938
# wealthindex=apply(wealthindex.weighted,1,sum)
939
#
940
# # weighted cumulative returns
941
# weightedcumcont=t(apply (wealthindex.assets,1, function(x,weights){ as.vector((x-startingwealth)* weights)},weights=weights))
942
# weightedreturns=diff(rbind(0,weightedcumcont))
943
# colnames(weightedreturns)=colnames(wealthindex.assets)
944
# #browser()
945
# wealthindex=matrix(cumprod(startingwealth + as.matrix(apply(weightedreturns,1, sum), ncol = 1)),ncol=1)
946
# # or, the equivalent
947
# #wealthindex=matrix(startingwealth+apply(weightedcumcont,1,sum),ncol=1)
948
# # }
949
#
950
# if(method=="simple"){
951
# # stop("Calculating wealth index for simple returns not yet supported.")
952
# #weighted simple returns
953
# # probably need to add 1 to the column before doing this
954
# weightedreturns=Return.calculate(wealthindex,method="simple")
955
# }
956
#
957
# # uncomment this to test
958
# #browser()
959
#
960
# if (!wealth.index){
961
# result=as.matrix(apply(weightedreturns,1,sum),ncol=1)
962
# colnames(result)="portfolio.returns"
963
# } else {
964
# # stop("This is broken right now. Calculate your wealth index from the return series.")
965
# result=wealthindex
966
# colnames(result)="portfolio.wealthindex"
967
# }
968
#
969
# if (contribution==TRUE){
970
# # show the contribution to the returns in each period.
971
# result=cbind(weightedreturns,result)
972
# }
973
#
974
# result
975
# } # end function Return.portfolio
976
#
977
# pfolioReturn <- function (x, weights=NULL, ...)
978
# { # @author Brian G. Peterson
979
# # pfolioReturn wrapper - replaces RMetrics pfolioReturn fn
980
#
981
# Return.portfolio(R=x, weights=weights, ...=...)
982
# }
983
###############################################################################
984
# R (http://r-project.org/) Numeric Methods for Optimization of Portfolios
985
#
986
# Copyright (c) 2004-2014 Kris Boudt, Peter Carl and Brian G. Peterson
987
#
988
# This library is distributed under the terms of the GNU Public License (GPL)
989
# for full details see the file COPYING
990
#
991
# $Id$
992
#
993
###############################################################################
994
# $Log: not supported by cvs2svn $
995
# Revision 1.85 2009-09-22 21:21:37 peter
996
# - added licensing details
997
#
998
# Revision 1.84 2008-01-31 17:31:00 brian
999
# - add startingweight to contribution calc
1000
#
1001
# Revision 1.83 2008/01/31 12:21:50 brian
1002
# - add wealth index calcs back in
1003
# - uncomment the old wealthindex.weighted for comparison
1004
#
1005
# Revision 1.82 2008/01/31 04:16:24 peter
1006
# - removed method line from Return.portfolio.multiweight
1007
#
1008
# Revision 1.81 2008/01/31 02:10:32 brian
1009
# - pass ... instead of method argument in Return.portfolio.multiweights
1010
#
1011
# Revision 1.80 2008/01/31 01:23:00 brian
1012
# - add as.vector in method simle for weights in Return.portfolio
1013
# - **not sure the simple method works properly**
1014
#
1015
# Revision 1.79 2008/01/31 01:15:07 brian
1016
# - add method argument to Return.portfolio.multiweights
1017
#
1018
# Revision 1.78 2008/01/31 00:48:49 brian
1019
# - add new function Return.portfolio.multiweight
1020
#
1021
# Revision 1.77 2008/01/30 23:41:54 brian
1022
# - add contributions as output again to Return.portfolio
1023
#
1024
# Revision 1.76 2008/01/30 23:34:00 brian
1025
# - add rowname for cumulative returns
1026
#
1027
# Revision 1.74 2008/01/29 20:16:21 brian
1028
# - fixed, tested contribution option for Return.portfolio fn
1029
#
1030
# Revision 1.73 2008/01/29 18:23:20 brian
1031
# - add contribution to Return.portfolio
1032
#
1033
# Revision 1.72 2008/01/29 02:59:24 brian
1034
# - comment browser() command
1035
#
1036
# Revision 1.71 2008/01/29 02:58:30 brian
1037
# - reverse output of BacktestWeightDisplay fn to make it easier to graph weights.
1038
#
1039
# Revision 1.70 2008/01/25 02:14:06 brian
1040
# - fix errors in data frrame/matrix handling in Return generating functions
1041
#
1042
# Revision 1.69 2008/01/25 01:28:54 brian
1043
# - complete function MonthlyBacktestResults
1044
#
1045
# Revision 1.68 2008/01/24 23:59:38 brian
1046
# - add Return, skewness, kurtosis to BacktestDisplay
1047
# - always display results for equal weighted portfolio
1048
#
1049
# Revision 1.67 2008/01/24 22:10:01 brian
1050
# - working version of BacktestDisplay fn
1051
# - still needs Return, skewness, kurtosis
1052
#
1053
# Revision 1.66 2008/01/24 01:51:12 brian
1054
# - resolve conflicts from editing in two directories
1055
#
1056
# Revision 1.65 2008/01/24 01:48:29 brian
1057
# - lay groundwork for rewriting BacktestDisplay fn
1058
#
1059
# Revision 1.64 2008/01/24 00:13:43 brian
1060
# - rename pfolioReturn fn Return.portfolio
1061
# - create wrapper for RMetrics pfolioReturn fn for compatibility
1062
# - add notes about contribution of assets to portfolio return
1063
#
1064
# Revision 1.63 2008/01/23 21:48:35 brian
1065
# - move rbind outside inner if statements to remove dup code
1066
#
1067
# Revision 1.62 2008/01/23 21:46:44 brian
1068
# - update to not lose first period in return stream
1069
# - add column names to make clear what the output is
1070
#
1071
# Revision 1.60 2008-01-23 05:34 brian
1072
# - new version of BacktestWeightDisplay works with output of Backtest fn
1073
#
1074
# Revision 1.61 2008/01/23 20:32:52 brian
1075
# - replacement pfolioReturn function to calculate weighted returns
1076
#
1077
# Revision 1.59 2008/01/23 11:04:17 brian
1078
# - fix 3yr/period confusion in two ThreeYr utility functions in WeightedPortfolios
1079
#
1080
# Revision 1.58 2008/01/22 20:33:49 brian
1081
# - update three yr to to-35 for proper 36 month window
1082
#
1083
# Revision 1.57 2008/01/22 02:58:56 brian
1084
# - Backtest fn now tested and working with new output of BruteForcePortfolios->BacktestData
1085
#
1086
# Revision 1.56 2008/01/22 02:10:20 brian
1087
# -working much better, Backtest fn still fails with a subscriupt out of bounds error on some data
1088
#
1089
# Revision 1.55 2008/01/21 23:40:42 brian
1090
# - adjust the way we reference list elements to do it numberically. apparently it's not easy to reference by a string
1091
#
1092
# Revision 1.54 2008/01/21 17:50:24 brian
1093
# - partial fix, Backtest fn still not working around lines 515-518
1094
#
1095
# Revision 1.53 2008/01/21 17:24:09 brian
1096
# - adjust use of rownames for insample/outofsample in Backtest fn
1097
#
1098
# Revision 1.52 2008/01/21 17:18:38 brian
1099
# - fix typo in matrix assignment
1100
#
1101
# Revision 1.51 2008/01/21 17:16:12 brian
1102
# - add matrix for reult to Backtest fn
1103
# - change max and min tests in Backtest fn to insert rowname of weighting vector rather than array index
1104
#
1105
# Revision 1.50 2008/01/21 16:31:36 brian
1106
# - revise Backtest function to have utility functions for maximizing and minimizing lists
1107
# - still need to initialize the result matrix
1108
#
1109
# Revision 1.49 2008/01/21 13:52:46 brian
1110
# - fix typo in ThreeYrStdDev method in WeightedPortfolioUtility
1111
#
1112
# Revision 1.48 2008/01/21 13:49:09 brian
1113
# - fix typo in ThreeYrGVaR method in WeightedPortfolioUtility
1114
# - add comments on the subsetting method we had to use to make this work on large weightgrid
1115
#
1116
# Revision 1.47 2008/01/21 04:41:47 brian
1117
# - fix naming and assignment of results in subsets
1118
#
1119
# Revision 1.46 2008/01/21 03:58:58 brian
1120
# - move weightgridsave out of the outer loopy
1121
#
1122
# Revision 1.45 2008/01/21 03:26:32 brian
1123
# - add drop=FALSE to subsetting of weightgrid to preserve rownames
1124
#
1125
# Revision 1.44 2008/01/21 03:02:19 brian
1126
# - add ugly outer loop hack so this will work
1127
#
1128
# Revision 1.43 2008/01/21 01:39:15 brian
1129
# - add switch and print statements for debug
1130
#
1131
# Revision 1.42 2008/01/20 23:07:58 brian
1132
# - use matrix for results to avoid data.frame factor BS
1133
#
1134
# Revision 1.41 2008/01/20 21:13:59 brian
1135
# - set colnames on result var when we create the object
1136
#
1137
# Revision 1.40 2008/01/20 21:05:45 brian
1138
# - change to create structure with correct number of rows and columns on first pass
1139
# - avoids warnings about replacing 0-element row with x-element row
1140
#
1141
# Revision 1.39 2008/01/20 19:55:33 brian
1142
# - create empty result var dataframe with right names for resultrows
1143
# - assign resultrow by index to avoid memcopy problem
1144
#
1145
# Revision 1.38 2008/01/20 17:22:15 brian
1146
# - fix row.names in initialization of resultrow data.frame
1147
#
1148
# Revision 1.37 2008/01/20 17:08:24 kris
1149
# Compute SR more efficiently
1150
#
1151
# Revision 1.36 2008/01/20 16:30:50 brian
1152
# - move multivariate moment calculations outside the row loop
1153
#
1154
# Revision 1.35 2008/01/20 16:26:21 brian
1155
# - add M3 and M4 moments to parameters for all modSR function calls
1156
#
1157
# Revision 1.34 2008/01/20 16:14:53 brian
1158
# - initialize result outside the loop in WeightedPortfolioUtility
1159
# - initialize resultrow to have one row
1160
#
1161
# Revision 1.33 2008/01/20 14:54:55 brian
1162
# - quote methods
1163
#
1164
# Revision 1.32 2008/01/20 14:53:05 brian
1165
# - fix syntax errors and handling of inception, threeyr, form, to
1166
#
1167
# Revision 1.31 2008/01/20 13:55:44 brian
1168
# - fix syntax error in switch on InceptionStdDev (missing comma)
1169
#
1170
# Revision 1.30 2008/01/20 13:49:39 brian
1171
# - add Kris to copyright line
1172
#
1173
# Revision 1.29 2008/01/20 13:48:37 brian
1174
# - fix syntax error
1175
# - update methods to reflect changes to multivariate moments
1176
#
1177
# Revision 1.28 2008/01/20 13:35:34 brian
1178
# - add missing brace in switch statement
1179
#
1180
# Revision 1.27 2008/01/20 12:07:24 kris
1181
# - Changed function definitions in optim_functions.R and updated the function calls in optimizer.R to these functions
1182
#
1183
# Revision 1.26 2008/01/20 06:23:12 brian
1184
# - convert GVaR functions
1185
#
1186
# Revision 1.25 2008/01/20 05:02:17 brian
1187
# - add in centered moments and standard variables for period, inception, and 3yr series
1188
#
1189
# Revision 1.24 2008/01/19 16:48:01 brian
1190
# - fix column name issues
1191
# - add period, inception, and 3yr for each method
1192
#
1193
# Revision 1.23 2008/01/05 04:49:25 brian
1194
# - add 'methods' argument to parameterize WeightedPortfolioUtility and BrutForcePortfolios functions
1195
# - not yet tested, may have issues with column names
1196
#
1197
# Revision 1.22 2008/01/04 14:27:07 brian
1198
# - convert to use functions from package PerformanceAnalytics
1199
#
1200
# Revision 1.21 2007/01/31 18:23:16 brian
1201
# - cascade function name standardization from performance-analytics.R
1202
#
1203
# Revision 1.20 2007/01/30 15:54:57 brian
1204
# - cascade function name standardization from extra_moments.R
1205
#
1206
# Revision 1.19 2007/01/26 13:24:02 brian
1207
# - fix typo
1208
#
1209
# Revision 1.18 2006/12/03 17:42:02 brian
1210
# - adjust utility functions in Backtest() to match 3yr statistices from BruteForcePortfolios
1211
# - add more descriptive comments to BacktestDisplay()
1212
# - add BacktestWeightDisplay() fn, not yet complete
1213
# Bug 840
1214
#
1215
# Revision 1.17 2006/12/02 12:54:53 brian
1216
# - modify BacktestData() fn to take a 'yeargrid' that matches
1217
# yeargrid from BruteForcePortfolios and loads those portfolios
1218
# Bug 840
1219
#
1220
# Revision 1.16 2006/11/30 00:24:11 brian
1221
# - remove 'inception' statistics from BruteForcePortfolios and Backtest fns
1222
# - fix error in 'show' parameter of BacktestDisplay fn
1223
# Bug 840
1224
#
1225
# Revision 1.15 2006/11/28 02:52:03 brian
1226
# - add 3yr SharpeRatio.modified and 3yr modVaR
1227
# - add fOptions require for Omega
1228
# Bug 840
1229
#
1230
# Revision 1.14 2006/10/12 17:42:48 brian
1231
# - put back omega utility fn
1232
#
1233
# Revision 1.13 2006/09/26 23:42:53 brian
1234
# - add Equalweighted as column in Backtest vector fns
1235
# - clean up NA handling in utility functions
1236
# - add more error handling
1237
#
1238
# Revision 1.12 2006/09/26 21:53:41 brian
1239
# - more fixes for NA's in data
1240
#
1241
# Revision 1.11 2006/09/26 12:07:04 brian
1242
# - add more NA handlinf and data series size checks
1243
# - comment out Omega for speed for now
1244
#
1245
# Revision 1.10 2006/09/22 15:30:44 brian
1246
# - add separate vector to BacktestDisplay fn for benchmark returns
1247
#
1248
# Revision 1.9 2006/09/22 12:45:45 brian
1249
# - add separate vector for benckmarkreturns to Backtest fn
1250
# - better describe inputs to Backtest fn in comments
1251
#
1252
# Revision 1.8 2006/09/21 13:43:39 brian
1253
# - add start timestamp for Backtest function
1254
#
1255
# Revision 1.7 2006/09/12 14:37:43 brian
1256
# - add CVS tags
1257
# - add CVS log
1258
# - add confidentiality notice to top of file
1259
#
1260
# Revision 1.6 2006-09-12 09:31:37 brian
1261
# - snapshot 2006-09-05 15:36
1262
# - add functions and tweak existing to better handle larger data sets, cutting data
1263
#
1264
# Revision 1.5 2006-09-12 09:29:12 brian
1265
# - snapshot 2006-08-30 19:03
1266
# - add functions for conthly compounding returns
1267
#
1268
# Revision 1.4 2006-09-12 09:28:01 brian
1269
# - snapshot 2006-08-29 23:01
1270
# - add equal weighted utility functions
1271
#
1272
# Revision 1.3 2006-09-12 09:27:00 brian
1273
# - snapshot 2006-08-29 21:58
1274
# - Add functions to actually perform the backtest
1275
# using the results of the brute force statistics
1276
# generated on all possible portfolios.
1277
#
1278
# Revision 1.2 2006-09-12 09:25:06 brian
1279
# - snapshot 2006-08-29
1280
# - add BruteForcePortfolios, WeightedPortfolioUtility, and other small utility functions
1281
#
1282
# Revision 1.1 2006-09-12 09:23:14 brian
1283
# - initial revision 2006-08-28
1284
# Bug 840
1285
###############################################################################
1286
1287