[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