Learn R Programming

AssetPricing (version 1.0-3)

xsolve: Optimal pricing policy

Description

Determines (by solving a coupled system of differential equations) the optimal prices as functions of (residual) time for a number perishable assets. Prices may be discrete or continuous. For continuous prices, the price sensitivity function may either be a smooth (twice differentiable) function or a function which is piecewise linear in price.

Usage

xsolve(S, lambda, gprob=1, tmax=NULL, qmax, prices=NULL, nout=300,
          type="sip", alpha=NULL, salval=0, epsilon=NULL,
          method="lsoda",verbInt=0)

Arguments

S

An expression, or list of expressions, or a function or list of functions, specifying the price sensitivity functions S_j(x,t). See Details.

lambda

A function (of residual time t --- see tmax) or a positive constant, specifying the intensity of the (generally inhomogeneous) Poisson process of arrival times of groups of potential customers.

gprob

A function (to calculate probabilities) or a numeric vector of probabilities determining the distribution of the size of an arriving group of customers.

tmax

The maximum residual time; think of this as being the initial time at which the assets go on sale (with time decreasing to zero, at which point the value of each asset drops to the “salvage value” (salval), usually 0). The system of differential equations is solved over the time interval [0,tmax]. See Details.

qmax

The maximum number of assets available for sale, i.e. the number of assets available at the starting (residual) time tmax.

prices

A numeric vector (with positive values) listing the possible prices at which items may be offered for sale in the discrete pricing scenario.

nout

The number of points at which values of the solution are to be provided. These are taken to be equispaced on [0,tmax].

type

Scalar character string taking one of the two values "sip" (singly indexed prices) and "dip" (doubly indexed prices). In the "dip" case the price of the asset which is quoted to the arriving group is allowed to depend upon the group size (as well as upon (residual) time as well as on the number of assets remaining for sale. In the "sip" case the quoted price does not depend upon group size.

alpha

A numeric scalar between 0 and 1 specifying the probability that an arriving group of size j > q (where q is the number of assets remaining for sale) will consider purchasing (all of) these remaining assets. It is irrelevant (and defaults to 1 as a “place holder”) if customers always arrive singly.

salval

A (non-negative) numeric scalar specifying the “salvage value” of an asset --- i.e. the quantity to which the value of an asset drops at residual time t=0. Usually salval is equal to 0.

epsilon

A numeric scalar used in determining the optimal price in settings in which this involves maximizing over a discrete set. See Details. It defaults to .Machine$double.eps^0.25 in the case of discrete prices and to .Machine$double.eps^0.5 when the price sensitivity function is piecewise linear. It is ignored if the price sensitivity function is smooth.

method

Character string specified the solution method to be used by the differential equation solver ode(). There is a fairly large number of possible methods. See ode() for details.

verbInt

A scalar value which controls “verbosity”. If verbInt > 0 then a “progress report” is printed every verbInt seconds (roughly). That is if the current value of Sys.time() is greater than or equal to the value stored at the time of the last report, plus verbInt seconds, then a new “report” is printed out. If verbInt is less than or equal to 0 then the solution process runs “silently”. See section Progress Reports for a bit more detail.

Value

A list with components:

x

The optimal pricing policy, chosen to maximize the expected value of the remaining assets at any given time; an object of class flap (“function list for asset pricing”). (In the case of discrete prices it also inherits from pwc.flap (pwc stands for “piecewise constant”), and if type=="dip" it also inherits from di.flap.) If type=="sip" it has the form of a list of functions x_q(t), with q running from 1 to qmax If type=="dip" if has the form of a list of functions x_qj(t) with q running from 1 to qmax and j running from 1 to min(q,jmax) where jmax is the maximum group size.

In the case of continuous prices these functions will be continuous functions created by splinefun(). In the case of discrete prices these functions will be piecewise constant (of class stepfun) created by stepfun().

Note that x has an attribute qmax specifying the maximum number of assets available for sale, i.e. the number of assets available at the starting (residual) time tmax. Of course if type=="sip" then this attribute is simply the length of x. Note that if type == "dip" then the entry x[[i]] is equal to the function x_qj(t) where i = (j-1)*(qmax - j/2) + q.

v

An object of class flap whose entries are (spline) functions v_q(t) specifying the (optimal) expected value of q assets at time t corresponding to the (optimal) pricing policy x.

vdot

An object of class flap whose entries are the derivatives (with respect to t) of the functions v_q(t) described above. The values of these derivatives are determined sequentially in the process of solving the system of differential equations for the optimal pricing policy.

Progress Reports

The “progress reports” produced when verbInt > 0 consist of rough estimates of the percentage of [0,tmax] (the interval over which the differential equation is being solved) remaining to be covered. A rough estimate of the total elapsed time since the solution process started is also printed out.

Having “progress reports” printed out appears to have no (or at worst negligible) impact on computation time.`

Details

If prices are modelled as being continuous, and if the price sensitivity function is differentiable, a coupled system of differential equations for the optimal prices is solved. If the prices are modelled as being discrete or if the price sensitivity function is piecewise linear in price, then a coupled system of differential equations for the expected value of the stock is solved, with the optimal price being determined at each step by maximizing over an appropriate finite discrete set. These differential equations are solved by the ode() function from the deSolve package.

The components of the argument S should be provided as expressions when the price sensitivity functions are assumed to be smooth, and these should be amenable to differentiation with respect to x and t via the function deriv3().

Note that in general the expression or expressions will depend upon a number of parameters as well as upon x and t. The values of these parameters are specified via an attribute or attributes. If S is a (single) expression it has (must have) an attribute called parvec which is a named vector of parameter values. If S is a list of expressions each entry of the list has (must have) such an attribute.

In the “piecewise linear” context S can be specified only as a single function. It is then assumed that the price sensitivity function for a group of size j is given by S_j(x,t) = S(x,t)^j. Such piecewise linear price sensitivity functions should be built using the function buildS().

In the case of discrete prices the argument S must be a function or list of functions specifying the price sensitivity functions S_j(x,t). These functions need only be defined for the prices listed in the prices argument.

If S is a single expression or function, then S_j(x,t) is taken to be this expression or function raised to the power j. If S is a list, then S_j(x,t) is taken to be its j-th entry.

In the case where argument S is a piecewise linear price sensitivity function, the argument tmax is, if not specified, taken to be the value of the corresponding attribute of S. In this setting, if tmax is specified it must be less than or equal to the corresponding attribute of S.

For discrete prices and for piecewise linear price sensitivity functions, determining the optimal price involves maximizing expected values over finite discrete sets. It can happen that the location of the maximum can make a sudden “jump” from one time step to the next, causing anomalous looking discontinuities in the optimal price functions. To avoid this, we check on the change in the expected value at each of the possible new prices as compared with that at the “previous” price.

If the maximal “improvement” in expected value is less than or equal to epsilon then the “new” price is set equal to the previous value. If the maximal improvement is greater than epsilon then those values of price, where the expected value is greater than the maximum value minus epsilon, are considered and the one which is closest to the previous price is chosen.

If epsilon is set equal to a value less than or equal to 0 then the smoothing strategy described above is dispensed with. In this case the maximum is taken to be the first of the (possibly) multiple maxima of the expected value.

References

P. K. Banerjee, and T. R. Turner (2012). A flexible model for the pricing of perishable assets. Omega 40:5, 533--540. DOI https://doi.org/10.1016/j.omega.2011.10.001

Rolf Turner, Pradeep Banerjee and Rayomand Shahlori (2014). Optimal Asset Pricing. Journal of Statistical Software 58:11, 1--25. DOI https://doi.org/10.18637/jss.v058.i11

See Also

vsolve(), plot.AssetPricing(), buildS()

Examples

Run this code
# NOT RUN {
#
# In these examples "qmax" has been set equal to 5 which is
# an unrealistically low value for the total number of assets.
# This is done so as to reduce the time for package checking on CRAN.
#
# Smooth price sensitivity function.
S <- expression(exp(-kappa*x/(1+gamma*exp(-beta*t))))
attr(S,"parvec") <- c(kappa=10/1.5,gamma=9,beta=1)

# Optimal pricing policy assuming customers arrive singly:
lambda1 <- function(tt){
	84*(1-tt)
}
X1 <- xsolve(S=S,lambda=lambda1,gprob=1,tmax=1,qmax=5,
             type="sip",verbInt=5)
# Optimal pricing policy assuming customers arrive in groups of
# size up to 5, with group size probabilities 1/3, 4/15, 1/5, 2/15,
# and 1/15 respectively.
lambda2 <- function(tt){
	36*(1-tt)
}
X2 <- xsolve(S=S,lambda=lambda2,gprob=(5:1)/15,tmax=1,qmax=5,
             type="sip", alpha=0.5,verbInt=5)

# Note that the intensity functions lambda1() and lambda2() are
# such that the expected total number of customers is 42 in each case.

# Discrete prices:
lambda3 <- function(t){42}
S      <- function(x,t){
                e <- numeric(2)
                e[x==1] <- exp(-2*t)
                e[x==0.6] <- 1.0
                e
          }
X3 <- xsolve(S=S,lambda=lambda3,gprob=1,tmax=1,qmax=5,prices=c(1,0.6),
             type="sip",verbInt=5)

# Piecewise linear price sensitivity function.
#
# Take S as in the example for buildS.
# This takes a loonnngggg time; the procedure is slow
# in the piecewise linear setting.
# }
# NOT RUN {
l0 <- get("lambda",envir=environment(get("alpha",envir=environment(S))[[1]]))
lambda4 <- function(t){apply(l0(t),1,sum)}
X4 <- xsolve(S=S,lambda=lambda4,gprob=(5:1)/15,qmax=30,type="sip",
                   alpha=0.5,verbInt=20)
# }

Run the code above in your browser using DataLab