[Blotter-commits] r242 - in pkg/quantstrat: . R man

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Wed Feb 10 23:13:59 CET 2010


Author: braverock
Date: 2010-02-10 23:13:59 +0100 (Wed, 10 Feb 2010)
New Revision: 242

Added:
   pkg/quantstrat/.project
   pkg/quantstrat/man/ruleOrderProc.Rd
   pkg/quantstrat/man/updateOrderMatrix.Rd
Removed:
   pkg/quantstrat/man/getOrdersByStatus.Rd
   pkg/quantstrat/man/updateOrder.Rd
Modified:
   pkg/quantstrat/NAMESPACE
   pkg/quantstrat/R/indicators.R
   pkg/quantstrat/R/orders.R
   pkg/quantstrat/R/rules.R
   pkg/quantstrat/R/signals.R
   pkg/quantstrat/R/strategy.R
   pkg/quantstrat/man/addOrder.Rd
   pkg/quantstrat/man/applyRules.Rd
   pkg/quantstrat/man/applyStrategy.Rd
   pkg/quantstrat/man/getOrders.Rd
   pkg/quantstrat/man/updateOrders.Rd
Log:
- multiple updates and new functions to integrate order and rule processing
- update docs and NAMESPACE

Added: pkg/quantstrat/.project
===================================================================
--- pkg/quantstrat/.project	                        (rev 0)
+++ pkg/quantstrat/.project	2010-02-10 22:13:59 UTC (rev 242)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>quantstrat</name>
+	<comment></comment>
+	<projects>
+		<project>blotter</project>
+		<project>FinancialInstrument</project>
+		<project>PerformanceAnalytics</project>
+		<project>PortfolioAnalytics</project>
+		<project>quantmod</project>
+		<project>xts</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>de.walware.statet.r.builders.RSupport</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>de.walware.statet.base.StatetNature</nature>
+		<nature>de.walware.statet.r.RNature</nature>
+	</natures>
+</projectDescription>

Modified: pkg/quantstrat/NAMESPACE
===================================================================
--- pkg/quantstrat/NAMESPACE	2010-02-10 02:33:13 UTC (rev 241)
+++ pkg/quantstrat/NAMESPACE	2010-02-10 22:13:59 UTC (rev 242)
@@ -2,9 +2,12 @@
 export(applyIndicators)
 export(match.names)
 export(getOrderBook)
+export(initOrders)
 export(getOrders)
 export(addOrder)
 export(updateOrders)
+export(updateOrderMatrix)
+export(ruleOrderProc)
 export(add.rule)
 export(applyRules)
 export(add.signal)

Modified: pkg/quantstrat/R/indicators.R
===================================================================
--- pkg/quantstrat/R/indicators.R	2010-02-10 02:33:13 UTC (rev 241)
+++ pkg/quantstrat/R/indicators.R	2010-02-10 22:13:59 UTC (rev 242)
@@ -94,7 +94,10 @@
         }
         #print(tmp_val)
     } #end indicators loop
-    if(is.null(ret)) return(mktdata)
+    mkdata<<-mktdata
+    if(is.null(ret)) {
+        return(mktdata)
+    }
     else return(ret)
 }
 

Modified: pkg/quantstrat/R/orders.R
===================================================================
--- pkg/quantstrat/R/orders.R	2010-02-10 02:33:13 UTC (rev 241)
+++ pkg/quantstrat/R/orders.R	2010-02-10 22:13:59 UTC (rev 242)
@@ -24,9 +24,10 @@
 #' @param portfolio text name of the portfolio to associate the order book with
 #' @param symbols a list of identfiers of the instruments to be contained in the Portfolio.  The name of any associated price objects (xts prices, usually OHLC) should match these
 #' @param initDate date (ISO8601) prior to the first close price given in mktdata, used to initialize the order book with a dummy order
+#' @export
 initOrders <- function(portfolio=NULL, symbols=NULL, initDate = '1999-12-31')
 {
-    # NOTE we could stor all of these in one object, but I think that might get big
+    # NOTE we could store all of these in one object, but I think that might get big
     orders<- try(getOrderBook(portfolio))
     if(inherits(orders,"order_book")) {
         stop(paste("Order Book for portfolio",portfolio,"already exists."))
@@ -63,7 +64,7 @@
 #' @param symbol identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these
 #' @param status one of "open", "closed", "canceled", or "replaced", default "open"
 #' @param timestamp timestamp coercible to POSIXct that will be the period to find orders of the given status and ordertype 
-#' @param ordertype one of NULL, "market","limit",or "stop", default NULL
+#' @param ordertype one of NULL, "market","limit","stoplimit", or "stoptrailing" default NULL
 #' @param side one of NULL, "long" or "short", default NULL 
 #' @param starttime difference to current timestamp to search, in seconds(numeric) or as a POSIXct timestamp, defaults to -86400 (one day) 
 #' @export
@@ -76,7 +77,7 @@
     
     #data quality checks
     if(!is.null(status) & !length(grep(status,c("open", "closed", "canceled","replaced")))==1) stop(paste("order status:",status,' must be one of "open", "closed", "canceled", or "replaced"'))
-    if(!is.null(ordertype) & !length(grep(ordertype,c("market","limit","stop")))==1) stop(paste("ordertype:",ordertype,' must be one of "market","limit",or "stop"'))
+    if(!is.null(ordertype) & !length(grep(ordertype,c("market","limit","stoplimit","stoptrailing")))==1) stop(paste("ordertype:",ordertype,' must be one of "market","limit","stoplimit", or "stoptrailing"'))
 
     # subset by time and symbol
     if(!is.null(timestamp)){
@@ -109,25 +110,36 @@
 #' add an order to the order book
 #' 
 #' By default, this function will locate and replace any 'open' order(s) 
-#' on the requested portfolio/symbol that have the same type and side.
+#' on the requested portfolio/symbol that have the same type and side.  
+#' This is the equivalent of what is sometimes called an 
+#' OCO (Order Cancels Other) order.  If you do not want the function to 
+#' behave this way, set \code{replace=FALSE}.
 #'  
-#' we need to figure out how to handle stop entry and stop exit orders, maybe via a negative price to specify the pullback that would trigger the order at the market.
+#' We have modeled two types of stop orders, which should be sufficient to model most types of stops.  
+#' We have modeled the simplest type, a 'stoplimit' order, which is just a limit order used to enter 
+#' or exit a position at a specific price.  There is no functional different between a regular 'limit'
+#' order and a 'stoplimit' order, but the distinction will likely be useful for reporting on when stops
+#' have been triggered.
+#' We have also modeled a 'stoptrailing' order, which may be used to model dynamic limit-based entry or exit.  
+#' The 'stoptrailing' order type is the only order type that makes use of the order \code{threshold}, which 
+#' is the difference either positive or negative from the current price when the order is entered.  
+#' Some markets and brokers recognize a stop that triggers a market order, when the stop is triggered, 
+#' a market order will be executed at the then-prevailing price.  We have not modeled this type of order.   
 #' 
-#' trailing stops should be modeled with replaced orders as prices change
-#' 
 #' @param portfolio text name of the portfolio to associate the order book with
 #' @param symbol identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these
 #' @param timestamp timestamp coercible to POSIXct that will be the time the order will be inserted on 
 #' @param qty numeric quantity of the order
 #' @param price numeric price at which the order is to be inserted
-#' @param ordertype one of "market","limit",or "stop"
+#' @param ordertype one of "market","limit","stoplimit", or "stoptrailing"
 #' @param side one of either "long" or "short" 
+#' @param threshold numeric threshold to apply to trailing stop orders, default NULL
 #' @param status one of "open", "closed", "canceled", or "replaced", default "open"
 #' @param replace TRUE/FALSE, whether to replace any other open order(s) on this portfolio symbol, default TRUE 
 #' @param statustimestamp timestamp of a status update, will be blank when order is initiated 
 #' @param delay what delay to add to timestamp when inserting the order into the order book, in seconds
 #' @export
-addOrder <- function(portfolio, symbol, timestamp, qty, price, ordertype, side, status="open", replace=TRUE, statustimestamp='' , delay=.00001)
+addOrder <- function(portfolio, symbol, timestamp, qty, price, ordertype, side, threshold=NULL, status="open", replace=TRUE, statustimestamp='' , delay=.00001)
 {
     # get order book
     orderbook <- getOrderBook(portfolio)
@@ -137,14 +149,17 @@
     if(!is.numeric(qty)) stop (paste("Quantity must be numeric:",qty))
     if(!is.numeric(price)) stop (paste("Price must be numeric:",price))
     if(!length(grep(side,c('long','short')))==1) stop(paste("side:",side," must be one of 'long' or 'short'"))
-    if(!length(grep(ordertype,c("market","limit","stop")))==1) stop(paste("ordertype:",ordertype,' must be one of "market","limit",or "stop"'))
+    if(!length(grep(ordertype,c("market","limit","stoplimit","stoptrailing")))==1) stop(paste("ordertype:",ordertype,' must be one of "market","limit","stoplimit", or "stoptrailing"'))
+    if(!is.null(threshold) & !is.numeric(threshold) & !length(grep(ordertype,c("stoplimit","stoptrailing")))==1){ 
+        stop(paste("Threshold may only be applied to a stop order type, and must be numeric",ordertype,threshold))
+    }
     if(!length(grep(status,c("open", "closed", "canceled","replaced")))==1) stop(paste("order status:",status,' must be one of "open", "closed", "canceled", or "replaced"'))
     # TODO do we need to check for collision, and increment timestamp?  or alternately update?
     
     if(isTRUE(replace)) updateOrders(portfolio=portfolio, symbol=symbol,timestamp=timestamp, ordertype=ordertype, side=side, oldstatus="open", newstatus="replaced", statustimestamp=timestamp)
     # insert new order
-    order<-xts(c(qty, price, ordertype, side, status, statustimestamp),order.by=(as.POSIXct(timestamp)+delay))
-    colnames(order) <- c("Order.Qty","Order.Price","Order.Type","Order.Side","Order.Status","Order.StatusTime")
+    order<-xts(c(qty, price, ordertype, side, threshold, status, statustimestamp),order.by=(as.POSIXct(timestamp)+delay))
+    colnames(order) <- c("Order.Qty","Order.Price","Order.Type","Order.Side", "Order.Threshold", "Order.Status","Order.StatusTime")
     orderbook[[symbol]]<-rbind(orderbook[[symbol]],order)
     
     # assign order book back into place (do we need a non-exported "put" function?)
@@ -155,15 +170,19 @@
 #' 
 #' When an order gets filled, it should have its status moved to 'closed'.
 #' 
-#' When an order is updated with a new order, the order status should change to 'replaced' with a StatusTime that is the same as the one for the new order.
+#' When an order is updated with a new order, the order status should change to 'replaced' 
+#' with a StatusTime that is the same as the one for the new order.  This could happen in 
+#' the case of a traditional Cancel/Replace, because of a trailing stop, or in the
+#' case of a partial fill that needs to enter a replaced order for the remainder. 
 #' 
-#' When a risk event or over-limit event happens, typically open orders will be 'canceled'.  Possibly new orders will be added to close open positions.  
+#' When a risk event or over-limit event happens, typically open orders will be 'canceled'.  
+#' Possibly new orders will be added to close open positions.  
 #' Many models will also want to run a process at the close of market that will cancel all open orders. 
 #' 
 #' @param portfolio text name of the portfolio to associate the order book with
 #' @param symbol identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these
 #' @param timestamp timestamp coercible to POSIXct that will be the time to search for orders before this time 
-#' @param ordertype one of NULL, "market","limit",or "stop", default NULL
+#' @param ordertype one of NULL, "market","limit","stoplimit", or "stoptrailing" default NULL
 #' @param side one of NULL, "long" or "short", default NULL 
 #' @param oldstatus one of NULL, "open", "closed", "canceled", or "replaced", default "open"
 #' @param newstatus one of "open", "closed", "canceled", or "replaced"
@@ -175,7 +194,7 @@
     if(!is.null(oldstatus) & !length(grep(oldstatus,c("open", "closed", "canceled","replaced")))==1) stop(paste("old order status:",oldstatus,' must be one of "open", "closed", "canceled", or "replaced"'))
     if(!length(grep(newstatus,c("open", "closed", "canceled","replaced")))==1) stop(paste("new order status:",newstatus,' must be one of "open", "closed", "canceled", or "replaced"'))
     if(!is.null(side) & !length(grep(side,c('long','short')))==1) stop(paste("side:",side," must be one of 'long' or 'short'"))
-    if(!is.null(ordertype) & !length(grep(ordertype,c("market","limit","stop")))==1) stop(paste("ordertype:",ordertype,' must be one of "market","limit",or "stop"'))
+    if(!is.null(ordertype) & !length(grep(ordertype,c("market","limit","stoplimit","stoptrailing")))==1) stop(paste("ordertype:",ordertype,' must be one of "market","limit","stoplimit", or "stoptrailing"'))
     
     # need the ability to pass a range like we do in blotter
     updatedorders<-getOrders(portfolio=portfolio, symbol=symbol, status=oldstatus, timestamp=timestamp, ordertype=ordertype, side=side) 
@@ -190,15 +209,188 @@
     updatedorders[,"Order.StatusTime"]<-statustimestamp
     
     #orderbook<-merge.xts(orderbook,updatedorders,join='left')
-    orderbook[index(updatedorders)]<-updatedorders
+    orderbook[[symbol]][index(updatedorders)]<-updatedorders
 
     # assign order book back into place (do we need a non-exported "put" function?)
     assign(paste("order_book",portfolio,sep='.'),orderbook,envir=.strategy)
 }
 
-# TODO ruleOrderProc
-# process orders at time t, generating transactions
+#' insert a block of updated orders
+#' @param portfolio text name of the portfolio to associate the order book with
+#' @param symbol identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these
+#' @param updatedorders time series containing updated orders 
+#' @export
+updateOrderMatrix<-function(portfolio, symbol, updatedorders){
+    orderbook <- getOrderBook(portfolio)
 
+    orderbook[[symbol]][index(updatedorders)]<-updatedorders
+    
+    # assign order book back into place (do we need a non-exported "put" function?)
+    assign(paste("order_book",portfolio,sep='.'),orderbook,envir=.strategy)
+}
+
+#' process open orders at time t, generating transactions or new orders
+#' @param portfolio text name of the portfolio to associate the order book with
+#' @param symbol identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these
+#' @param mktdata an xts object containing market data.  depending on indicators, may need to be in OHLCV or BBO formats, default NULL
+#' @param timestamp timestamp coercible to POSIXct that will be the time to search for orders before this time 
+#' @param ordertype one of NULL, "market","limit","stoplimit", or "stoptrailing" default NULL
+#' @param ... any other passthru parameters
+#' @param slippageFUN default  NULL, not yet implemented
+#' @export
+ruleOrderProc <- function(portfolio, symbol, mktdata, timestamp, ordertype=NULL, ..., slippageFUN=NULL)
+{
+    # get open orders
+    procorders<-getOrders(portfolio=portfolio, symbol=symbol, status="open", timestamp=timestamp, ordertype=ordertype)
+    freq = periodicity(mktdata)
+    if (nrow(procorders)>=1){
+        # get previous bar
+        prevtime=time(mktdata[mktdata[timestamp,which.i=TRUE]-1])
+        #switch on frequency
+        switch(freq$scale,
+            yearly = ,
+            quarterly = ,
+            monthly = ,{
+                # first process low frequencies with look-back assumption
+                for (ii in 1:nrow(procorders) ){
+                    if(procorders[[ii]]$Order.Type=='market'){
+                        addTxn(Portfolio=portfolio, Symbol=symbol, TxnDate=prevtime, TxnQty=procorders[[ii]]$Order.Qty, TxnPrice=Cl(mktdata) ,...=...)
+                        procorders[[ii]]$Order.Status<-'closed'
+                        procorders[[ii]]$Order.StatusTime<-timestamp
+                    } else {
+                        stop("order types other than market not (yet?) supported for low-frequency strategies")
+                    }
+                }
+            }, # end low frequency processing
+            daily = { 
+                # next process daily
+                for (ii in 1:nrow(procorders) ){
+                    switch(procorders[[ii]]$Order.Type,
+                        market = ,
+                        limit = {
+                            if (procorders[[ii]]$Order.Type == 'market' ){
+                                txnprice=getPrice(mktdata[prevtime], prefer='close')
+                                if(ncol(txnprice)>1) txnprice = getPrice(mktdata[timestamp], symbol=symbol, prefer='close')
+                                txntime=prevtime
+                            } else {
+                                # check to see if price moved through the limit
+                                if(procorders[[ii]]$Order.Price>Lo(mktdata[timestamp]) & procorders[[ii]]$Order.Price<Hi(mktdata[timestamp]) ) {
+                                    txnprice=procorders[[ii]]$Order.Price
+                                    txntime=timestamp
+                                } else {
+                                    # price did not move through my order
+                                    next() # should go to next order
+                                }   
+                            }   
+                        },
+                        {
+                            stop("order types other than market and limit not (yet?) supported for daily frequencies")
+                        }
+                    )
+                    addTxn(Portfolio=portfolio, Symbol=symbol, TxnDate=txntime, TxnQty=procorders[[ii]]$Order.Qty, TxnPrice=Cl(mktdata) ,...=...)
+                    procorders[[ii]]$Order.Status<-'closed'
+                    procorders[[ii]]$Order.StatusTime<-timestamp
+                } #end loop over open orders       
+            }, #end daily processing
+            {
+                # now do higher frequencies
+                for (ii in 1:nrow(procorders) ){
+                    txnprice=NULL
+                    switch(procorders[[ii]]$Order.Type,
+                            market = {
+                                txnprice = getPrice(mktdata[timestamp])
+                                if(ncol(txnprice)>1) txnprice = getPrice(mktdata[timestamp], symbol=symbol)
+                                txntime  = timestamp
+                            },
+                            limit= ,
+                            stoplimit = {
+                                if (is.OHLC(mktdata)){
+                                    # check to see if price moved through the limit
+                                    if(procorders[[ii]]$Order.Price>Lo(mktdata[timestamp]) & procorders[[ii]]$Order.Price<Hi(mktdata[timestamp]) ) {
+                                        txnprice = procorders[[ii]]$Order.Price
+                                        txntime  = timestamp
+                                    } else {
+                                        # price did not move through my order
+                                        next() # should go to next order
+                                    }   
+                                } else if(is.BBO(mktdata)){
+                                    # check side/qty
+                                    if(procorders[[ii]]$Order.Qty>0){ # positive quantity 'buy'
+                                        if(procorders[[ii]]$Order.Price>=getPrice(mktdata[timestamp],prefer='offer')){
+                                            # price we're willing to pay is higher than the offer price, so execute at the limit
+                                            txnprice = procorders[[ii]]$Order.Price
+                                            txntime  = timestamp
+                                        } else next()
+                                    } else { # negative quantity 'sell'
+                                        if(getPrice(procorders[[ii]]$Order.Price<=mktdata[timestamp],prefer='bid')){
+                                            # we're willing to sell at a better price than the bid, so execute at the limit
+                                            txnprice = procorders[[ii]]$Order.Price
+                                            txntime  = timestamp
+                                        } else next() 
+                                    } 
+                                } else {
+                                    # no depth data, either OHLC or BBO, getPrice explicitly using symbol
+                                    if(procorders[[ii]]$Order.Price==getPrice(mktdata[timestamp], symbol=symbol, prefer='Price')){
+                                        txnprice = procorders[[ii]]$Order.Price
+                                        txntime  = timestamp
+                                    } else next()                                     
+                                }
+                                
+                            },
+                            stoptrailing = {
+                                # if market moved through my price, execute
+                                if(procorders[[ii]]$Order.Qty>0){ # positive quantity 'buy'
+                                    if(procorders[[ii]]$Order.Price>=getPrice(mktdata[timestamp],prefer='offer')){
+                                        # price we're willing to pay is higher than the offer price, so execute at the limit
+                                        txnprice = procorders[[ii]]$Order.Price
+                                        txntime  = timestamp
+                                    } 
+                                } else { # negative quantity 'sell'
+                                    if(procorders[[ii]]$Order.Price<=getPrice(mktdata[timestamp],prefer='bid')){
+                                        # we're willing to sell at a better price than the bid, so execute at the limit
+                                        txnprice = procorders[[ii]]$Order.Price
+                                        txntime  = timestamp
+                                    }  
+                                } 
+                                # if market is beyond price+(-threshold), replace order
+                                if(is.null(txnprice)){ 
+                                    if(procorders[[ii]]$Order.Qty>0){
+                                        prefer='offer'
+                                    } else {
+                                        prefer='bid'
+                                    }
+                                    # we didn't trade, so check to see if we need to move the stop
+                                    if( getPrice(mktdata[timestamp],prefer=prefer)-procorders[[ii]]$Order.Threshold > procorders[[ii]]$Order.Price ){
+                                        addOrder(portfolio=portfolio, 
+                                                 symbol=symbol, 
+                                                 timestamp=timestamp, 
+                                                 qty=procorders[[ii]]$Order.Qty, 
+                                                 price=getPrice(mktdata[timestamp],prefer=prefer)-procorders[[ii]]$Order.Threshold, 
+                                                 ordertype=procorders[[ii]]$Order.Type, 
+                                                 side=procorders[[ii]]$Order.Side, 
+                                                 threshold=procorders[[ii]]$Order.Threshold, 
+                                                 status="open", 
+                                                 replace=TRUE)
+                                        procorders[[ii]]$Order.Status<-'replaced'
+                                        procorders[[ii]]$Order.StatusTime<-timestamp 
+                                        next()
+                                    }
+                                }
+                                # else next
+                            }
+                    )
+                    if(!is.null(txnprice)){
+                        addTxn(Portfolio=portfolio, Symbol=symbol, TxnDate=txntime, TxnQty=procorders[[ii]]$Order.Qty, TxnPrice=Cl(mktdata) ,...=...)
+                        procorders[[ii]]$Order.Status<-'closed'
+                        procorders[[ii]]$Order.StatusTime<-timestamp
+                    }
+                } #end loop over open orders       
+            } # end higher frequency processing
+        ) # end switch on freq
+    } # end check for open orders
+    # now put the orders back in
+    updateOrderMatrix(portfolio=portfolio, symbol=symbol, updatedorders=procorders)
+}
 ###############################################################################
 # R (http://r-project.org/) Quantitative Strategy Model Framework
 #

Modified: pkg/quantstrat/R/rules.R
===================================================================
--- pkg/quantstrat/R/rules.R	2010-02-10 02:33:13 UTC (rev 241)
+++ pkg/quantstrat/R/rules.R	2010-02-10 22:13:59 UTC (rev 242)
@@ -56,6 +56,7 @@
     if (!is.list(arguments)) stop("arguments must be passed as a named list")
     arguments$label=label
     tmp_rule$arguments<-arguments
+    tmp_rule$path.dep<-path.dep
     if(!hasArg(indexnum) | (hasArg(indexnum) & is.null(indexnum))) indexnum = length(strategy$rules[type])+1
     tmp_rule$call<-match.call()
     strategy$rules[type][[indexnum]]<-tmp_rule
@@ -69,6 +70,12 @@
 #' In typical usage, this function will be called via \code{\link{applyStrategy}}.  
 #' In this mode, this function will be called twice, once with \code{path.dep=FALSE} 
 #' and then again in stepping over the time indexes of the mktdata object.
+#' 
+#' Individual rule functions may need to use <<- to place \code{hold} and \code{holdtill}
+#' variables into play.  These would be mosrt likely implemented by risk rules.
+#' 
+#' @param portfolio text name of the portfolio to associate the order book with
+#' @param symbol identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these
 #' @param strategy an object of type 'strategy' to add the rule to
 #' @param mktdata an xts object containing market data.  depending on rules, may need to be in OHLCV or BBO formats, and may include indicator and signal information
 #' @param Dates default NULL, list of time stamps to iterate over, ignored if \code{path.dep=FALSE}
@@ -78,7 +85,7 @@
 #' @param path.dep TRUE/FALSE whether rule is path dependent, default TRUE, see Details 
 #' @seealso \code{\link{add.rule}} \code{\link{applyStrategy}} 
 #' @export
-applyRules <- function(strategy, mktdata, Dates=NULL, indicators=NULL, signals=NULL,  ..., path.dep=TRUE) {
+applyRules <- function(portfolio, symbol, strategy, mktdata, Dates=NULL, indicators=NULL, signals=NULL,  ..., path.dep=TRUE) {
     # TODO check for symbol name in mktdata using Josh's code:
     # symbol <- strsplit(colnames(mktdata)[1],"\\.")[[1]][1]
     
@@ -97,10 +104,10 @@
         nargs=NULL
     }
     
-    ruleProc <- function (ruletypelist,Date=NULL){
+    ruleProc <- function (ruletypelist,timestamp=NULL, ...){
         for (rule in ruletypelist){
             #TODO check to see if they've already been calculated
-            
+            if (!rule$path.dep==path.dep) next()
             if(!is.function(get(rule$name))){
                 if(!is.function(get(paste("sig",rule$name,sep='.')))){
                     message(paste("Skipping rule",rule$name,"because there is no function by that name to call"))
@@ -117,7 +124,7 @@
             
             .formals  <- formals(fun)
             onames <- names(.formals)
-            rule$arguments$Date=Date
+            rule$arguments$timestamp=timestamp
             pm <- pmatch(names(rule$arguments), onames, nomatch = 0L)
             if (any(pm == 0L))
                 warning(paste("some arguments stored for",rule$name,"do not match"))
@@ -158,46 +165,57 @@
     for(d in 1:length(Dates)){ # d is a date slot counter
         # I shouldn't have to do this but we lose the class for the element 
         # when we do for(date in Dates)
-        Date=Dates[d]    
+        timestamp=Dates[d]    
+        
+        # check to see if we need to release a hold
+        if(isTRUE(hold) & holdtill<timestamp){
+            hold=FALSE
+            holdtill=NULL
+        }
         for ( type in names(strategy$rules)){
             switch( type ,
                     pre = {
-                        # TODO check to see if we need to release hold
-                        #      holdtill would be before current time stamp
-                        if(length(strategy$rules[type])>=1)
-                            ruleProc(strategy$rules$pre,Date=Date)    
+                        if(length(strategy$rules[type])>=1){
+                            ruleProc(strategy$rules$pre,timestamp=timestamp)    
+                        }
                     },
                     risk = {
-                        if(length(strategy$rules$risk)>=1)
-                            ruleProc(strategy$rules$risk,Date=Date)    
+                        if(length(strategy$rules$risk)>=1){
+                            ruleProc(strategy$rules$risk,timestamp=timestamp)    
+                        }       
                     },
                     order = {
                         if(isTRUE(hold)) next()
                         if(length(strategy$rules[type])>=1) {
-                            ruleProc(strategy$rules[type],Date=Date)
+                            ruleProc(strategy$rules[type],timestamp=timestamp)
                         } else {
-                            # TODO call ruleOrderProc(symbol=Symbol, Date=Date, portfolio=Portfolio)
+                            #(mktdata, portfolio, symbol, timestamp, slippageFUN=NULL)
+                            ruleOrderProc(portfolio=portfolio, symbol=symbol, mktdata=mktdata, timestamp=timestamp)
                         }
                     },
                     rebalance =, exit = , enter = {
+                        if(isTRUE(hold)) next()    
                         if(length(strategy$rules[type])>=1) {
-                            if(isTRUE(hold)) next()
-                            ruleProc(strategy$rules[type],Date=Date)
-                        } else next()       
+                            ruleProc(strategy$rules$risk,timestamp=timestamp)
+                        }      
                     },
                     post = {
-                        if(length(strategy$rules$post)>=1)
-                            ruleProc(strategy$rules$post,Date=Date)    
+                        #TODO do we processfor hold here, or not?
+                        if(length(strategy$rules$post)>=1) {
+                            ruleProc(strategy$rules$post,timestamp=timestamp)    
+                        }
                     }
             ) # end switch            
         } #end type loop
     } # end dates loop
     
-    if(is.null(ret)) return(mktdata)
+    mkdata<<-mktdata
+    if(is.null(ret)) {
+        return(mktdata)
+    }
     else return(ret)
 }
 
-
 ###############################################################################
 # R (http://r-project.org/) Quantitative Strategy Model Framework
 #

Modified: pkg/quantstrat/R/signals.R
===================================================================
--- pkg/quantstrat/R/signals.R	2010-02-10 02:33:13 UTC (rev 241)
+++ pkg/quantstrat/R/signals.R	2010-02-10 22:13:59 UTC (rev 242)
@@ -99,7 +99,10 @@
         }
         #print(tmp_val)
     } #end signals loop
-    if(is.null(ret)) return(mktdata)
+    mkdata<<-mktdata
+    if(is.null(ret)) {
+        return(mktdata)
+    }
     else return(ret)
 }
 

Modified: pkg/quantstrat/R/strategy.R
===================================================================
--- pkg/quantstrat/R/strategy.R	2010-02-10 02:33:13 UTC (rev 241)
+++ pkg/quantstrat/R/strategy.R	2010-02-10 22:13:59 UTC (rev 242)
@@ -61,11 +61,13 @@
 
 #' apply the strategy to arbitrary market data
 #' @param strategy an object of type 'strategy' to add the indicator to
-#' @param mktdata an xts object containing market data.  depending on indicators, may need to be in OHLCV or BBO formats
+#' @param portfolios a list of portfolios to apply the strategy to
+#' @param mktdata an xts object containing market data.  depending on indicators, may need to be in OHLCV or BBO formats, default NULL
 #' @param ... any other passthru parameters
 #' @export
-applyStrategy <- function(strategy , mktdata , ... ) {
+applyStrategy <- function(strategy , portfolios, mktdata=NULL , ... ) {
     #TODO add Date subsetting
+    #TODO add saving of modified market data
     
     ret<-list()
     
@@ -74,17 +76,31 @@
         if(inherits(strategy,"try-error"))
             stop ("You must supply an object of type 'strategy'.")
     } 
+    i=1
+    for (portfolio in portfolios) {
+        ret[portfolio]<-list() # this is slot [[i]] which we will use later
+        pobj<-getPortfolio(portfolio)
+        symbols<-names(pobj)
+        sret<-list()
+        for (symbol in symbols){
+            if(is.null(mktdata)) mktdata <- get(symbol)
+            #loop over indicators
+            sret$indicators <- applyIndicators(strategy , mktdata , ... )
+            
+            #loop over signal generators
+            sret$signals <- applySignals(strategy, mktdata, ret$indicators, ... )
+            
+            #loop over rules  
+            # non-path-dep first
+            sret$rules<-list()
[TRUNCATED]

To get the complete diff run:
    svnlook diff /svnroot/blotter -r 242


More information about the Blotter-commits mailing list