quantstrat icon indicating copy to clipboard operation
quantstrat copied to clipboard

Enable WFA across a portfolio of assets

Open jaymon0703 opened this issue 5 years ago • 0 comments

Description

WFA does not work as expected for portfolios with more than one symbol.

Expected behavior

Perform parameter optimization and WFA across a portfolio of assets based on their own unique optimal paramater combinations.

Minimal, reproducible example

require(quantstrat)
suppressWarnings(rm("order_book.macd",pos=.strategy))
suppressWarnings(rm("account.macd","portfolio.macd",pos=.blotter))
suppressWarnings(rm("account.st","portfolio.st","stock.str","stratMACD","startDate","initEq",'start_t','end_t'))

#correct for TZ issues if they crop up
oldtz<-Sys.getenv('TZ')
if(oldtz=='') {
  Sys.setenv(TZ="GMT")
}

stock.str=c('AAPL','MSFT') # what are we trying it on

#MA parameters for MACD
fastMA = 12 
slowMA = 26 
signalMA = 9
maType="EMA"

currency('USD')
stock(stock.str,currency='USD',multiplier=1)

startDate='2006-12-31'
initEq=1000000
portfolio.st='macd'
account.st='macd'

initPortf(portfolio.st,symbols=stock.str)
initAcct(account.st,portfolios=portfolio.st)
initOrders(portfolio=portfolio.st)

strat.st<-portfolio.st
# define the strategy
strategy(strat.st, store=TRUE)

#one indicator
add.indicator(strat.st, name = "MACD", 
              arguments = list(x=quote(Cl(mktdata)),
                               nFast=fastMA, 
                               nSlow=slowMA),
              label='_' 
)

#two signals
add.signal(strat.st,name="sigThreshold",
           arguments = list(column="signal._",
                            relationship="gt",
                            threshold=0,
                            cross=TRUE),
           label="signal.gt.zero"
)

add.signal(strat.st,name="sigThreshold",
           arguments = list(column="signal._",
                            relationship="lt",
                            threshold=0,
                            cross=TRUE),
           label="signal.lt.zero"
)

####
# add rules

# entry
add.rule(strat.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero",
                          sigval=TRUE, 
                          orderqty=100, 
                          ordertype='market', 
                          orderside='long', 
                          threshold=NULL),
         type='enter',
         label='enter',
         storefun=FALSE
)

# exit
add.rule(strat.st,name='ruleSignal', 
         arguments = list(sigcol="signal.lt.zero",
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='market', 
                          orderside='long', 
                          threshold=NULL,
                          orderset='exit2'),
         type='exit',
         label='exit'
)

#end rules
####

getSymbols(stock.str,from=startDate, to='2014-06-01', src='yahoo')
start_t<-Sys.time()
out<-applyStrategy(strat.st , portfolios=portfolio.st,parameters=list(nFast=fastMA, nSlow=slowMA, nSig=signalMA,maType=maType),verbose=TRUE)
end_t<-Sys.time()
print(end_t-start_t)

start_t<-Sys.time()
updatePortf(Portfolio=portfolio.st,Dates=paste('::',as.Date(Sys.time()),sep=''))
end_t<-Sys.time()
print("trade blotter portfolio update:")
print(end_t-start_t)

# set tz as it was before the demo
Sys.setenv(TZ=oldtz)


require(foreach,quietly=TRUE)
require(iterators)
require(quantstrat)

#retrieve the strategy from the environment, since the 'macd' strategy uses store=TRUE
strategy.st <- 'macd'

### Set up Parameter Values
.FastMA = (1:10)
.SlowMA = (5:25)
.nsamples = 15 #for random parameter sampling, less important if you're using doParallel or doMC


### MA paramset

add.distribution(strategy.st,
                 paramset.label = 'MA',
                 component.type = 'indicator',
                 component.label = '_', #this is the label given to the indicator in the strat
                 variable = list(n = .FastMA),
                 label = 'nFAST'
)

add.distribution(strategy.st,
                 paramset.label = 'MA',
                 component.type = 'indicator',
                 component.label = '_', #this is the label given to the indicator in the strat
                 variable = list(n = .SlowMA),
                 label = 'nSLOW'
)

add.distribution.constraint(strategy.st,
                            paramset.label = 'MA',
                            distribution.label.1 = 'nFAST',
                            distribution.label.2 = 'nSLOW',
                            operator = '<',
                            label = 'MA'
)


###
wfportfolio <- "wf.macd"
initPortf(wfportfolio,symbols=stock.str)
initOrders(portfolio=wfportfolio)
wf_start <- Sys.time()
registerDoSEQ() # for debugging
wfresults <- walk.forward(strategy.st, 
                          paramset.label = 'MA', 
                          portfolio.st = wfportfolio, 
                          account.st = account.st, 
                          nsamples = .nsamples,
                          period = 'months',
                          k.training = 36,
                          k.testing = 12,
                          verbose =TRUE,
                          anchored = TRUE,
                          include.insamples = TRUE,
                          savewf = FALSE
)
wf_end <-Sys.time()

cat("\n Running the walk forward search: \n ")
print(wf_end-wf_start)
cat(" Total trials:",.strategy$macd$trials,"\n")

wfa.stats <- wfresults$tradeStats

print(wfa.stats)

chart.forward(wfresults)

# resulting stats are identical for both symbols, AAPL and MSFT

Session Info

R version 4.0.2 (2020-06-22)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.1 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
 [4] LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
[10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] graphics  grDevices utils     datasets  stats     methods   base     

other attached packages:
 [1] iterators_1.0.12           quantstrat_0.16.8          foreach_1.5.0             
 [4] blotter_0.15.0             PerformanceAnalytics_2.0.4 FinancialInstrument_1.3.1 
 [7] quantmod_0.4.17            TTR_0.23-6                 xts_0.12-0                
[10] zoo_1.8-8                 

loaded via a namespace (and not attached):
[1] quadprog_1.5-8   lattice_0.20-41  codetools_0.2-16 MASS_7.3-51.6    grid_4.0.2      
[6] curl_4.3         boot_1.3-25      tools_4.0.2      compiler_4.0.2  

jaymon0703 avatar Aug 25 '20 14:08 jaymon0703