{"id":14276,"url":"\/distributions\/14276\/click?bit=1&hash=721b78297d313f451e61a17537482715c74771bae8c8ce438ed30c5ac3bb4196","title":"\u0418\u043d\u0432\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u0439 \u0442\u043e\u0432\u0430\u0440 \u0438\u043b\u0438 \u0443\u0441\u043b\u0443\u0433\u0443 \u0431\u0435\u0437 \u0431\u0438\u0440\u0436\u0438","buttonText":"","imageUuid":""}

Оптимизация инвестиционного портфеля по методу Марковица

Пожалуй это уже не первая статья по портфельной оптимизации. Но она может стать быстрой закладкой (справочником) когда необходимо быстро реализовать оптимизацию инвестиционного портфеля на Python.

Источники

Следующие источники позволят получить общее представление о портфельной оптимизации по методу Марковица.

Загрузка данных по котировкам

Используем данные с сервиса Yahoo.Finance

! pip install yfinance import yfinance as yf

Берем несколько акций американского рынка за последние 3 месяца.

data = yf.download(['AAPL','GE','BAC','AMD','PLUG','F'],period='3mo')

Курсы закрытия

В расчетах будем использовать дневные курсы закрытия

closeData = data.Close closeData
Курсы закрытия Енин А.В.

Графики курсов

import matplotlib.pyplot as plt for name in closeData.columns: closeData[name].plot() plt.grid() plt.title(name) plt.show()
AAPL (история курса за последние 3 месяца) Енин А.В.
AMD (история курса за последние 3 месяца) Енин А.В.
BAC (история курса за последние 3 месяца) Енин А.В.
F (история курса за последние 3 месяца) Енин А.В.
GE (история курса за последние 3 месяца) Енин А.В.
PLUG (история курса за последние 3 месяца) Енин А.В.

Изменение курсов

Далее понадобятся относительные изменения к предыдущему дню.

dCloseData = closeData.pct_change() dCloseData
Относительные изменения курсов Енин А.В.

Графики относительных изменений

for name in dCloseData.columns: dCloseData[name].plot() plt.title(name) plt.grid() plt.show()
AAPL (относительные изменения курса за последние 3 месяца) Енин А.В.
AMD(относительные изменения курса за последние 3 месяца) Енин А.В.
BAC(относительные изменения курса за последние 3 месяца) Енин А.В.
F(относительные изменения курса за последние 3 месяца) Енин А.В.
GE(относительные изменения курса за последние 3 месяца) Енин А.В.
PLUG(относительные изменения курса за последние 3 месяца) Енин А.В.

Средняя доходность

Средняя дневная доходность по каждой акции для расчета доходности портфеля.

dohMean = dCloseData.mean() dohMean
Средняя доходность Енин А.В.

Ковариация

Для расчета риска портфеля потребуется ковариационная матрица.

cov = dCloseData.cov() cov
Ковариационная матрица Енин А.В.

Случайный портфель

Будем генерить случайные портфели. В них сумма долей равна 1 (единице).

import numpy as np cnt = len(dCloseData.columns) def randPortf(): res = np.exp(np.random.randn(cnt)) res = res / res.sum() return res r = randPortf() print(r) print(r.sum())
[0.07519908 0.07594622 0.20932539 0.40973202 0.1234458 0.10635148] 1.0

Доходность портфеля

Доходность портфеля считаем как сумму долей доходностей по каждой акции в портфеле.

def dohPortf(r): return np.matmul(dohMean.values,r) r = randPortf() print(r) d = dohPortf(r) print(d)
[0.0789135 0.13031559 0.25977124 0.21157419 0.13506695 0.18435853] 0.006588795350151513

Риск портфеля

Риск портфеля считаем через матричные произведения долей портфеля и матрицы ковариации.

def riskPortf(r): return np.sqrt(np.matmul(np.matmul(r,cov.values),r)) r = randPortf() print(r) rs = riskPortf(r) print(rs)
[0.10999361 0.13739338 0.20412889 0.13648828 0.24021123 0.17178461] 0.02483674110724784

Облако портфелей

Сгенерируем множество портфелей и выведем результат на график риск-доходность. Найдем параметры оптимального портфеля по минимальному риску и по максимальному коэффициенту Шарпа. Сравним с данными усредненного портфеля.

N = 1000 risk = np.zeros(N) doh = np.zeros(N) portf = np.zeros((N,cnt)) for n in range(N): r = randPortf() portf[n,:] = r risk[n] = riskPortf(r) doh[n] = dohPortf(r) plt.figure(figsize=(10,8)) plt.scatter(risk*100,doh*100,c='y',marker='.') plt.xlabel('риск, %') plt.ylabel('доходность, %') plt.title("Облако портфелей") min_risk = np.argmin(risk) plt.scatter([(risk[min_risk])*100],[(doh[min_risk])*100],c='r',marker='*',label='минимальный риск') maxSharpKoef = np.argmax(doh/risk) plt.scatter([risk[maxSharpKoef]*100],[doh[maxSharpKoef]*100],c='g',marker='o',label='максимальный коэф-т Шарпа') r_mean = np.ones(cnt)/cnt risk_mean = riskPortf(r_mean) doh_mean = dohPortf(r_mean) plt.scatter([risk_mean*100],[doh_mean*100],c='b',marker='x',label='усредненный портфель') plt.legend() plt.show()
Облако портфелей Енин А.В.

Выведем данные найденных портфелей.

import pandas as pd print('---------- Минимальный риск ----------') print() print("риск = %1.2f%%" % (float(risk[min_risk])*100.)) print("доходность = %1.2f%%" % (float(doh[min_risk])*100.)) print() print(pd.DataFrame([portf[min_risk]*100],columns=dCloseData.columns,index=['доли, %']).T) print() print('---------- Максимальный коэффициент Шарпа ----------') print() print("риск = %1.2f%%" % (float(risk[maxSharpKoef])*100.)) print("доходность = %1.2f%%" % (float(doh[maxSharpKoef])*100.)) print() print(pd.DataFrame([portf[maxSharpKoef]*100],columns=dCloseData.columns,index=['доли, %']).T) print() print('---------- Средний портфель ----------') print() print("риск = %1.2f%%" % (float(risk_mean)*100.)) print("доходность = %1.2f%%" % (float(doh_mean)*100.)) print() print(pd.DataFrame([r_mean*100],columns=dCloseData.columns,index=['доли, %']).T) print()
Данные найденных портфелей Енин А.В.

Выводы

Повторили классический метод расчета долей инвестиционного портфеля. Получили вполне конкретные результаты.

Оптимизация портфеля по методу Марковица предполагает сохранение параметров в будущем (корреляций между отдельными инструментами и уровня их доходности). Но это не гарантировано. В следующих работах предстоит это проверить.

Понятно, что положительного результата от обозначенной выше проверки ожидать не стоит. Но тогда можно поискать как доработать метод Марковица для получения более гарантированного дохода в будущем. Вот тема для еще одного исследования.

0
Комментарии
-3 комментариев
Раскрывать всегда