benchTradePerf: Trade Execution Performance Benchmarks

View source: R/benchTradePerf.R

benchTradePerfR Documentation

Trade Execution Performance Benchmarks

Description

This function gathers different benchmarking methods used to evaluate the average execution price P_{avg} of a given trading strategy. When sensical the relavant quantities are compoted in a period-by-period cumulative fashion. The P_{avg} is compared against a number of benchmark metrics, in order to assess its performance in terms of profit or loss relative to a given benchmark. These benchmarks are not mutually exclusive, each of them provides different insights and may have shortcomings. They can be used in conjuction to account for this aspects.

Usage

benchTradePerf(Portfolio, Symbol, side = 1, benchmark = c("TradeBench",
  "MktBench", "VWAP", "PWP", "RPM"), type = list(price = c(), vwap =
  c("interval", "full")), MktData, POV = NULL, priceToBench)

Arguments

Portfolio

A portfolio name that points to a portfolio object structured with initPortf()

Symbol

A string identifying the traded symbol to benchmark

side

A numeric value, that indicates the side of the trade. Either 1 or -1, side = 1 (default) means "Buy" and side = -1 is "Sell"

benchmark

A string providing one of the benchmarks metrics 'TradeBench', 'MktBench', 'VWAP', 'PWP' or 'RPM'

type

A list with named elements, price or vwap, of strings. Relevant only for the corresponding benchmark = 'MktBench' and benchmark = 'VWAP'. When benchmark = 'MktBench', it is only pasted to the corresponding console output column. It does not influence the PnL metric computation. When benchmark = 'VWAP', it specifies the VWAP benchmark and defaults to type = list(vwap = 'interval'). See details.

MktData

An xts object containing 'MktPrice' and 'MktQty' required columns. Or a numeric value when benchmark = 'MktBench'. See details

POV

A numeric value between 0 and 1, specifying the POV rate

priceToBench

A numeric value. The MktData row position of the 'MktPrice' to use as benchmark price (default is 1)

Details

The performance is quantified by means of a Profit and Loss (PnL) metric. A positive PnL metric indicates that the trading strategy outperformed a chosen benchmark on average, vice versa negative values register an underperformance.

By and large, PnL metrics are computed as:

PnL = -1 . side . \frac{\bar{P} - P_{B}}{P_{B}} . 10^{4}

where P_{avg} is the average execution price and P_{B} is a given benchmark price. It is worth stressing that they are expressed in basis points (bps) units.

A common instance is given by the trading PnL, where we consider the arrival price of the transactions, P_{B} = P_{0}, in which case is of interest the timing in entering the market.

Another common and simple benchmark used is the benchmark price, in this case P_{B} can be a single current open/close price, future ones such as next day prices, or any other benchmark price specified.

A widely used one is the Volume Weighted Average Price (VWAP) benchamark. The benchmark is defined as:

VWAP = \frac{∑{P_{j}Q_{j}}}{∑{Q_{j}}}

P_{j} is the market price and Q_{j} the market volume, during j trading periods activity of the market. Two different types of VWAP benchmarks are included in the present function, the Interval VWAP and the Full VWAP. Referring to the former as the VWAP where the j market trading periods considered are the ones during which the order is being executed, whereas the latter includes all the j market periods from order execution beginning to last transaction. The VWAP benchmark varies by timespan considered and is commonly used as a proxy for fair market price. It can differ by data vendors specific market data filtering. There are recognized drawbacks of this benchamrk. First of all, the larger the order the closer the execution will be to VWAP. Second, where large block trades occur these could skew the benchmark. Lastly, it is not an indicated comparison across stocks or different days for the same stock.

A variation of the VWAP benchmark is given by the Participation Weighted Price (PWP) benchmark, where the weighting is with respect to the PWP shares:

PWP shares = \frac{Traded shares}{POV}

being POV the percentage of volume. The PWP benchwark is:

PWP price = \frac{∑{P_{h}Q_{h}}}{∑{Q_{h}}}

where h are the periods from the arrival time of the order into the market until when the PWP shares are completely executed. As the VWAP, the PWP benchmark provides a glimpse into market fair prices. However this benchmark have limitations similar to the VWAP. It is subject to manipulation in that the market price can be kept inflated by larger orders. Furthermore, as the VWAP, it is not comparable between stocks or across days for the same stock. Also, the benchmark may be biased by temporary impact dissipation.

Lastly, the Relative Performance Measure (RPM), which differs from the PnL metrics above, is a percentile ranking of trading activity. Its expression depends on the side of the trade:

RPM_{buy} = 0.5 * \frac{Total volume + Volume at P > P_{avg} - Volume at P < P_{avg}}{Total volume}

RPM_{sell} = 0.5 * \frac{Total volume + Volume at P < P_{avg} - Volume at P > P_{avg}}{Total volume}

where P is the market price specified. The an RPM over 50% is considered as an indication of superior trades, more precisely the RPM can be mapped to a qualitative score of the trades:

0 <= RPM < 20 Fair
20 <= RPM < 40 Poor
40 <= RPM <= 60 Average
60 < RPM <= 80 Good
80 < RPM <= 100 Excellent

This measure is considered as preferred to the VWAP metric because it overcomes some of its drawbacks: it can be used to compare performance across different stocks, days, and volatility; it is not less influenced by large blocks trade at extreme prices.

The priceToBench parameter, relevant only when benchmark='MktBench', is provided as a convenience parameter, to be used when the benchmark price to compare the average execution price of the transactions belongs to the MktData xts input. This allows to use the function having other benchmarks computations. A different usage of the function is available, giving two ways to use an arbitrary benchmark price: input this single price as an xts object through the MktData parameter (note that of an object with length greater than one only the first element will be used and the 'MktPrice' column requirement), or alternatively input a single numeric value in MktData.

The type parameter allows different usages of the function. In the benchmark='MktBench', the kind of market price used as a benchmark is up to the analyst and his research. The string provided through type=list(price='') is completely arbitrary and does not influence the corresponding PnL metric computation, it is available only for customization purposes. In other words, tohave a way to distinguish the elements of the return object in case different benchmarking analyses are being carried, e.g. benchmarking against both 'Open' prices and 'Close' prices (separately, providing each of these prices with a function call). Whereas, when benchmark='VWAP', then type is used to select the VWAP benchmark to use in the PnL metric computation, namely the Interval VWAP (type=list(vwap = 'interval')) or the "Full VWAP" (type=list(vwap = 'full')).

Value

A list whose unique element is a data.frame that can be one of the ones described below, Depending on the benchmark of choice.

For benchmark = 'TradeBench' it contains:

Dates:

Dates of reference, the longer period between the trading period and a subset of MktData

Symbol:

A string identifying the traded symbol to benchmark

Side:

The side of the trades, as "Buy" or "Sell"

Avg.Exec.Price:

Symbol transactions average execution price

TradeBench:

The arrival price of transactions

Performance:

The Trading PnL performance, in bps

For benchmark = 'MktBench' it contains:

Dates:

Dates of reference, the longer period between the trading period and a subset of MktData

Symbol:

A string identifying the traded symbol to benchmark

Side:

The side of the trades, as "Buy" or "Sell"

Avg.Exec.Price:

Symbol transactions average execution price

MktBench.*:

The benchmark and an arbitrary type=list(price) provided as input (e.g. 'Open', 'Close')

Performance:

The Benchmark PnL performance, in bps

For benchmark = 'VWAP' it contains:

Dates:

Dates of reference, the longer period between the trading period and a subset of MktData

Symbol:

A string identifying the traded symbol to benchmark

Side:

The side of the trades, as "Buy" or "Sell"

Avg.Exec.Price:

Symbol transactions average execution price

VWAP.*:

The benchmark and depending on type=list(vwap) parameter either 'interval' or 'full'

Performance:

The VWAP PnL metric, in bps

For benchmark = 'PWP' it contains:

Dates:

Dates of reference, the longer period between the trading period and a subset of MktData

Symbol:

A string identifying the traded symbol to benchmark

Side:

The side of the trades, as "Buy" or "Sell"

Cum.Txn.Qty:

The cumulative units quantity traded

POV:

The POV rate of the order

PWP.Shares:

The ratio between the total unit traded and the POV rate

Avg.Exec.Price:

Symbol transactions average execution price

PWP.Price:

Volume weighted price of the first PWP.Shares traded

Performance:

The PWP PnL metric, in bps

For benchmark = 'RPM' it contains:

Dates:

Dates of reference, the longer period between the trading period and a subset of MktData

Symbol:

A string identifying the traded symbol to benchmark

Side:

The side of the trades, as "Buy" or "Sell".

Avg.Exec.Price:

Symbol transactions average execution price

Mkt.Price:

The market price in MktData, retrived for console comparison

t.Mkt.Volmn:

Total market volume over the order timespan

t.Fav.Volmn:

Total market volume over the order timespan for which the average execution price of a 'Buy' ('Sell') order was lower (greater) than market prices

t.Unfav.Volmn:

The opposite of t.Fav.Volmn

RPM:

The relative performance measure. Decimal in the 0 to 1 range.

Quality:

A qualitiative RPM score over quintiles, bottom-up one of 'Poor', 'Fair', 'Average', 'Good', 'Excellent'. Present if verbose = TRUE

Author(s)

Vito Lestingi

References

Kissell, R. The Science of Algorithmic Trading and Portfolio Management (ISBN 978-0-12-401689-7)

See Also

initPortf, addTxn

Examples


# examples consider daily data, perhaps the most common use case for the practitioners of the field

set.seed(333)
.blotter <- new.env()
data(ABC)
ABC.day <- ABC[which(as.Date(index(ABC)) == "2019-02-01"), ]
colnames(ABC.day) <- c('MktPrice', 'MktQty')
inds <- sample(nrow(ABC.day), 50)
abc.trades.day <- ABC.day[inds]
colnames(abc.trades.day) <- c('TxnPrice', 'TxnQty')
currency('USD')
stock('ABC', currency = 'USD', multiplier = 1, tick_size = 0.01)
initPortf('abc.port.day', symbols = 'ABC')
addTxns('abc.port.day', 'ABC', TxnData = abc.trades.day)
updatePortf('abc.port.day', 'ABC')

benchTradeBench <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'TradeBench', MktData = ABC.day)
benchMktBenchOpen <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'MktBench', type = list(price = 'Open'), MktData = ABC.day[1]) # performance against the daily open price
benchMktBenchClose <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'MktBench', type = list(price = 'Close'), MktData = ABC.day[nrow(ABC.day)]) # performance against the daily closing price
benchMktBench <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'MktBench', type = list(price = 'price-of-choice'), MktData = 5000)
benchVWAPinterv <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'VWAP', type = list(vwap = 'interval'), MktData = ABC.day)
benchVWAPfull <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'VWAP', type = list(vwap = 'full'), MktData = ABC.day)
benchPWP <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'PWP', POV = 0.3, MktData = ABC.day)
benchRPM <- benchTradePerf('abc.port.day', 'ABC', side = 1, benchmark = 'RPM', MktData = ABC.day)

plot(benchTradeBench, benchmark = 'TradeBench')
plot(benchMktBenchOpen, benchmark = 'MktBench')
plot(benchMktBenchClose, benchmark = 'MktBench')
plot(benchVWAPfull, benchmark = 'VWAP')
plot(benchPWP, benchmark = 'PWP')
plot(benchRPM, benchmark = 'RPM')


braverock/blotter documentation built on Feb. 13, 2023, 1 p.m.