SCM

SCM Repository

[blotter] Annotation of /pkg/blotter/R/addTxn.R
ViewVC logotype

Annotation of /pkg/blotter/R/addTxn.R

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1081 - (view) (download)

1 : peter_carl 478 #' Add transactions to a portfolio.
2 : braverock 133 #'
3 : braverock 513 #' When a trade or adjustment is made to the Portfolio, the addTxn function
4 :     #' calculates the value and average cost of the transaction, the change in
5 : peter_carl 526 #' position, the resulting positions average cost, and any realized profit
6 : braverock 513 #' or loss (net of fees) from the transaction. Then it stores the transaction
7 :     #' and calculations in the Portfolio object.
8 : peter_carl 478 #'
9 : braverock 513 #' Fees are indicated as negative values and will be subtracted from the
10 :     #' transaction value. TxnFees can either be a fixed amount, or a function
11 : peter_carl 526 #' in which case the function is evaluated to
12 : braverock 513 #' determine the fee amount.
13 : peter_carl 526 #' The \code{pennyPerShare} function provides a simple example of a transaction cost
14 :     #' function.
15 : braverock 133 #'
16 : braverock 1007 #' Transactions which would cross your position through zero will be split
17 :     #' into two transactions, one to flatten the position, and another to initiate
18 :     #' a new position on the opposite side of the market. The new (split)
19 :     #' transaction will have it's timestamp inclremented by eps to preserve ordering.
20 :     #' This transaction splitting vastly simplifies realized P&L calculations elsewhere in the code.
21 :     #'
22 : peter_carl 526 #' @param Portfolio A portfolio name that points to a portfolio object structured with \code{initPortf()}
23 :     #' @param Symbol An instrument identifier for a symbol included in the portfolio, e.g., "IBM"
24 : peter_carl 478 #' @param TxnDate Transaction date as ISO 8601, e.g., '2008-09-01' or '2010-01-05 09:54:23.12345'
25 :     #' @param TxnQty Total units (such as shares or contracts) transacted. Positive values indicate a 'buy'; negative values indicate a 'sell'
26 :     #' @param TxnPrice Price at which the transaction was done
27 :     #' @param \dots Any other passthrough parameters
28 :     #' @param TxnFees Fees associated with the transaction, e.g. commissions., See Details
29 : braverock 513 #' @param ConMult Contract/instrument multiplier for the Symbol if it is not dened in an instrument specication
30 : bodanker 571 #' @param verbose If TRUE (default) the function prints the elements of the transaction in a line to the screen, e.g., "2007-01-08 IBM 50 @@ 77.6". Suppress using FALSE.
31 : braverock 1007 #' @param eps value to add to force unique indices
32 : braverock 513 #' @note
33 :     #' The addTxn function will eventually also handle other transaction types,
34 :     #' such as adjustments for corporate actions or expire/assign for options.
35 : peter_carl 526
36 : peter_carl 478 #' @seealso \code{\link{addTxns}}, \code{\link{pennyPerShare}}, \code{\link{initPortf}}
37 : braverock 133 #' @author Peter Carl
38 :     #' @export
39 : braverock 1007 addTxn <- function(Portfolio, Symbol, TxnDate, TxnQty, TxnPrice, ..., TxnFees=0, ConMult=NULL, verbose=TRUE, eps=1e-06)
40 : peter_carl 3 { # @author Peter Carl
41 : braverock 394
42 : braverock 1007 pname <- Portfolio
43 :     PrevPosQty = getPosQty(pname, Symbol, TxnDate)
44 : braverock 1052
45 : braverock 1053 if(!is.timeBased(TxnDate) ){
46 : braverock 1052 TxnDate<-as.POSIXct(TxnDate)
47 :     }
48 :    
49 : braverock 1007 # split transactions that would cross through zero
50 :     if(PrevPosQty!=0 && sign(PrevPosQty+TxnQty)!=sign(PrevPosQty) && PrevPosQty!=-TxnQty){
51 :     addTxn(Portfolio=pname, Symbol=Symbol, TxnDate=TxnDate, TxnQty=-PrevPosQty, TxnPrice=TxnPrice, ...,
52 :     TxnFees = TxnFees, ConMult = ConMult, verbose = verbose, eps=eps)
53 : braverock 1052 TxnDate=TxnDate+2*eps #transactions need unique timestamps, so increment a bit
54 : braverock 1007 TxnQty=TxnQty+PrevPosQty
55 :     PrevPosQty=0
56 :     }
57 :    
58 : braverock 133 Portfolio<-get(paste("portfolio",pname,sep='.'),envir=.blotter)
59 : braverock 394
60 : braverock 171 if(is.null(ConMult) | !hasArg(ConMult)){
61 : braverock 153 tmp_instr<-try(getInstrument(Symbol))
62 : braverock 171 if(inherits(tmp_instr,"try-error") | !is.instrument(tmp_instr)){
63 : peter_carl 156 warning(paste("Instrument",Symbol," not found, using contract multiplier of 1"))
64 : braverock 153 ConMult<-1
65 :     } else {
66 :     ConMult<-tmp_instr$multiplier
67 : braverock 394 }
68 : braverock 153 }
69 : braverock 394
70 : braverock 352 #If there is no table for the symbol then create a new one
71 : braverock 378 if (is.null(Portfolio$symbols[[Symbol]])){
72 : braverock 352 addPortfInstr(Portfolio=pname, symbols=Symbol)
73 :     Portfolio<-get(paste("portfolio",pname,sep='.'),envir=.blotter)
74 :     }
75 :    
76 : peter_carl 3
77 :     # FUNCTION
78 : edd 66 # Compute transaction fees if a function was supplied
79 : braverock 395 if (is.function(TxnFees)) txnfees <- TxnFees(TxnQty, TxnPrice) else txnfees<- as.numeric(TxnFees)
80 : braverock 394 if(is.null(txnfees) | is.na(txnfees)) txnfees = 0
81 : gsee 622 if(txnfees>0) warning('Positive Transaction Fees should only be used in the case of broker/exchange rebates for TxnFees ',TxnFees,'. See Documentation.')
82 : braverock 509
83 : peter_carl 3 # Calculate the value and average cost of the transaction
84 : braverock 524 TxnValue = .calcTxnValue(TxnQty, TxnPrice, 0, ConMult) # Gross of Fees
85 :     TxnAvgCost = .calcTxnAvgCost(TxnValue, TxnQty, ConMult)
86 : peter_carl 3
87 :     # Calculate the change in position
88 : edd 66 PosQty = PrevPosQty + TxnQty
89 : peter_carl 3
90 : braverock 1007
91 : peter_carl 3 # Calculate the resulting position's average cost
92 : braverock 438 PrevPosAvgCost = .getPosAvgCost(pname, Symbol, TxnDate)
93 : braverock 524 PosAvgCost = .calcPosAvgCost(PrevPosQty, PrevPosAvgCost, TxnValue, PosQty, ConMult)
94 : peter_carl 3
95 : braverock 412
96 : peter_carl 3 # Calculate any realized profit or loss (net of fees) from the transaction
97 : braverock 412 GrossTxnRealizedPL = TxnQty * ConMult * (PrevPosAvgCost - TxnAvgCost)
98 : peter_carl 3
99 : braverock 412 # if the previous position is zero, RealizedPL = 0
100 :     # if previous position is positive and position is larger, RealizedPL =0
101 :     # if previous position is negative and position is smaller, RealizedPL =0
102 :     if(abs(PrevPosQty) < abs(PosQty) | (PrevPosQty = 0))
103 :     GrossTxnRealizedPL = 0
104 :    
105 :     NetTxnRealizedPL = GrossTxnRealizedPL + txnfees
106 : braverock 1052
107 : peter_carl 3 # Store the transaction and calculations
108 : braverock 572 NewTxn = xts(t(c(TxnQty, TxnPrice, TxnValue, TxnAvgCost, PosQty, PosAvgCost, GrossTxnRealizedPL, txnfees, NetTxnRealizedPL, ConMult)), order.by=TxnDate)
109 : peter_carl 306 #colnames(NewTxns) = c('Txn.Qty', 'Txn.Price', 'Txn.Value', 'Txn.Avg.Cost', 'Pos.Qty', 'Pos.Avg.Cost', 'Gross.Txn.Realized.PL', 'Txn.Fees', 'Net.Txn.Realized.PL', 'Con.Mult')
110 : braverock 378 Portfolio$symbols[[Symbol]]$txn<-rbind(Portfolio$symbols[[Symbol]]$txn, NewTxn)
111 : peter_carl 3
112 :     if(verbose)
113 : opentrades 1079 # print(paste(TxnDate, Symbol, TxnQty, "@",TxnPrice, sep=" "))
114 : opentrades 1081 print(paste(format(TxnDate, "%Y-%m-%d %H:%M:%S"), Symbol, TxnQty, "@",TxnPrice, sep=" "))
115 : braverock 378 #print(Portfolio$symbols[[Symbol]]$txn)
116 : braverock 133
117 :     assign(paste("portfolio",pname,sep='.'),Portfolio,envir=.blotter)
118 : peter_carl 3 }
119 :    
120 : peter_carl 478 #' Example TxnFee cost function
121 : braverock 440 #' @param TxnQty total units (such as shares or contracts) transacted. Positive values indicate a 'buy'; negative values indicate a 'sell'
122 : peter_carl 469 #' This is an example intended to demonstrate how a cost function could be used in place of a flat numeric fee.
123 : braverock 440 #' @export
124 : peter_carl 469 pennyPerShare <- function(TxnQty) {
125 :     return(abs(TxnQty) * -0.01)
126 : edd 66 }
127 :    
128 : peter_carl 478 #' Add multiple transactions to a portfolio
129 : peter_carl 529 #' @param Portfolio A portfolio name that points to a portfolio object structured with \code{\link{initPortf}}
130 :     #' @param Symbol An instrument identifier for a symbol included in the portfolio, e.g., "IBM"
131 : peter_carl 478 #' @param TxnData An xts object containing all required txn fields
132 :     #' @param \dots Any other passthrough parameters
133 : bodanker 571 #' @param verbose If TRUE (default) the function prints the elements of the transaction in a line to the screen, e.g., "2007-01-08 IBM 50 @@ 77.6". Suppress using FALSE.
134 : braverock 513 #' @param ConMult Contract or instrument multiplier for the Symbol if it is not dened in an instrument specication
135 : peter_carl 478 #' @seealso \code{\link{addTxn}}, \code{\link{initPortf}}
136 : peter_carl 528 #' @note
137 : braverock 489 #' TODO figure out if we can fully vectorize this function to make it faster
138 : braverock 153 addTxns<- function(Portfolio, Symbol, TxnData , verbose=TRUE, ..., ConMult=NULL)
139 : braverock 137 {
140 :     pname<-Portfolio
141 :     Portfolio<-get(paste("portfolio",pname,sep='.'),envir=.blotter)
142 :    
143 : braverock 171 if(is.null(ConMult) | !hasArg(ConMult)){
144 : braverock 153 tmp_instr<-try(getInstrument(Symbol))
145 : braverock 171 if(inherits(tmp_instr,"try-error") | !is.instrument(tmp_instr)){
146 :     warning(paste("Instrument",Symbol," not found, using contract multiplier of 1"))
147 : braverock 153 ConMult<-1
148 :     } else {
149 :     ConMult<-tmp_instr$multiplier
150 :     }
151 : braverock 509 }
152 : braverock 153
153 : braverock 137 for (row in 1:nrow(TxnData)) {
154 : braverock 139 if(row==1) {
155 :     PrevPosQty <- getPosQty(pname, Symbol, index(TxnData[row,]))
156 : braverock 438 PrevPosAvgCost <- .getPosAvgCost(pname, Symbol, index(TxnData[row,]))
157 : braverock 139 }
158 : braverock 137 #TODO create vectorized versions of all these functions so we don't have to loop
159 : braverock 138 TxnQty <- as.numeric(TxnData[row,'Quantity'])
160 :     TxnPrice <- as.numeric(TxnData[row,'Price'])
161 : braverock 137 TxnFee <- 0 #TODO FIXME support transaction fees in addTxns
162 : braverock 153 #TxnFee <- ifelse( is.function(TxnFees), TxnFees(TxnQty, TxnPrice), TxnFees)
163 : braverock 524 TxnValue <- .calcTxnValue(TxnQty, TxnPrice, TxnFee, ConMult)
164 :     TxnAvgCost <- .calcTxnAvgCost(TxnValue, TxnQty, ConMult)
165 : braverock 139 #PrevPosQty <- getPosQty(pname, Symbol, index(TxnData[row,]))
166 : braverock 137 PosQty <- PrevPosQty+TxnQty
167 : braverock 524 PosAvgCost <- .calcPosAvgCost(PrevPosQty, PrevPosAvgCost, 0, PosQty, ConMult) # lag this over the data?
168 : braverock 413 GrossTxnRealizedPL = TxnQty * ConMult * (PrevPosAvgCost - TxnAvgCost)
169 :     NetTxnRealizedPL = GrossTxnRealizedPL - TxnFee
170 : braverock 139 PrevPosQty <- PosQty
171 :     PrevPosAvgCost <- PosAvgCost
172 : braverock 137
173 :     NewTxn = xts(t(c(TxnQty,
174 :     TxnPrice,
175 :     TxnValue,
176 :     TxnAvgCost,
177 :     PosQty,
178 :     PosAvgCost,
179 : peter_carl 306 GrossTxnRealizedPL,
180 :     TxnFee,
181 :     NetTxnRealizedPL,
182 : braverock 153 ConMult)),
183 : braverock 137 order.by=index(TxnData[row,]))
184 : braverock 138
185 : braverock 137 if(row==1){
186 :     NewTxns <- NewTxn
187 : peter_carl 306 colnames(NewTxns) = c('Txn.Qty', 'Txn.Price', 'Txn.Value', 'Txn.Avg.Cost', 'Pos.Qty', 'Pos.Avg.Cost', 'Gross.Txn.Realized.PL', 'Txn.Fees', 'Net.Txn.Realized.PL', 'Con.Mult')
188 : braverock 137 } else {
189 :     NewTxns<-rbind(NewTxns, NewTxn)
190 :     }
191 :     }
192 : braverock 378 Portfolio$symbols[[Symbol]]$txn<-rbind(Portfolio$symbols[[Symbol]]$txn,NewTxns)
193 : braverock 137
194 :     if(verbose) print(NewTxns)
195 :    
196 :     assign(paste("portfolio",pname,sep='.'),Portfolio,envir=.blotter)
197 :     }
198 :    
199 : peter_carl 478 #' Add cash dividend transactions to a portfolio.
200 : braverock 438 #'
201 : peter_carl 478 #' Adding a cash dividend does not affect position quantity, like a split would.
202 : braverock 440 #'
203 : peter_carl 529 #' @param Portfolio A portfolio name that points to a portfolio object structured with \code{\link{initPortf}}.
204 : peter_carl 526 #' @param Symbol An instrument identifier for a symbol included in the portfolio, e.g., IBM.
205 : peter_carl 478 #' @param TxnDate Transaction date as ISO 8601, e.g., '2008-09-01' or '2010-01-05 09:54:23.12345'.
206 :     #' @param DivPerShare The amount of the cash dividend paid per share or per unit quantity.
207 :     #' @param \dots Any other passthrough parameters.
208 : peter_carl 529 #' @param TxnFees Fees associated with the transaction, e.g. commissions. See Details.
209 : bodanker 571 #' @param verbose If TRUE (default) the function prints the elements of the transaction in a line to the screen, e.g., "2007-01-08 IBM 50 @@ 77.6". Suppress using FALSE.
210 : braverock 513 #' @param ConMult Contract or instrument multiplier for the Symbol if it is not dened in an instrument specication.
211 : braverock 438 #' @export
212 : braverock 513 #' @note
213 : braverock 489 #' # TODO add TxnTypes to $txn table
214 :     #'
215 :     #' # TODO add AsOfDate
216 :     #'
217 : peter_carl 308 addDiv <- function(Portfolio, Symbol, TxnDate, DivPerShare, ..., TxnFees=0, ConMult=NULL, verbose=TRUE)
218 :     { # @author Peter Carl
219 :     pname<-Portfolio
220 :     Portfolio<-get(paste("portfolio",pname,sep='.'),envir=.blotter)
221 :    
222 :     if(is.null(ConMult) | !hasArg(ConMult)){
223 :     tmp_instr<-try(getInstrument(Symbol))
224 :     if(inherits(tmp_instr,"try-error") | !is.instrument(tmp_instr)){
225 :     warning(paste("Instrument",Symbol," not found, using contract multiplier of 1"))
226 :     ConMult<-1
227 :     } else {
228 :     ConMult<-tmp_instr$multiplier
229 :     }
230 :     }
231 :    
232 :     # FUNCTION
233 : braverock 440 #
234 : peter_carl 308 TxnQty = 0
235 :     TxnPrice = 0
236 :     # TxnType = "Dividend"
237 :     # TODO add TxnTypes to $txn table
238 :    
239 :     # Get the current position quantity
240 :     PrevPosQty = getPosQty(pname, Symbol, TxnDate)
241 :     PosQty = PrevPosQty # no change to position, but carry it forward
242 :     # Calculate the value and average cost of the transaction
243 :     # The -1 multiplier allows a positive DivPerShare value to create a
244 :     # positive realized gain
245 :     TxnValue = -1 * PrevPosQty * DivPerShare * ConMult # Calc total dividend paid
246 :     TxnAvgCost = DivPerShare
247 :    
248 :     # No change to the the resulting position's average cost
249 : braverock 438 PrevPosAvgCost = .getPosAvgCost(pname, Symbol, TxnDate)
250 : peter_carl 308 PosAvgCost = PrevPosAvgCost # but carry it forward in $txn
251 :    
252 :     # Calculate any realized profit or loss (net of fees) from the transaction
253 :     GrossTxnRealizedPL = PrevPosQty * DivPerShare * ConMult
254 :     NetTxnRealizedPL = GrossTxnRealizedPL + TxnFees
255 :    
256 :     # Store the transaction and calculations
257 :     NewTxn = xts(t(c(TxnQty, TxnPrice, TxnValue, TxnAvgCost, PosQty, PosAvgCost, GrossTxnRealizedPL, TxnFees, NetTxnRealizedPL, ConMult)), order.by=as.POSIXct(TxnDate))
258 :     #colnames(NewTxns) = c('Txn.Qty', 'Txn.Price', 'Txn.Value', 'Txn.Avg.Cost', 'Pos.Qty', 'Pos.Avg.Cost', 'Gross.Txn.Realized.PL', 'Txn.Fees', 'Net.Txn.Realized.PL', 'Con.Mult')
259 : braverock 378 Portfolio$symbols[[Symbol]]$txn<-rbind(Portfolio$symbols[[Symbol]]$txn, NewTxn)
260 : peter_carl 308
261 :     if(verbose)
262 : gsee 657 print(paste(TxnDate, Symbol, "Dividend", DivPerShare, "on", PrevPosQty, "shares:", -TxnValue, sep=" "))
263 : braverock 378 #print(Portfolio$symbols[[Symbol]]$txn)
264 : peter_carl 308
265 :     assign(paste("portfolio",pname,sep='.'),Portfolio,envir=.blotter)
266 :     }
267 : peter_carl 3 ###############################################################################
268 :     # Blotter: Tools for transaction-oriented trading systems development
269 : edd 66 # for R (see http://r-project.org/)
270 : braverock 516 # Copyright (c) 2008-2011 Peter Carl and Brian G. Peterson
271 : peter_carl 3 #
272 :     # This library is distributed under the terms of the GNU Public License (GPL)
273 :     # for full details see the file COPYING
274 :     #
275 : peter_carl 44 # $Id$
276 : peter_carl 3 #
277 :     ###############################################################################

root@r-forge.r-project.org
ViewVC Help
Powered by ViewVC 1.0.0  
Thanks to:
Vienna University of Economics and Business Powered By FusionForge