[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