В этом примере показано, как настроить базовую задачу распределения активов, которая использует оптимизацию портфеля со средним отклонением с Portfolio
объект для оценки эффективных портфелей.
Предположим, что вы хотите управлять фондом распределения активов с четырьмя классами активов: облигации, акции с большой капитализацией, акции с малой капитализацией и новые акции. Фонд длинный только без заимствований или кредитного плеча, должен иметь не более 85% портфеля в акциях и не более 35% портфеля в формирующихся акциях. Стоимость торговли первыми тремя активами составляет 10 базисные точки в годовом исчислении, а стоимость торговли новыми акциями в четыре раза выше. Наконец, вы хотите убедиться, что средний оборот не более 15%. Чтобы решить эту задачу, вы настройте задачу оптимизации портфеля основных средних дисперсий, а затем медленно вводите различные ограничения на задачу, чтобы получить решение.
Чтобы настроить задачу оптимизации портфеля, начните с основных определений известных величин, связанных со структурой этой задачи. Каждый класс основных средств считается имеющим торгуемое основное средство с ценой в реальном времени. Такие активы могут быть, пример, биржевыми фондами (ETF). Первоначальный портфель с владениями в каждом активе, который в общей сложности составляет 7,5 млн. долл. США, а также дополнительная денежная позиция в размере 60 000 долл. США. Эти основные количества и затраты на торговлю настраиваются в следующих переменных с именами активов в массиве ячеек Asset
, текущие цены в вектор Price
, текущие портфельные активы в вектор Holding
, и транзакционные издержки в вектор UnitCost
.
Чтобы проанализировать это портфолио, можно настроить блоттер в table
объект, чтобы помочь отслеживать цены, холдинги, веса и так далее. В частности, можно вычислить начальные веса портфеля и сохранить их в новом поле blotter под названием InitPort
.
Asset = { 'Bonds', 'Large-Cap Equities', 'Small-Cap Equities', 'Emerging Equities' }; Price = [ 52.4; 122.7; 35.2; 46.9 ]; Holding = [ 42938; 24449; 42612; 15991 ]; UnitCost = [ 0.001; 0.001; 0.001; 0.004 ]; Blotter = table('RowNames', Asset); Blotter.Price = Price; Blotter.InitHolding = Holding; Wealth = sum(Blotter.Price .* Blotter.InitHolding); Blotter.InitPort = (1/Wealth)*(Blotter.Price .* Blotter.InitHolding); Blotter.UnitCost = UnitCost; Blotter
Blotter=4×4 table
Price InitHolding InitPort UnitCost
_____ ___________ ________ ________
Bonds 52.4 42938 0.3 0.001
Large-Cap Equities 122.7 24449 0.4 0.001
Small-Cap Equities 35.2 42612 0.2 0.001
Emerging Equities 46.9 15991 0.1 0.004
Поскольку это гипотетический пример, для моделирования цен на активы из заданного среднего и ковариации годовых общих возвратов активов для классов активов, portsim
функция используется для создания возвратов активов с желаемым средним значением и ковариацией. В частности, portsim
используется для моделирования пяти лет ежемесячных общих возвратов и затем нанесен на график, чтобы показать журнал моделируемых общих возвратных цен
Среднее значение и ковариация годовых общих возвратов активов поддерживаются в переменных AssetMean
и AssetCovar
. Моделируемые общие цены возврата основных средств (которые являются объединенными совокупными возвратами) ведутся в переменной Y
. Все начальные цены возврата активов нормированы к 1
в этом примере.
AssetMean = [ 0.05; 0.1; 0.12; 0.18 ]; AssetCovar = [ 0.0064 0.00408 0.00192 0; 0.00408 0.0289 0.0204 0.0119; 0.00192 0.0204 0.0576 0.0336; 0 0.0119 0.0336 0.1225 ]; X = portsim(AssetMean'/12, AssetCovar/12, 60); % Monthly total returns for 5 years (60 months) [Y, T] = ret2tick(X, [], 1/12); % form total return prices. plot(T, log(Y)); title('\bfSimulated Asset Class Total Return Prices'); xlabel('Year'); ylabel('Log Total Return Price'); legend(Asset,'Location','best');
Чтобы исследовать портфели на эффективной границе, создайте Portfolio
объект, использующий следующие спецификации:
Веса портфеля неотрицательны и равны 1
.
Распределение капитала составляет не более 85% от портфеля.
Формирующийся капитал составляет не более 35% портфеля.
Эти спецификации включены в Portfolio
p объекта
в следующей последовательности использования функций, которая начинается с использования Portfolio
объект.
Спецификация начального портфеля от Blotter
задает количество активов в вашей вселенной, поэтому вам не нужно указывать NumAssets
свойство непосредственно. Затем настройте ограничения по умолчанию (только для long с ограничением бюджета). В сложение установите групповое ограничение, которое накладывает верхнюю границу на акции в портфеле (акции идентифицируются в матрице групп с 1
s) и верхнее ограничение на появляющиеся акции. Хотя вы могли установить верхнюю границу для новых акций, используя setBounds
function, заметьте, как addGroups
функция используется для настройки этого ограничения.
Чтобы иметь полностью заданную задачу оптимизации портфеля со средним отклонением, необходимо задать среднее и ковариационное значения возвратов активов. Начиная с этих моментов в переменных AssetMean
и AssetCovar
, можно использовать setAssetMoments
функция, чтобы ввести эти переменные в вашу Portfolio
объект (помните, что вы предполагаете, что ваши необработанные данные являются ежемесячными возвратами, из-за чего вы делите ваши ежегодные входные моменты на 12, чтобы получить ежемесячные возвраты).
Используйте общие цены возврата с estimateAssetMoments
функция со спецификацией, что ваши данные в Y
цены, а не возвраты, для оценки моментов возврата активов для вашего Portfolio
объект.
Хотя возвращается в вашем Portfolio
объект находится в модулях ежемесячных возвратов, и поскольку последующие затраты указаны в годовом исчислении, удобно указывать их как годовые общие возвраты с этим прямым преобразованием AssetMean
и AssetCovar
свойства вашего Portfolio
p объекта
.
Отобразите Portfolio
p объекта
.
p = Portfolio('Name', 'Asset Allocation Portfolio', ... 'AssetList', Asset, 'InitPort', Blotter.InitPort); p = setDefaultConstraints(p); p = setGroups(p, [ 0, 1, 1, 1 ], [], 0.85); p = addGroups(p, [ 0, 0, 0, 1 ], [], 0.35); p = setAssetMoments(p, AssetMean/12, AssetCovar/12); p = estimateAssetMoments(p, Y, 'DataFormat', 'Prices'); p.AssetMean = 12*p.AssetMean; p.AssetCovar = 12*p.AssetCovar; display(p)
p = Portfolio with properties: BuyCost: [] SellCost: [] RiskFreeRate: [] AssetMean: [4x1 double] AssetCovar: [4x4 double] TrackingError: [] TrackingPort: [] Turnover: [] BuyTurnover: [] SellTurnover: [] Name: 'Asset Allocation Portfolio' NumAssets: 4 AssetList: {1x4 cell} InitPort: [4x1 double] AInequality: [] bInequality: [] AEquality: [] bEquality: [] LowerBound: [4x1 double] UpperBound: [] LowerBudget: 1 UpperBudget: 1 GroupMatrix: [2x4 double] LowerGroup: [] UpperGroup: [2x1 double] GroupA: [] GroupB: [] LowerRatio: [] UpperRatio: [] MinNumAssets: [] MaxNumAssets: [] BoundType: [4x1 categorical]
Важным шагом в оптимизации портфеля является подтверждение того, что задача портфеля является допустимой, и основным тестом является обеспечение того, чтобы набор портфелей был непустым и ограниченным. Используйте estimateBounds
функция для определения границ для набора портфелей. В этом случае, так как оба lb
и ub
являются конечными, множество ограничено.
[lb, ub] = estimateBounds(p); display([lb, ub])
0.1500 1.0000 0 0.8500 0 0.8500 0 0.3500
Учитывая построенные Portfolio
объект, используйте plotFrontier
функция для просмотра эффективной границы. Вместо использования по умолчанию 10 портфелей вдоль границы можно отобразить границу с 40 портфелями. Заметьте, что валовые эффективные возвраты портфеля составляют от примерно 6% до 16% в год.
plotFrontier(p, 40)
The Portfolio
p объекта
не включает транзакционные издержки, так что задача оптимизации портфеля, указанная в p
использует валовые возвраты портфеля в качестве возврата прокси. Чтобы обработать чистые возвраты, создайте вторую Portfolio
q объекта
включая транзакционные издержки.
q = setCosts(p, UnitCost, UnitCost); display(q)
q = Portfolio with properties: BuyCost: [4x1 double] SellCost: [4x1 double] RiskFreeRate: [] AssetMean: [4x1 double] AssetCovar: [4x4 double] TrackingError: [] TrackingPort: [] Turnover: [] BuyTurnover: [] SellTurnover: [] Name: 'Asset Allocation Portfolio' NumAssets: 4 AssetList: {1x4 cell} InitPort: [4x1 double] AInequality: [] bInequality: [] AEquality: [] bEquality: [] LowerBound: [4x1 double] UpperBound: [] LowerBudget: 1 UpperBudget: 1 GroupMatrix: [2x4 double] LowerGroup: [] UpperGroup: [2x1 double] GroupA: [] GroupB: [] LowerRatio: [] UpperRatio: [] MinNumAssets: [] MaxNumAssets: [] BoundType: [4x1 categorical]
Для более конкретного определения областей значений эффективных возвратов портфеля и рисков используйте estimateFrontierLimits
функция для получения портфелей в конечных точках эффективной границы. Учитывая эти портфели, вычислите их моменты с помощью estimatePortMoments
функция. Следующий код генерирует таблицу, в которой перечислены риск и возврат начального портфеля, а также валовые и чистые моменты возвратов портфеля для портфелей в конечных точках эффективной границы:
[prsk0, pret0] = estimatePortMoments(p, p.InitPort); pret = estimatePortReturn(p, p.estimateFrontierLimits); qret = estimatePortReturn(q, q.estimateFrontierLimits); displayReturns(pret0, pret, qret)
Annualized Portfolio Returns ... Gross Net Initial Portfolio Return 9.70 % 9.70 % Minimum Efficient Portfolio Return 5.90 % 5.77 % Maximum Efficient Portfolio Return 13.05 % 12.86 %
Результаты показывают, что стоимость торговли колеблется от 14 до 19 базисных пунктов, чтобы получить от текущего портфеля к эффективным портфелям на конечных точках эффективной границы (эти затраты являются различием между валовыми и чистыми возвратами портфеля). В сложение заметьте, что максимальный эффективный возврат портфеля (13%) меньше максимального возврата актива (18%) из-за ограничений на распределение капитала.
Общим подходом к выбору эффективных портфелей является выбор портфеля, который имеет желаемую долю области значений ожидаемых возвратов портфеля. Чтобы получить портфель, который составляет 30% от области значений от минимальной до максимального возврата на эффективной границе, получите область значений чистых возвратов в qret
использование Portfolio
q объекта
и интерполяция, чтобы получить 30% -ный уровень с interp1
функция для получения портфеля qwgt
.
Level = 0.3; qret = estimatePortReturn(q, q.estimateFrontierLimits); qwgt = estimateFrontierByReturn(q, interp1([0, 1], qret, Level)); [qrsk, qret] = estimatePortMoments(q, qwgt); displayReturnLevel(Level, qret, qrsk);
Portfolio at 30% return level on efficient frontier ... Return Risk 7.90 9.09
display(qwgt)
qwgt = 4×1
0.6252
0.1856
0.0695
0.1198
Целевой портфель, который составляет 30% от области значений от минимальной до максимальных чистых возвратов, имеет возврат 7,9% и риск 9,1%.
Хотя можно принять этот результат, предположим, что необходимо определить значения для риска портфеля. В частности, предположим, что у вас есть консервативный целевой риск 10%, умеренный целевой риск 15% и агрессивный целевой риск 20%, и вы хотите получить портфели, которые удовлетворяют каждому целевому риску. Используйте estimateFrontierByRisk
функция для получения целевых рисков, заданных в переменной TargetRisk
. Получившиеся три эффективных портфеля получаются в qwgt
.
TargetRisk = [ 0.10; 0.15; 0.20 ]; qwgt = estimateFrontierByRisk(q, TargetRisk); display(qwgt)
qwgt = 4×3
0.5407 0.2020 0.1500
0.2332 0.4000 0.0318
0.0788 0.1280 0.4682
0.1474 0.2700 0.3500
Используйте estimatePortRisk
функция для вычисления портфельных рисков по трем портфелям для подтверждения достижения целевых рисков:
display(estimatePortRisk(q, qwgt))
0.1000 0.1500 0.2000
Предположим, что вы хотите переместиться с текущего портфеля на умеренный. Вы можете оценить покупки и продажи, чтобы добраться до этого портфеля:
[qwgt, qbuy, qsell] = estimateFrontierByRisk(q, 0.15);
Если вы усредните покупки и продажи по этому портфелю, то увидите, что средний оборот составляет 17%, что больше целевого показателя в 15%:
disp(sum(qbuy + qsell)/2)
0.1700
Поскольку вы также хотите убедиться, что средний оборот не более 15%, можно добавить среднее ограничение оборота к Portfolio
объект, использующий setTurnover
:
q = setTurnover(q, 0.15); [qwgt, qbuy, qsell] = estimateFrontierByRisk(q, 0.15);
Вы можете ввести предполагаемый эффективный портфель с покупками и продажами в Blotter
:
qbuy(abs(qbuy) < 1.0e-5) = 0;
qsell(abs(qsell) < 1.0e-5) = 0; % Zero out near 0 trade weights.
Blotter.Port = qwgt;
Blotter.Buy = qbuy;
Blotter.Sell = qsell;
display(Blotter)
Blotter=4×7 table
Price InitHolding InitPort UnitCost Port Buy Sell
_____ ___________ ________ ________ _______ ____ ________
Bonds 52.4 42938 0.3 0.001 0.18787 0 0.11213
Large-Cap Equities 122.7 24449 0.4 0.001 0.4 0 0
Small-Cap Equities 35.2 42612 0.2 0.001 0.16213 0 0.037871
Emerging Equities 46.9 15991 0.1 0.004 0.25 0.15 0
The Buy
и Sell
элементы Blotter
- изменения в весах портфеля, которые должны быть преобразованы в изменения в портфельных холдингах для определения сделок. Поскольку вы работаете с чистыми возвратами портфеля, сначала необходимо вычислить стоимость торговли от вашего начального портфеля до нового портфеля. Это достигается следующим образом:
TotalCost = Wealth * sum(Blotter.UnitCost .* (Blotter.Buy + Blotter.Sell))
TotalCost = 5.6248e+03
Стоимость торговли составляет $5,625, так что, в целом, вам придется скорректировать свое начальное богатство соответственно, прежде чем настраивать новые веса портфеля. Однако, чтобы сохранить анализ простым, обратите внимание, что у вас есть достаточные денежные средства ($60 0000), выделенные для оплаты торговых расходов и что вы не будете касаться денежной позиции, чтобы создать какие-либо позиции в вашем портфеле. Таким образом, вы можете заполнить свой блоттер новыми портфельными холдингами и сделками, чтобы добраться до нового портфеля, не производя никаких изменений в вашем общем инвестированном богатстве. Во-первых, вычислите портфельный холдинг:
Blotter.Holding = Wealth * (Blotter.Port ./ Blotter.Price);
Вычисление количества общих ресурсов в Buy
и Sell
в вашем Blotter
:
Blotter.BuyShare = Wealth * (Blotter.Buy ./ Blotter.Price); Blotter.SellShare = Wealth * (Blotter.Sell ./ Blotter.Price);
Заметьте, как вы использовали специальное правило усечения для получения модуля количества акций для покупки и продажи. Очистите Blotter
путем удаления удельных затрат и веса портфеля покупок и продаж:
Blotter.Buy = []; Blotter.Sell = []; Blotter.UnitCost = [];
Конечным результатом является блоттер, который содержит предложенные сделки для перехода от вашего текущего портфеля к портфелю с умеренным риском. Чтобы совершить сделку, вам нужно будет продать 16 049 акций вашего облигационного актива и 8 069 акций вашего акционерного актива с малой капитализацией, и вам нужно будет приобрести 23 986 акций вашего нового акционерного актива.
display(Blotter)
Blotter=4×7 table
Price InitHolding InitPort Port Holding BuyShare SellShare
_____ ___________ ________ _______ _______ ________ _________
Bonds 52.4 42938 0.3 0.18787 26889 0 16049
Large-Cap Equities 122.7 24449 0.4 0.4 24449 0 0
Small-Cap Equities 35.2 42612 0.2 0.16213 34543 0 8068.8
Emerging Equities 46.9 15991 0.1 0.25 39977 23986 0
Конечный график использует plotFrontier
функция для отображения эффективной границы и начального портфеля для полностью заданной задачи оптимизации портфеля. Он также добавляет расположение портфеля умеренного риска или конечного портфеля на эффективной границе.
plotFrontier(q, 40); hold on scatter(estimatePortRisk(q, qwgt), estimatePortReturn(q, qwgt), 'filled', 'r'); h = legend('Initial Portfolio', 'Efficient Frontier', 'Final Portfolio', 'location', 'best'); set(h, 'Fontsize', 8); hold off
function displayReturns(pret0, pret, qret) fprintf('Annualized Portfolio Returns ...\n'); fprintf(' %6s %6s\n','Gross','Net'); fprintf('Initial Portfolio Return %6.2f %% %6.2f %%\n',100*pret0,100*pret0); fprintf('Minimum Efficient Portfolio Return %6.2f %% %6.2f %%\n',100*pret(1),100*qret(1)); fprintf('Maximum Efficient Portfolio Return %6.2f %% %6.2f %%\n',100*pret(2),100*qret(2)); end function displayReturnLevel(Level, qret, qrsk) fprintf('Portfolio at %g%% return level on efficient frontier ...\n',100*Level); fprintf('%10s %10s\n','Return','Risk'); fprintf('%10.2f %10.2f\n',100*qret,100*qrsk); end
addGroups
| estimateAssetMoments
| estimateBounds
| estimateFrontierByRisk
| estimateFrontierLimits
| estimatePortRisk
| plotFrontier
| Portfolio
| setAssetMoments
| setBounds