# Section 1: Future Value Calculations
V <- 1000
R <- 0.03
FV1 <- V * (1 + R)
FV5 <- V * (1 + R)^5
FV10 <- V * (1 + R)^10
c(FV1, FV5, FV10)
## [1] 1030.000 1159.274 1343.916
# Section 2: Doubling Time Calculations
R <- seq(0.01, 0.10, by = 0.01)
nExact <- log(2) / log(1 + R)
nRule70 <- 0.7 / R
cbind(R, nExact, nRule70)
## R nExact nRule70
## [1,] 0.01 69.660717 70.000000
## [2,] 0.02 35.002789 35.000000
## [3,] 0.03 23.449772 23.333333
## [4,] 0.04 17.672988 17.500000
## [5,] 0.05 14.206699 14.000000
## [6,] 0.06 11.895661 11.666667
## [7,] 0.07 10.244768 10.000000
## [8,] 0.08 9.006468 8.750000
## [9,] 0.09 8.043232 7.777778
## [10,] 0.10 7.272541 7.000000
# Section 3: Compounding Frequency and Future Value
V <- 1000
R <- 0.1
m <- c(1, 2, 4, 356, 10000)
FV <- V * (1 + R / m)^(m)
print(cbind(m, FV), digits = 7)
## m FV
## [1,] 1 1100.000
## [2,] 2 1102.500
## [3,] 4 1103.813
## [4,] 356 1105.155
## [5,] 10000 1105.170
# Section 4: Continuous Compounding
print(V * exp(R), digits = 7)
## [1] 1105.171
# Section 5: Annualized Rate of Return
RA <- FV / V - 1
print(cbind(m, FV, RA), digits = 7)
## m FV RA
## [1,] 1 1100.000 0.1000000
## [2,] 2 1102.500 0.1025000
## [3,] 4 1103.813 0.1038129
## [4,] 356 1105.155 0.1051554
## [5,] 10000 1105.170 0.1051704
print(exp(R) - 1, digits = 7)
## [1] 0.1051709
# Section 6: Simple Return Calculation
P0 <- 90
Pm1 <- 85
R0 <- (P0 - Pm1) / Pm1
c(R0, 1 + R0)
## [1] 0.05882353 1.05882353
# Section 7: Price Vector and Returns
Pm2 <- 80
P <- c(Pm2, Pm1, P0)
R <- (P[2:3] - P[1:2]) / P[1:2]
R
## [1] 0.06250000 0.05882353
(1 + R[1]) * (1 + R[2]) - 1
## [1] 0.125
cumprod(1 + R) - 1
## [1] 0.0625 0.1250
c(log(1 + R0), log(P0) - log(Pm1))
## [1] 0.05715841 0.05715841
# Section 8: Portfolio Returns
P.msft <- c(85, 90)
P.sbux <- c(30, 28)
V <- P.msft[1] * 10 + P.sbux[1] * 10
x.msft <- 10 * P.msft[1] / V
x.sbux <- 10 * P.sbux[1] / V
R.msft <- (P.msft[2] - P.msft[1]) / P.msft[1]
R.sbux <- (P.sbux[2] - P.sbux[1]) / P.sbux[1]
R.p <- x.msft * R.msft + x.sbux * R.sbux
V1 <- V * (1 + R.p)
c(R.p, x.msft * R.msft, x.sbux * R.sbux, V1)
## [1] 0.02608696 0.04347826 -0.01739130 1180.00000000
# Section 9: Security Prices and Portfolio Values
s.A <- 100
s.B <- 50
P.A <- c(5, 7, 6, 7)
V.A <- s.A * P.A
P.B <- c(10, 11, 12, 8)
V.B <- s.B * P.B
V.p <- V.A + V.B
table.vals <- cbind(P.A, V.A, P.B, V.B, V.p)
rownames(table.vals) <- c("t-3", "t-2", "t-1", "t")
table.vals
## P.A V.A P.B V.B V.p
## t-3 5 500 10 500 1000
## t-2 7 700 11 550 1250
## t-1 6 600 12 600 1200
## t 7 700 8 400 1100
# Section 10: Returns and Weights
R.A <- (V.A[2:4] - V.A[1:3]) / V.A[1:3]
R.B <- (V.B[2:4] - V.B[1:3]) / V.B[1:3]
R.p <- (V.p[2:4] - V.p[1:3]) / V.p[1:3]
table.returns <- cbind(R.A, R.B, R.p)
rownames(table.returns) <- c("t-2", "t-1", "t")
table.returns
## R.A R.B R.p
## t-2 0.4000000 0.10000000 0.25000000
## t-1 -0.1428571 0.09090909 -0.04000000
## t 0.1666667 -0.33333333 -0.08333333
x.A <- V.A / V.p
x.B <- V.B / V.p
table.weights <- cbind(x.A, x.B)
rownames(table.weights) <- c("t-3", "t-2", "t-1", "t")
table.weights
## x.A x.B
## t-3 0.5000000 0.5000000
## t-2 0.5600000 0.4400000
## t-1 0.5000000 0.5000000
## t 0.6363636 0.3636364
# Section 11: Contribution to Returns
R.p <- x.A[1:3] * R.A + x.B[1:3] * R.B
ctr.A <- (V.A[2:4] - V.A[1:3]) / V.p[1:3]
ctr.B <- (V.B[2:4] - V.B[1:3]) / V.p[1:3]
table.ctr <- cbind(ctr.A, ctr.B, ctr.A + ctr.B)
colnames(table.ctr)[3] <- "R.p"
rownames(table.ctr) <- c("t-2", "t-1", "t")
table.ctr
## ctr.A ctr.B R.p
## t-2 0.20000000 0.0500000 0.25000000
## t-1 -0.08000000 0.0400000 -0.04000000
## t 0.08333333 -0.1666667 -0.08333333
ctr.A <- x.A[1:3] * R.A
ctr.B <- x.B[1:3] * R.B
table.ctr <- cbind(ctr.A, ctr.B, R.p)
rownames(table.ctr) <- c("t-2", "t-1", "t")
table.ctr
## ctr.A ctr.B R.p
## t-2 0.20000000 0.0500000 0.25000000
## t-1 -0.08000000 0.0400000 -0.04000000
## t 0.08333333 -0.1666667 -0.08333333
# Section 12: Portfolio Values Over Time
V.A <- V.B <- V.p <- rep(0, 4)
V.p[1] <- 1000
V.A[1] <- V.B[1] <- 0.5 * V.p[1]
V.A[2:4] <- cumprod(1 + R.A) * V.A[1]
V.B[2:4] <- cumprod(1 + R.B) * V.B[1]
V.p[2:4] <- V.A[2:4] + V.B[2:4]
table.vals <- cbind(V.A, V.B, V.p)
rownames(table.vals) <- c("t-3", "t-2", "t-1", "t")
table.vals
## V.A V.B V.p
## t-3 500 500 1000
## t-2 700 550 1250
## t-1 600 600 1200
## t 700 400 1100
x.A <- V.A / V.p
x.B <- V.B / V.p
table.weights <- cbind(x.A, x.B)
rownames(table.weights) <- c("t-3", "t-2", "t-1", "t")
table.weights
## x.A x.B
## t-3 0.5000000 0.5000000
## t-2 0.5600000 0.4400000
## t-1 0.5000000 0.5000000
## t 0.6363636 0.3636364
diff(table.vals[, "V.p"]) / table.vals[1:3, "V.p"]
## t-2 t-1 t
## 0.25000000 -0.04000000 -0.08333333
x.A[1:3] * R.A + x.B[1:3] * R.B
## [1] 0.25000000 -0.04000000 -0.08333333
# Section 13: Rebalancing Portfolio
value.table <- matrix(0, 4, 3)
rownames(value.table) <- c("t-3", "t-2", "t-1", "t")
colnames(value.table) <- c("V.A", "V.B", "V.p")
value.table["t-3", ] <- c(V.A[1], V.B[1], V.p[1])
for (t in 2:4) {
value.table[t, "V.A"] <- value.table[t-1, "V.A"] * (1 + R.A[t-1])
value.table[t, "V.B"] <- value.table[t-1, "V.B"] * (1 + R.B[t-1])
value.table[t, "V.p"] <- value.table[t, "V.A"] + value.table[t, "V.B"]
RB <- max(value.table[t, "V.A"], value.table[t, "V.B"]) - value.table[t, "V.p"] / 2
if (value.table[t, "V.A"] > value.table[t, "V.B"]) {
value.table[t, "V.A"] <- value.table[t, "V.A"] - RB
value.table[t, "V.B"] <- value.table[t, "V.B"] + RB
} else {
value.table[t, "V.A"] <- value.table[t, "V.A"] + RB
value.table[t, "V.B"] <- value.table[t, "V.B"] - RB
}
value.table[t, "V.p"] <- value.table[t, "V.A"] + value.table[t, "V.B"]
}
value.table
## V.A V.B V.p
## t-3 500.0000 500.0000 1000.000
## t-2 625.0000 625.0000 1250.000
## t-1 608.7662 608.7662 1217.532
## t 558.0357 558.0357 1116.071
diff(value.table[, "V.p"]) / value.table[1:3, "V.p"]
## t-2 t-1 t
## 0.25000000 -0.02597403 -0.08333333
0.5 * R.A + 0.5 * R.B
## [1] 0.25000000 -0.02597403 -0.08333333
suppressPackageStartupMessages(library(xts))
suppressPackageStartupMessages(library(methods))
data(msftDailyPrices, sbuxDailyPrices)
## Warning in data(msftDailyPrices, sbuxDailyPrices): data set 'msftDailyPrices'
## not found
## Warning in data(msftDailyPrices, sbuxDailyPrices): data set 'sbuxDailyPrices'
## not found
# Load required libraries
suppressPackageStartupMessages(library(xts))
suppressPackageStartupMessages(library(PerformanceAnalytics))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(quantmod))
# Sample data creation (as the original data is not available)
# Here we create some example data to use in the code.
set.seed(123)
dates <- seq.Date(from = as.Date("2010-01-01"), to = as.Date("2020-01-01"), by = "days")
msftDailyPrices <- xts(rnorm(length(dates), 100, 10), order.by = dates)
sbuxDailyPrices <- xts(rnorm(length(dates), 50, 5), order.by = dates)
# Display the first three rows of combined MSFT and SBUX daily prices
head(cbind(msftDailyPrices, sbuxDailyPrices), 3)
## msftDailyPrices sbuxDailyPrices
## 2010-01-01 94.39524 49.46854
## 2010-01-02 97.69823 47.87935
## 2010-01-03 115.58708 49.29843
# Check the class of the MSFT daily prices
class(msftDailyPrices)
## [1] "xts" "zoo"
# Extract the core data and display the first three rows
matrix.data = coredata(msftDailyPrices)
head(matrix.data, 3)
## [,1]
## [1,] 94.39524
## [2,] 97.69823
## [3,] 115.58708
# Extract the date index and display the first three dates
date.index = index(msftDailyPrices)
head(date.index, 3)
## [1] "2010-01-01" "2010-01-02" "2010-01-03"
# Check the class of the date index
class(date.index)
## [1] "Date"
# Convert the first date to numeric
as.numeric(date.index[1])
## [1] 14610
# Extract data for specific dates
msftDailyPrices["2014-01-03"]
## [,1]
## 2014-01-03 106.3425
msftDailyPrices["2014-01-03::2014-01-07"]
## [,1]
## 2014-01-03 106.34250
## 2014-01-04 104.23645
## 2014-01-05 97.98162
## 2014-01-06 99.23134
## 2014-01-07 106.87364
msftDailyPrices["2014-01"]
## [,1]
## 2014-01-01 107.29560
## 2014-01-02 105.00266
## 2014-01-03 106.34250
## 2014-01-04 104.23645
## 2014-01-05 97.98162
## 2014-01-06 99.23134
## 2014-01-07 106.87364
## 2014-01-08 101.71632
## 2014-01-09 91.69891
## 2014-01-10 97.09841
## 2014-01-11 86.80874
## 2014-01-12 90.32968
## 2014-01-13 98.55389
## 2014-01-14 82.01867
## 2014-01-15 83.11458
## 2014-01-16 111.02565
## 2014-01-17 94.23381
## 2014-01-18 81.48308
## 2014-01-19 98.87137
## 2014-01-20 113.21069
## 2014-01-21 106.62254
## 2014-01-22 104.41383
## 2014-01-23 111.83746
## 2014-01-24 92.28499
## 2014-01-25 107.29689
## 2014-01-26 94.12914
## 2014-01-27 100.00764
## 2014-01-28 122.14465
## 2014-01-29 109.69434
## 2014-01-30 107.68008
## 2014-01-31 88.91672
# Merge MSFT and SBUX daily prices and display the first three rows
msftSbuxDailyPrices = merge(msftDailyPrices, sbuxDailyPrices)
head(msftSbuxDailyPrices, n=3)
## msftDailyPrices sbuxDailyPrices
## 2010-01-01 94.39524 49.46854
## 2010-01-02 97.69823 47.87935
## 2010-01-03 115.58708 49.29843
# Calculate the logarithm of MSFT daily prices and display the first three rows
msftDailyLogPrices = log(msftDailyPrices)
head(msftDailyLogPrices, 3)
## [,1]
## 2010-01-01 4.547491
## 2010-01-02 4.581883
## 2010-01-03 4.750024
# Sum MSFT and SBUX daily prices and display the first three rows
msftPlusSbuxDailyPrices = msftDailyPrices + sbuxDailyPrices
colnames(msftPlusSbuxDailyPrices) = "MSFT+SBUX"
head(msftPlusSbuxDailyPrices, 3)
## MSFT+SBUX
## 2010-01-01 143.8638
## 2010-01-02 145.5776
## 2010-01-03 164.8855
# Calculate the mean of MSFT daily prices
mean(msftDailyPrices)
## [1] 100.0879
mean(coredata(msftDailyPrices))
## [1] 100.0879
# Convert daily prices to monthly prices
msftMonthlyPrices = to.monthly(msftDailyPrices, OHLC=FALSE)
sbuxMonthlyPrices = to.monthly(sbuxDailyPrices, OHLC=FALSE)
msftSbuxMonthlyPrices = to.monthly(msftSbuxDailyPrices, OHLC=FALSE)
head(msftMonthlyPrices, 3)
## [,1]
## Jan 2010 104.2646
## Feb 2010 101.2385
## Mar 2010 111.4881
# Convert daily prices to monthly prices with last of the month as index
head(to.monthly(msftDailyPrices, OHLC=FALSE, indexAt="lastof"), 3)
## [,1]
## 2010-01-31 104.2646
## 2010-02-28 101.2385
## 2010-03-31 111.4881
# Convert daily prices to weekly prices
msftWeeklyPrices = to.weekly(msftDailyPrices, OHLC=FALSE)
head(msftWeeklyPrices, 3)
## [,1]
## 2010-01-03 115.58708
## 2010-01-10 95.54338
## 2010-01-17 104.97850
# Display the weekdays of the weekly prices
head(weekdays(index(msftWeeklyPrices)), 3)
## [1] "Sunday" "Sunday" "Sunday"
# Plot monthly closing prices for MSFT and SBUX
plot(msftSbuxMonthlyPrices, main="Monthly Closing Prices", legend.loc="topleft")
plot(msftSbuxMonthlyPrices, main="Monthly Closing Prices", multi.panel=TRUE)
# Plot monthly closing prices with customizations
plot.zoo(msftSbuxMonthlyPrices, plot.type="single", main="Monthly Closing Prices", lwd=2, col=c("black", "red"), ylab="Price")
grid()
legend(x="topleft", legend=colnames(msftSbuxMonthlyPrices), lwd=2, col=c("black", "red"))
# Plot multiple panels
plot.zoo(msftSbuxMonthlyPrices, plot.type="multiple", main="", lwd=2, col=c("black", "red"), cex.axis=0.8)
# Use ggplot2 to plot daily closing prices
autoplot(msftSbuxDailyPrices, facets=NULL) +
ggtitle("Daily Closing Prices") +
ylab("Closing Price Per Share") +
xlab("Year")
autoplot(msftSbuxDailyPrices, facets=Series ~ .) +
ggtitle("Daily Closing Prices") +
ylab("Closing Price Per Share") +
xlab("Year")
# Calculate and display SBUX monthly returns
sbuxMonthlyReturns = diff(sbuxMonthlyPrices)/stats::lag(sbuxMonthlyPrices)
head(sbuxMonthlyReturns, n=3)
## [,1]
## Jan 2010 NA
## Feb 2010 0.2525447
## Mar 2010 -0.1982704
# Alternative method for calculating returns
head(sbuxMonthlyPrices/stats::lag(sbuxMonthlyPrices) - 1, n=3)
## [,1]
## Jan 2010 NA
## Feb 2010 0.2525447
## Mar 2010 -0.1982704
# Remove NA values from returns
head(na.omit(sbuxMonthlyReturns), n=3)
## [,1]
## Feb 2010 0.2525447
## Mar 2010 -0.1982704
## Apr 2010 0.1017712
head(sbuxMonthlyReturns[-1], n=3)
## [,1]
## Feb 2010 0.2525447
## Mar 2010 -0.1982704
## Apr 2010 0.1017712
# Calculate continuous compounded returns
sbuxMonthlyReturnsC = na.omit(log(1 + sbuxMonthlyReturns))
head(sbuxMonthlyReturnsC, n=3)
## [,1]
## Feb 2010 0.22517723
## Mar 2010 -0.22098394
## Apr 2010 0.09691902
# Alternative method for continuous compounded returns
sbuxMonthlyReturnsC = na.omit(diff(log(sbuxMonthlyPrices)))
head(sbuxMonthlyReturnsC, n=3)
## [,1]
## Feb 2010 0.22517723
## Mar 2010 -0.22098394
## Apr 2010 0.09691902
# Calculate monthly returns for merged data
msftSbuxMonthlyReturns = diff(msftSbuxMonthlyPrices)/stats::lag(msftSbuxMonthlyPrices)
head(msftSbuxMonthlyReturns, n=3)
## msftDailyPrices sbuxDailyPrices
## Jan 2010 NA NA
## Feb 2010 -0.02902326 0.2525447
## Mar 2010 0.10124142 -0.1982704
msftSbuxMonthlyReturnsC = diff(log(msftSbuxMonthlyPrices))
head(msftSbuxMonthlyReturnsC, n=3)
## msftDailyPrices sbuxDailyPrices
## Jan 2010 NA NA
## Feb 2010 -0.02945277 0.2251772
## Mar 2010 0.09643811 -0.2209839
# Calculate returns using PerformanceAnalytics package
sbuxMonthlyReturns = Return.calculate(sbuxMonthlyPrices)
head(sbuxMonthlyReturns, n=3)
## [,1]
## Jan 2010 NA
## Feb 2010 0.2525447
## Mar 2010 -0.1982704
sbuxMonthlyReturnsC = Return.calculate(sbuxMonthlyPrices, method="log")
head(sbuxMonthlyReturnsC, n=3)
## [,1]
## Jan 2010 NA
## Feb 2010 0.2251772
## Mar 2010 -0.2209839
msftSbuxMonthlyReturns = Return.calculate(msftSbuxMonthlyPrices)
head(msftSbuxMonthlyReturns, 3)
## msftDailyPrices sbuxDailyPrices
## Jan 2010 NA NA
## Feb 2010 -0.02902326 0.2525447
## Mar 2010 0.10124142 -0.1982704
# Calculate equity curves
msftMonthlyReturns = na.omit(Return.calculate(msftMonthlyPrices))
sbuxMonthlyReturns = na.omit(Return.calculate(sbuxMonthlyPrices))
equityCurveMsft = cumprod(1 + msftMonthlyReturns)
equityCurveSbux = cumprod(1 + sbuxMonthlyReturns)
dataToPlot = merge(equityCurveMsft, equityCurveSbux)
plot(dataToPlot, main="Monthly Equity Curves", legend.loc="topleft")
# Calculate equal weight portfolio monthly returns
x.msft = x.sbux = 0.5
equalWeightPortMonthlyReturns = x.msft * msftMonthlyReturns + x.sbux * sbuxMonthlyReturns
head(equalWeightPortMonthlyReturns, 3)
## [,1]
## Feb 2010 0.11176071
## Mar 2010 -0.04851451
## Apr 2010 -0.04656594
equalWeightPortMonthlyReturns = Return.portfolio(na.omit(msftSbuxMonthlyReturns), weights=c(x.msft, x.sbux), rebalance_on="months")
head(equalWeightPortMonthlyReturns, 3)
## portfolio.returns
## Feb 2010 0.11176071
## Mar 2010 -0.04851451
## Apr 2010 -0.04656594
equalWeightPortMonthlyReturns = Return.portfolio(na.omit(msftSbuxMonthlyReturns), weights=c(x.msft, x.sbux), rebalance_on="months", contribution=TRUE)
head(equalWeightPortMonthlyReturns, 3)
## portfolio.returns msftDailyPrices sbuxDailyPrices
## Feb 2010 0.11176071 -0.01451163 0.12627234
## Mar 2010 -0.04851451 0.05062071 -0.09913522
## Apr 2010 -0.04656594 -0.09745152 0.05088558
equalWeightPortMonthlyReturns = Return.portfolio(na.omit(msftSbuxMonthlyReturns), weights=c(x.msft, x.sbux), rebalance_on="months", verbose=TRUE)
names(equalWeightPortMonthlyReturns)
## [1] "returns" "contribution" "BOP.Weight" "EOP.Weight" "BOP.Value"
## [6] "EOP.Value"
head(equalWeightPortMonthlyReturns$BOP.Weight, 3)
## msftDailyPrices sbuxDailyPrices
## Feb 2010 0.5 0.5
## Mar 2010 0.5 0.5
## Apr 2010 0.5 0.5
head(equalWeightPortMonthlyReturns$EOP.Weight, 3)
## msftDailyPrices sbuxDailyPrices
## Feb 2010 0.4366842 0.5633158
## Mar 2010 0.5786959 0.4213041
## Apr 2010 0.4222090 0.5777910
# Calculate buy and hold portfolio monthly returns
buyHoldPortMonthlyReturns = Return.portfolio(na.omit(msftSbuxMonthlyReturns), weights=c(x.msft, x.sbux))
head(buyHoldPortMonthlyReturns, 3)
## portfolio.returns
## Feb 2010 0.11176071
## Mar 2010 -0.06747834
## Apr 2010 -0.05122161
# Calculate equal weight quarterly portfolio monthly returns
equalWeightQtrPortMonthlyReturns = Return.portfolio(na.omit(msftSbuxMonthlyReturns), weights=c(x.msft, x.sbux), rebalance_on="quarters")
head(equalWeightQtrPortMonthlyReturns, 3)
## portfolio.returns
## Feb 2010 0.11176071
## Mar 2010 -0.06747834
## Apr 2010 -0.04656594
# Fetch stock data for AMZN and GOOG
getSymbols(Symbols=c("AMZN", "GOOG"), from="2007-01-03", to="2020-01-03", auto.assign=TRUE, warnings=FALSE)
## [1] "AMZN" "GOOG"
class(AMZN)
## [1] "xts" "zoo"
head(AMZN, 3)
## AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume AMZN.Adjusted
## 2007-01-03 1.9340 1.9530 1.9025 1.9350 248102000 1.9350
## 2007-01-04 1.9295 1.9570 1.9130 1.9450 126368000 1.9450
## 2007-01-05 1.9360 1.9395 1.8800 1.9185 132394000 1.9185
head(GOOG, 3)
## GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume GOOG.Adjusted
## 2007-01-03 11.60650 11.87200 11.48470 11.64610 309415434 11.64610
## 2007-01-04 11.68122 12.05357 11.66503 12.03638 316686586 12.03638
## 2007-01-05 12.01746 12.14199 11.90812 12.13427 275914333 12.13427
This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE
parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.