[Blotter-commits] r1188 - in pkg/blotter: . R man
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Sat Sep 15 21:51:02 CEST 2012
Author: braverock
Date: 2012-09-15 21:51:01 +0200 (Sat, 15 Sep 2012)
New Revision: 1188
Added:
pkg/blotter/R/perTradeStats.R
pkg/blotter/man/tradeQuantiles.Rd
Modified:
pkg/blotter/DESCRIPTION
pkg/blotter/NAMESPACE
pkg/blotter/R/chart.ME.R
pkg/blotter/man/chart.ME.Rd
Log:
- add tradeQuantiles function
Modified: pkg/blotter/DESCRIPTION
===================================================================
--- pkg/blotter/DESCRIPTION 2012-09-15 16:07:10 UTC (rev 1187)
+++ pkg/blotter/DESCRIPTION 2012-09-15 19:51:01 UTC (rev 1188)
@@ -2,7 +2,7 @@
Type: Package
Title: Tools for transaction-oriented trading systems
development.
-Version: 0.8.11
+Version: 0.8.12
Date: $Date$
Author: Peter Carl, Brian G. Peterson
Maintainer: Brian G. Peterson <brian at braverock.com>
@@ -23,8 +23,8 @@
Hmisc,
RUnit,
quantmod
-Contributors: Dirk Eddelbuettel, Lance Levenson, Ben McCann,
- Jeff Ryan, Garrett See, Joshua Ulrich, Wolfgang Wu
+Contributors: Dirk Eddelbuettel, Jan Humme, Lance Levenson,
+ Ben McCann, Jeff Ryan, Garrett See, Joshua Ulrich, Wolfgang Wu
URL: https://r-forge.r-project.org/projects/blotter/
Copyright: (c) 2008-2011
Collate:
@@ -60,3 +60,4 @@
'updateEndEq.R'
'updatePortf.R'
'updatePosPL.R'
+ 'perTradeStats.R'
Modified: pkg/blotter/NAMESPACE
===================================================================
--- pkg/blotter/NAMESPACE 2012-09-15 16:07:10 UTC (rev 1187)
+++ pkg/blotter/NAMESPACE 2012-09-15 19:51:01 UTC (rev 1188)
@@ -22,6 +22,7 @@
export(pennyPerShare)
export(perTradeStats)
export(PortfReturns)
+export(tradeQuantiles)
export(tradeStats)
export(updateAcct)
export(updateEndEq)
Modified: pkg/blotter/R/chart.ME.R
===================================================================
--- pkg/blotter/R/chart.ME.R 2012-09-15 16:07:10 UTC (rev 1187)
+++ pkg/blotter/R/chart.ME.R 2012-09-15 19:51:01 UTC (rev 1188)
@@ -1,4 +1,4 @@
-#' Chart Maximum Adverse/Forward Excursion
+#' Chart Maximum Adverse/Favorable Excursion
#'
#' Produces a scatterplot with one point per trade, with x-axis: absolute
#' value of Drawdown (Adverse), or Run Up (Favourable),
@@ -92,134 +92,6 @@
)
}
-#' calculate flat to flat per-trade statistics
-#'
-#' One 'trade' is defined as the entire time the symbol is not flat.
-#' It may contain many transactions. From the initial transaction that
-#' moves the position away from zero to the last transaction that flattens the
-#' position is all one 'trade' for the purposes of this function.
-#'
-#' This is sometimes referred to as 'flat to flat' analysis.
-#'
-#' Note that a trade that is open at the end of the measured period will
-#' be marked to the timestamp of the end of the series.
-#' If that trade is later closed, the stats for it will likely change.
-#' This is 'mark to market' for the open position, and corresponds to
-#' most trade accounting systems and risk systems in including the open
-#' position in reporting.
-#'
-#' @param Portfolio string identifying the portfolio
-#' @param Symbol string identifying the symbol to examin trades for. If missing, the first symbol found in the \code{Portfolio} portfolio will be used
-#' @param includeOpenTrade whether to process only finished trades, or the last trade if it is still open, default TRUE
-#' @param \dots any other passthrough parameters
-#' @author Brian G. Peterson, Jan Humme
-#' @references Tomasini, E. and Jaekle, U. \emph{Trading Systems - A new approach to system development and portfolio optimisation} (ISBN 978-1-905641-79-6)
-#' @return
-#' A \code{data.frame} containing:
-#'
-#' \describe{
-#' \item{Start}{the \code{POSIXct} timestamp of the start of the trade}
-#' \item{End}{the \code{POSIXct} timestamp of the end of the trade, when flat}
-#' \item{Init.Pos}{the initial position on opening the trade}
-#' \item{Max.Pos}{the maximum (largest) position held during the open trade}
-#' \item{Num.Txns}{ the number of transactions included in this trade}
-#' \item{Max.Notional.Cost}{ the largest notional investment cost of this trade}
-#' \item{Net.Trading.PL}{ net trading P&L in the currency of \code{Symbol}}
-#' \item{MAE}{ Maximum Adverse Excursion (MAE), in the currency of \code{Symbol}}
-#' \item{MFE}{ Maximum Favorable Excursion (MFE), in the currency of \code{Symbol}}
-#' \item{Pct.Net.Trading.PL}{ net trading P&L in percent of invested \code{Symbol} price gained or lost}
-#' \item{Pct.MAE}{ Maximum Adverse Excursion (MAE), in percent}
-#' \item{Pct.MFE}{ Maximum Favorable Excursion (MFE), in percent}
-#' \item{tick.Net.Trading.PL}{ net trading P&L in ticks}
-#' \item{tick.MAE}{ Maximum Adverse Excursion (MAE) in ticks}
-#' \item{tick.MFE}{ Maximum Favorable Excursion (MFE) in ticks}
-#' }
-#' @seealso \code{\link{chart.ME}} for a chart of MAE and MFE derived from this function,
-#' and \code{\link{tradeStats}} for a summary view of the performance
-#' @export
-perTradeStats <- function(Portfolio, Symbol, includeOpenTrade=TRUE, ...) {
- portf <- getPortfolio(Portfolio)
-
- if(missing(Symbol)) Symbol <- names(portf$symbols)[[1]]
-
- posPL <- portf$symbols[[Symbol]]$posPL
-
- instr <- getInstrument(Symbol)
- tick_value <- instr$multiplier*instr$tick_size
-
- trades <- list()
-
- # identify start and end for each trade, where end means flat position
- trades$Start <- index(posPL[which(posPL$Pos.Value!=0 & lag(posPL$Pos.Value)==0),])
- trades$End <- index(posPL[which(posPL$Pos.Value==0 & lag(posPL$Pos.Value)!=0),])
-
- # if the last trade is still open, adjust depending on whether wants open trades or not
- if(length(trades$Start)>length(trades$End))
- {
- if(includeOpenTrade)
- trades$End <- c(trades$End,last(index(posPL)))
- else
- trades$Start <- head(trades$Start, -1)
- }
-
- # calculate information about each trade
- for(i in 1:length(trades$End))
- {
- timespan <- paste(format(trades$Start[[i]], "%Y-%m-%d %H:%M:%OS6"),
- format(trades$End[[i]], "%Y-%m-%d %H:%M:%OS6"), sep="::")
-
- trade <- posPL[timespan]
-
- # close and open may occur in at same index timestamp, must be corrected
- if(first(trade)$Pos.Qty==0) trade <- tail(trade, -1)
- if(last(trade)$Pos.Qty!=0) trade <- head(trade, -1)
-
- # add cost basis column
- trade$Pos.Cost.Basis <- cumsum(trade$Txn.Value)
- #add running posPL column
- trade$PosPL <- trade$Pos.Value-trade$Pos.Cost.Basis
-
- #position sizes
- trades$Init.Pos[i] <- first(trade$Pos.Qty)
- trades$Max.Pos[i] <- first(trade[which(abs(trade$Pos.Qty)==max(abs(trade$Pos.Qty))),]$Pos.Qty)
-
- #count number of transactions
- trades$Num.Txns[i]<-length(which(trade$Txn.Value!=0))
-
- # investment
- trades$Max.Notional.Cost[i] <- first(trade[which(abs(trade$Pos.Qty)==max(abs(trade$Pos.Qty))),]$Pos.Cost.Basis)
-
- # cash P&L
- trades$Net.Trading.PL[i] <- last(trade)$PosPL
- trades$MAE[i] <- min(0,trade$PosPL)
- trades$MFE[i] <- max(0,trade$PosPL)
-
- # percentage P&L
- trade$Pct.PL <- trade$PosPL/abs(trade$Pos.Cost.Basis) #broken for last timestamp
- trade$Pct.PL[length(trade$Pct.PL)]<-last(trade)$PosPL/abs(trades$Max.Notional.Cost[i])
-
- trades$Pct.Net.Trading.PL[i] <- last(trade$Pct.PL)
- trades$Pct.MAE[i] <- min(0,trade$Pct.PL)
- trades$Pct.MFE[i] <- max(0,trade$Pct.PL)
-
- # tick P&L
- #Net.Trading.PL/position/tick value=ticks
- trade$tick.PL <- trade$PosPL/abs(trade$Pos.Qty)/tick_value #broken for last observation
- trade$tick.PL[length(trade$tick.PL)] <- last(trade$PosPL)/abs(trades$Max.Pos[i])/tick_value
-
- trades$tick.Net.Trading.PL[i] <- last(trade$tick.PL)
- trades$tick.MAE[i] <- min(0,trade$tick.PL)
- trades$tick.MFE[i] <- max(0,trade$tick.PL)
- }
-
- return(as.data.frame(trades))
-}
-
-# to algorithmically set stops, the classic answer is to calculate quantiles.
-# i'm not sure if this belongs in tradeStats, perhaps?
-# perhaps include MFE and MAE stats in tradeStats, plus some quantile information
-# for MAE of the 90% and 95% quantiles of profitable trades?
-
###############################################################################
# Blotter: Tools for transaction-oriented trading systems development
# for R (see http://r-project.org/)
Copied: pkg/blotter/R/perTradeStats.R (from rev 1187, pkg/blotter/R/chart.ME.R)
===================================================================
--- pkg/blotter/R/perTradeStats.R (rev 0)
+++ pkg/blotter/R/perTradeStats.R 2012-09-15 19:51:01 UTC (rev 1188)
@@ -0,0 +1,223 @@
+#' calculate flat to flat per-trade statistics
+#'
+#' One 'trade' is defined as the entire time the symbol is not flat.
+#' It may contain many transactions. From the initial transaction that
+#' moves the position away from zero to the last transaction that flattens the
+#' position is all one 'trade' for the purposes of this function.
+#'
+#' This is sometimes referred to as 'flat to flat' analysis.
+#'
+#' Note that a trade that is open at the end of the measured period will
+#' be marked to the timestamp of the end of the series.
+#' If that trade is later closed, the stats for it will likely change.
+#' This is 'mark to market' for the open position, and corresponds to
+#' most trade accounting systems and risk systems in including the open
+#' position in reporting.
+#'
+#' @param Portfolio string identifying the portfolio
+#' @param Symbol string identifying the symbol to examin trades for. If missing, the first symbol found in the \code{Portfolio} portfolio will be used
+#' @param includeOpenTrade whether to process only finished trades, or the last trade if it is still open, default TRUE
+#' @param \dots any other passthrough parameters
+#' @author Brian G. Peterson, Jan Humme
+#' @references Tomasini, E. and Jaekle, U. \emph{Trading Systems - A new approach to system development and portfolio optimisation} (ISBN 978-1-905641-79-6)
+#' @return
+#' A \code{data.frame} containing:
+#'
+#' \describe{
+#' \item{Start}{the \code{POSIXct} timestamp of the start of the trade}
+#' \item{End}{the \code{POSIXct} timestamp of the end of the trade, when flat}
+#' \item{Init.Pos}{the initial position on opening the trade}
+#' \item{Max.Pos}{the maximum (largest) position held during the open trade}
+#' \item{Num.Txns}{ the number of transactions included in this trade}
+#' \item{Max.Notional.Cost}{ the largest notional investment cost of this trade}
+#' \item{Net.Trading.PL}{ net trading P&L in the currency of \code{Symbol}}
+#' \item{MAE}{ Maximum Adverse Excursion (MAE), in the currency of \code{Symbol}}
+#' \item{MFE}{ Maximum Favorable Excursion (MFE), in the currency of \code{Symbol}}
+#' \item{Pct.Net.Trading.PL}{ net trading P&L in percent of invested \code{Symbol} price gained or lost}
+#' \item{Pct.MAE}{ Maximum Adverse Excursion (MAE), in percent}
+#' \item{Pct.MFE}{ Maximum Favorable Excursion (MFE), in percent}
+#' \item{tick.Net.Trading.PL}{ net trading P&L in ticks}
+#' \item{tick.MAE}{ Maximum Adverse Excursion (MAE) in ticks}
+#' \item{tick.MFE}{ Maximum Favorable Excursion (MFE) in ticks}
+#' }
+#' @seealso \code{\link{chart.ME}} for a chart of MAE and MFE derived from this function,
+#' and \code{\link{tradeStats}} for a summary view of the performance
+#' @export
+perTradeStats <- function(Portfolio, Symbol, includeOpenTrade=TRUE, ...) {
+ portf <- getPortfolio(Portfolio)
+
+ if(missing(Symbol)) Symbol <- names(portf$symbols)[[1]]
+
+ posPL <- portf$symbols[[Symbol]]$posPL
+
+ instr <- getInstrument(Symbol)
+ tick_value <- instr$multiplier*instr$tick_size
+
+ trades <- list()
+
+ # identify start and end for each trade, where end means flat position
+ trades$Start <- index(posPL[which(posPL$Pos.Value!=0 & lag(posPL$Pos.Value)==0),])
+ trades$End <- index(posPL[which(posPL$Pos.Value==0 & lag(posPL$Pos.Value)!=0),])
+
+ # if the last trade is still open, adjust depending on whether wants open trades or not
+ if(length(trades$Start)>length(trades$End))
+ {
+ if(includeOpenTrade)
+ trades$End <- c(trades$End,last(index(posPL)))
+ else
+ trades$Start <- head(trades$Start, -1)
+ }
+
+ # calculate information about each trade
+ for(i in 1:length(trades$End))
+ {
+ timespan <- paste(format(trades$Start[[i]], "%Y-%m-%d %H:%M:%OS6"),
+ format(trades$End[[i]], "%Y-%m-%d %H:%M:%OS6"), sep="::")
+
+ trade <- posPL[timespan]
+
+ # close and open may occur in at same index timestamp, must be corrected
+ if(first(trade)$Pos.Qty==0) trade <- tail(trade, -1)
+ if(last(trade)$Pos.Qty!=0) trade <- head(trade, -1)
+
+ # add cost basis column
+ trade$Pos.Cost.Basis <- cumsum(trade$Txn.Value)
+ #add running posPL column
+ trade$PosPL <- trade$Pos.Value-trade$Pos.Cost.Basis
+
+ #position sizes
+ trades$Init.Pos[i] <- first(trade$Pos.Qty)
+ trades$Max.Pos[i] <- first(trade[which(abs(trade$Pos.Qty)==max(abs(trade$Pos.Qty))),]$Pos.Qty)
+
+ #count number of transactions
+ trades$Num.Txns[i]<-length(which(trade$Txn.Value!=0))
+
+ # investment
+ trades$Max.Notional.Cost[i] <- first(trade[which(abs(trade$Pos.Qty)==max(abs(trade$Pos.Qty))),]$Pos.Cost.Basis)
+
+ # cash P&L
+ trades$Net.Trading.PL[i] <- last(trade)$PosPL
+ trades$MAE[i] <- min(0,trade$PosPL)
+ trades$MFE[i] <- max(0,trade$PosPL)
+
+ # percentage P&L
+ trade$Pct.PL <- trade$PosPL/abs(trade$Pos.Cost.Basis) #broken for last timestamp
+ trade$Pct.PL[length(trade$Pct.PL)]<-last(trade)$PosPL/abs(trades$Max.Notional.Cost[i])
+
+ trades$Pct.Net.Trading.PL[i] <- last(trade$Pct.PL)
+ trades$Pct.MAE[i] <- min(0,trade$Pct.PL)
+ trades$Pct.MFE[i] <- max(0,trade$Pct.PL)
+
+ # tick P&L
+ #Net.Trading.PL/position/tick value=ticks
+ trade$tick.PL <- trade$PosPL/abs(trade$Pos.Qty)/tick_value #broken for last observation
+ trade$tick.PL[length(trade$tick.PL)] <- last(trade$PosPL)/abs(trades$Max.Pos[i])/tick_value
+
+ trades$tick.Net.Trading.PL[i] <- last(trade$tick.PL)
+ trades$tick.MAE[i] <- min(0,trade$tick.PL)
+ trades$tick.MFE[i] <- max(0,trade$tick.PL)
+ }
+
+ return(as.data.frame(trades))
+}
+
+#' quantiles of per-trade stats
+#' @param Portfolio string identifying the portfolio
+#' @param Symbol string identifying the symbol to examin trades for. If missing, the first symbol found in the \code{Portfolio} portfolio will be used
+#' @param \dots any other passthrough parameters
+#' @param scale string specifying 'cash', or 'percent' for percentage of investment, or 'tick'
+#' @param probs vector of probabilities for \code{quantile}
+#' @author Brian G. Peterson
+#' @references Tomasini, E. and Jaekle, U. \emph{Trading Systems - A new approach to system development and portfolio optimisation} (ISBN 978-1-905641-79-6)
+#' @export
+tradeQuantiles <- function(Portfolio, Symbol, ..., scale=c('cash','percent','tick'),probs=c(.5,.75,.9,.95,.99,1))
+{
+ trades <- perTradeStats(Portfolio, Symbol, ...)
+
+ post <- trades[trades$Net.Trading.PL>0,]
+ negt <- trades[trades$Net.Trading.PL<0,]
+
+ ret<-NULL
+ for (sc in scale){
+ switch(sc,
+ cash = {
+ posq <- quantile(post$Net.Trading.PL,probs=probs)
+ names(posq)<-paste('posPL',names(posq))
+
+ negq <- -1*quantile(abs(negt$Net.Trading.PL),probs=probs)
+ names(negq)<-paste('negPL',names(negq))
+
+ posMFEq <-quantile(post$MFE,probs=probs)
+ names(posMFEq) <- paste('posMFE',names(posMFEq))
+ posMAEq <--1*quantile(abs(post$MAE),probs=probs)
+ names(posMAEq) <- paste('posMAE',names(posMAEq))
+
+ negMFEq <-quantile(negt$MFE,probs=probs)
+ names(negMFEq) <- paste('negMFE',names(negMFEq))
+ negMAEq <--1*quantile(abs(negt$MAE),probs=probs)
+ names(negMAEq) <- paste('negMAE',names(negMAEq))
+
+ ret<-c(ret,posq,negq,posMFEq,posMAEq,negMFEq,negMAEq)
+ },
+ percent = {
+ posq <- quantile(post$Pct.Net.Trading.PL,probs=probs)
+ names(posq)<-paste('posPctPL',names(posq))
+
+ negq <- -1*quantile(abs(negt$Pct.Net.Trading.PL),probs=probs)
+ names(negq)<-paste('negPctPL',names(negq))
+
+ posMFEq <-quantile(post$Pct.MFE,probs=probs)
+ names(posMFEq) <- paste('posPctMFE',names(posMFEq))
+ posMAEq <--1*quantile(abs(post$Pct.MAE),probs=probs)
+ names(posMAEq) <- paste('posPctMAE',names(posMAEq))
+
+ negMFEq <-quantile(negt$Pct.MFE,probs=probs)
+ names(negMFEq) <- paste('negPctMFE',names(negMFEq))
+ negMAEq <--1*quantile(abs(negt$Pct.MAE),probs=probs)
+ names(negMAEq) <- paste('negPctMAE',names(negMAEq))
+
+ ret<-c(ret,posq,negq,posMFEq,posMAEq,negMFEq,negMAEq) },
+ tick = {
+ posq <- quantile(post$tick.Net.Trading.PL,probs=probs)
+ names(posq)<-paste('posTickPL',names(posq))
+
+ negq <- -1*quantile(abs(negt$tick.Net.Trading.PL),probs=probs)
+ names(negq)<-paste('negTickPL',names(negq))
+
+ posMFEq <-quantile(post$tick.MFE,probs=probs)
+ names(posMFEq) <- paste('posTickMFE',names(posMFEq))
+ posMAEq <--1*quantile(abs(post$tick.MAE),probs=probs)
+ names(posMAEq) <- paste('posTickMAE',names(posMAEq))
+
+ negMFEq <-quantile(negt$tick.MFE,probs=probs)
+ names(negMFEq) <- paste('negTickMFE',names(negMFEq))
+ negMAEq <--1*quantile(abs(negt$tick.MAE),probs=probs)
+ names(negMAEq) <- paste('negTickMAE',names(negMAEq))
+
+ ret<-c(ret,posq,negq,posMFEq,posMAEq,negMFEq,negMAEq)
+ }
+ ) #end scale switch
+ } #end for loop
+
+ #return a single column for now, could be multiple column if we looped on Symbols
+ ret<-t(t(ret))
+ colnames(ret)<-Symbol
+ ret
+}
+
+# to algorithmically set stops, the classic answer is to calculate quantiles.
+# i'm not sure if this belongs in tradeStats, perhaps?
+# perhaps include MFE and MAE stats in tradeStats, plus some quantile information
+# for MAE of the 90% and 95% quantiles of profitable trades?
+
+################tradeQuantiles('bbands','IBM')###############################################################
+# Blotter: Tools for transaction-oriented trading systems development
+# for R (see http://r-project.org/)
+# Copyright (c) 2008-2011 Peter Carl and Brian G. Peterson
+#
+# This library is distributed under the terms of the GNU Public License (GPL)
+# for full details see the file COPYING
+#
+# $Id$
+#
+###############################################################################
Modified: pkg/blotter/man/chart.ME.Rd
===================================================================
--- pkg/blotter/man/chart.ME.Rd 2012-09-15 16:07:10 UTC (rev 1187)
+++ pkg/blotter/man/chart.ME.Rd 2012-09-15 19:51:01 UTC (rev 1188)
@@ -1,6 +1,6 @@
\name{chart.ME}
\alias{chart.ME}
-\title{Chart Maximum Adverse/Forward Excursion}
+\title{Chart Maximum Adverse/Favorable Excursion}
\usage{
chart.ME(Portfolio, Symbol, type = c("MAE", "MFE"),
scale = c("cash", "percent", "tick"), ...)
Added: pkg/blotter/man/tradeQuantiles.Rd
===================================================================
--- pkg/blotter/man/tradeQuantiles.Rd (rev 0)
+++ pkg/blotter/man/tradeQuantiles.Rd 2012-09-15 19:51:01 UTC (rev 1188)
@@ -0,0 +1,34 @@
+\name{tradeQuantiles}
+\alias{tradeQuantiles}
+\title{quantiles of per-trade stats}
+\usage{
+ tradeQuantiles(Portfolio, Symbol, ...,
+ scale = c("cash", "percent", "tick"),
+ probs = c(0.5, 0.75, 0.9, 0.95, 0.99, 1))
+}
+\arguments{
+ \item{Portfolio}{string identifying the portfolio}
+
+ \item{Symbol}{string identifying the symbol to examin
+ trades for. If missing, the first symbol found in the
+ \code{Portfolio} portfolio will be used}
+
+ \item{\dots}{any other passthrough parameters}
+
+ \item{scale}{string specifying 'cash', or 'percent' for
+ percentage of investment, or 'tick'}
+
+ \item{probs}{vector of probabilities for \code{quantile}}
+}
+\description{
+ quantiles of per-trade stats
+}
+\author{
+ Brian G. Peterson
+}
+\references{
+ Tomasini, E. and Jaekle, U. \emph{Trading Systems - A new
+ approach to system development and portfolio
+ optimisation} (ISBN 978-1-905641-79-6)
+}
+
More information about the Blotter-commits
mailing list