Hello I am working on a pairs trading strategy. Currently I am on the process of back-testing any pair I've found under certain assumptions. For this I'm using the "quantstrat" package in R. I've found it very difficult to understand what exactly is going on within the applyStrategy function, specially after I experienced the following:
I ran a demo code for two pairs:
suppressWarnings(rm("order_book.pair1",pos=.strategy))
suppressWarnings(rm("account.pairs", "portfolio.pair1", pos=.blotter))
suppressWarnings(rm("startDate", "endDate", "startDate", "initEq", "SD", "N",
"symb1", "symb2", "portfolio1.st", "account.st",
"pairStrat", "out1"))
initDate <- '2015-04-21'
endDate <- '2016-04-21'
startDate <- '2015-04-22'
initEq <- 100000
MaxPos <- 1500 #max position in stockA;
lvls <- 3 #how many times to fade; Each order's qty will = MaxPos/lvls
symb1 <- 'SYY' #change these to try other pairs
symb2 <- 'SRE' #if you change them, make sure position limits still make sense
portfolio1.st <- 'pair1'
account.st <- 'pairs'
getSymbols(c(symb1, symb2), from=startDate, to=endDate, adjust=TRUE)
alignSymbols <- function(symbols, env=.GlobalEnv) {
# This is a simplified version of qmao::alignSymbols()
if (length(symbols) < 2)
stop("Must provide at least 2 symbols")
if (any(!is.character(symbols)))
stop("Symbols must be vector of character strings.")
ff <- get(symbols[1],env=env)
for (sym in symbols[-1]) {
tmp.sym <- get(sym,env=env)
ff <- merge(ff, tmp.sym, all=FALSE)
}
for (sym in symbols) {
assign(sym,ff[,grep(sym, colnames(ff))], env=env)
}
symbols
}
alignSymbols(c(symb1, symb2))
currency("USD")
stock(symb1, currency="USD", multiplier=1)
stock(symb2, currency="USD", multiplier=1)
initPortf(name=portfolio1.st, c(symb1,symb2))
initAcct(account.st, portfolios=portfolio1.st, initEq=initEq)
initOrders(portfolio=portfolio1.st)
The rest of the code is available here (https://r-forge.r-project.org/scm/viewvc.php/pkg/quantstrat/demo/pair_trade.R?view=markup&root=blotter)
After running the "strategy" I calculate the cumulative return and obtain a total of -0.05818081.
Now, if the next thing I do is run again the last part of the code:
out1<-applyStrategy(strategy=pairStrat, portfolios=portfolio1.st)
updatePortf(Portfolio=portfolio1.st,
Dates=paste("::", as.Date(Sys.time()), sep=''))
updateAcct(account.st, Dates=paste(startDate, endDate, sep="::"))
updateEndEq(account.st, Dates=paste(startDate, endDate, sep="::"))
getEndEq(account.st, Sys.time())
dev.new()
chart.Posn(Portfolio=portfolio1.st, Symbol=symb1)
dev.new()
chart.Posn(Portfolio=portfolio1.st, Symbol=symb2)
dev.new()
chartSeries(Cl(get(symb1))/Cl(get(symb2)), TA="addBBands(n=N,sd=SD)")
ret1 <- PortfReturns(account.st)
ret1$total <- rowSums(ret1)
Return.cumulative(ret1)
then I get -0.9044952 as the cumulative return. I know that if I want to obtain the -0.05818081 return again, then I need to restart the portfolio. However, what I am looking for is help understanding what the effects are of running
applyStrategy()
twice as explained in this comment. Help will be really appreciated!
Related
I am trying to estimate the static yield curve for Brazil using termstrc package in R. I am using the function estim_nss.couponbonds and putting 0% coupon-rates and $0 cash-flows, except for the last one which is $1000 (the face-value at maturity) -- as far as I know this is the function to do this, because the estim_nss.zeroyields only calculates the dynamic curve. The problem is that I receive the following error message:
"Error in (pos_cf[i] + 1):pos_cf[i + 1] : NA/NaN argument In addition: Warning message: In max(n_of_cf) : no non-missing arguments to max; returning -Inf "
I've tried to trace the problem using trace(estim_nss.couponbons, edit=T) but I cannot find where pos_cf[i]+1 is calculated. Based on the name I figured it could come from the postpro_bondfunction and used trace(postpro_bond, edit=T), but I couldn't find the calculation again. I believe "cf" comes from cashflow, so there could be some problem in the calculation of the cashflows somehow. I used create_cashflows_matrix to test this theory, but it works well, so I am not sure the problem is in the cashflows.
The code is:
#Creating the 'couponbond' class
ISIN <- as.character(c('ltn_2017','ltn_2018', 'ltn_2019', 'ltn_2021','ltn_2023')) #Bond's identification
MATURITYDATE <- as.Date(c(42736, 43101, 43466, 44197, 44927), origin='1899-12-30') #Dates are in system's format
ISSUEDATE <- as.Date(c(41288,41666,42395, 42073, 42395), origin='1899-12-30') #Dates are in system's format
COUPONRATE <- rep(0,5) #Coupon rates are 0 because these are zero-coupon bonds
PRICE <- c(969.32, 867.77, 782.48, 628.43, 501.95) #Prices seen 'TODAY'
ACCRUED <- rep(0.1,5) #There is no accrued interest in the brazilian bond's market
#Creating the cashflows sublist
CFISIN <- as.character(c('ltn_2017','ltn_2018', 'ltn_2019', 'ltn_2021', 'ltn_2023')) #Bond's identification
CF <- c(1000,1000,1000,1000,1000)# The face-values
DATE <- as.Date(c(42736, 43101, 43466, 44197, 44927), origin='1899-12-30') #Dates are in system's format
CASHFLOWS <- list(CFISIN,CF,DATE)
names(CASHFLOWS) <- c("ISIN","CF","DATE")
TODAY <- as.Date(42646, origin='1899-12-30')
brasil <- list(ISIN,MATURITYDATE,ISSUEDATE,
COUPONRATE,PRICE,ACCRUED,CASHFLOWS,TODAY)
names(brasil) <- c("ISIN","MATURITYDATE","ISSUEDATE","COUPONRATE",
"PRICE","ACCRUED","CASHFLOWS","TODAY")
mybonds <- list(brasil)
class(mybonds) <- "couponbonds"
#Estimating the zero-yield curve
ns_res <-estim_nss.couponbonds(mybonds, 'brasil' ,method = "ns")
#Testing the hypothesis that the error comes from the cashflow matrix
cf_p <- create_cashflows_matrix(mybonds[[1]], include_price = T)
m_p <- create_maturities_matrix(mybonds[[1]], include_price = T)
b <- bond_yields(cf_p,m_p)
Note that I am aware of this question which reports the same problem. However, it is for the dynamic curve. Besides that, there is no useful answer.
Your code has two problems. (1) doesn't name the 1st list (this is the direct reason of the error. But if modifiy it, another error happens). (2) In the cashflows sublist, at least one level of ISIN needs more than 1 data.
# ...
CFISIN <- as.character(c('ltn_2017','ltn_2018', 'ltn_2019',
'ltn_2021', 'ltn_2023', 'ltn_2023')) # added a 6th element
CF <- c(1000,1000,1000,1000,1000, 1000) # added a 6th
DATE <- as.Date(c(42736,43101,43466,44197,44927, 44928), origin='1899-12-30') # added a 6th
CASHFLOWS <- list(CFISIN,CF,DATE)
names(CASHFLOWS) <- c("ISIN","CF","DATE")
TODAY <- as.Date(42646, origin='1899-12-30')
brasil <- list(ISIN,MATURITYDATE,ISSUEDATE,
COUPONRATE,PRICE,ACCRUED,CASHFLOWS,TODAY)
names(brasil) <- c("ISIN","MATURITYDATE","ISSUEDATE","COUPONRATE",
"PRICE","ACCRUED","CASHFLOWS","TODAY")
mybonds <- list(brasil = brasil) # named the list
class(mybonds) <- "couponbonds"
ns_res <-estim_nss.couponbonds(mybonds, 'brasil', method = "ns")
Note: the error came from these lines
bonddata <- bonddata[group] # prepro_bond()'s 1st line (the direct reason).
# cf <- lapply(bonddata, create_cashflows_matrix) # the additional error
create_cashflows_matrix(mybonds[[1]], include_price = F) # don't run
Afternoon! I'm just starting out with R and learning about data frames, packages, etc... read a lot of the messages here but couldn't find an answer.
I have a table I'm accessing with R that has the following fields:
[Symbol],[Date],[Open],[High],[Low],[Close],[Volume]
And, I'm calculating SMAs on the close prices:
sqlQuery <- "Select * from [dbo].[Stock_Data]"
conn <- odbcDriverConnect(connectionString)
dfSMA <- sqlQuery(conn, sqlQuery)
sma20 <- SMA(dfSMA$Close, n = 20)
dfSMA["SMA20"] <- sma20
When I look at the output, it appears to be calculating the SMA without any regard for what the symbol is. I haven't tried to replicate the calculation, but I would suspect it's just doing it by 20 moving rows, regardless of date/symbol.
How do I restrict the calculation to a given symbol?
Any help is appreciated - just need to be pointed in the right direction.
Thanks
You're far more likely to get answers if you provide reproducible examples. First, let's replicate your data:
library(quantmod)
symbols <- c("GS", "MS")
getSymbols(symbols)
# Create example data:
dGS <- data.frame("Symbol" = "GS", "Date" = index(GS), coredata(OHLCV(GS)))
names(dGS) <- str_replace(names(dGS), "GS\\.", "")
dMS <- data.frame("Symbol" = "MS", "Date" = index(MS), coredata(OHLCV(MS)))
names(dMS) <- str_replace(names(dMS), "MS\\.", "")
dfSMA <- rbind(dGS, dMS)
> head(dfSMA)
Symbol Date Open High Low Close Volume Adjusted
1 GS 2007-01-03 200.60 203.32 197.82 200.72 6494900 178.6391
2 GS 2007-01-04 200.22 200.67 198.07 198.85 6460200 176.9748
3 GS 2007-01-05 198.43 200.00 197.90 199.05 5892900 177.1528
4 GS 2007-01-08 199.05 203.95 198.10 203.73 7851000 181.3180
5 GS 2007-01-09 203.54 204.90 202.00 204.08 7147100 181.6295
6 GS 2007-01-10 203.40 208.44 201.50 208.11 8025700 185.2161
What you want to do is subset your long data object, and then apply technical indicators on each symbol in isolation. Here is one approach to guide you toward acheiving your desired result.
You could do this using a list, and build the indicators on xts data objects for each symbol, not on a data.frame like you do in your example (You can apply the TTR functions to columns in a data.frame but it is ugly -- work with xts objects is much more ideal). This is template for how you could do it. The final output l.data should be intuitive to work with. Keep each symbol in a separate "Container" (element of the list) rather than combining all the symbols in one data.frame which isn't easy to work with.
make_xts_from_long_df <- function(x) {
# Subset the symbol you desire
res <- dfSMA[dfSMA$Symbol == x, ]
#Create xts, then allow easy merge of technical indicators
x_res <- xts(OHLCV(res), order.by = res$Date)
merge(x_res, SMA(Cl(x_res), n = 20))
}
l.data <- setNames(lapply(symbols, make_xts_from_long_df), symbols)
What is the correct method to have signals reference other signals? Is it not intended functionality? I cant seem to find a way to do it in my code.
library(PerformanceAnalytics)
library(quantmod)
library(lattice)
startDate <- '2010-01-01' # start of data
endDate <- '2015-05-01' # end of data
.blotter<-new.env()
.strategy<-new.env()
Sys.setenv(TZ="EST") # set time zone
symbols<-c("GOOG")
data<-getSymbols(symbols, from=startDate, to=endDate, index.class="POSIXct",env=NULL)
library(quantstrat)
initDate <- '2009-12-31'
initEq <- 1e6
currency("USD")
stock(symbols, currency="USD", multiplier=1)
rm.strat("multiAsset.bb1") # remove portfolio, account, orderbook if re-run
initPortf(name="multiAsset.bb1", symbols, initDate=initDate)
initAcct(name="multiAsset.bb1", portfolios="multiAsset.bb1",initDate=initDate, initEq=initEq)
initOrders(portfolio="multiAsset.bb1", initDate=initDate)
strategy("bbands", store=TRUE)
#Indicators are applied before signals and rules, and the output of indicators may be used as inputs to construct signals or fire rules
#mktdata is the time series object that holds the current symbols data during evaluation (pg 55)
add.indicator("bbands", name = "BBands",arguments = list(HLC = quote(HLC(mktdata)), maType='SMA'), label='bbInd')
test <- applyIndicators("bbands", mktdata=data)
head(test, 10)
add.signal("bbands", name="sigThreshold", arguments=list(columns=c("pctB.bbInd",".77"),relationship="gt"),label="H.gt.UpperBand")
add.signal("bbands", name="sigThreshold", arguments=list(columns=c("H.gt.UpperBand","0"),relationship="gt"),label="true.upper.band")
test <- applySignals("bbands", mktdata=test)
head(test, 10)
Error
Error in match.names(column, colnames(data)) :
argument "column" is missing, with no default
Note that this is a generalized example. It would be trivial to make the first signal an indicator and avoid this problem in this specific case.
You've passed the wrong arguments to sigThreshold. This corrected code works as expected, with the second signal using the H.gt.UpperBand column (singular) from the first signal. The missing arguments in your code for the sigThreshold function are column (singular) and threshold.
library(quantstrat)
startDate <- '2010-01-01' # start of data
endDate <- '2015-05-01' # end of data
Sys.setenv(TZ="EST") # set time zone
symbols<-c("GOOG")
data<-getSymbols.yahoo(symbols, from=startDate, to=endDate, index.class="POSIXct",auto.assign=FALSE)
initDate <- '2009-12-31'
initEq <- 1e6
currency("USD")
stock(symbols, currency="USD", multiplier=1)
rm.strat("multiAsset.bb1") # remove portfolio, account, orderbook if re-run
initPortf(name="multiAsset.bb1", symbols, initDate=initDate)
initAcct(name="multiAsset.bb1", portfolios="multiAsset.bb1",initDate=initDate, initEq=initEq)
initOrders(portfolio="multiAsset.bb1", initDate=initDate)
strategy("bbands", store=TRUE)
#Indicators are applied before signals and rules, and the output of indicators may be used as inputs to construct signals or fire rules
#mktdata is the time series object that holds the current symbols data during evaluation (pg 55)
add.indicator("bbands"
, name = "BBands"
, arguments = list(HLC = quote(HLC(mktdata))
, maType='SMA')
, label='bbInd')
test <- applyIndicators("bbands", mktdata=data)
head(test, 10)
add.signal("bbands"
, name="sigThreshold"
, arguments=list(column="pctB.bbInd"
, threshold=.77
, relationship="gt")
, label="H.gt.UpperBand")
add.signal("bbands"
, name="sigThreshold"
, arguments=list(column="H.gt.UpperBand"
, threshold=0
, relationship="gt")
,label="true.upper.band")
test <- applySignals("bbands", mktdata=test)
head(test, 10)
I am trying to tell whether a specific column value is greater than .77, but this code returns 1 if the value is greater then 0. Is there any way to use a known function (not a custom one) to do a simple greater then check?
library(PerformanceAnalytics)
library(quantmod)
library(lattice)
startDate <- '2010-01-01' # start of data
endDate <- '2015-05-01' # end of data
.blotter<-new.env()
.strategy<-new.env()
Sys.setenv(TZ="EST") # set time zone
symbols<-c("GOOG")
data<-getSymbols(symbols, from=startDate, to=endDate, index.class="POSIXct",env=NULL)
library(quantstrat)
initDate <- '2009-12-31'
initEq <- 1e6
currency("USD")
stock(symbols, currency="USD", multiplier=1)
rm.strat("multiAsset.bb1") # remove portfolio, account, orderbook if re-run
initPortf(name="multiAsset.bb1", symbols, initDate=initDate)
initAcct(name="multiAsset.bb1", portfolios="multiAsset.bb1",initDate=initDate, initEq=initEq)
initOrders(portfolio="multiAsset.bb1", initDate=initDate)
strategy("bbands", store=TRUE)
#Indicators are applied before signals and rules, and the output of indicators may be used as inputs to construct signals or fire rules
#mktdata is the time series object that holds the current symbols data during evaluation (pg 55)
add.indicator("bbands", name = "BBands",arguments = list(HLC = quote(HLC(mktdata)), maType='SMA'), label='bbInd')
test <- applyIndicators("bbands", mktdata=data)
head(test, 10)
add.signal("bbands", name="sigThreshold", arguments=list(columns=c("pctB.bbInd",".77"),relationship="gt"),label="H.gt.UpperBand")
test <- applySignals("bbands", mktdata=test) #DOESNT WORK
head(test, 10)
Error:
Error in match.names(column, colnames(data)) :
argument "column" is missing, with no default
My solution was to change:
add.signal("bbands", name="sigThreshold", arguments=list(columns=c("pctB.bbInd",".77"),relationship="gt"),label="H.gt.UpperBand")
to:
add.signal("bbands", name="sigThreshold", arguments=list(threshold=.77,column="pctB.bbInd",relationship="gt"),label="H.gt.UpperBand")
Hi I am looking at the addTxns function in blotter, and I would like to add fees data/information in the TxnData argument (as a column).
When looking at the function, by running
blotter:::addTxns
it seems to use the column names "Price" and "Quantity" but automatically sets/assigns the TxnFees to zero.
Is there a way of overwriting this, so that it can be included in my analysis?
Here is an example:
rm(list=ls(pos=.blotter),pos=.blotter)
rm(list=ls(pos=.instrument),pos=.instrument)
rm(list=ls(pos=.strategy),pos=.strategy)
currency('USD')
stock("SPY", currency="USD", mulitplier=1)
getSymbols('SPY', from='2012-03-01', to='2012-07-04')
portf.name <- "dummy.Portfolio"
initPortf(portf.name, 'SPY', initDate='2012-02-29')
initAcct(portf.name, portf.name, initDate='2012-02-29', initEq=1e6)
qty <- rep(c(1,-1), nrow(SPY)/2)
price <- SPY[,4]
txnfees <- rep(-5, nrow(SPY))
txndata <- cbind(qty, price, txnfees)
colnames(txndata) <- c("Quantity","Price","txnfees")
blotter:::addTxns(Portfolio=portf.name, Symbol='SPY', TxnData=txndata )
txns <- getTxns(Portfolio=portf.name, Symbol='SPY')
head(txns)
This will show the buying and selling of 1 share on alternate days at the close but will not show any of the fees relating to each transaction.
Patched in Rev. 1100.
After checking out, building and installing the new code, I believe this will do what you want:
library(blotter)
currency('USD')
stock("SPY", currency="USD", mulitplier=1)
getSymbols('SPY', from='2012-03-01', to='2012-07-04')
portf.name <- "dummy.Portfolio"
initPortf(portf.name, 'SPY', initDate='2012-02-29')
initAcct(portf.name, portf.name, initDate='2012-02-29', initEq=1e6)
qty <- rep(c(1,-1), nrow(SPY)/2)
price <- SPY[,4]
txnfees <- rep(-5, nrow(SPY))
txndata <- cbind(qty, price, txnfees)
colnames(txndata) <- c("Quantity","Price","TxnFees")
blotter:::addTxns(Portfolio=portf.name, Symbol='SPY', TxnData=txndata )
txns <- getTxns(Portfolio=portf.name, Symbol='SPY')
head(txns)
(Here is link to our discussion on r-sig-finance)