pl: Profit and Loss

View source: R/pl.R

plR Documentation

Profit and Loss

Description

Compute profit and (or) loss of financial transactions.

Usage

pl(amount, ... )

## Default S3 method:
pl(amount, price, timestamp = NULL,
   instrument = NULL, multiplier = 1,
   multiplier.regexp = FALSE,
   along.timestamp = FALSE, approx = FALSE,
   initial.position = NULL, initial.price = NULL,
   vprice = NULL, tol = 1e-10, do.warn = TRUE,
   do.sum = FALSE, pl.only = FALSE,
   footnotes = TRUE, ... )

## S3 method for class 'journal'
pl(amount, multiplier = 1,
   multiplier.regexp = FALSE,
   along.timestamp = FALSE, approx = FALSE,
   initial.position = NULL, initial.price = NULL,
   vprice = NULL, tol = 1e-10, do.warn = TRUE, ... )

## S3 method for class 'pl'
pl(amount, ... )

## S3 method for class 'pl'
print(x, ..., use.crayon = NULL, na.print = ".",
        footnotes = TRUE)

## S3 method for class 'pl'
as.data.frame(x, ... )

.pl(amount, price, tol = 1e-10, do.warn = TRUE)
.pl_stats(amount, price, tol = sqrt(.Machine$double.eps))

Arguments

amount

numeric or a journal

price

numeric

instrument

character or numeric (though typically character)

timestamp

An atomic vector of mode numeric or character. Timestamps should typically be sortable.

along.timestamp

logical; or a a vector of timestamps. If the latter, vprice must be specified as well. See the vignette “Profit/Loss for Open Positions” (pl_open_positions) for details. Timestamps must be in ascending order and will be sorted if they are not (and vprice will then be sorted as well).

initial.position

a position

initial.price

prices to evaluate initial position

vprice

valuation price; a numeric vector. With several instruments, the prices must be named, e.g. c(stock1 = 100, stock2 = 101). See Details.

multiplier

numeric vector. When instrument is specified and the vector is named, the names will be matched against instruments.

multiplier.regexp

logical. If TRUE, the names of multiplier are interpreted as regular expressions. See Examples.

approx

logical

tol

numeric: threshold to consider a position zero.

x

a pl object to be printed or to be coerced to a data.frame

...

further argument

use.crayon

logical

na.print

character: how to print NA values

do.warn

logical: issue warnings?

do.sum

logical: sum profit/loss across instruments?

pl.only

logical: if TRUE, return only numeric vector of profit/loss

footnotes

logical, with default TRUE: collect and print notes?

Details

Computes profit and/or loss and returns a list with several statistics (see Section Value, below). To get only the profit/loss numbers as a numeric vector, set argument pl.only to TRUE.

pl is a generic function: The default input is vectors for amount, price, etc. Alternatively (and often more conveniently), the function may also be called with a journal or a data.frame as its input. For data frames, columns must be named amount, price, and so on, as in a journal.

pl may be called in two ways: either to compute total profit/loss from a list of trades, possibly broken down by instrument and account; or to compute profit/loss over time. The latter case typically requires setting arguments along.timestamp and/or vprice (see Examples). Profit/loss over time is always computed with time in ascending order: so if the timestamps in along.timestamp are not sorted, the function will sort them (and vprice as well).

Using vprice: when along.timestamp is logical (FALSE or TRUE), vprice can be used to value an open position. For a single asset, it should be a single number; for several assets, it should be named vector, with names indicating the instrument. When along.timestamp is used to pass a custom timestamp: for a single asset, vprice must be a vector with the same length as along.timestamp; for several assets, it must be a numeric matrix with dimension length(along.timestamp) times number of assets.

.pl and .pl_stats are helper functions that are called by pl. .pl_stats requires amount and price to be sorted in time, and to be of length > 0.

To use package crayon – which is only sensible in interactive use –, either explicitly set use.crayon to TRUE or set an option PMwR.use.crayon to TRUE.

Value

For pl, an object of class pl, which is a list of lists: one list for each instrument. Each such list contains numeric vectors: pl, realised, unrealised, buy, sell, volume. If along.timestamp is not FALSE, a vector timestamp is also present.

For .pl, a numeric vector with four elements: profit/loss in units of the instrument, sum of absolute amounts, average buy price, average sell price. For zero-length vector, the function evaluates to c(0, 0, NaN, NaN).

For .pl_stats, a list of two elements: the average entry-price, and the realized profit/loss. profit/loss in units of the instrument, sum of absolute amounts, average buy price, average sell price. For zero-length vector, the function evaluates to c(0, 0, NaN, NaN).

Author(s)

Enrico Schumann <es@enricoschumann.net>

References

Schumann, E. (2023) Portfolio Management with R. http://enricoschumann.net/PMwR/; in particular http://enricoschumann.net/R/packages/PMwR/manual/PMwR.html#profit-and-loss

See Also

btest, returns

Examples

J <- journal(timestamp = c(  1,   2,   3),
             amount    = c(  1,   1,  -2),
             price     = c(100, 102, 101))
pl(J)

pl(amount = c(  1,   1,  -2),
   price  = c(100, 102, 101))  ## without a 'journal'


J <- journal(timestamp  = c(  1,   2,   3,   1,   2,   3),
             amount     = c(  1,   1,  -2,   1,   1,  -2),
             price      = c(100, 102, 101, 100, 102, 105),
             instrument = c(rep("Bond A", 3), rep("Bond B", 3)))

pl(J)
## Bond A
##   P/L total       0
##   average buy   101
##   average sell  101
##   cum. volume     4
##
## Bond B
##   P/L total       8
##   average buy   101
##   average sell  105
##   cum. volume     4
##
## 'P/L total' is in units of instrument;
## 'volume' is sum of /absolute/ amounts.

as.data.frame(pl(J))  ## a single data.frame
##        pl buy sell volume
## Bond A  0 101  101      4
## Bond B  8 101  105      4

lapply(pl(J), as.data.frame)  ## => a list of data.frames
## $`Bond A`
##   pl realised unrealised buy sell volume
## 1  0       NA         NA 101  101      4
##
## $`Bond B`
##   pl realised unrealised buy sell volume
## 1  8       NA         NA 101  105      4

pl(pl(J))  ## P/L as a numeric vector
## Bond A Bond B
##      0      8




## Example for 'vprice'
instrument  <- c(rep("Bond A", 2), rep("Bond B", 2))
amount <- c(1, -2, 2, -1)
price <- c(100, 101, 100, 105)

## ... no p/l because positions not closed:
pl(amount, price, instrument = instrument, do.warn = FALSE)

## ... but with vprice specified, p/l is computed:
pl(amount, price, instrument = instrument,
   vprice = c("Bond A" = 103, "Bond B" = 100))

### ... and is, except for volume, the same as here:
instrument  <- c(rep("Bond A", 3), rep("Bond B", 3))
amount <- c(1, -2, 1, 2, -1, -1)
price <- c(100, 101, 103, 100, 105, 100)
pl(amount, price, instrument = instrument)



## p/l over time: example for 'along.timestamp' and 'vprice'
j <- journal(amount = c(1, -1),
             price = c(100, 101),
             timestamp  = as.Date(c("2017-07-05", "2017-07-06")))
pl(j)

pl(j,
   along.timestamp = TRUE)

pl(j,
   along.timestamp = seq(from = as.Date("2017-07-04"),
                         to = as.Date("2017-07-07"),
                         by = "1 day"),
   vprice = 101:104)



## Example for 'multiplier'
jnl <- read.table(text =
"instrument, price, amount
 FGBL MAR 16, 165.20,  1
 FGBL MAR 16, 165.37, -1
 FGBL JUN 16, 164.12,  1
 FGBL JUN 16, 164.13, -1
 FESX JUN 16,   2910,  5
 FESX JUN 16,   2905, -5",
header = TRUE, stringsAsFactors = FALSE, sep = ",")


jnl <- as.journal(jnl)
pl(jnl,  multiplier.regexp = TRUE, ## regexp matching is case sensitive
   multiplier = c("FGBL" = 1000, "FESX" = 10))



## use package 'crayon'
## Not run: 
## on Windows, you may also need 'options(crayon.enabled = TRUE)'
options(PMwR.use.crayon = FALSE)
pl(amount = c(1, -1), price = c(1, 2))
options(PMwR.use.crayon = TRUE)
pl(amount = c(1, -1), price = c(1, 2))

## End(Not run)


enricoschumann/PMwR documentation built on April 13, 2024, 12:18 p.m.