Conditional Rebalancing

The default in btest is to compute a signal and rebalance at every instance of time, which typically means at any price observation passed to the function. Sometimes we may prefer to rebalance only when the current position deviates meaningfully from the target position. This example shows a way to implement such conditional rebalancing.

We start by attaching the package and creating some toy data.

library("PMwR")
p1 <- rep(100, 5)
p2 <- p1 + seq(from = 0, to = 20, length.out = length(p1))
P <- cbind(p1, p2)
P
      p1  p2
[1,] 100 100
[2,] 100 105
[3,] 100 110
[4,] 100 115
[5,] 100 120

Suppose we wish to hold an equally-weighted portfolio of both assets.

bt <- btest(list(P),
      signal = function() c(0.5, 0.5),
      convert.weights = TRUE,
      initial.cash = 100)

journal(bt)
   instrument  timestamp       amount  price
1          p1          2   0.50000000    100
2          p2          2   0.50000000    105
3          p2          3  -0.02380952    110
4          p1          4   0.01250000    100
5          p2          4  -0.01028139    115
6          p1          5   0.01190476    100
7          p2          5  -0.00990495    120

7 transactions

btest accepts an argument do.rebalance, which is a function that should return TRUE if rebalancing is to take place. Its effect is most clearly demonstrated when we have it return FALSE instead.

journal(bt <- btest(list(P),
                    signal = function() c(0.5, 0.5),
                    do.rebalance = function() FALSE,
                    convert.weights = TRUE,
                    initial.cash = 100))
no transactions

There is no trade at all. It is more useful to have do.rebalance react to the current position.

do.rebalance <- function() {
    ## btest stores only positions, not weights; but
    ## weights may be computed from positions
    weights <- Portfolio()*Close()/Wealth()
    cat(Time(), ": ", weights, "\n")

    if (any(abs(weights - c(0.5, 0.5)) > 0.03))
        TRUE
    else
        FALSE
}
do.rebalance2 <- function() {
    ## btest stores only positions, not weights; but
    ## weights may be computed from positions
    weights <- Portfolio()*Close()/Wealth()
    cat(Time(), ": ", weights, "\n")
    TRUE
}

journal(bt <- btest(list(P),
                    signal = function() c(.5, .5),
                    do.rebalance = do.rebalance,
                    convert.weights = TRUE,
                    initial.cash = 100))
journal(bt <- btest(list(P),
                    signal = function() c(.5, .5),
                    do.rebalance = do.rebalance2,
                    tol.p = 0.03,
                    convert.weights = TRUE,
                    initial.cash = 100))

1 :  0 0 
2 :  0.5 0.525 
3 :  0.4878049 0.5365854 
4 :  0.4880952 0.5102814 



   instrument  timestamp       amount  price
1          p1          2   0.50000000    100
2          p2          2   0.50000000    105
3          p1          4   0.01250000    100
4          p2          4  -0.03409091    115

4 transactions


1 :  0 0 
2 :  0.5 0.525 
3 :  0.4878049 0.5365854 
4 :  0.4761905 0.5102814 
   instrument  timestamp       amount  price
1          p1          2   0.50000000    100
2          p2          2   0.50000000    105
3          p2          4  -0.03409091    115

3 transactions