Asset limits

Task

Restrict amounts for individual assets in various ways.

Preparation

This presumes that you can do basic random portfolio generation.  For example, that you have mastered “Very simple long-only”.

  • Portfolio Probe

You need to have the Portfolio Probe package loaded into your R session:

require(PortfolioProbe)

If you don’t have Portfolio Probe, see “Demo or Buy”.

Doing the example

 Doing it

We will generate random portfolios that:

  • limit maximum weight of assets
  • limit the contribution to portfolio variance of assets
  • limit minimum and maximum amount in a long-only portfolio
  • limit amount traded by asset

Limit maximum weight of assets

We generate portfolios that restrict the maximum weight to 10%:

rpMaxWt <- random.portfolio(100, priceVector, 
   existing=curPortfol, gross=grossVal, long.only=TRUE, 
   max.weight=.1)

We can get the maximum weight in each portfolio and then do a summary of those numbers:

> summary(sapply(valuation(rpMaxWt, priceVector, 
+     weight=TRUE), max))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.08140 0.09079 0.09527 0.09479 0.09830 0.10000

Limit the contribution to portfolio variance of assets

The constraint in the previous example — limiting maximum weight — is quite commonly done, but is not likely to be what people really want.  Closer to what is wanted is to constrain the amount of risk that each asset brings to the portfolio.

Do that with:

rpRiskFrac <- random.portfolio(100, priceVector, 
   variance=xaLWvar06, existing=curPortfol, 
   gross=grossVal, long.only=TRUE, risk.fraction=.1)

There are two changes between this and the previous example: “max.weight” is changed to “risk.fraction“, and a variance matrix is given.

The summary of the maximum weights is:

> summary(sapply(valuation(rpRiskFrac, priceVector, 
+     weight=TRUE), max))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.04648 0.07284 0.08416 0.09031 0.09394 0.17360

Since we are restricting risk rather than weight, the maximum weight can be bigger than 10%.  Interestingly there are some portfolios with quite low maximum weight as well.

Limit minimum and maximum amount in a long-only portfolio

There is no “min.weight” argument to match the max.weight argument.  One way of getting a minimum weight constraint is to use the positions argument.

To get a minimum weight of 5% and maximum weight of 20% for all assets, we can set up the positions argument as:

posArg <- cbind(rep(.05, 10), .2) * grossVal

This argument expects its inputs in terms of money.  The first few rows look like:

> head(posArg, 3)
         [,1]   [,2]
[1,] 151671.5 606686
[2,] 151671.5 606686
[3,] 151671.5 606686

Now we can generate the portfolios .  Note that we are restricting the universe to only the first 10 assets (the ones that are in the existing portfolio):

rpMinMaxWt <- random.portfolio(100, 
   head(priceVector, 10), existing=curPortfol, 
   gross=grossVal, long.only=TRUE, positions=posArg)

The summary of minimum weights is:

> summary(sapply(valuation(rpMinMaxWt, priceVector, 
+    weight=TRUE), min))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.05000 0.05001 0.05291 0.05391 0.05672 0.06965

Limit amount traded by asset

We can limit the number of units (that is, shares, contracts, …) that are traded by asset with the arguments lower.trade and upper.trade.

First we create a vector for the maximum number of shares we are willing to sell for each of the assets in the existing portfolio:

lowArg <- seq(-1500, by=100, length=10)
names(lowArg) <- names(curPortfol)

This looks like:

XA101 XA103 XA105 XA107 XA108 XA111 XA113 XA115 
-1500 -1400 -1300 -1200 -1100 -1000  -900  -800 
XA120 XA126 
 -700  -600

In general the upper.trade need not be related to the values in lower.trade, but in the interests of simplicity we’ll make the trading limits symmetric:

rpLoHiTrade <- random.portfolio(100, priceVector, 
   existing=curPortfol, gross=grossVal, long.only=TRUE, 
   lower.trade=lowArg, upper.trade=-lowArg)

This restricts the trading of the ten assets named in lowArg but not any of the other assets.  Often all assets are restricted, but you can constrain or not constrain any assets as you please.

Explanation

Maximum weight

A blanket weight constraint as in the first example is almost surely better as a risk fraction constraint.  However, there are maximum weight constraints that do make sense.  For example, you may want to hold no more than x days of average volume of each asset.  That can be stated as a maximum weight, but will be a different weight for each asset.

To give such a constraint, give a named vector to max.weight.  For example:

max.weight=c(XA101=.057, XA103=.015, XA120=.712)

This constrains the three assets named but does not constrain any others.

Risk fraction

The generalization of the max.weight argument explained just above also works for risk.fraction.  It is possible to put a lower bound on the risk fractions as well (in the same spirit as the third example).

Minimum and maximum amount

The matrix that we gave to the positions argument had all its rows the same.  In order to give different amounts for different assets, the matrix needs row names that are the identifiers of the assets.

Lower and upper trade

The values in lower.trade need to be negative or zero, and the values in upper.trade need to be positive or zero.

Otherwise, they would be forcing a trade.  You can force trades, but you need to use either the forced.trade argument or the positions argument.

Further details

The example with minimum weights was restricted to have only 10 assets in the universe because that form of constraint says that all assets should obey it.  If instead you want a minimum weight given that the asset is in the portfolio at all, then that is a threshold constraint.  Threshold constraints may be imposed either with the threshold argument or with the positions argument (using more columns).

For long-short portfolios, max.weight constrains the absolute value of the weight.  In this case weight is defined as the position value divided by the gross value of the portfolio.

Troubleshooting

  •  Be mindful that these arguments are mostly in different units from each other:
  • max.weight: weight
  • risk.fraction: fraction of variance (by default)
  • positions: monetary value
  • lower.trade, upper.trade: units (shares, contracts, …)
  • threshold: units
  • forced.trade: units

See also

Navigate