Implements a two-fund strategy where allocations to each fund are adjusted to maintain some user-specified portfolio beta. For example, you could back-test a zero-beta (i.e. market neutral) UPRO/VBLTX strategy using this function.
targetbeta_twofunds(tickers = NULL, intercepts = NULL, slopes = NULL, ...,
benchmark.ticker = NULL, reference.tickers = NULL, tickers.gains = NULL,
benchmark.gains = NULL, reference.gains = NULL, target.beta = 0,
tol = 0.15, window.units = 50, failure.method = "closer",
maxall.tol = tol - 0.05, initial = 10000)
Character vector specifying 2 ticker symbols that Yahoo! Finance recognizes, if you want to download data on the fly.
Numeric vector of values to add to daily gains for each ticker.
Numeric vector of values to multiply daily gains for each ticker by. Slopes are multiplied prior to adding intercepts.
Arguments to pass along with tickers
to
load_gains
.
Character string specifying ticker symbol for
benchmark index for calculating beta. If unspecified, the first fund in
tickers
is used as the benchmark.
Character vector of ticker symbols to include on graph as data points for comparative purposes.
Numeric matrix of gains, where each column has gains for a particular fund.
Numeric vector of gains for the benchmark index for
calculating beta. If unspecified, the first fund in tickers.gains
is
used as the benchmark.
Numeric vector or matrix of gains for funds to include on graph as data points for comparative purposes.
Numeric value.
Numeric value specifying how far the effective portfolio beta has
to deviate from target.beta
to trigger a rebalancing trade.
Numeric value specifying the width of the trailing moving window used to estimate each fund's beta.
Character string or vector specifying method(s) to use
when fund betas are such that the target portfolio beta cannot be achieved.
Choices are "cash"
, "fund1"
, "fund2"
,
"fund1.maxall"
, "fund2.maxall"
, "inverse1"
,
"inverse2"
, and "closer"
. See Details.
Numeric value specifying tolerance to use when implementing
the "fund1.maxall"
or "fund2.maxall"
failure method. To
illustrate, if target.beta = 0
, fund 1 has a current beta of 1, fund 2
has a current beta of 0.25, failure.method = "fund2.maxall"
, and
maxall.tol = 0.1
, a trade will be triggered that results in 40% fund
2 and 60% cash. The portfolio beta is 0.4 * 0.25 = 0.1
. The reason
you might want maxall.tol
to be less than tol
is to avoid
frequently triggering another trade on the very next day, as fund 2's beta
changes a little and moves the portfolio beta outside of
[target.beta - tol, target.beta + tol]
.
Numeric value specifying what value to scale initial prices to.
For each method, a 4-element list containing:
Numeric matrix named fund.balances
giving fund balances over
time.
Numeric matrix named fund.betas
giving fund betas over time.
Numeric vector named effective.betas
giving effective portfolio
beta over time.
Numeric value named trades
giving the total number of trades
executed.
The general implementation is as follows. Beta for each of the two funds is
estimated based on the first window.units
gains. Initial allocations
are selected to achieve portfolio beta of target.beta
. If that is not
possible - for example, if target.beta = 0
and both funds have
positive beta - then the action taken depends on what method is selected
through the failure.method
input (details below).
Assuming the target beta is attainable, the function moves over 1 day, and
applies each fund's gains for that day. It then re-calculates each fund's
beta based on the window.units
-width interval, and determines the
effective portfolio beta based on fund allocations and betas. If the
effective beta is outside of [target.beta - tol, target.beta + tol]
, a
rebalancing trade is triggered. As before, if the target beta cannot be
achieved, certain actions are taken depending on the selected method.
When outside of a trade because the target beta could not be achieved, the function attempts to rebalance each time it shifts over to a new day, regardless of the effective portfolio beta.
When failure.method = "cash"
, the entire portfolio balance is
allocated to cash when the target beta cannot be achieved.
When failure.method = "fund1"
(or "fund2"
), the entire
portfolio balance is allocated to the first (or second) fund when the target
beta cannot be achieved.
When failure.method = "fund1.maxall"
(or "fund2.maxall"
), when
the target beta cannot be achieved, fund 1 (or fund 2) is combined with cash,
with the fund 1 (fund 2) allocation as high as possible while staying within
maxall.tol
of target.beta
.
When failure.method = "inverse1"
(or "inverse2"
), an inverse
version of the first (or second) fund is used when the target beta cannot be
achieved. In many cases where the target beta cannot be achieved with the two
funds, it can be achieved with an inverse version of one and the other. If
the target beta still cannot be achieved, the entire portfolio balance is
allocated to cash.
When failure.method = "closer"
, the entire portfolio balance is
allocated to whichever fund has a beta closer to target.beta
.
Ryan, J.A. and Ulrich, J.M. (2017) quantmod: Quantitative Financial Modelling Framework. R package version 0.4-12, https://CRAN.R-project.org/package=quantmod.
# NOT RUN {
# Backtest zero-beta UPRO/VBLTX strategy
beta0 <- targetbeta_twofunds(tickers = c("UPRO", "VBLTX"), target.beta = 0)
plot(beta0$fund.balances[, "Portfolio"])
# }
# NOT RUN {
# }
Run the code above in your browser using DataLab