안녕하세요, 다빈치스탁의 시청자 여러분. 오늘은 포트폴리오 전략의 중요성과 다양한 접근 방법에 대해 알아보겠습니다.
"계란을 한 바구니에 담지 말라"는 오래된 격언은 투자의 세계에서도 그대로 적용됩니다. 이 말은 위험 분산의 중요성을 강조하는데, 주식투자에서는 다양한 종목에 분산하여 투자함으로써 리스크를 관리하라는 의미입니다.
예를 들어, 반도체 산업이 호황일 때 삼성전자, 하이닉스, 한미반도체 등 반도체 관련 종목에만 집중 투자하는 것은 과연 효율적인 분산투자일까요? 이러한 접근은 DRAM, 낸드플래시 등 종목별로 세부 카테고리가 다양하긴 하지만, 여전히 한 산업에 치중하는 것이므로 진정한 의미의 분산투자라고 보기 어렵습니다.
이런 고민에 대한 해답을 제시한 이가 바로 해리 마코위츠입니다. 그의 포트폴리오 이론은 1952년에 발표되어, 투자자들이 위험을 최소화하면서 기대 수익률을 극대화할 수 있는 포트폴리오 구성 방법을 제시했습니다. 이 이론에 따르면, 포트폴리오의 기대 수익률은 자산들의 기대 수익률의 가중 평균으로 계산되며, 위험은 자산 간의 상관관계를 고려하여 측정됩니다.
이로부터 '효율적 투자기회선(Efficient Frontier)'이라는 개념이 도출되었는데, 이는 주어진 위험 수준에서 가장 높은 기대 수익률을 제공하거나, 주어진 기대 수익률에서 가장 낮은 위험을 제공하는 포트폴리오의 집합을 의미합니다.
그럼 이제, 실제로 어떻게 이러한 이론을 투자에 적용할 수 있는지 살펴보겠습니다. 파이썬을 이용한 수치최적화 방법으로 샤프비율을 최대화하는 최적 포트폴리오를 구성하는 방법을 통해서 말이죠.
샤프비율을 최대화하는 포트폴리오 최적화
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import yfinance as yf
from scipy.optimize import minimize
# 주식 종목 코드 리스트
my_stocks = ['009470.KS', '103590.KS', '005380.KS', '000270.KS'] # 예시 종목 코드
# yfinance를 통해 주식 데이터 다운로드
data = yf.download(my_stocks, start='2020-01-01', end='2024-01-01')['Adj Close']
# 일일 수익률 계산
returns = data.pct_change().dropna()
# 포트폴리오 수익률, 표준편차, 샤프 비율 계산 함수
def get_portfolio_performance(weights, mean_returns, cov_matrix, risk_free_rate):
returns = np.sum(mean_returns * weights) * 252
std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
sharpe = (returns - risk_free_rate) / std
return returns, std, sharpe
# 최적화 목적 함수
def minimize_sharpe(weights, mean_returns, cov_matrix, risk_free_rate):
return -get_portfolio_performance(weights, mean_returns, cov_matrix, risk_free_rate)[2]
# 포트폴리오 최적화
mean_returns = returns.mean()
cov_matrix = returns.cov()
num_assets = len(my_stocks)
args = (mean_returns, cov_matrix, 0.03)
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
bounds = tuple((0, 1) for asset in range(num_assets))
initial_guess = num_assets * [1. / num_assets,]
"""
SLSQP는 Sequential Least Squares Programming의 약자로, 제약 조건이 있는 최적화 문제를 풀기 위한 수치적 최적화 알고리즘입니다.
이 방법은 비선형 목적 함수와 제약 조건을 가진 최적화 문제에 적합하며, 내부적으로 선형 또는 비선형 제약 조건을 처리할 수 있습니다.
minimize 함수에서 method 매개변수에 SLSQP를 사용하는 것은 이 알고리즘을 선택하여 최적화 문제를 해결하겠다는 의미입니다.
SLSQP는 일반적으로 제약 조건이 있는 최적화 문제에 널리 사용되며, 효율적이고 실용적인 해를 찾는 데 유용합니다.
SLSQP 외에도 scipy.optimize.minimize 함수에서 사용할 수 있는 다른 최적화 알고리즘들이 있습니다.
Nelder-Mead: 제약 조건이 없는 최적화에 적합한 단순하고 견고한 방법입니다.
Powell: 제약 조건이 없는 복잡한 최적화 문제에 사용됩니다.
CG (Conjugate Gradient): 대규모 문제에 적합한 제약 조건이 없는 최적화 방법입니다.
BFGS: 제약 조건이 없는 최적화에 사용되는 효율적인 방법으로, 중간 규모의 문제에 적합합니다.
TNC (Truncated Newton Conjugate Gradient): 제약 조건이 있는 최적화에 사용되며, 대규모 문제에 적합합니다.
각 알고리즘은 특정 유형의 문제에 더 적합하거나, 특정 조건에서 더 나은 성능을 보일 수 있습니다.
따라서 최적화 문제의 특성과 요구 사항에 따라 적절한 알고리즘을 선택해야 합니다.
또한, 각 알고리즘의 성능은 초기 추측값, 문제의 복잡성, 제약 조건의 유형 등에 따라 달라질 수 있으므로,
여러 알고리즘을 시도해보고 결과를 비교하는 것이 좋습니다.
"""
optimal_portfolio = minimize(minimize_sharpe, initial_guess, args=args, method='SLSQP', bounds=bounds, constraints=constraints)
# 최적 포트폴리오의 기대 수익률, 표준편차, 샤프 비율
optimal_return, optimal_std, optimal_sharpe = get_portfolio_performance(optimal_portfolio.x, mean_returns, cov_matrix, 0.03)
# 결과 출력
print("Optimal Portfolio Return:", optimal_return)
print("Optimal Portfolio Volatility:", optimal_std)
print("Optimal Portfolio Sharpe Ratio:", optimal_sharpe)
# 최적 포트폴리오의 자산별 비중 출력
optimal_weights = optimal_portfolio.x
stock_names = ['Samsung Electronics', 'SK Hynix', 'Hyundai', 'Kia'] # 예시 종목 이름
for stock, weight in zip(stock_names, optimal_weights):
print(f"{stock}: {weight:.2%}")
# 효율적 투자 기회선 시각화
plt.scatter(optimal_std, optimal_return, marker='*', color='r', s=200, label='Optimal Portfolio')
plt.title('Efficient Frontier')
plt.xlabel('Volatility')
plt.ylabel('Expected Return')
plt.legend(labelspacing=0.8)
plt.show()
샤프비율은 기대 수익률과 무위험 수익률의 차이를 포트폴리오의 표준편차로 나눈 값으로, 투자의 효율성을 측정하는 지표인데요. 삼성전자, SK하이닉스, 현대차, 기아로 이루어진 포트폴리오에 대해 샤프비율을 최대화하는 방법을 사용했습니다.
과거 4년간의 데이터로 계산한 변동성과 수익률에 기반한 추정 결과 삼성전자는 비중 57%, 하이닉스 0%, 현대차 0%, 그리고 기아는 43%의 비중으로 나타났습니다. 물론 맹신할 수는 없겠지만 한가지 눈에 띄는 점은 동일한 산업의 종목으로 구성된 포트폴리오는 비효율적이라 판단한다는 것입니다.
하지만 마코위츠의 이론은 과거 데이터에 기반한 것이므로, 미래 시장 상황을 정확하게 예측하지 못한다는 한계가 있습니다. 이를 보완하기 위해 등장한 자본자산가격결정모델(CAPM)은 자산의 기대 수익률이 시장 전체의 위험과 자산의 시장 위험에 대한 민감도(베타)에 의해 결정된다고 설명합니다.
CAPM은 투자자들이 시장 포트폴리오에 대해 동질적인 예측을 하고, 무위험자산과의 조합을 통해 자신의 위험 선호도에 맞는 포트폴리오를 구성한다고 가정합니다. 그러나 이 모델 역시 체계적 위험만을 고려하는 단일변수 모델이라는 한계를 지니고 있습니다.
이에 따라, 다요인 모델인 Fama-French 모델이 등장하여 CAPM을 확장하였습니다. 이 모델은 여러 가지 경제적 요인이나 재무적 지표가 자산의 수익률에 영향을 미친다고 가정합니다.
또한, 행동 금융 이론은 투자자의 비합리적 행동과 심리적 요인이 시장의 움직임과 투자 결정에 영향을 미친다고 주장합니다. 이 외에도 최소분산법은 주어진 기대수익에서 분산을 최소화하는 방법을 제시합니다.
이처럼 다양한 이론과 모델이 존재하지만, 모든 이론에는 한계가 있습니다. 따라서 실제 투자 결정에는 개인의 투자 목표, 시장 환경, 개인의 위험 선호도 등을 종합적으로 고려해야 합니다.
이상 오늘의 강의를 마치며, 여러분의 투자 여정에 이러한 이론들이 유용한 지침이 되길 바랍니다. 다음 시간에는 더 유익한 내용으로 찾아뵙겠습니다. 시청해주셔서 감사합니다.
베타추정
import numpy as np
import pandas as pd
import yfinance as yf
# 주식 데이터와 시장 지수 데이터 가져오기
stock_symbol = 'NVDA' # 예시 주식 심볼
market_index_symbol = '^IXIC' # 예시 시장 지수 심볼 (나스닥)
risk_free_rate = 0.01 # 예시 무위험 수익률 (2%)
# yfinance를 통해 데이터 다운로드
stock_data = yf.download(stock_symbol, start='2023-01-01', end='2024-01-01')['Adj Close']
market_data = yf.download(market_index_symbol, start='2023-01-01', end='2024-01-01')['Adj Close']
# 일일 수익률 계산
stock_returns = stock_data.pct_change().dropna()
market_returns = market_data.pct_change().dropna()
# 베타 계산
covariance = np.cov(stock_returns, market_returns)[0][1]
market_variance = np.var(market_returns)
beta = covariance / market_variance
# 시장 포트폴리오의 기대 수익률 계산
market_expected_return = np.mean(market_returns)
# 개별 주식의 기대 수익률 계산 (CAPM 공식)
expected_return = risk_free_rate + beta * (market_expected_return - risk_free_rate)
print(f"주식 {stock_symbol}의 베타 값: {beta:.2f}")
print(f"주식 {stock_symbol}의 기대 수익률: {expected_return:.2%}")
파마프렌치
import numpy as np
import pandas as pd
import yfinance as yf
# 주식 종목과 시장 지수 데이터 가져오기
symbols = ['AAPL', 'MSFT', 'GOOGL'] # 포트폴리오 종목
market_index_symbol = '^GSPC' # 시장 지수 심볼 (S&P 500)
# yfinance를 통해 주식 데이터 다운로드
stock_data = yf.download(symbols + [market_index_symbol], start='2020-01-01', end='2021-01-01')['Adj Close']
# 재무제표 데이터를 사용하여 시가총액과 장부가치 대비 시장가치 비율 계산
# 여기서는 예시로 임의의 값들을 사용합니다.
# 실제 사용 시에는 Kenneth R. French의 웹사이트에서 제공하는 SMB와 HML 데이터를 사용해야 합니다.
market_caps = {'AAPL': 1000, 'MSFT': 800, 'GOOGL': 1200} # 시가총액 (단위: 백만 달러)
book_to_market_ratios = {'AAPL': 0.5, 'MSFT': 0.8, 'GOOGL': 0.7} # 장부가치 대비 시장가치 비율
# 종목을 시가총액과 장부가치 대비 시장가치 비율에 따라 분류
small_caps = [symbol for symbol, cap in market_caps.items() if cap < 1000]
big_caps = [symbol for symbol, cap in market_caps.items() if cap >= 1000]
high_bm = [symbol for symbol, bm in book_to_market_ratios.items() if bm > 0.6]
low_bm = [symbol for symbol, bm in book_to_market_ratios.items() if bm <= 0.6]
# 일일 수익률 계산
returns = stock_data.pct_change().dropna()
# SMB와 HML 요인 계산
smb_returns = returns[small_caps].mean(axis=1) - returns[big_caps].mean(axis=1)
hml_returns = returns[high_bm].mean(axis=1) - returns[low_bm].mean(axis=1)
# SMB와 HML 요인의 평균값 계산
smb_factor = smb_returns.mean()
hml_factor = hml_returns.mean()
print(f"SMB Factor: {smb_factor:.2%}")
print(f"HML Factor: {hml_factor:.2%}")
import statsmodels.api as sm
import matplotlib.pyplot as plt
# 시장 지수의 수익률을 벤치마크로 사용
market_returns = stock_data[market_index_symbol].pct_change().dropna()
# 무위험 수익률을 가정 (예: 연 2%)
risk_free_rate = 0.02 / 252
# 초과 수익률 계산
excess_returns = returns.sub(risk_free_rate, axis=0)
market_excess_returns = market_returns - risk_free_rate
# 회귀분석을 위한 데이터 준비
Y = excess_returns.mean(axis=1) # 포트폴리오의 평균 초과 수익률
X = pd.DataFrame({
'Market': market_excess_returns,
'SMB': smb_returns,
'HML': hml_returns
})
# 상수항 추가
X = sm.add_constant(X)
# OLS 회귀분석 수행
model = sm.OLS(Y, X).fit()
# 회귀분석 결과 출력
print(model.summary())
# 회귀분석 결과 플롯
plt.figure(figsize=(10, 6))
plt.scatter(X['Market'], Y, label='Data Points')
plt.plot(X['Market'], model.predict(), color='red', label='Regression Line')
plt.title('Fama-French 3-Factor Model Regression')
plt.xlabel('Market Excess Returns')
plt.ylabel('Portfolio Excess Returns')
plt.legend()
plt.show()
'인과관계분석' 카테고리의 다른 글
의사결정나무(Decision Tree) with R (0) | 2020.09.10 |
---|---|
요인분석(Factor Analysis) with R (0) | 2020.09.09 |
주성분분석(PCA) with R (0) | 2020.09.09 |
중회귀분석의 변수선정 with R (0) | 2020.09.08 |
삼성전자 중회귀분석 with R - 심화편 (0) | 2020.09.07 |
댓글