Cost models#
This module implements cost functions used by optimization-based policies.
Currently these are two: StocksTransactionCost
and
StocksHoldingCost
.
The default parameters are chosen to approximate real costs for the stock market as well as possible.
- class cvxportfolio.HoldingCost(short_fees=None, long_fees=None, dividends=None, periods_per_year=None)#
Generic holding cost model, as described in page 11 of the book.
There are two ways to use this class. Either in the costs attribute of a
MarketSimulator
, in which case the costs are evaluated on the post-trade dollar positions \(h^+_t\). Or, as part of the objective function (or as a constraint!) of aSinglePeriodOptimization
orMultiPeriodOptimization
trading policy, in which case they are evaluated on the post-trade weights \(w_t + z_t\). The mathematical form is the same (see the discussion at pages 11-12 of the book).This particular implementation represents the following objective terms (expressed here in terms of the post-trade dollar positions):
\[s^T_t {(h^+_t)}_- + l^T_t {(h^+_t)}_+ - d^T_t h^+_t\]where \(s_t\) are the (short) borrowing fees, \(l_t\) are the fees on long positions, and \(d_t\) are dividend rates (their sign is flipped because the costs are deducted from the cash account at each period). See below for their precise definition.
Example usage as simulator cost:
borrow_fees = pd.Series([5, 10], index=['AAPL', 'ZM']) simulator = cvx.MarketSimulator(['AAPL', 'ZM'], costs=cvx.HoldingCost(short_fees=borrow_fees))
Example usage as trading policy cost:
objective = cvx.ReturnsForecast() - 5 * cvx.FullCovariance() \ - cvx.HoldingCost(short_fees=10) constraints = [cvx.LeverageLimit(3)] policy = cvx.SinglePeriodOptimization(objective, constraints)
- Parameters:
short_fees (float, pd.Series, pd.DataFrame or None) – Short borrowing fees expressed as annual percentage; you can provide them as a float (constant for all times and all assets), a
pd.Series
indexed by time (constant for all assets but varying in time) or by assets’ names (constant in time but varying across assets), or apd.DataFrame
indexed by time and whose columns are the assets’ names, if varying both in time and across assets. If you use a time-indexed pandas object be careful to include all times at which a backtest is evaluated (otherwise you’ll get aMissingValueError
exception). If None, the term is ignored.long_fees (float, pd.Series, pd.DataFrame or None) – Fees on long positions expressed as annual percentage; same convention as above applies.
dividends (float, pd.Series, pd.DataFrame or None) – Dividend rates per period. Dividends are already included in the market returns by the default data interface (based on Yahoo Finance “adjusted prices”) and thus this parameter should not be used in normal circumstances.
periods_per_year (float or None) – How many trading periods are there in a year, for example 252 (for trading days in the US). This is only relevant when using this class as part of a trading policy. If you leave this to None the following happens. The value of periods per year are estimated at each period by looking at the past market returns at that point in time: the number of past periods is divided by the timestamp of the most recent period minus the timestamp of the first period (in years). That works well in most cases where there is enough history (say, a few years) and saves the user from having to manually enter this. If instead you use this object as a cost in a market simulator the parameter has no effect. (The length of each trading period in the simulation is known and so the per-period rates are evaluated exactly. For example, the rate over a weekend will be higher than overnight.)
- class cvxportfolio.StocksHoldingCost(short_fees=5)#
Holding cost specialized to stocks.
This implements the simple model describe at page 11 of the book, i.e. the cost (in terms of the post-trade dollar positions):
\[s^T_t {(h^+_t)}_-\]This class is a specialized version of
HoldingCost
, and you should read its documentation for all details. Here we drop most of the parameters and use the default values explained above. We use a default value of \(5\%\) annualized borrowing fee which is a rough (optimistic) approximation of the cost of shorting liquid US stocks. This cost is included by default inStockMarketSimulator
, the market simulator specialized to US (liquid) stocks.- Parameters:
short_fees (float, pd.Series, pd.DataFrame or None) – Same as in
HoldingCost
.
- class cvxportfolio.TransactionCost(a=None, pershare_cost=None, b=0.0, window_sigma_est=None, window_volume_est=None, exponent=None)#
This is a generic model for transaction cost of financial assets.
Currently it is not meant to be used directly. Look at
StocksTransactionCost
for its version specialized to the stock market.
- class cvxportfolio.StocksTransactionCost(a=0.0, pershare_cost=0.005, b=1.0, window_sigma_est=None, window_volume_est=None, exponent=1.5)#
A model for transaction costs of stocks.
See pages 10-11 in the book. We don’t include the short-term alpha term c here because it can be expressed with a separate ReturnsForecast object.
- Parameters:
a (float or pd.Series or pd.DataFrame) – linear cost, which multiplies the absolute value of each trade. This can model (half) the bid-ask spread, or any fee linear in the size of a trade.
pershare_cost (float or pd.Series or pd.DataFrame) – per-share trade cost, amount of dollars paid for each share traded.
b (float or pd.Series or pd.DataFrame) – coefficient of the non-linear term of the transaction cost model, which multiplies the estimated volatility for each stock.
window_sigma_est (int or None) – we use an historical rolling standard deviation to estimate the average size of the return on a stock on each day, and this multiplies the second term of the transaction cost model. See the paper for an explanation of the model. Here you specify the length of the rolling window to use. If None (the default) it uses a length of 1 year (approximated with the data provided).
window_volume_est (int) – length of the window for the mean of past volumes used as estimate of each period’s volume. Has no effect on the simulator version of this which uses the actual volume. If None (the default) it uses a length of 1 year (approximated with the data provided).
exponent (float or None) – exponent of the non-linear term, defaults (if set to
None
) to 1.5 for the simulator version, and 2 for the optimization version (because it is more efficient numerically and the difference is small, you can change it if you want).
- class cvxportfolio.SoftConstraint(constraint)#
Soft constraint cost.
- Parameters:
constraint (cvxportfolio.constraints.EqualityConstraint or cvxportfolio.constraints.InequalityConstraint) – Cvxportfolio constraint instance whose violation we penalize.
- class cvxportfolio.TcostModel(a=None, pershare_cost=None, b=0.0, window_sigma_est=None, window_volume_est=None, exponent=None)#
Alias of
TransactionCost
.As it was defined originally in section 6.1 of the paper.
- class cvxportfolio.HcostModel(short_fees=None, long_fees=None, dividends=None, periods_per_year=None)#
Alias of
HoldingCost
.As it was defined originally in section 6.1 of the paper.