Liquidate Dollar Value from Portfolio
This example shows how to liquidate a dollar value from a portfolio while minimizing market-impact costs using transaction cost analysis from the Kissell Research Group. This example always results in a portfolio that shrinks in size. The market-impact cost minimization is expressed as
where MI is the market-impact cost for the traded shares and x denotes the final weights for each stock.
This example requires an Optimization Toolbox™ license. For background information, see Optimization Theory Overview (Optimization Toolbox).
The optimization finds a local minimum for the market-impact cost of liquidating a dollar value from a portfolio. For ways to search for the global minimum, see Local vs. Global Optima (Optimization Toolbox).
To access the example code, enter edit
                    KRGLiquidityOptimizationExample.m at the command line.
Retrieve Market-Impact Parameters and Load Data
Retrieve the market-impact data from the Kissell Research Group FTP site.
                    Connect to the FTP site using the ftp function with a user
                    name and password. Navigate to the MI_Parameters folder and
                    retrieve the market-impact data in the
                        MI_Encrypted_Parameters.csv file.
                        miData contains the encrypted market-impact date, code,
                    and parameters.
f = ftp('ftp.kissellresearch.com','username','pwd'); mget(f,'MI_Encrypted_Parameters.csv'); close(f) miData = readtable('MI_Encrypted_Parameters.csv','delimiter', ... ',','ReadRowNames',false,'ReadVariableNames',true);
Create a Kissell Research Group transaction cost analysis object
                        k. Specify initial settings for the date, market-impact
                    code, and number of trading days.
k = krg(miData,datetime('today'),1,250);Load the example data TradeDataPortOpt and the covariance
                    data CovarianceData from the file
                        KRGExampleData.mat, which is included with the
                        Datafeed Toolbox™. Limit the data set to the first 10 rows.
load KRGExampleData.mat TradeDataPortOpt CovarianceData n = 10; TradeDataPortOpt = TradeDataPortOpt(1:n,:); CovarianceData = CovarianceData(1:n,1:n); C = table2array(CovarianceData);
For a description of the example data, see Interpret Variables in Kissell Research Group Data Sets.
Define Optimization Parameters
Set the portfolio liquidation value to $100,000,000. Set the portfolio risk boundaries between 90% and 110%. Set the maximum total market-impact cost to 50 basis points. Determine the number of stocks in the portfolio. Retrieve the upper bound constraint for the maximum market-impact cost for liquidating shares in each stock.
PortLiquidationValue = 100000000; PortRiskBounds = [0.9 1.10]; maxTotalMI = 0.005; numPortStocks = length(TradeDataPortOpt.Symbol); maxMI = TradeDataPortOpt.UB_MaxMI;
Determine the target portfolio value PortfolioTargetValue
                    by subtracting the portfolio liquidation value from the total portfolio
                    value.
PortfolioValue = sum(TradeDataPortOpt.Value); absPortValue = abs(TradeDataPortOpt.Value); PortfolioAbsValue = sum(absPortValue); PortfolioTargetValue = PortfolioValue-PortLiquidationValue;
Determine the current portfolio weight w based on the value
                    of each stock in the portfolio.
w = sign(TradeDataPortOpt.Shares).*absPortValue/PortfolioAbsValue;
Specify constraints Aeq and beq to
                    indicate that the weights must sum to one. Initialize the linear inequality
                    constraints A and b.
Aeq = ones(1,numPortStocks); beq = 1; A = []; b = [];
Retrieve the lower and upper bounds for the final portfolio weight in
                        TradeDataPortOpt.
LB = TradeDataPortOpt.LB_Wt; UB = TradeDataPortOpt.UB_Wt;
Determine the lower and upper bounds for the number of shares in the final portfolio using other optional constraints in the example data set.
lbShares = max([TradeDataPortOpt.LB_MinShares, ... TradeDataPortOpt.LB_MinValue./TradeDataPortOpt.Price, ... TradeDataPortOpt.LB_MinPctADV.*TradeDataPortOpt.ADV],[],2); ubShares = min([TradeDataPortOpt.UB_MaxShares, ... TradeDataPortOpt.UB_MaxValue./TradeDataPortOpt.Price, ... TradeDataPortOpt.UB_MaxPctADV.*TradeDataPortOpt.ADV],[],2);
Specify the initial portfolio weights.
x0 = TradeDataPortOpt.Value./sum(TradeDataPortOpt.Value); x = x0;
Define optimization options. Set the optimization algorithm to sequential
                    quadratic programming. Set the termination tolerance on the function value and
                    on x. Set the tolerance on the constraint violation. Set the
                    termination tolerance on the PCG iteration. Set the maximum number of function
                    evaluations 'MaxFunEvals' and iterations
                        'MaxIter'. The options 'MaxFunEvals'
                    and 'MaxIter' are set to large values so that the
                    optimization can iterate many times to find a local minimum. Set the minimum
                    change in variables for finite differencing.
options = optimoptions('fmincon','Algorithm','sqp', ... 'TolFun',10E-8,'TolX',10E-16,'TolCon',10E-8,'TolPCG',10E-8, ... 'MaxFunEvals',50000,'MaxIter',50000,'DiffMinChange',10E-8);
Minimize Market-Impact Costs for Portfolio Liquidation
Define the function handle objectivefun for the sample
                    objective function krgLiquidityFunction. To access the code
                    for this function, enter edit krgLiquidityFunction.m. Define
                    the function handle constraintsfun for the sample function
                        krgLiquidityConstraint that sets additional
                    constraints. To access the code for this function, enter edit
                        krgLiquidityConstraint.m.
objectivefun = @(x) krgLiquidityFunction(x,TradeDataPortOpt, ... PortfolioTargetValue,k); constraintsfun = @(x) krgLiquidityConstraint(x,w,C,TradeDataPortOpt, ... PortfolioTargetValue,PortRiskBounds,lbShares,ubShares,maxMI,maxTotalMI,k);
Minimize the market-impact costs for the portfolio liquidation.
                        fmincon finds the optimal value for the portfolio
                    weight for each stock based on the lower and upper bound values. It does this by
                    finding a local minimum for the market-impact cost.
[x,~,exitflag] = fmincon(objectivefun,x0,A,b,Aeq,beq,LB,UB, ...
    constraintsfun,options);To check whether fmincon found a local minimum, display
                    the reason why the function stopped.
exitflag
exitflag =
     1.00
fmincon returns 1 when it finds a
                    local minimum. For details, see exitflag (Optimization Toolbox).
Determine the optimized weight value x1 of each stock in
                    the portfolio in decimal format.
x1 = x.*PortfolioTargetValue/PortfolioValue;
Determine the optimized portfolio target value TargetValue
                    and number of shares SharesToTrade for each stock in the
                    portfolio.
TargetShares = x*PortfolioTargetValue./TradeDataPortOpt.Price; SharesToTrade = TradeDataPortOpt.Shares-TargetShares; TargetValue = x*PortfolioTargetValue; TradeDataPortOpt.Shares = abs(SharesToTrade);
Determine the optimized percentage of volume strategy.
TradeDataPortOpt.TradeTime = TradeDataPortOpt.TradeTime ... .* TradeDataPortOpt.ADV; TradeDataPortOpt.POV = krg.tradetime2pov(TradeDataPortOpt.TradeTime, ... TradeDataPortOpt.Shares);
Estimate the market-impact costs MI for the number of
                    shares to liquidate.
MI = marketImpact(k,TradeDataPortOpt)/10000;
To view the market-impact cost in decimal format, specify the display format. Display the market-impact cost for the first three stocks in the portfolio.
format MI(1:3)
ans =
   1.0e-03 *
    0.1477
    0.1405
    0.1405To view the target number of shares with two decimal places, specify the display format. Display the target number of shares for the first three stocks in the portfolio.
format bank
TargetShares(1:3)ans =
     -23640.11
    -154656.73
     -61193.04The negative values denote selling shares from the portfolio.
Display the traded value for the first three stocks in the portfolio.
TargetValue(1:3)
ans =
    -968062.45
   -1521760.41
   -2448131.64To simulate trading the target number of shares on a historical date range, you can now conduct a stress test on the optimized portfolio. For details about conducting a stress test, see Conduct Stress Test on Portfolio.
References
[1] Kissell, Robert. “Creating Dynamic Pre-Trade Models: Beyond the Black Box.” Journal of Trading. Vol. 6, Number 4, Fall 2011, pp. 8–15.
[2] Kissell, Robert. “TCA in the Investment Process: An Overview.” Journal of Index Investing. Vol. 2, Number 1, Summer 2011, pp. 60–64.
[3] Kissell, Robert. The Science of Algorithmic Trading and Portfolio Management. Cambridge, MA: Elsevier/Academic Press, 2013.
[4] Chung, Grace and Robert Kissell. “An Application of Transaction Costs in the Portfolio Optimization Process.” Journal of Trading. Vol. 11, Number 2, Spring 2016, pp. 11–20.
See Also
krg | marketImpact | fmincon (Optimization Toolbox) | optimoptions (Optimization Toolbox)