В этом примере показано, как настроить базовую проблему распределения основных средств, которая использует оптимизацию портфеля средних отклонений с помощью Portfolio объект оценки эффективных портфелей.
Предположим, что вы хотите управлять фондом распределения активов с четырьмя классами активов: облигации, акции с большим капиталом, акции с малым капиталом и новые акции. Фонд давно только без заимствований или левериджа, должен иметь не более 85% портфеля в акциях, и не более 35% портфеля в формирующихся акциях. Стоимость торговли первыми тремя активами составляет 10 базисных пунктов в годовом исчислении, а стоимость торговли формирующимися акциями в четыре раза выше. Наконец, необходимо убедиться, что средний оборот составляет не более 15%. Для решения этой проблемы необходимо настроить базовую задачу оптимизации портфеля средних отклонений, а затем медленно ввести различные ограничения для решения проблемы.
Чтобы настроить задачу оптимизации портфеля, начните с базовых определений известных количеств, связанных со структурой этой задачи. Предполагается, что каждый класс основных средств имеет оборотное основное средство с ценой в реальном времени. Такими активами могут быть, например, биржевые фонды (ETF). Первоначальный портфель с запасами в каждом активе, общая сумма которого составляет 7,5 млн. долл. США, а также дополнительная денежная позиция в размере 60 000 долл. США. Эти основные количества и затраты на торговлю настраиваются в следующих переменных с именами активов в массиве ячеек. Asset, текущие цены в векторе Price, текущие портфельные владения в векторе Holdingи транзакционные затраты в векторе UnitCost.
Для анализа этого портфеля можно настроить блоттер в table объект для отслеживания цен, холдингов, весов и т.д. В частности, можно вычислить начальные веса портфеля и выполнить их ведение в новом поле блоттера, называемом 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;
BlotterBlotter=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 непосредственно свойство. Затем настройте ограничения по умолчанию (только длинные с ограничением бюджета). Кроме того, настройте групповое ограничение, которое накладывает верхнюю границу на акции в портфеле (акции идентифицируются в матрице групп с 1) и ограничение верхней границы для появляющихся акций. Хотя вы могли бы установить верхнюю границу для появляющихся акций, используя setBounds функция, обратите внимание, как 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)

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
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