Portfolio Optimization - PyPortfolioOpt (1)
https://github.com/robertmartin8/PyPortfolioOpt/commits?author=robertmartin8 git
https://pyportfolioopt.readthedocs.io/en/latest/ official document
Efficient Frontier?
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=gdpresent&logNo=220890967416
Harry Markowitz의 이론인데, 1952년도 논문이라 되게 오래 되었다. 금융쪽 비전공자인 나도 포트폴리오 이론이니, CAPM이나 CAL같은건 어디서 주워들어봤으니까 완전 기초중의 기초일 것 같다. 저 분야에서 바이블인가?
뜬금없이 이걸 셋업하게된 계기는 최근에 arxiv sanity에 top recent 1주 기준으로 흥미롭고 따끈한 논문이 나왔기 때문이다.
http://arxiv.org/pdf/2107.11371v1.pdf
요즘 transformer 뇌절이 가득한 아카이브에 Portfolio optimization problem이 뜨는건 처음 봤다! 인도 주식에 적용했다고.
뭔가 나같은 인간들이 울면서 서베이하러 왔다가 주식얘기보고 신나서 클릭한게 틀림없다.
암튼 이 논문에서 Markowitz의 mean-variance portfolio를 비교언급하고 있어서, 본 논문을 보기 전에 고전을 좀 알고 봐야할것같아서 빠르게 서베이 해봤음.
이 논문은 PCA 쓴 것 같은데. ML 카테고리에 들어가있고 역시나 코드 공개는 안한걸로 보여서 기초라도 한번 돌려보고 가려고 함. 필요하면 구현해야지
중간에 모듈 없다는 에러 뜬건
pip install cvxpy
pip install cvxopt
해서 해결. 뭐 solver 모듈 없는 에러같음.
파일을 읽고, 포트폴리오를 구성한 후에 투자금액에 맞춰서 (데이터의 가장 최근 주가 기준) 몇주를 사야하는지 계산하는 코드이다.
max_sharpe()를 통해 얻은 weights를 확인하면, 텍스트파일에 있는 몇 주식을 가지고 효율적인 포트폴리오를 구성한다.
저게 tangent portfolio를 구성하는건데 각 주식 비중들. 무위험이자율은 기본으로 2%로 되어있다.
L2 Regularization을 constraint로 추가.
여기선 종목 몇개만 뽑아서 했는데, 종목 많이 합치면 optimization problem 풀 수 있긴 한건가...? 으으;;
몇가지 아이디어가 있으니 집가서 적용해봐야겠다.
import pandas as pd
from pypfopt.efficient_frontier import EfficientFrontier
from pypfopt import risk_models
from pypfopt import expected_returns
from pypfopt import objective_functions
def print_orderdict(dict, postfix='%', space=8, title='', line=5):
print(title)
idx = 0
for i in dict:
idx += 1
if postfix=='%':
num = str(round(dict[i]*100, 2))
else:
num = str(dict[i])
print(i.ljust(6), (num+postfix).rjust(space), end=" | ")
if idx % line == 0:
print()
# Read in price data
df = pd.read_csv("tests/resources/stock_prices.csv", parse_dates=True, index_col="date")
# Calculate expected returns and sample covariance
mu = expected_returns.mean_historical_return(df)
S = risk_models.sample_cov(df)
ef = EfficientFrontier(mu, S)
ef.add_objective(objective_functions.L2_reg, gamma=0.1)
w = ef.max_sharpe()
print("Portfolio Optimization")
print("Based on Efficient Frontier with L2 regulzariztion")
#print(ef.clean_weights())
print_orderdict(ef.clean_weights(), title="** Optimal Weights **")
############ post-processing
print()
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices
money = 20000.0
latest_prices = get_latest_prices(df)
da = DiscreteAllocation(w, latest_prices, total_portfolio_value=money)
allocation, leftover = da.lp_portfolio()
buy = 0
for k in allocation:
buy += latest_prices[k] * allocation[k]
print("Total Asset: ", money)
print("Total buy: ", buy, ", leftover:", money - buy)
print_orderdict(allocation,
postfix=" stk",
title="** Optimal Weights **")
실행하면 대충 이렇다.
귀찮아서 안붙였는데 Total Asset같은 저 숫자들은 달러 기준이다.