Reputation: 45
I use tradestatistics on Quantstrat and obtained positive ending equities that look out of this world (starting equity=1m). However, what is puzzling is, cumulative returns is -1.0 when I tabulate performance.
How can you have positive ending equity and negative cumulative returns? Is my understanding of ending equity wrong?
library(quantmod)
library(FinancialInstrument)
library(PerformanceAnalytics)
library(foreach)
library(blotter)
library(quantstrat)
options("getSymbols.yahoo.warning"=FALSE)
options("getSymbols.warning4.0"=FALSE)
initDate="1990-01-01"
from ="2009-01-01"
to ="2013-01-01"
symbols = c("SPY")
currency("USD")
getSymbols(symbols, from=from, to=to, adjust=TRUE)
stock(symbols, currency="USD", multiplier=1)
initEq=1000000
strategy.st <- portfolio.st <- account.st <- "mystrat"
rm.strat(portfolio.st)
rm.strat(account.st)
initPortf(name=portfolio.st,
symbols=symbols,
initDate=initDate,
currency='USD')
initAcct(name=account.st,
portfolios=portfolio.st,
initDate=initDate,
currency='USD',
initEq=initEq)
initOrders(portfolio=portfolio.st,
initDate=initDate)
strategy(strategy.st, store=TRUE)
### Add Indicators
nRSI <- 21
buyThresh <- 50
sellThresh <- 50
#Indicator for EMA long medium short
nEMAL<- 200
nEMAM<- 30
nEMAS<- 13
nEMAF<- 5
add.indicator(strategy.st, name="RSI",
arguments=list(price=quote(Cl(mktdata)), n=nRSI),
label="rsi")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAL),
label="EMAL")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAM),
label="EMAM")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAS),
label="EMAS")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAF),
label="EMAF")
upsig <- function(data) {
sig <- data[, "rsi"] >50 & data[, "EMA.EMAM"] > data[, "EMA.EMAL"]
colnames(sig) <- "upSig"
sig
}
downsig <- function(data) {
sig <- data[, "rsi"] <50 & data[, "EMA.EMAM"] < data[, "EMA.EMAL"]
colnames(sig) <- "downSig"
sig
}
### Add Signal- Enter
add.signal(strategy.st, name="upsig",
arguments=list(data = quote(mktdata)),
label = "entersig")
add.signal(strategy.st, name="downsig",
arguments=list(data = quote(mktdata)),
label = "exitsig")
### Add rule - Enter
add.rule(strategy.st,
name='ruleSignal',
arguments = list(sigcol="upSig.entersig",
sigval=TRUE,
orderqty=1000,
ordertype='market',
orderside='long',
threshold=NULL),
type='enter',
path.dep=TRUE)
### Add rule- Exit
add.rule(strategy.st,
name='ruleSignal',
arguments = list(sigcol="downSig.exitsig",
sigval=TRUE,
orderqty= -1000,
ordertype='market',
orderside='long',
pricemethod='market',
replace=FALSE),
type='exit',
path.dep=TRUE)
start_t<-Sys.time()
out<-try(applyStrategy(strategy=strategy.st,
portfolios=portfolio.st))
updatePortf(portfolio.st)
updateAcct(portfolio.st)
updateEndEq(account.st)
for(symbol in symbols) {
chart.Posn(
Portfolio=portfolio.st,
Symbol=symbol,
log=TRUE)
}
tstats <- tradeStats(portfolio.st)
t(tstats)
rets <- PortfReturns(Account = account.st)
rownames(rets) <- NULL
charts.PerformanceSummary(rets, colorset = bluefocus)
tab.perf <- table.Arbitrary(rets,
metrics=c(
"Return.cumulative",
"Return.annualized",
"SharpeRatio.annualized",
"CalmarRatio"),
metricsNames=c(
"Cumulative Return",
"Annualized Return",
"Annualized Sharpe Ratio",
"Calmar Ratio"))
tab.perf
#Test here
#test <-try(applyIndicators(strategy.st,mktdata=OHLC(AAPL)))
#head(test, n=40)
Upvotes: 1
Views: 557
Reputation: 6891
First, you're only entering lots of long positions. And then lots of consecutive exit trades! The problem is you're getting long entry signals on every signal bar for long chunks of time. And you're not restricting your strategy from entering more and more long positions, each of size 1000. You could use osMaxPos
and addPosLimit
to deal with capping the amount of trades possible when a position is opened in a particular direction.
Here's how you could stop having so many long entries happen on everybar. You want the entry to be true when the rsi crosses 50 above and below. Use sigCrossover
. Second, use addPosLimit
to cap the size of the total positions allowed. Look at mktdata
to debug your strategy next time too, checking you dont have multiple entry signals one row after another.
You're getting -1 cum returns because you're providing nonsensical input. So much buying (you buy 1k units every consectuive day while the entry signal is true, and then sell more many days in a row too). Clearly this wasn't intended. Inspect the output of getTxns
to see the problem. Also, your end equity can be negative because you're simply adding up your cash PnL from your portfolio to your inital capital. i.e. quantstrat doesn't stop trading once your actual equity goes negative. You could think of it like this: quantstrat just keeps trading assuming you have more funds to trade with, even if your losses exceed initial equity.
If you put sensible parameters, your equity will never go negative in quantstrat(unless your strategy is really bad and consistently loses cash, or you trade for a really long time in the backtest so that going broke or worse has a decent probability of happening in the time allowed).
here are some adjustments, namely sigCrossover
and using a trade size of 300, in your strategy to get more sensible numbers. Also making use of osMaxPos
. It is still buying stacked positions in at most 3 levels here.
library(quantmod)
library(FinancialInstrument)
library(PerformanceAnalytics)
library(foreach)
library(blotter)
library(quantstrat)
options("getSymbols.yahoo.warning"=FALSE)
options("getSymbols.warning4.0"=FALSE)
initDate="1990-01-01"
from ="2009-01-01"
to ="2013-01-01"
symbols = c("SPY")
currency("USD")
getSymbols(symbols, from=from, to=to, adjust=TRUE)
stock(symbols, currency="USD", multiplier=1)
initEq=1000000
strategy.st <- portfolio.st <- account.st <- "mystrat"
rm.strat(portfolio.st)
rm.strat(account.st)
initPortf(name=portfolio.st,
symbols=symbols,
initDate=initDate,
currency='USD')
initAcct(name=account.st,
portfolios=portfolio.st,
initDate=initDate,
currency='USD',
initEq=initEq)
initOrders(portfolio=portfolio.st,
initDate=initDate)
strategy(strategy.st, store=TRUE)
### Add Indicators
nRSI <- 21
buyThresh <- 50
sellThresh <- 50
#Indicator for EMA long medium short
nEMAL<- 200
nEMAM<- 30
nEMAS<- 13
nEMAF<- 5
tradeSize <- 100
for (sym in symbols) {
addPosLimit(portfolio.st, sym, start(get(sym)), maxpos = 300, longlevels = 3)
}
add.indicator(strategy.st, name="RSI",
arguments=list(price=quote(Cl(mktdata)), n=nRSI),
label="rsi")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAL),
label="EMAL")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAM),
label="EMAM")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAS),
label="EMAS")
add.indicator(strategy.st, name="EMA",
arguments=list(x=quote(Cl(mktdata)), n=nEMAF),
label="EMAF")
# important to set cross = TRUE in sigThreshold
add.signal(strategy.st, name = "sigThreshold",
arguments = list(column = "rsi", threshold = 50, relationship = "gt", cross = TRUE),
label = "rsiUp")
add.signal(strategy.st, name = "sigThreshold",
arguments = list(column = "rsi", threshold = 50, relationship = "lt", cross = TRUE),
label = "rsiDn")
upsig <- function(data) {
sig <- data[, "rsiUp"] & data[, "EMA.EMAM"] > data[, "EMA.EMAL"]
colnames(sig) <- "upSig"
sig
}
downsig <- function(data) {
sig <- data[, "rsiDn"] & data[, "EMA.EMAM"] < data[, "EMA.EMAL"]
colnames(sig) <- "downSig"
sig
}
### Add Signal- Enter
add.signal(strategy.st, name="upsig",
arguments=list(data = quote(mktdata)),
label = "entersig")
add.signal(strategy.st, name="downsig",
arguments=list(data = quote(mktdata)),
label = "exitsig")
### Add rule - Enter
add.rule(strategy.st,
name='ruleSignal',
arguments = list(sigcol="upSig.entersig",
sigval=TRUE,
orderqty=100,
ordertype='market',
orderside='long',
threshold=NULL,
osFUN = osMaxPos), # <- need this to cap trade levels to at most 3
type='enter',
path.dep=TRUE)
### Add rule- Exit
add.rule(strategy.st,
name='ruleSignal',
arguments = list(sigcol="downSig.exitsig",
sigval=TRUE,
orderqty= -100,
ordertype='market',
orderside='long',
pricemethod='market',
replace=FALSE),
type='exit',
path.dep=TRUE)
start_t<-Sys.time()
out<-try(applyStrategy(strategy=strategy.st,
portfolios=portfolio.st))
updatePortf(portfolio.st)
updateAcct(portfolio.st)
updateEndEq(account.st)
for(symbol in symbols) {
chart.Posn(
Portfolio=portfolio.st,
Symbol=symbol,
log=TRUE)
}
tstats <- tradeStats(portfolio.st)
t(tstats)
rets <- PortfReturns(Account = account.st)
rownames(rets) <- NULL
charts.PerformanceSummary(rets, colorset = bluefocus)
tab.perf <- table.Arbitrary(rets,
metrics=c(
"Return.cumulative",
"Return.annualized",
"SharpeRatio.annualized",
"CalmarRatio"),
metricsNames=c(
"Cumulative Return",
"Annualized Return",
"Annualized Sharpe Ratio",
"Calmar Ratio"))
tab.perf
tail(.blotter$account.mystrat$summary)
# Additions Withdrawals Realized.PL Unrealized.PL Interest Gross.Trading.PL Txn.Fees Net.Trading.PL Advisory.Fees Net.Performance End.Eq
# 2012-12-20 19:00:00 0 0 0 -392.4 0 -392.4006 0 -392.4006 0 -392.4006 1012255
# 2012-12-23 19:00:00 0 0 0 -132.0 0 -131.9961 0 -131.9961 0 -131.9961 1012123
# 2012-12-25 19:00:00 0 0 0 -180.0 0 -180.0018 0 -180.0018 0 -180.0018 1011943
# 2012-12-26 19:00:00 0 0 0 -57.0 0 -57.0006 0 -57.0006 0 -57.0006 1011886
# 2012-12-27 19:00:00 0 0 0 -459.0 0 -458.9997 0 -458.9997 0 -458.9997 1011427
# 2012-12-30 19:00:00 0 0 0 714.0 0 714.0015 0 714.0015 0 714.0015 1012141
Upvotes: 1