Part 3. How Much Alpha is Enough to Cover the Taxes of the Financially Immortal?

Introduction

How much more expected return is required to justify the turnover and the taxes that must be paid immediately? That’s the question we will continue to explore. In Part 1 we began with a simple example and built the tools to better address the question. In Part 2 we explored how the answered varies with the capital gain and time horizon. In this part, we consider the case of an investor who is “financially immortal” by which we mean the investor does not need to sell the current investment before he or she passes and that its basis can be stepped up at death thereby avoiding capital gains.

In this case, we will compare the terminal value of the current portfolio with the value of a portfolio assuming the current one is immediately liquidated and capital gains are paid. We use the same assumptions as Part 2.

The previoius posts contained some functions we will use here. To streamline the post we have put that code into a separate file and source it below. All the code is available in this GitHub repository.

source("TaxAlphaUtilities.r") # load the code (functions) 
marketAssumptions <- rbind(c(0.024,0.019,0.005),c(0.068,0.031,0.037),c(0.079,0.024,0.054))
rownames(marketAssumptions)<-c("US Large Stocks","EAFE","Emerging Markets")
colnames(marketAssumptions)<-c("ExpectedReturns","Dividend Yield","Appreciation")

Every month Research Affiliates publishes 10 year return forecasts for a variety of asset classes. As of February 28, 2018, they assumed the following nominal annualized expected returns:

kable(marketAssumptions*100,digits = 1, align="c", caption="Market Assumptions (%)")
Market Assumptions (%)
ExpectedReturns Dividend Yield Appreciation
US Large Stocks 2.4 1.9 0.5
EAFE 6.8 3.1 3.7
Emerging Markets 7.9 2.4 5.4

So Research Affiliates expects stocks in international developed (EAFE) and emerging markets to outperform. The margin seems like enough, but is it? To add to the realism, consider the following chart of SPY, an ETF that tracks the S&P 500. Its price has more than tripled which is a gain of over 200% since the beginning of 2009. Should an investor bite the bullet and pay the capital gains taxes for the expected higher returns in other markets?
S&P 500 ETF since 2009

As an example, we compare two scenarios using the assumptions for Research Affiliates. In one scenario an investor continues to hold $100 in US Large Stocks at a basis of $33.33 (a 200% gain) for 10 years. In another scenario the investor liquidates and purchase EAFE stocks.

taxRateDiv <- 0.25  # Dividends are taxed at 25%
taxRateLTCG <- 0.25 # Capital gains are taxed at 25%
horizon <- 10 # The time horizon is 10 years
currentValue <- 100
currentBasis <- 33.33
h <- createScenario(currentValue,currentBasis,
                    marketAssumptions["US Large Stocks","Dividend Yield"], 
                    marketAssumptions["US Large Stocks","Appreciation"], 
                    taxRateDiv, taxRateLTCG, horizon)
currentValueAT <- currentValue - (currentValue - currentBasis) * h$taxRateLTCG
l <- createScenario(currentValueAT, currentValueAT, 
                    marketAssumptions["EAFE","Dividend Yield"], 
                    marketAssumptions["EAFE","Appreciation"], 
                    taxRateDiv, taxRateLTCG, horizon)
hAT <- ATValue_scenario(h)
lAT <- ATValue_scenario(l)
kable(hAT[,1:5], digits = 2, caption = "Hold US")
Hold US
Value Basis Dividend Tax Growth
0 100.00 33.33 0.00 0.00 0.00
1 101.93 34.75 1.90 0.48 0.50
2 103.89 36.21 1.94 0.48 0.51
3 105.89 37.69 1.97 0.49 0.52
4 107.93 39.20 2.01 0.50 0.53
5 110.00 40.73 2.05 0.51 0.54
6 112.12 42.30 2.09 0.52 0.55
7 114.28 43.90 2.13 0.53 0.56
8 116.48 45.53 2.17 0.54 0.57
9 118.72 47.19 2.21 0.55 0.58
10 121.01 48.88 2.26 0.56 0.59
kable(lAT[,1:5], digits = 2, caption = "Liquidate, buy EAFE")
Liquidate, buy EAFE
Value Basis Dividend Tax Growth
0 83.33 83.33 0.00 0.00 0.00
1 88.35 85.27 2.58 0.65 3.08
2 93.68 87.32 2.74 0.68 3.27
3 99.32 89.50 2.90 0.73 3.47
4 105.30 91.81 3.08 0.77 3.67
5 111.65 94.26 3.26 0.82 3.90
6 118.38 96.86 3.46 0.87 4.13
7 125.51 99.61 3.67 0.92 4.38
8 133.07 102.53 3.89 0.97 4.64
9 141.09 105.62 4.13 1.03 4.92
10 149.59 108.90 4.37 1.09 5.22

From the “Value” column, we see that liquidating and investing in the EAFE portfolio results in a higher expected terminal value $149.59 versus $121.01.

The question we asked initially was how much more return would be need to justify the trade. We have two sources of return: dividends and appreciation. Because dividends are more predictable, we will only solve for the appreciation required.

breakeven <- appreciationRoot(h,l,6,"Value")

In the example we are using, EAFE has higher dividends than US Large stocks. It turns out that the appreciation of EAFE needs to be 1.48% for the trade to be as good as not trading (we’ll call this a breakeven rate). This would make the total return 4.58% compared to the US Large Stock return of 2.4%. Below is the table for the values assuming the appreciation is the breakeven rate and note the terminal value matches the terminal value of holding onto the US Large Cap portfolio.

l2 <- l
l2$appreciation <- breakeven$root
kable(ATValue_scenario(l2)[,1:5], digits = 2, caption = "Liquidate, buy EAFE assuming breakeven appreciation")
Liquidate, buy EAFE assuming breakeven appreciation
Value Basis Dividend Tax Growth
0 83.33 83.33 0.00 0.00 0.00
1 86.50 85.27 2.58 0.65 1.23
2 89.79 87.28 2.68 0.67 1.28
3 93.20 89.37 2.78 0.70 1.32
4 96.74 91.54 2.89 0.72 1.38
5 100.42 93.78 3.00 0.75 1.43
6 104.23 96.12 3.11 0.78 1.48
7 108.20 98.54 3.23 0.81 1.54
8 112.31 101.06 3.35 0.84 1.60
9 116.58 103.67 3.48 0.87 1.66
10 121.01 106.38 3.61 0.90 1.72

Now that we’ve illustrated the concept and process, let’s consider 9 investors with $100 in SPY who purchased their position for $10, $20, $30, … $90. How much more return must they expect to induce them to trade given an expected return of 2.4% for US Large Stocks?

out <- sapply(seq(10,90,10), function(x) {
    h$initBasis <- x
    l$initValue <- h$initValue - (h$initValue-h$initBasis)*h$taxRateLTCG
    l$initBasis <- l$initValue
    appreciationRoot(h,l,6,"Value")$root
})
result <- cbind(out,out+l$dividendYld,out+l$dividendYld-h$dividendYld-h$appreciation)
row.names(result) <- paste0("$",seq(10,90,10))
colnames(result) <- c("Appreciation","Total Return", "Excess")
kable(result*100,digits=2, caption = "Breakeven rates (%)")
Breakeven rates (%)
Appreciation Total Return Excess
$10 2.23 5.33 2.93
$20 1.90 5.00 2.60
$30 1.58 4.68 2.28
$40 1.27 4.37 1.97
$50 0.97 4.07 1.67
$60 0.68 3.78 1.38
$70 0.40 3.50 1.10
$80 0.12 3.22 0.82
$90 -0.14 2.96 0.56
plot(seq(10,90,10),result[,"Appreciation"], col="red",
     pch=19, type="b",
     main="Breakeven based on cost basis",
     ylim=c(min(result),max(result)),
     xlab="Cost basis", ylab= "Return")
points(seq(10,90,10),result[,"Total Return"], col="blue", pch=18, type="b")
abline(h=h$dividendYld+h$appreciation,col="gray")
abline(h=0,col="gray")
legend(10, 0.015,legend=c("Appreciation","Total Return"),
       col=c("red","blue"), 
       lty=1:2, pch=c(19,18), box.lty = 0)

The appreciation is the return so that the terminal value “breaks even” with that of the hold scenario. The total return combines the appreciation with the dividend yield. The excess is the difference over the total return (yield + appreciation) of the hold strategy.

Time horizon

Let’s consider different time horizons while maintaining our $33.33 basis. We consider horizons out to 40 years given how long investors may live.

thorizon <- seq(1,40)
out <- sapply(thorizon, function(x) {
    h$horizon <- x
    l$horizon <- x
    l$initValue <- h$initValue - (h$initValue-h$initBasis)*h$taxRateLTCG
    l$initBasis <- l$initValue
    appreciationRoot(h,l,6, "Value")$root
})

result <- cbind(out,out+l$dividendYld,out+l$dividendYld-h$dividendYld-h$appreciation)
row.names(result) <- paste0(thorizon,"Y")
colnames(result) <- c("Appreciation","Total Return", "Excess")
kable(result*100,digits=2, caption = "Breakeven rates (%)")
Breakeven rates (%)
Appreciation Total Return Excess
1Y 19.99 23.09 20.69
2Y 9.33 12.43 10.03
3Y 5.99 9.09 6.69
4Y 4.35 7.45 5.05
5Y 3.39 6.49 4.09
6Y 2.74 5.84 3.44
7Y 2.29 5.39 2.99
8Y 1.95 5.05 2.65
9Y 1.69 4.79 2.39
10Y 1.48 4.58 2.18
11Y 1.30 4.40 2.00
12Y 1.16 4.26 1.86
13Y 1.04 4.14 1.74
14Y 0.94 4.04 1.64
15Y 0.85 3.95 1.55
16Y 0.77 3.87 1.47
17Y 0.70 3.80 1.40
18Y 0.64 3.74 1.34
19Y 0.58 3.68 1.28
20Y 0.53 3.63 1.23
21Y 0.49 3.59 1.19
22Y 0.45 3.55 1.15
23Y 0.41 3.51 1.11
24Y 0.38 3.48 1.08
25Y 0.35 3.45 1.05
26Y 0.32 3.42 1.02
27Y 0.29 3.39 0.99
28Y 0.27 3.37 0.97
29Y 0.24 3.34 0.94
30Y 0.22 3.32 0.92
31Y 0.20 3.30 0.90
32Y 0.18 3.28 0.88
33Y 0.16 3.26 0.86
34Y 0.15 3.25 0.85
35Y 0.13 3.23 0.83
36Y 0.12 3.22 0.82
37Y 0.10 3.20 0.80
38Y 0.09 3.19 0.79
39Y 0.08 3.18 0.78
40Y 0.07 3.17 0.77
plot(thorizon,result[,"Appreciation"], col="red",
     pch=19, type="b",
     main="Breakeven based on horizon",
     ylim=c(min(result),max(result)),
     xlab="Horizon (years)", ylab= "Return")
points(thorizon,result[,"Total Return"], col="blue", pch=18, type="b")
abline(h=h$dividendYld+h$appreciation,col="gray")
abline(h=0,col="gray")
legend(6, 0.15,legend=c("Appreciation","Total Return"),
       col=c("red","blue"), 
       lty=1:2, pch=c(19,18), box.lty = 0)

An excellent article on the subject is Is Your Alpha Big Enough to Cover Its Taxes? Revisited by Arnott, Berkin and Bouchey, 2011 Investments & Wealth Monitor.  For more on R visit [R-bloggers](https://www.r-bloggers.com/).

The code used in this article is available from this [Github repository](https://github.com/rexmacey/TaxAlpha).

Part 2: How much alpha is needed to cover your taxes

Introduction

How much more expected return is required to justify the turnover and the taxes that must be paid immediately? That’s the question we will continue to explore. In Part 1 we began with a simple example and built the tools to better address the question. Here in Part 2 we explore how the answer varies with a variety of inputs.

The post in Part 1 contained some functions we will use here. To streamline the post we have put that code into a separate file and source it below. All the code is available in this GitHub repository.

source("TaxAlphaUtilities.r") # load the code (functions) 
marketAssumptions <- rbind(c(0.024,0.019,0.005),c(0.068,0.031,0.037),c(0.079,0.024,0.054))
rownames(marketAssumptions)<-c("US Large Stocks","EAFE","Emerging Markets")
colnames(marketAssumptions)<-c("ExpectedReturns","Dividend Yield","Appreciation")

Size of unrealized gain

How does the size of the unrealized gain impact the extra return required to justify a trade? The size of unrealized gain we use the cost basis as a percent of the market value. An investor with a basis of $75 would have a value of 0.75 if the market value were $100. In this case the investor would have a 33% (=25/75) unrealized capital gain on his or her investment. The unrealized gain may be converted to the cost/value percentage by dividing 1 by the quantity 1 plus the percentage gain (e.g., 0.75 = 1/(1+0.3333)).

Let’s consider some real world assumptions. Every month Research Affiliates publishes 10 year return forecasts for a variety of asset classes. As of February 28, 2018, they assumed the following nominal annualized expected returns:

kable(marketAssumptions*100,digits = 1, align="c", caption="Market Assumptions (%)")
Market Assumptions (%)
ExpectedReturns Dividend Yield Appreciation
US Large Stocks 2.4 1.9 0.5
EAFE 6.8 3.1 3.7
Emerging Markets 7.9 2.4 5.4

An excellent article on the subject is Is Your Alpha Big Enough to Cover Its Taxes? Revisited by Arnott, Berkin and Bouchey, 2011 Investments & Wealth Monitor.

The code for this post is available in this GitHub repository.

So Research Affiliates expects stocks in international developed (EAFE) and emerging markets to outperform. The margin seems like enough, but is it? To add to the realism, consider the following chart of SPY, an ETF that tracks the S&P 500. Its price has more than tripled which is a gain of over 200% since the beginning of 2009. Should an investor bite the bullet and pay the capital gains taxes for the expected higher returns in other markets?
S&P 500 ETF since 2009

As an example, we’ compare two scenarios using the assumptions for Research Affiliates. In one scenario an investor continues to hold $100 in US Large Stocks at a basis of $33.33 (a 200% gain) for 10 years before liquidating. In another scenario the investor liquidates and purchase EAFE stocks.

taxRateDiv <- 0.25  # Dividends are taxed at 25%
taxRateLTCG <- 0.25 # Capital gains are taxed at 25%
horizon <- 10 # The time horizon is 10 years
currentValue <- 100
currentBasis <- 33.33
h <- createScenario(currentValue,currentBasis,
                    marketAssumptions["US Large Stocks","Dividend Yield"], 
                    marketAssumptions["US Large Stocks","Appreciation"], 
                    taxRateDiv, taxRateLTCG, horizon)
currentValueAT <- currentValue - (currentValue - currentBasis) * h$taxRateLTCG
l <- createScenario(currentValueAT, currentValueAT, 
                    marketAssumptions["EAFE","Dividend Yield"], 
                    marketAssumptions["EAFE","Appreciation"], 
                    taxRateDiv, taxRateLTCG, horizon)
hAT <- ATValue_scenario(h)
lAT <- ATValue_scenario(l)
kable(hAT, digits = 2, caption = "Hold US")
Hold US
Value Basis Dividend Tax Growth AT
0 100.00 33.33 0.00 0.00 0.00 0.00
1 101.93 34.75 1.90 0.48 0.50 85.13
2 103.89 36.21 1.94 0.48 0.51 86.97
3 105.89 37.69 1.97 0.49 0.52 88.84
4 107.93 39.20 2.01 0.50 0.53 90.74
5 110.00 40.73 2.05 0.51 0.54 92.69
6 112.12 42.30 2.09 0.52 0.55 94.67
7 114.28 43.90 2.13 0.53 0.56 96.68
8 116.48 45.53 2.17 0.54 0.57 98.74
9 118.72 47.19 2.21 0.55 0.58 100.84
10 121.01 48.88 2.26 0.56 0.59 102.97
kable(lAT, digits = 2, caption = "Liquidate, buy EAFE")
Liquidate, buy EAFE
Value Basis Dividend Tax Growth AT
0 83.33 83.33 0.00 0.00 0.00 0.00
1 88.35 85.27 2.58 0.65 3.08 87.58
2 93.68 87.32 2.74 0.68 3.27 92.09
3 99.32 89.50 2.90 0.73 3.47 96.87
4 105.30 91.81 3.08 0.77 3.67 101.93
5 111.65 94.26 3.26 0.82 3.90 107.30
6 118.38 96.86 3.46 0.87 4.13 113.00
7 125.51 99.61 3.67 0.92 4.38 119.03
8 133.07 102.53 3.89 0.97 4.64 125.43
9 141.09 105.62 4.13 1.03 4.92 132.22
10 149.59 108.90 4.37 1.09 5.22 139.42

From the rightmost after-tax column (AT), we see that liquidating and investing in the EAFE portfolio results in a higher expected terminal value $139.42 versus $102.97. (Before taxes, it will take 5 years for the EAFE portfolio to catch up to the US portfolio).

The question we asked initially was how much more return would be need to justify the trade. We have two sources of return: dividends and appreciation. Because dividends are more predictable, we will only solve for the appreciation required.

breakeven <- appreciationRoot(h,l,6)

In the example we are using, EAFE has higher dividends than US Large stocks. It turns out that the appreciation of EAFE can be slightly negative at -0.24% for the trade to be as good as not trading (we’ll call this a breakeven rate). This would make the total return 2.86% compared to the US Large Stock return of 2.4%. Below is the table for the values assuming the appreciation is the breakeven rate and note the terminal AT value matches the terminal AT value of holding onto the US Large Cap portfolio.

In this scenario the AT values exceed the pretax values due to capital losses and the assumption that there’s value to the losses in that they may be used to offset other gains whether current or future.

l2 <- l
l2$appreciation <- breakeven$root
kable(ATValue_scenario(l2), digits = 2, caption = "Liquidate, buy EAFE assuming breakeven appreciation")
Liquidate, buy EAFE assuming breakeven appreciation
Value Basis Dividend Tax Growth AT
0 83.33 83.33 0.00 0.00 0.00 0.00
1 85.07 85.27 2.58 0.65 -0.20 85.12
2 86.84 87.25 2.64 0.66 -0.20 86.94
3 88.65 89.27 2.69 0.67 -0.21 88.81
4 90.50 91.33 2.75 0.69 -0.21 90.71
5 92.39 93.43 2.81 0.70 -0.22 92.65
6 94.31 95.58 2.86 0.72 -0.22 94.63
7 96.28 97.77 2.92 0.73 -0.23 96.65
8 98.28 100.01 2.98 0.75 -0.23 98.72
9 100.33 102.30 3.05 0.76 -0.24 100.82
10 102.42 104.63 3.11 0.78 -0.24 102.97

Now that we’ve illustrated the concept and process, let’s consider 9 investors with $100 in SPY who purchased their position for $10, $20, $30, … $90. How much more return must they expect to induce them to trade given an expected return of 2.4% for US Large Stocks?

out <- sapply(seq(10,90,10), function(x) {
    h$initBasis <- x
    l$initValue <- h$initValue - (h$initValue-h$initBasis)*h$taxRateLTCG
    l$initBasis <- l$initValue
    appreciationRoot(h,l,6)$root
})
result <- cbind(out,out+l$dividendYld,out+l$dividendYld-h$dividendYld-h$appreciation)
row.names(result) <- paste0("$",seq(10,90,10))
colnames(result) <- c("Appreciation","Total Return", "Excess")
kable(result*100,digits=2, caption = "Breakeven rates (%)")
Breakeven rates (%)
Appreciation Total Return Excess
$10 -0.05 3.05 0.65
$20 -0.14 2.96 0.56
$30 -0.22 2.88 0.48
$40 -0.29 2.81 0.41
$50 -0.36 2.74 0.34
$60 -0.43 2.67 0.27
$70 -0.49 2.61 0.21
$80 -0.56 2.54 0.14
$90 -0.61 2.49 0.09
plot(seq(10,90,10),result[,"Appreciation"], col="red",
     pch=19, type="b",
     main="Breakeven based on cost basis",
     ylim=c(min(result),max(result)),
     xlab="Cost basis", ylab= "Return")
points(seq(10,90,10),result[,"Total Return"], col="blue", pch=18, type="b")
abline(h=h$dividendYld+h$appreciation,col="gray")
abline(h=0,col="gray")
legend(10, 0.015,legend=c("Appreciation","Total Return"),
       col=c("red","blue"), 
       lty=1:2, pch=c(19,18), box.lty = 0)

The appreciation is the return so that the AT terminal value “breaks even” with that of the hold scenario. The total return combines the appreciation with the dividend yield. The excess is the difference over the total return (yield + appreciation) of the hold strategy.

Time horizon

Let’s consider different time horizons while maintaining our $33.33 basis. A short horizon does not make as much difference as one might think because in our analysis we liquidate both portfolios at the end.

out <- sapply(seq(1,10), function(x) {
    h$horizon <- x
    l$horizon <- x
    l$initValue <- h$initValue - (h$initValue-h$initBasis)*h$taxRateLTCG
    l$initBasis <- l$initValue
    appreciationRoot(h,l,6)$root
})

result <- cbind(out,out+l$dividendYld,out+l$dividendYld-h$dividendYld-h$appreciation)
row.names(result) <- paste0(seq(1,10),"Y")
colnames(result) <- c("Appreciation","Total Return", "Excess")
kable(result*100,digits=2, caption = "Breakeven rates (%)")
Breakeven rates (%)
Appreciation Total Return Excess
1Y -0.22 2.88 0.48
2Y -0.22 2.88 0.48
3Y -0.22 2.88 0.48
4Y -0.23 2.87 0.47
5Y -0.23 2.87 0.47
6Y -0.23 2.87 0.47
7Y -0.23 2.87 0.47
8Y -0.24 2.86 0.46
9Y -0.24 2.86 0.46
10Y -0.24 2.86 0.46
plot(seq(1,10),result[,"Appreciation"], col="red",
     pch=19, type="b",
     main="Breakeven based on horizon",
     ylim=c(min(result),max(result)),
     xlab="Horizon (years)", ylab= "Return")
points(seq(1,10),result[,"Total Return"], col="blue", pch=18, type="b")
abline(h=h$dividendYld+h$appreciation,col="gray")
abline(h=0,col="gray")
legend(2, 0.015,legend=c("Appreciation","Total Return"),
       col=c("red","blue"), 
       lty=1:2, pch=c(19,18), box.lty = 0)

We see that the horizon is not meaningful. This is based on the assumption that we will liquidate the after-tax value of the hold portfolio or at least compare after-tax values of the two.

An excellent article on the subject is Is Your Alpha Big Enough to Cover Its Taxes? Revisited by Arnott, Berkin and Bouchey, 2011 Investments & Wealth Monitor.

The code for this post is available in this GitHub repository.

Part 1. How much alpha is needed to cover your taxes?

Introduction

How much more expected return is required to justify the turnover and the taxes that must be paid immediately? That’s the question we will explore. Here in Part 1 we begin with a simple example and build the tools to better address the question. In Part 2 we explore how the answer varies with a variety of inputs. This document is intended as an example to introduce R especially to investment professionals. As a spoiler, there is not much analysis we do in this part that can’t be done in Excel. However Part 2 builds on this to go well beyond Excel (at least without using Excel’s VBA). Also this entire document was created using R which couldn’t be done as easily in Excel.

A set of assumptions

taxRateDiv <- 0.25  # Dividends are taxed at 25%
taxRateLTCG <- 0.25 # Capital gains are taxed at 25%
horizon <- 10 # The time horizon is 10 years
basicPct <- 0.75 # The cost basis of the asset is 75% of its value (a 33% unrealized gain)
dividendYld <- 0.02 # The dividend yield is 2% annually
appreciation <- 0.03 # The capital appreciation is 3% annually

The simple model

If we hold our portfolio (not incurring capital gains), what will its after-tax value be over our horizon? Each year we will receive the dividend, pay taxes on it, and reinvest the remainder increasing our basis. The value will appreciate. At the end of the horizon, we assume we sell the entire position, pay capital gains and calculate the remainder. For years zero through 10 the value are shown in the following table where AT would be the after-tax value were we to liquidate at the end of that year.

initValue <- 100
initBasis <- initValue * basicPct
holdScenario <- matrix(0,nrow = horizon+1, ncol = 6,
                       dimnames = list(0:horizon,
                                    c("Value","Basis","Dividend","Tax","Growth","AT")))
holdScenario[1,"Value"] <- initValue # an intial starting value
holdScenario[1,"Basis"] <- initBasis # initial basis
for (i in 2:(horizon+1)){
    holdScenario[i,"Dividend"] <- holdScenario[i-1,"Value"]*dividendYld
    holdScenario[i,"Tax"] <- holdScenario[i,"Dividend"] * taxRateDiv
    holdScenario[i,"Growth"] <- holdScenario[i-1,"Value"]*appreciation
    holdScenario[i,"Value"] <- holdScenario[i-1,"Value"]+holdScenario[i,"Dividend"] -
        holdScenario[i,"Tax"]+holdScenario[i,"Growth"]
    holdScenario[i,"Basis"] <- holdScenario[i-1,"Basis"]+holdScenario[i,"Dividend"] -
        holdScenario[i,"Tax"]
    holdScenario[i,"AT"] <- holdScenario[i,"Value"] - 
        (holdScenario[i,"Value"]-holdScenario[i,"Basis"])*taxRateLTCG
}

kable(holdScenario, digits=2, caption = "Hold Scenario")
Hold Scenario
Value Basis Dividend Tax Growth AT
0 100.00 75.00 0.00 0.00 0.00 0.00
1 104.50 76.50 2.00 0.50 3.00 97.50
2 109.20 78.07 2.09 0.52 3.13 101.42
3 114.12 79.71 2.18 0.55 3.28 105.51
4 119.25 81.42 2.28 0.57 3.42 109.79
5 124.62 83.21 2.39 0.60 3.58 114.27
6 130.23 85.08 2.49 0.62 3.74 118.94
7 136.09 87.03 2.60 0.65 3.91 123.82
8 142.21 89.07 2.72 0.68 4.08 128.93
9 148.61 91.20 2.84 0.71 4.27 134.26
10 155.30 93.43 2.97 0.74 4.46 139.83

Below we encapsulate the above code into a function and make the initial value and basis parameters which will make our life easier later and no longer make the basicPct parameter necessary. Functions are powerful because they can be called repeatedly.

ATValue <- function(initValue=100,
                    initBasis=100,
                    taxRateDiv, 
                    taxRateLTCG, 
                    horizon = 10, 
                    dividendYld, 
                    appreciation){
    out <- matrix(0,nrow = horizon+1, ncol = 6,
                       dimnames = list(0:horizon,
                                    c("Value","Basis","Dividend","Tax","Growth","AT")))
    out[1,"Value"] <- initValue # an intial starting value
    out[1,"Basis"] <- initBasis # initial basis
    for (i in 2:(horizon+1)){
        out[i,"Dividend"] <- out[i-1,"Value"]*dividendYld
        out[i,"Tax"] <- out[i,"Dividend"] * taxRateDiv
        out[i,"Growth"] <- out[i-1,"Value"]*appreciation
        out[i,"Value"] <- out[i-1,"Value"]+out[i,"Dividend"] -
            out[i,"Tax"]+out[i,"Growth"]
        out[i,"Basis"] <- out[i-1,"Basis"]+out[i,"Dividend"] -
            out[i,"Tax"]
        out[i,"AT"] <- out[i,"Value"] - 
            (out[i,"Value"]-out[i,"Basis"])*taxRateLTCG
    }
    return(out)
}

To make our code easier to read, we are going to put our assumptions into a list. We’ll use different lists to create two scenarios representing hold and liquidate.

createScenario <- function(initValue=100, 
                           initBasis=100, 
                           dividendYld, 
                           appreciation, 
                           taxRateDiv, 
                           taxRateLTCG,
                           horizon=10){
    out<-list(initValue, 
           initBasis, 
           dividendYld, 
           appreciation, 
           taxRateDiv, 
           taxRateLTCG,
           horizon)
    names(out) <- c("initValue", 
           "initBasis", 
           "dividendYld", 
           "appreciation", 
           "taxRateDiv", 
           "taxRateLTCG",
           "horizon")
    return(out)
}

Hold vs. Liquidate

Below we run and display the results if we hold and if we sell immediately (liquidate). In the liquidate scenario the intial value and intial basis are set to 100 – (100-100basicPct)taxRateLTCG which would be the value left after paying taxes if we sold immediately.

h <- createScenario(initValue, initValue*basicPct, dividendYld, 
                       appreciation, taxRateDiv, taxRateLTCG, horizon)
hold <- ATValue(h$initValue, h$initBasis, h$taxRateDiv, h$taxRateLTCG, h$horizon, 
                h$dividendYld, h$appreciation)
initValueLiquidate <- initValue - (initValue - initBasis) * taxRateLTCG
l <- createScenario(initValueLiquidate, initValueLiquidate, dividendYld, 
                       appreciation, taxRateDiv, taxRateLTCG, horizon)
liquidate <- ATValue(l$initValue, l$initBasis, l$taxRateDiv, l$taxRateLTCG, l$horizon, 
                l$dividendYld, l$appreciation)
kable(hold, digits=2, caption = "Hold Scenario (function example")
Hold Scenario (function example
Value Basis Dividend Tax Growth AT
0 100.00 75.00 0.00 0.00 0.00 0.00
1 104.50 76.50 2.00 0.50 3.00 97.50
2 109.20 78.07 2.09 0.52 3.13 101.42
3 114.12 79.71 2.18 0.55 3.28 105.51
4 119.25 81.42 2.28 0.57 3.42 109.79
5 124.62 83.21 2.39 0.60 3.58 114.27
6 130.23 85.08 2.49 0.62 3.74 118.94
7 136.09 87.03 2.60 0.65 3.91 123.82
8 142.21 89.07 2.72 0.68 4.08 128.93
9 148.61 91.20 2.84 0.71 4.27 134.26
10 155.30 93.43 2.97 0.74 4.46 139.83
kable(liquidate, digits=2, caption = "Liquidate Scenario")
Liquidate Scenario
Value Basis Dividend Tax Growth AT
0 93.75 93.75 0.00 0.00 0.00 0.00
1 97.97 95.16 1.88 0.47 2.81 97.27
2 102.38 96.63 1.96 0.49 2.94 100.94
3 106.98 98.16 2.05 0.51 3.07 104.78
4 111.80 99.77 2.14 0.53 3.21 108.79
5 116.83 101.44 2.24 0.56 3.35 112.98
6 122.09 103.20 2.34 0.58 3.50 117.36
7 127.58 105.03 2.44 0.61 3.66 121.94
8 133.32 106.94 2.55 0.64 3.83 126.73
9 139.32 108.94 2.67 0.67 4.00 131.73
10 145.59 111.03 2.79 0.70 4.18 136.95

Getting to an Answer

We’re now a good deal closer to answering the question how much more return do we need? The ATValue function returns a matrix the last row of which contains the after-tax value in the field called AT. We need to find the return that causes terminal the after-tax values to be identical. The difference between this return and our initial return is our ultimate answer. To make the taxes more realistic, we have decomposed the return in to dividend yield and appreciation. For this example, we will just solve for appreciation.

The first thing we’ll do is create a new function to calculate the difference between the “liquidate” terminal after-tax value and the “hold” terminal after-tax value. We add a digits parameter which is the number of digits to round the result to. Then we’ll use a built-in function uniroot in R to find the appreciation value for the liquidate scenarios that sets the value of the difference function to zero (i.e. the root). The uniroot function finds x such that f(x) is zero. We want x to represent the appreciation in the liquidate scenario. In the function below, if x is NULL we ignore x; otherwise we make the appreciation value in the liquidateScenario equal to x. This is to make it work with the uniroot function which will vary x and also to allow the function to work when we just want to know the difference in terminal values when we know the appreciation rate.

DifferenceLiquidateAndHold <- function(x=NULL,
                    holdScenario,
                    liquidateScenario,
                    digits=4){
if(!is.null(x)) liquidateScenario$appreciation <- x
hold <- ATValue(holdScenario$initValue, holdScenario$initBasis, holdScenario$taxRateDiv, 
                holdScenario$taxRateLTCG, holdScenario$horizon, 
                holdScenario$dividendYld, holdScenario$appreciation)
liquidate <- ATValue(liquidateScenario$initValue, liquidateScenario$initBasis, 
                     liquidateScenario$taxRateDiv, 
                     liquidateScenario$taxRateLTCG, liquidateScenario$horizon, 
                     liquidateScenario$dividendYld, liquidateScenario$appreciation)
return(round(liquidate[horizon+1,"AT"]-hold[horizon+1,"AT"],digits))
}

Let’s check the difference function. It should produce 136.9507 – 139.8308 = -2.88.

resultLiquidateMinusHold <- DifferenceLiquidateAndHold(NULL,h,l,6)

It produces -2.880049.

So now we’ll make a function to calculate the appreciation that sets the diffence to zero.

appreciationRoot <- function(holdScenario, liquidateScenario, digits=4){
    result <- uniroot(DifferenceLiquidateAndHold,c(-.25,1),
                      holdScenario,
                      liquidateScenario,
                      digits)
    return(result)
}

exampleRoot <- appreciationRoot(h,l, digits = 6)

The appreciation needed to make the terminal after-tax values match is 3.267%. This is an additional appreciation of 0.267%. To check that this is correct, we show the tables using the original hold scenario and the liquidate scenario with this higher appreciation rate. Only the last AT values need to match.

hold <- ATValue(h$initValue, h$initBasis, h$taxRateDiv, 
                h$taxRateLTCG, h$horizon, 
                h$dividendYld, h$appreciation)
liquidate <- ATValue(l$initValue, l$initBasis, 
                     l$taxRateDiv, 
                     l$taxRateLTCG, l$horizon, 
                     l$dividendYld, exampleRoot$root)
kable(hold, digits=2, caption = "Hold Scenario (function example")
Hold Scenario (function example
Value Basis Dividend Tax Growth AT
0 100.00 75.00 0.00 0.00 0.00 0.00
1 104.50 76.50 2.00 0.50 3.00 97.50
2 109.20 78.07 2.09 0.52 3.13 101.42
3 114.12 79.71 2.18 0.55 3.28 105.51
4 119.25 81.42 2.28 0.57 3.42 109.79
5 124.62 83.21 2.39 0.60 3.58 114.27
6 130.23 85.08 2.49 0.62 3.74 118.94
7 136.09 87.03 2.60 0.65 3.91 123.82
8 142.21 89.07 2.72 0.68 4.08 128.93
9 148.61 91.20 2.84 0.71 4.27 134.26
10 155.30 93.43 2.97 0.74 4.46 139.83
kable(liquidate, digits=2, caption = "Liquidate Scenario")
Liquidate Scenario
Value Basis Dividend Tax Growth AT
0 93.75 93.75 0.00 0.00 0.00 0.00
1 98.22 95.16 1.88 0.47 3.06 97.45
2 102.90 96.63 1.96 0.49 3.21 101.33
3 107.81 98.17 2.06 0.51 3.36 105.40
4 112.95 99.79 2.16 0.54 3.52 109.66
5 118.33 101.48 2.26 0.56 3.69 114.12
6 123.97 103.26 2.37 0.59 3.87 118.79
7 129.88 105.12 2.48 0.62 4.05 123.69
8 136.07 107.07 2.60 0.65 4.24 128.82
9 142.56 109.11 2.72 0.68 4.45 134.20
10 149.36 111.25 2.85 0.71 4.66 139.83

An excellent article on the subject is Is Your Alpha Big Enough to Cover Its Taxes? Revisited by Arnott, Berkin and Bouchey, 2011 Investments & Wealth Monitor.  For more on R visit [R-bloggers](https://www.r-bloggers.com/).

The code used in this article is available from this [Github repository](https://github.com/rexmacey/TaxAlpha).