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

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Fri Feb 4 22:17:03 CET 2011


Author: braverock
Date: 2011-02-04 22:17:03 +0100 (Fri, 04 Feb 2011)
New Revision: 548

Modified:
   pkg/quantstrat/DESCRIPTION
   pkg/quantstrat/R/orders.R
   pkg/quantstrat/R/rules.R
   pkg/quantstrat/R/traderules.R
   pkg/quantstrat/man/getOrders.Rd
   pkg/quantstrat/man/osMaxPos.Rd
Log:
- remove character conversion of timestamp where possible
- minor improvements to dindex dimension reduction
- update roxygen documentation
- increase xts version requirement to 0.7-6.15 to take advantage of improved subsetting and make.index.unique
- bump version

Modified: pkg/quantstrat/DESCRIPTION
===================================================================
--- pkg/quantstrat/DESCRIPTION	2011-01-31 20:40:16 UTC (rev 547)
+++ pkg/quantstrat/DESCRIPTION	2011-02-04 21:17:03 UTC (rev 548)
@@ -1,10 +1,10 @@
 Package: quantstrat
 Type: Package
 Title: Quantitative Strategy Model Framework
-Version: 0.3.2
+Version: 0.4.0
 Date: $Date$
 Author: Peter Carl, Dirk Eddelbuettel, Brian G. Peterson, Jeffrey A. Ryan, Joshua Ulrich
-Depends: xts(>= 0.7-6.1),TTR(>= 0.2),blotter(>= 0.7.2), FinancialInstrument, quantmod (>= 0.3-14)
+Depends: xts(>= 0.7-6.15),TTR(>= 0.2),blotter(>= 0.7.2), FinancialInstrument, quantmod (>= 0.3-14)
 Suggests: PerformanceAnalytics,PortfolioAnalytics
 Maintainer: Jeffrey A. Ryan <jeff.a.ryan at gmail.com>
 Description: Specify, build, and back-test quantitative financial trading and portfolio strategies

Modified: pkg/quantstrat/R/orders.R
===================================================================
--- pkg/quantstrat/R/orders.R	2011-01-31 20:40:16 UTC (rev 547)
+++ pkg/quantstrat/R/orders.R	2011-02-04 21:17:03 UTC (rev 548)
@@ -65,7 +65,7 @@
 #' @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 status one of "open", "closed", "canceled", or "replaced", default "open"
-#' @param timespan xts-style character timespan to be the period to find orders of the given status and ordertype, not yet used 
+#' @param timespan xts-style character timespan to be the period to find orders of the given status and ordertype
 #' @param ordertype one of NULL, "market","limit","stoplimit", "stoptrailing", or "iceberg" default NULL
 #' @param side one of NULL, "long" or "short", default NULL 
 #' @param which.i if TRUE, return the row index numbers rather than the order rows matching the criteria, default FALSE
@@ -97,6 +97,8 @@
     } else {
         # extract
         ordersubset<-orderbook[[portfolio]][[symbol]][indices,]
+        #subset by time
+        if(nrow(ordersubset)>1) ordersubset<-ordersubset[timespan]
         return(ordersubset)
     }
 }
@@ -441,7 +443,7 @@
                                 {
                                     txnprice = as.numeric(getPrice(mktdataTimestamp))
                                     #TODO extend this to figure out which side to prefer
-                                    txntime  = as.character(timestamp)
+                                    txntime = timestamp
                                 }) # end switch on frequency
                     },
                     limit= ,
@@ -456,7 +458,7 @@
                                 orderPrice < as.numeric(Hi(mktdataTimestamp)) ) 
                             {
                                 txnprice = orderPrice
-                                txntime  = as.character(timestamp)
+                                txntime = timestamp
                             } else {
                                 # price did not move through my order
                                 next() # should go to next order
@@ -467,13 +469,13 @@
                                 if(orderPrice >= as.numeric(getPrice(mktdataTimestamp,prefer='offer'))){
                                     # price we're willing to pay is higher than the offer price, so execute at the limit
                                     txnprice = orderPrice
-                                    txntime  = as.character(timestamp)
+                                    txntime = timestamp
                                 } else next()
                             } else { # negative quantity 'sell'
                                 if(orderPrice <= as.numeric(getPrice(mktdataTimestamp,prefer='bid'))){
                                     # we're willing to sell at a better price than the bid, so execute at the limit
                                     txnprice = orderPrice
-                                    txntime  = as.character(timestamp)
+                                    txntime = timestamp
                                 } else next()
                             }
                             if( orderType == 'iceberg'){
@@ -498,7 +500,7 @@
                             # no depth data, either OHLC or BBO, getPrice explicitly using symbol ?
                             if(orderPrice == getPrice(mktdataTimestamp, symbol=symbol, prefer='price')){
                                 txnprice = orderPrice
-                                txntime  = as.character(timestamp)
+                                txntime = timestamp
                             } else next()
                         }
 
@@ -509,18 +511,20 @@
                             if(isBBOmktdata){
                                 prefer='offer'
                                 if(orderPrice >= getPrice(mktdataTimestamp,prefer=prefer)){ #TODO maybe use last(getPrice) to catch multiple prints on timestamp?
-                                    # price we're willing to pay is higher than the offer price, so execute at the limit
-                                    txnprice = orderPrice
-                                    txntime  = as.character(timestamp)
+                                    # price we're willing to pay is higher than the offer price, so execute at the prevailing price
+                                    #txnprice = orderPrice
+                                    txnprice = as.numeric(getPrice(mktdataTimestamp,prefer=prefer)) #presumes unique timestamps
+                                    txntime = timestamp
                                 } 
                             } 
                         } else { # negative quantity 'sell'
                             if(isBBOmktdata){
                                 prefer='bid'
                                 if(orderPrice <= getPrice(mktdataTimestamp,prefer=prefer)){
-                                    # we're willing to sell at a better price than the bid, so execute at the limit
-                                    txnprice = orderPrice
-                                    txntime  = as.character(timestamp)
+                                    # we're willing to sell at a better price than the bid, so execute at the prevailing price
+                                    # txnprice = orderPrice
+                                    txnprice = as.numeric(getPrice(mktdataTimestamp,prefer=prefer)) #presumes unique timestamp
+                                    txntime = timestamp
                                 }  
                             } 
                         } 
@@ -530,7 +534,7 @@
                                 orderPrice < as.numeric(Hi(mktdataTimestamp)) ) 
                             {
                                 txnprice = orderPrice
-                                txntime  = as.character(timestamp)
+                                txntime = timestamp
                             } 
                         }
                         # if market is beyond price+(-threshold), replace order

Modified: pkg/quantstrat/R/rules.R
===================================================================
--- pkg/quantstrat/R/rules.R	2011-01-31 20:40:16 UTC (rev 547)
+++ pkg/quantstrat/R/rules.R	2011-02-04 21:17:03 UTC (rev 548)
@@ -291,7 +291,7 @@
 
     #we could maybe do something more sophisticated, but this should work
     if(isTRUE(path.dep)){
-        dindex<-c(1,length(Dates)) # set the dimension reduction/loop jumping index vector
+        dindex<-c(1,length(Dates)-1) # set the dimension reduction/loop jumping index vector
         assign.dindex(dindex)
         #pre-process for dimension reduction here
         for ( type in names(strategy$rules)){
@@ -303,7 +303,7 @@
                         if(is.null(rule$arguments$sigcol) | is.null(rule$arguments$sigval) ){
                             assign.dindex(1:length(Dates))
                         } else {
-                            assign.dindex(sort(unique(c(get.dindex(),which(mktdata[,rule$arguments$sigcol] == rule$arguments$sigval)))))   
+                            assign.dindex(c(get.dindex(),which(mktdata[,rule$arguments$sigcol] == rule$arguments$sigval)))   
                         }
                     }
                 }
@@ -314,7 +314,7 @@
         
         #for debugging, set dindex to all index values:
         #assign.dindex(1:length(index(mktdata)))
-        
+        #print(dindex)
     } else {
         Dates=''
         dindex=1
@@ -347,9 +347,13 @@
                 # no open orders between now and the next index
                 nidx=FALSE
             } else {
-                if(!length(grep('market',ordersubset[oo.idx,'Order.Type']))==0 || hasArg('prefer')) {
-                    #if any type is market
-                    #TODO right now, 'prefer' arguments loop through all observations.  we could probably change the code below on finding price to handle prefer, but not sure it matters
+                if(!length(grep('market',ordersubset[oo.idx,'Order.Type']))==0 ) {
+                    # if block above had a prefer exclusion, as below:
+                    # || hasArg('prefer')
+                    # 'prefer' arguments would loop through all observations.  
+                    # we could probably change the code below on finding price to handle prefer, but not sure it matters
+                                
+                    #if any type is market    
                     # set to curIndex+1
                     curIndex<-curIndex+1
                     if (is.na(curIndex) || curIndex > length(index(mktdata))) curIndex=FALSE
@@ -396,7 +400,7 @@
                             assign.dindex(c(get.dindex(),newidx))                  
                         } else{
                             # no cross, move ahead
-                            nidx=TRUE
+                            # nidx=TRUE #WHY WAS THIS HERE?
                         }
                     } # end loop over open limit orders
                 } # end if for limit order handling
@@ -480,7 +484,11 @@
             dindex<-get.dindex()
             curIndex<-min(dindex[dindex>curIndex])
         }
-        if (is.na(curIndex) || curIndex > length(index(mktdata))) curIndex=FALSE
+        if (is.na(curIndex) || curIndex >= length(index(mktdata))) curIndex=FALSE
+        
+        #debug line
+        #print(curIndex)
+        
         return(curIndex)
     } # end function nextIndex
         
@@ -535,6 +543,13 @@
                         if(length(strategy$rules[[type]])>=1) {
                             ruleProc(strategy$rules[[type]],timestamp=timestamp, path.dep=path.dep, mktdata=mktdata,portfolio=portfolio, symbol=symbol, ruletype=type, mktinstr=mktinstr, ...)
                         }
+                        if(isTRUE(path.dep) && length(getOrders(portfolio=portfolio, symbol=symbol, status="open", timespan=timestamp,which.i=TRUE))) {
+                            ## TODO FIXME this doesn't appear to work correctly
+                            # we opened orders in this timestamp, make sure to increment dindex w/ curIndex+1 so the order slot gets checked next index ?
+                            #browser()
+                            #assign.dindex(c(get.dindex(),curIndex+1))
+                            #
+                        }
                     },
                     post = {
                         #TODO do we process for hold here, or not?
@@ -567,3 +582,4 @@
 # $Id$
 #
 ###############################################################################
+

Modified: pkg/quantstrat/R/traderules.R
===================================================================
--- pkg/quantstrat/R/traderules.R	2011-01-31 20:40:16 UTC (rev 547)
+++ pkg/quantstrat/R/traderules.R	2011-02-04 21:17:03 UTC (rev 548)
@@ -42,14 +42,8 @@
     if(!is.function(osFUN)) osFUN<-match.fun(osFUN)
     #print(paste(symbol,timestamp))
     #print(data[timestamp][,sigcol])
-    if (!is.na(data[as.character(timestamp)][,sigcol]) & data[as.character(timestamp)][,sigcol] == sigval) {
-        #TODO add fancy formals matching for osFUN
-        if(orderqty>0 & orderqty<1){
-            # TODO add proportional order?  or should that go in order sizing function?
-        } 
-        orderqty <- osFUN(strategy=strategy, data=mktdata, timestamp=timestamp, orderqty=orderqty, ordertype=ordertype, orderside=orderside, portfolio=portfolio, symbol=symbol,...=...,ruletype=ruletype)
-
-		#calculate order price using pricemethod
+    if (!is.na(data[timestamp][,sigcol]) && data[timestamp][,sigcol] == sigval) {
+        #calculate order price using pricemethod
         pricemethod<-pricemethod[1] #only use the first if not set by calling function
 
 		if(hasArg(prefer)) prefer=match.call(expand.dots=TRUE)$prefer
@@ -64,10 +58,17 @@
                         prefer='ask'  # we're buying, so pay what they're asking
                     else
                         prefer='bid'  # we're selling, so give it to them for what they're bidding
-                    orderprice <- try(getPrice(x=data, prefer=prefer))[as.character(timestamp)]
+                    orderprice <- try(getPrice(x=data, prefer=prefer))[timestamp]
 				}, 
                 market = {
-					orderprice <- try(getPrice(x=data, prefer=prefer))[as.character(timestamp)] 
+                    if(is.BBO(mktdata)){
+                        if (orderqty>0) 
+                            prefer='bid'  # we're buying, so work the bid price
+                        else
+                            prefer='ask'  # we're selling, so work the ask price
+                        
+                    }
+					orderprice <- try(getPrice(x=data, prefer=prefer))[timestamp] 
 				},
 				maker = {
 					if(hasArg(price) & length(match.call(expand.dots=TRUE)$price)>1) {
@@ -75,9 +76,9 @@
 						orderprice <- try(match.call(expand.dots=TRUE)$price)
 					} else {
 						if(!is.null(threshold)) {
-							baseprice<- last(getPrice(x=data)[as.character(timestamp)]) # this should get either the last trade price or the Close
+							baseprice<- last(getPrice(x=data)[timestamp]) # this should get either the last trade price or the Close
 							if(hasArg(tmult) & isTRUE(match.call(expand.dots=TRUE)$tmult)) {
-								baseprice<- last(getPrice(x=data)[as.character(timestamp)]) # this should get either the last trade price or the Close
+								baseprice<- last(getPrice(x=data)[timestamp]) # this should get either the last trade price or the Close
 								# threshold is a multiplier of current price
 								if (length(threshold)>1){
 									orderprice <- baseprice * threshold # assume the user has set proper threshold multipliers for each side
@@ -106,7 +107,8 @@
 				}
         )
         if(inherits(orderprice,'try-error')) orderprice<-NULL
-        if(length(orderprice>1) & !pricemethod=='maker') orderprice<-last(orderprice[as.character(timestamp)])
+        if(length(orderprice>1) & !pricemethod=='maker') orderprice<-last(orderprice[timestamp])
+
         if(is.null(orderside) & !isTRUE(orderqty == 0)){
             curqty<-getPosQty(Portfolio=portfolio, Symbol=symbol, Date=timestamp)
             if (curqty>0 ){
@@ -123,6 +125,12 @@
                     orderside<-'short'
             }
         }
+        
+        ## now size the order
+        #TODO add fancy formals matching for osFUN
+        orderqty <- osFUN(strategy=strategy, data=mktdata, timestamp=timestamp, orderqty=orderqty, ordertype=ordertype, orderside=orderside, portfolio=portfolio, symbol=symbol,...=...,ruletype=ruletype, orderprice=as.numeric(orderprice))
+        
+        
         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, threshold=threshold, status="open", replace=replace , delay=delay, tmult=tmult, ...=..., TxnFees=TxnFees)
         }
@@ -222,6 +230,9 @@
 #' but this is the default.  If you don't want to use levels, set 
 #' them to 1.
 #' 
+#' \code{orderqty='all'} in a risk rule will return an order size 
+#' appropriate to flatten the current position.
+#' 
 #' @param data 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 timestamp timestamp coercible to POSIXct that will be the time the order will be inserted on 
 #' @param orderqty numeric quantity of the desired order, modified by osFUN
@@ -233,8 +244,9 @@
 #' @param ... any other passthru parameters
 #' @seealso \code{\link{addPosLimit}},\code{\link{getPosLimit}}
 #' @export
+#' @note 
+#' TODO integrate orderqty='all' into osMaxPos for non-risk exit orders by combining side and pos for exits
 osMaxPos <- function(data, timestamp, orderqty, ordertype, orderside, portfolio, symbol, ruletype, ...){
-	# TODO integrate orderqty='all' into osMaxPos by combining side 
 	# check for current position
     pos<-getPosQty(portfolio,symbol,timestamp)
     # check against max position
@@ -280,7 +292,10 @@
     
     #sell long
     if(orderqty<0 & orderside=='long'){
-		if(ruletype=='risk') return(orderqty)
+		if(ruletype=='risk'){
+          if(orderqty=='all') return(-1*pos)
+          else return(orderqty)
+        } 
 		if ((orderqty+pos)>=0) {
             return(orderqty)
         } else {
@@ -309,8 +324,11 @@
     
     #buy cover short
     if(orderqty>0 & orderside=='short'){
-		if(ruletype=='risk') return(orderqty)
-		if ((orderqty+pos)<=0) {
+        if(ruletype=='risk'){
+            if(orderqty=='all') return(-1*pos)
+            else return(orderqty)
+        } 
+        if ((orderqty+pos)<=0) {
             return(orderqty)
         } else {
             orderqty<-pos #flatten position, don't cross through zero

Modified: pkg/quantstrat/man/getOrders.Rd
===================================================================
--- pkg/quantstrat/man/getOrders.Rd	2011-01-31 20:40:16 UTC (rev 547)
+++ pkg/quantstrat/man/getOrders.Rd	2011-02-04 21:17:03 UTC (rev 548)
@@ -11,7 +11,7 @@
 \arguments{\item{portfolio}{text name of the portfolio to associate the order book with}
 \item{symbol}{identfier of the instrument to find orders for.  The name of any associated price objects (xts prices, usually OHLC) should match these}
 \item{status}{one of "open", "closed", "canceled", or "replaced", default "open"}
-\item{timespan}{xts-style character timespan to be the period to find orders of the given status and ordertype, not yet used}
+\item{timespan}{xts-style character timespan to be the period to find orders of the given status and ordertype}
 \item{ordertype}{one of NULL, "market","limit","stoplimit", "stoptrailing", or "iceberg" default NULL}
 \item{side}{one of NULL, "long" or "short", default NULL}
 \item{which.i}{if TRUE, return the row index numbers rather than the order rows matching the criteria, default FALSE}}

Modified: pkg/quantstrat/man/osMaxPos.Rd
===================================================================
--- pkg/quantstrat/man/osMaxPos.Rd	2011-01-31 20:40:16 UTC (rev 547)
+++ pkg/quantstrat/man/osMaxPos.Rd	2011-02-04 21:17:03 UTC (rev 548)
@@ -8,8 +8,12 @@
 the max orderqty returned will be the limit/levels
 Obviously the strategy rules could ask for smaller order sizes, 
 but this is the default.  If you don't want to use levels, set 
-them to 1.}
+them to 1.
+
+\code{orderqty='all'} in a risk rule will return an order size 
+appropriate to flatten the current position.}
 \seealso{\code{\link{addPosLimit}},\code{\link{getPosLimit}}}
+\note{TODO integrate orderqty='all' into osMaxPos for non-risk exit orders by combining side and pos for exits}
 \arguments{\item{data}{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}
 \item{timestamp}{timestamp coercible to POSIXct that will be the time the order will be inserted on}
 \item{orderqty}{numeric quantity of the desired order, modified by osFUN}



More information about the Blotter-commits mailing list