[Blotter-commits] r1428 - pkg/quantstrat/demo

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Sun Apr 7 00:34:04 CEST 2013


Author: gsee
Date: 2013-04-07 00:34:04 +0200 (Sun, 07 Apr 2013)
New Revision: 1428

Modified:
   pkg/quantstrat/demo/pair_trade.R
Log:
 formatting: "\t" --> "  ", 80 margins, spaces between args, etc.


Modified: pkg/quantstrat/demo/pair_trade.R
===================================================================
--- pkg/quantstrat/demo/pair_trade.R	2013-04-06 22:10:42 UTC (rev 1427)
+++ pkg/quantstrat/demo/pair_trade.R	2013-04-06 22:34:04 UTC (rev 1428)
@@ -1,26 +1,28 @@
 #Kindly contributed to quantstrat by Garrett See
 #code borrowed heavily from existing quantstrat demos
 
-#This is a simple pairs trading example intended to illustrate how you can extend
-#existing quantstrat functionality.  It uses addPosLimits to specify levels and 
-#position limits, and shows how to pass a custom order sizing function to osFUN 
+# This is a simple pairs trading example intended to illustrate how you can 
+# extend existing quantstrat functionality.  It uses addPosLimits to specify 
+# levels and position limits, and shows how to pass a custom order sizing 
+# function to osFUN 
 
-#Note that it would be easier to build a spread first and treat it as a single instrument
-#instead of dealing with a portfolio of stocks.
+# Note that it would be easier to build a spread first and treat it as a single 
+# instrument instead of dealing with a portfolio of stocks.
 
-## given 2 stocks, calculate the ratio of their notional values.  If the ratio falls below it's
-# 2 stdev band, then when it crosses back above it, buy stock 1 and sell stock 2.  
-# If the ratio rises above it's 2 stdev band, then when it crosses back below
-# it, sell stock 1 and buy stock 2.  If the ratio crosses it's moving average,
-# then flatten any open positions.
+## given 2 stocks, calculate the ratio of their notional values.  If the ratio 
+# falls below it's 2 stdev band, then when it crosses back above it, buy stock 1 
+# and sell stock 2.  If the ratio rises above it's 2 stdev band, then when it 
+# crosses back below it, sell stock 1 and buy stock 2.  If the ratio crosses 
+# its moving average, then flatten any open positions.
 
 # The Qty of Stock A that it buys (sells) = MaxPos / lvls
 # The Qty of Stock B that is sells (buys) = MaxPos * Ratio / lvls  
 
 suppressWarnings(rm("order_book.pair1",pos=.strategy))
 suppressWarnings(rm("account.pairs", "portfolio.pair1", pos=.blotter))
-suppressWarnings(rm("initDate", "endDate", "startDate", "initEq", "SD", "N", "symb1", "symb2", 
-	"portfolio1.st", "account.st", "pairStrat", "out1"))
+suppressWarnings(rm("initDate", "endDate", "startDate", "initEq", "SD", "N", 
+                    "symb1", "symb2", "portfolio1.st", "account.st", 
+                    "pairStrat", "out1"))
 
 require(quantstrat)
 
@@ -37,16 +39,17 @@
 #  {initDate="1999-12-31"
 #  endDate=Sys.Date()}
 
-initDate = '2009-01-01'		
-endDate = '2011-05-01'
-startDate = '2009-01-02'
-initEq = 100000
-SD = 2
-N = 20
+initDate <- '2009-01-01'    
+endDate <- '2011-05-01'
+startDate <- '2009-01-02'
+initEq <- 100000
+SD <- 2
+N <- 20
 
-MaxPos = 1500  #max position in stockA; 
-#max position in stock B will be max * ratio, i.e. no hard position limit in Stock B
-lvls = 3	#how many times to fade; Each order's qty will = MaxPos/lvls
+MaxPos <- 1500  #max position in stockA; 
+# max position in stock B will be max * ratio, i.e. no hard position limit in 
+# Stock B
+lvls <- 3  #how many times to fade; Each order's qty will = MaxPos/lvls
 
 symb1 <- 'SPY' #change these to try other pairs
 symb2 <- 'DIA' #if you change them, make sure position limits still make sense
@@ -56,160 +59,218 @@
 
 getSymbols(c(symb1, symb2), from=startDate, to=endDate, adjust=TRUE) 
 
-#generic used to make sure the timestamps of all symbols are the same
-#deletes rows where one of the stocks is missing data
+# The following function is used to make sure the timestamps of all symbols are 
+# the same deletes rows where one of the stocks is missing data
 alignSymbols <- function(symbols, env=.GlobalEnv) {
-	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
+  # 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)) 
+alignSymbols(c(symb1, symb2))
 
-#Define Instruments
+# Define Instruments
 currency("USD")
 stock(symb1, currency="USD", multiplier=1)
 stock(symb2, currency="USD", multiplier=1)
 
-#Initialize Portfolio, Account, and Orders
+# Initialize Portfolio, Account, and Orders
 initPortf(name=portfolio1.st, c(symb1,symb2), initDate=initDate)
 initAcct(account.st, portfolios=portfolio1.st, initDate=initDate, initEq=initEq)
-initOrders(portfolio=portfolio1.st,initDate=initDate)
+initOrders(portfolio=portfolio1.st, initDate=initDate)
 
-#osFUN will need to know which symbol is leg 1 and which is leg 2 as well as what the 
-#values are for MaxPos and lvls.  So, create a slot in portfolio to hold this info.
-pair <- c(1,2,MaxPos,lvls)
-names(pair) <- c(symb1,symb2,"MaxPos","lvls")
-.blotter[[paste('portfolio',portfolio1.st,sep='.')]]$pair <- pair
+# osFUN will need to know which symbol is leg 1 and which is leg 2 as well as 
+# what the values are for MaxPos and lvls.  So, create a slot in portfolio to 
+# hold this info.
+pair <- c(1, 2, MaxPos, lvls)
+names(pair) <- c(symb1, symb2, "MaxPos", "lvls")
+.blotter[[paste('portfolio', portfolio1.st, sep='.')]]$pair <- pair
 
 # Create initial position limits and levels by symbol
 # allow 3 entries for long and short if lvls=3.
-addPosLimit(portfolio=portfolio1.st, timestamp=initDate, symbol=symb1, maxpos=MaxPos, longlevels=lvls, minpos=-MaxPos, shortlevels=lvls)
-addPosLimit(portfolio=portfolio1.st, timestamp=initDate, symbol=symb2, maxpos=MaxPos, longlevels=lvls, minpos=-MaxPos, shortlevels=lvls)
+addPosLimit(portfolio=portfolio1.st, timestamp=initDate, symbol=symb1, 
+            maxpos=MaxPos, longlevels=lvls, minpos=-MaxPos, shortlevels=lvls)
+addPosLimit(portfolio=portfolio1.st, timestamp=initDate, symbol=symb2, 
+            maxpos=MaxPos, longlevels=lvls, minpos=-MaxPos, shortlevels=lvls)
 
 # Create a strategy object 
 pairStrat <- strategy('pairStrat')
 
 # Indicator function
-calcRatio <- function(x) { #returns the ratio of notional close prices for 2 symbols
-	x1 <- get(x[1])
-	x2 <- get(x[2])
-	mult1 <- getInstrument(x[1])$multiplier
-	mult2 <- getInstrument(x[2])$multiplier
-	rat <- (mult1 * Cl(x1)) / (mult2 * Cl(x2))
-	colnames(rat) <- 'Ratio'
-	rat
-} 
-Ratio <- calcRatio(c(symb1[1],symb2[1])) #Indicator used for determining entry/exits
+calcRatio <- function(x) { 
+  #returns the ratio of notional close prices for 2 symbols
+  x1 <- get(x[1])
+  x2 <- get(x[2])
+  mult1 <- getInstrument(x[1])$multiplier
+  mult2 <- getInstrument(x[2])$multiplier
+  rat <- (mult1 * Cl(x1)) / (mult2 * Cl(x2))
+  colnames(rat) <- 'Ratio'
+  rat
+}
+# Indicator used for determining entry/exits
+Ratio <- calcRatio(c(symb1[1], symb2[1]))  
 
-#Put a slot in portfolio to hold hedge ratio so that it's available for order sizing function. 
-#In this example, the hedge ratio happens to be the same as the Ratio indicator.
+# Store hedge ratio in portfolio so that it's available for order sizing 
+# function. In this example, the hedge ratio happens to be the same as the 
+# Ratio indicator.
 .blotter[[paste('portfolio',portfolio1.st,sep='.')]]$HedgeRatio <- Ratio
 #and make a function to get the most recent HedgeRatio
 getHedgeRatio <- function(portfolio, timestamp) {
-	portf <- getPortfolio(portfolio)
-	timestamp <- format(timestamp,"%Y-%m-%d %H:%M:%S") #ensures you don't get last value of next day if using intraday data and timestamp=midnight
-	toDate <- paste("::", timestamp, sep="")
-	Ratio <- last(portf$HedgeRatio[toDate])
-	as.numeric(Ratio)
+  portf <- getPortfolio(portfolio)
+  timestamp <- format(timestamp,"%Y-%m-%d %H:%M:%S")
+  # above line ensures you don't get last value of next day if using intraday 
+  # data and timestamp=midnight
+  toDate <- paste("::", timestamp, sep="")
+  Ratio <- last(portf$HedgeRatio[toDate])
+  as.numeric(Ratio)
 }
 
 # Create an indicator - BBands on the Ratio
-pairStrat <- add.indicator(strategy = pairStrat, name = "calcRatio", arguments = list(x=c(symb1,symb2)))
-pairStrat <- add.indicator(strategy = pairStrat, name = "BBands", arguments = list(HLC=quote(Ratio), sd=SD, n=N, maType='SMA'))
+pairStrat <- add.indicator(strategy=pairStrat, name = "calcRatio", 
+                           arguments=list(x=c(symb1,symb2)))
+pairStrat <- add.indicator(strategy=pairStrat, name = "BBands", 
+                           arguments=list(HLC=quote(Ratio), sd=SD, n=N, 
+                                          maType='SMA'))
 
 #applyIndicators(strategy=pairStrat,mktdata=get(symb1[1])) #for debugging
 
-# Create signals - buy when crossing lower band from below, sell when crossing upper band from above, flatten when crossing mavg from above or from below
-pairStrat <- add.signal(strategy = pairStrat, name = "sigCrossover", arguments= list(columns=c("Ratio","up"), relationship="lt"), label="cross.up")
-pairStrat <- add.signal(strategy = pairStrat, name = "sigCrossover", arguments= list(columns=c("Ratio","dn"), relationship="gt"), label="cross.dn")
-pairStrat <- add.signal(strategy = pairStrat, name = "sigCrossover", arguments= list(columns=c("Ratio","mavg"), relationship="lt"), label="cross.mid.fa")
-pairStrat <- add.signal(strategy = pairStrat, name = "sigCrossover", arguments= list(columns=c("Ratio","mavg"), relationship="gt"), label="cross.mid.fb")
+# Create signals - buy when crossing lower band from below, sell when crossing 
+# upper band from above, flatten when crossing mavg from above or from below
+pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover", 
+                        arguments=list(columns=c("Ratio","up"), 
+                                        relationship="lt"),
+                        label="cross.up")
+pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover", 
+                        arguments=list(columns=c("Ratio","dn"), 
+                                        relationship="gt"), 
+                        label="cross.dn")
+pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover", 
+                        arguments=list(columns=c("Ratio","mavg"), 
+                                  relationship="lt"), 
+                        label="cross.mid.fa")
+pairStrat <- add.signal(strategy=pairStrat, name="sigCrossover", 
+                        arguments=list(columns=c("Ratio","mavg"), 
+                                       relationship="gt"), 
+                        label="cross.mid.fb")
 
-#make an order sizing function
-#######################_ORDER SIZING FUNCTION_##########################################################
-#check to see which stock it is. If it's the second stock, reverse orderqty and orderside
-osSpreadMaxPos <- function (data, timestamp, orderqty, ordertype, orderside, portfolio, symbol, ruletype, ..., orderprice) 
-{
-	portf <- getPortfolio(portfolio)
-	#check to make sure pair slot has the things needed for this function
-	if (!any(portf$pair == 1) && !(any(portf$pair == 2))) stop('pair must contain both values 1 and 2')
-	if (!any(names(portf$pair) == "MaxPos") || !any(names(portf$pair) == "lvls")) stop('pair must contain MaxPos and lvls')	
-		
-	if (portf$pair[symbol] == 1) legside <- "long"
-	if (portf$pair[symbol] == 2) legside <- "short"	
-	MaxPos <- portf$pair["MaxPos"]
-	lvls <- portf$pair["lvls"]
-	ratio <- getHedgeRatio(portfolio, timestamp)
-	pos <- getPosQty(portfolio, symbol, timestamp) 	    
-	PosLimit <- getPosLimit(portfolio, symbol, timestamp) 
-	qty <- orderqty
-	if (legside == "short") {#symbol is 2nd leg
-		## Comment out next line to use equal ordersizes for each stock. 
-		addPosLimit(portfolio=portfolio, timestamp=timestamp, symbol=symbol, maxpos=round(MaxPos*ratio,0), longlevels=lvls, minpos=round(-MaxPos*ratio,0), shortlevels=lvls)
-		## 
-		qty <- -orderqty #switch orderqty for Stock B
-	}
-	
-	if (qty > 0) orderside = 'long'
-	if (qty < 0) orderside = 'short'
+# make an order sizing function
+#######################_ORDER SIZING FUNCTION_##################################
+# check to see which stock it is. If it's the second stock, reverse orderqty and 
+# orderside
+osSpreadMaxPos <- function (data, timestamp, orderqty, ordertype, orderside, 
+                            portfolio, symbol, ruletype, ..., orderprice) {
+  portf <- getPortfolio(portfolio)
+  #check to make sure pair slot has the things needed for this function
+  if (!any(portf$pair == 1) && !(any(portf$pair == 2))) 
+    stop('pair must contain both values 1 and 2')
+  if (!any(names(portf$pair) == "MaxPos") || !any(names(portf$pair) == "lvls")) 
+    stop('pair must contain MaxPos and lvls')  
+    
+  if (portf$pair[symbol] == 1) legside <- "long"
+  if (portf$pair[symbol] == 2) legside <- "short"  
+  MaxPos <- portf$pair["MaxPos"]
+  lvls <- portf$pair["lvls"]
+  ratio <- getHedgeRatio(portfolio, timestamp)
+  pos <- getPosQty(portfolio, symbol, timestamp)       
+  PosLimit <- getPosLimit(portfolio, symbol, timestamp) 
+  qty <- orderqty
+  if (legside == "short") {#symbol is 2nd leg
+    ## Comment out next line to use equal ordersizes for each stock. 
+    addPosLimit(portfolio=portfolio, timestamp=timestamp, symbol=symbol, 
+                maxpos=round(MaxPos*ratio,0), longlevels=lvls, 
+                minpos=round(-MaxPos*ratio,0), shortlevels=lvls)
+    ## 
+    qty <- -orderqty #switch orderqty for Stock B
+  }
+  
+  if (qty > 0) orderside = 'long'
+  if (qty < 0) orderside = 'short'
  
-	orderqty <- osMaxPos(data=data,timestamp=timestamp,orderqty=qty,ordertype=ordertype,
-					orderside=orderside,portfolio=portfolio,symbol=symbol,ruletype=ruletype, ...)
-					
-	#Add the order here instead of in the ruleSignal function
-	if (!is.null(orderqty) & !orderqty == 0 & !is.null(orderprice)) {
-            addOrder(portfolio = portfolio, symbol = symbol, 
-                timestamp = timestamp, qty = orderqty, price = as.numeric(orderprice), 
-                ordertype = ordertype, side = orderside, replace = FALSE,
-                status = "open", ... = ...)
-    }
-	return(0) #so that ruleSignal function doesn't also try to place an order
+  orderqty <- osMaxPos(data=data,timestamp=timestamp, orderqty=qty,
+                       ordertype=ordertype, orderside=orderside,
+                       portfolio=portfolio, symbol=symbol, ruletype=ruletype, 
+                       ...)
+          
+  #Add the order here instead of in the ruleSignal function
+  if (!is.null(orderqty) & !orderqty == 0 & !is.null(orderprice)) {
+    addOrder(portfolio=portfolio, symbol=symbol, 
+             timestamp=timestamp, qty=orderqty, price=as.numeric(orderprice), 
+             ordertype=ordertype, side=orderside, replace=FALSE,
+             status="open", ...=...)
+  }
+  return(0) #so that ruleSignal function doesn't also try to place an order
 }
-########################################################################################################
+################################################################################
 
-# Create entry and exit rules for longs  and for shorts. Both symbols will get the same buy/sell signals, but osMaxPos will reverse those for the second symbol.
-# orderqty's are bigger than PosLimits allow. osMaxPos will adjust the orderqty down to 1/3 the max allowed. (1/3 is because we are using 3 levels in PosLimit)
-pairStrat <- add.rule(strategy = pairStrat, name='ruleSignal', arguments = list(sigcol="cross.dn", sigval=TRUE, orderqty=1e6, ordertype='market', orderside=NULL, osFUN='osSpreadMaxPos'), type='enter' ) 
-pairStrat <- add.rule(strategy = pairStrat, name='ruleSignal', arguments = list(sigcol="cross.up", sigval=TRUE, orderqty=-1e6, ordertype='market', orderside=NULL, osFUN='osSpreadMaxPos'), type='enter')
-pairStrat <- add.rule(strategy = pairStrat, name='ruleSignal', arguments = list(sigcol="cross.mid.fb", sigval=TRUE, orderqty='all', ordertype='market', orderside=NULL), type='exit') 
-pairStrat <- add.rule(strategy = pairStrat, name='ruleSignal', arguments = list(sigcol="cross.mid.fa", sigval=TRUE, orderqty='all', ordertype='market', orderside=NULL), type='exit')
+# Create entry and exit rules for longs  and for shorts. Both symbols will get 
+# the same buy/sell signals, but osMaxPos will reverse those for the second 
+# symbol.
+# orderqty's are bigger than PosLimits allow. osMaxPos will adjust the orderqty 
+# down to 1/3 the max allowed. (1/3 is because we are using 3 levels in 
+# PosLimit)
+pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal', 
+                      arguments=list(sigcol="cross.dn", sigval=TRUE, 
+                                     orderqty=1e6, ordertype='market', 
+                                     orderside=NULL, osFUN='osSpreadMaxPos'), 
+                      type='enter')
+pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal', 
+                      arguments=list(sigcol="cross.up", sigval=TRUE, 
+                                     orderqty=-1e6, ordertype='market', 
+                                     orderside=NULL, osFUN='osSpreadMaxPos'), 
+                      type='enter')
+pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal', 
+                      arguments=list(sigcol="cross.mid.fb", sigval=TRUE, 
+                                     orderqty='all', ordertype='market', 
+                                     orderside=NULL), 
+                      type='exit')
+pairStrat <- add.rule(strategy=pairStrat, name='ruleSignal', 
+                      arguments=list(sigcol="cross.mid.fa", sigval=TRUE, 
+                                     orderqty='all', ordertype='market', 
+                                     orderside=NULL), 
+                      type='exit')
 
-#applySignals(strategy=pairStrat, mktdata=applyIndicators(strategy=pairStrat,mktdata=get(symb1))) #for debugging
 
+## for debugging
+# applySignals(strategy=pairStrat, 
+#              mktdata=applyIndicators(strategy=pairStrat, mktdata=get(symb1)))
+##
+
 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())
+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)
+chart.Posn(Portfolio=portfolio1.st, Symbol=symb1)
 dev.new()
-chart.Posn(Portfolio=portfolio1.st,Symbol=symb2)
+chart.Posn(Portfolio=portfolio1.st, Symbol=symb2)
 dev.new()
-chartSeries(Cl(get(symb1))/Cl(get(symb2)),TA="addBBands(n=N,sd=SD)")
+chartSeries(Cl(get(symb1))/Cl(get(symb2)), TA="addBBands(n=N,sd=SD)")
 
 ret1 <- PortfReturns(account.st)
 ret1$total <- rowSums(ret1)
 #ret1
 
-if("package:PerformanceAnalytics" %in% search() || require("PerformanceAnalytics",quietly=TRUE)) {
-#	getSymbols("SPY", from='1999-01-01')
-#	SPY.ret <- Return.calculate(SPY$SPY.Close)
-#	tmp <- merge(SPY.ret,ret1$total,all=FALSE)
-	dev.new()
-	charts.PerformanceSummary(ret1$total,geometric=FALSE,wealth.index=TRUE)
+if("package:PerformanceAnalytics" %in% search() || 
+   require("PerformanceAnalytics",quietly=TRUE)) {
+#  getSymbols("SPY", from='1999-01-01')
+#  SPY.ret <- Return.calculate(SPY$SPY.Close)
+#  tmp <- merge(SPY.ret,ret1$total,all=FALSE)
+  dev.new()
+  charts.PerformanceSummary(ret1$total, geometric=FALSE, wealth.index=TRUE)
 }
 
 



More information about the Blotter-commits mailing list