Этот пример показывает, как настроить проблему выделения основой фонда, которая использует оптимизацию портфеля среднего отклонения с объектом Portfolio
оценить эффективные портфели.
Предположим, что вы хотите управлять фондом распределения активов с четырьмя классами активов: связи, акции с большой капитализацией, акции маленькой прописной буквы и появляющиеся акции. Фонд является длинно-единственным без заимствования или рычагов, должен иметь не больше, чем 85% портфеля в акциях, и не больше, чем 35% портфеля в появляющихся акциях. Стоимость, чтобы торговать первыми тремя активами составляет пересчитанных на год 10 пунктов, и стоимость, чтобы торговать появляющимися акциями в четыре раза выше. Наконец, вы хотите гарантировать, что средний оборот - не больше, чем 15%. Чтобы решить эту проблему, вы настроите основную задачу оптимизации портфеля среднего отклонения и затем медленно вводить различные ограничения на проблему добраться до решения.
Чтобы настроить задачу оптимизации портфеля, запустите с основных определений известных количеств, сопоставленных со структурой этой проблемы. Каждый класс активов принят, чтобы иметь tradeable актив с ценой в реальном времени. Такие активы могут быть, например, биржевыми индексными фондами (ETFs). Начальный портфель с активами в каждом активе, который имеет в общей сложности $7,5 миллионов наряду с дополнительной денежной позицией 60 000$. Эти основные количества и затраты для торговли настраиваются в следующих переменных с именами актива в массиве ячеек Asset
, текущие цены в векторном Price
, текущие активы портфеля в векторном Holding
и операционные издержки в векторном UnitCost
.
Чтобы анализировать этот портфель, можно настроить промокательную бумагу в объекте dataset
помочь отследить цены, активы, веса, и т.д. В частности, можно вычислить начальные веса портфеля и поддержать их в новом поле промокательной бумаги под названием 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 = dataset({Price, 'Price'}, {Holding, 'InitHolding'},'obsnames',Asset); Wealth = sum(Blotter.Price .* Blotter.InitHolding); Blotter.InitPort = (1/Wealth)*(Blotter.Price .* Blotter.InitHolding); Blotter.UnitCost = UnitCost; disp(Blotter);
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
Warning: This syntax will be removed in a future release. See the documentation for recommended usage.
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);
p
объекта Portfolio
не включает операционные издержки так, чтобы задача оптимизации портфеля, заданная в использовании 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);
Можно ввести предполагаемый эффективный портфель с покупками и продажами в Промокательную бумагу:
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 = 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 Port Buy Sell Bonds 0.18787 0 0.11213 Large-Cap Equities 0.4 0 0 Small-Cap Equities 0.16213 0 0.037871 Emerging Equities 0.25 0.15 0
Buy
и элементы Sell
Промокательной бумаги являются изменениями в весах портфеля, которые должны быть преобразованы в изменения в активах портфеля, чтобы определить отрасли. Поскольку вы работаете с сетевым портфелем, возвращается, необходимо сначала вычислить стоимость, чтобы торговать от начального портфеля до нового портфеля. Это может быть выполнено можно следующим образом:
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.BuyShare = Wealth * (Blotter.Buy ./ Blotter.Price); Blotter.SellShare = Wealth * (Blotter.Sell ./ Blotter.Price);
Заметьте, как вы использовали оперативное правило усечения, чтобы получить модульные количества долей, чтобы купить и продать. Очистите промокательную бумагу путем удаления себестоимости единицы продукции и покупки и продайте веса портфеля:
Blotter.Buy = []; Blotter.Sell = []; Blotter.UnitCost = [];
Конечным результатом является промокательная бумага, которая содержит предложенные отрасли, чтобы добраться от вашего текущего портфеля до портфеля умеренного риска. Чтобы сделать торговлю, вы должны были бы продать 16 049 акций своего актива связи и 8 069 долей вашего актива акции маленькой прописной буквы и должны будете приобрести 23 986 акций вашего появляющегося актива акций.
display(Blotter);
Blotter = Price InitHolding InitPort Port Holding Bonds 52.4 42938 0.3 0.18787 26889 Large-Cap Equities 122.7 24449 0.4 0.4 24449 Small-Cap Equities 35.2 42612 0.2 0.16213 34543 Emerging Equities 46.9 15991 0.1 0.25 39977 BuyShare SellShare Bonds 0 16049 Large-Cap Equities 0 0 Small-Cap Equities 0 8068.8 Emerging Equities 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