Calculating Strategy Returns from ROC and Lagged Trading Signals
Summary
The document presents a beginner’s question about why summing rate-of-change values multiplied by trading signals gives a different return from the price change between a stated entry and exit. The example uses Bollinger Bands, stochastic indicators, and MACD to construct lagged signals, then compares aggregate ROC-based returns with a simple holding-period price return. It also shows calculations for per-share profit and cumulative equity, illustrating that these are distinct return measures.
The post supplies code and a discrepancy but includes no answer explaining or correcting it. The shown methods therefore should not be treated as validated performance calculations. In particular, interpreting daily returns requires aligning each position with the following price move, handling flat and short positions consistently, and distinguishing a sum of daily returns from compounded account growth. The signal-generation and lagging steps also make timing conventions important; the example alone does not establish whether its reported strategy return is accurate.
Key ideas
- A sum of daily rate-of-change values need not equal the simple return between a trade’s entry and exit prices.
- Return calculations depend on aligning each signal with the price change it is intended to capture.
- Per-share profit, summed daily returns, and compounded account returns are different quantities.
- The example uses lagged signals from several technical indicators but does not provide a verified correction.
- Signal timing, position direction, and return compounding should be checked before interpreting strategy results.
Tags
Full text
# ROC -- Output from Calculating Stock Returns Producing Lower Numbers Than Actual
# ROC -- Output from Calculating Stock Returns Producing Lower Numbers Than Actual
I tried this on stack exchange, but think it is a better question here. I am beginning user and I need help with an error / bad output I am getting when calculating returns (using ROC) on stock closing prices. I created a trading strategy using 1,0,-1 as signals, but can't return an accurate percentage for my returns. I know the code is incorrect, but unsure how to correct it. Any help is much appreciated!
```
sum(ROC(Cl(x)) * x$signal, na.rm=TRUE) # Return of fully invested account
```
This returns: -0.004259766 Where, based on my strategy, it actually should be: 0.101174
Calculating this using: (88.16-80.06) / 80.06
```
Date Closing Price Signal
2015-03-06: 80.06 1 # enter trade
2015-05-12: 88.16 -1 # exit trade
```
Hopefully that helps clarify my question. If not, please leave comments on how to improve it further.
Find sample code below:
```
getSymbols("CAT", src="google", from="2014-07-30", to="2015-07-29")
#######################################
######### BOLLINGER BANDS #############
#######################################
x <- na.omit(merge(CAT, BBands(Cl(CAT))))
x$sig <- NA
x$sig[c(FALSE, diff(sign(Cl(x) - x$mavg), na.pad=FALSE) != 0)] <- 0
x$sig[Cl(x) > x$up] <- -1 # short when Close is above up
x$sig[Cl(x) < x$dn] <- 1 # long when Close is below dn
x$sig[1] <- 0 # flat on the first day
x$sig[nrow(x)] <- 0 # flat on the last day
# Fill in the signal for other times
x$sig <- na.locf(x$sig)
x$sig <- Lag(x$sig)
x$sig[1] <- 0
#######################################
############ STOCHASTICS ##############
#######################################
y <- na.omit(merge(CAT, stoch(Cl(CAT))))
y$diff <- y$fastK - y$slowD
y$sig <- ifelse(y$diff >= -.1 & y$diff <= .1,1,0)
y$sig <- Lag(y$sig)
y$sig[1] <- 0
#######################################
############### MACD ##################
#######################################
z <- na.omit(merge(CAT, MACD(Cl(CAT))))
z$diff <- z$macd - z$signal
z$sig <- ifelse(z$diff >= -0.1 & z$diff <= 0.1,1,0)
z$sig <- Lag(z$sig)
z$sig[1] <- 0
#######################################
################ MERGE ################
#######################################
all <- merge(x$sig,y$sig,z$sig)
all[is.na(all)] <- 0
all <- cbind(all,rowSums(all))
all$..2 <- all$sig*all$sig.1*all$sig.2;
x$signal <- cbind(all$..2)
x$signal <- na.locf(x$signal)
x$signal <- Lag(x$signal)
x$signal[1] <- 1
#######################################
######## $$$ RETURNS $$$ ##############
#######################################
sum(abs(diff(x$signal, na.pad=FALSE))) # number of trades
sum(diff(Cl(x)) * x$signal, na.rm=TRUE) # PnL of 1 share
cumsum(diff(Cl(x), na.pad=FALSE) * x$signal[-1]) # equity over time
sum(ROC(Cl(x)) * x$signal, na.rm=TRUE) # Return of fully invested account
cumsum(ROC(Cl(x), na.pad=FALSE) * x$sig[-1]) # cumulative return
myReturn <- lag(x$signal) * dailyReturn(x)
charts.PerformanceSummary(cbind(dailyReturn(x),myReturn))
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.