Loading [MathJax]/jax/output/CommonHTML/jax.js
본문 바로가기
주식분석/주식전략

자산배분 #1 : 포트폴리오의 위험과 기대수익률

by hustler78 2023. 2. 17.
728x90
반응형

이번 글에서는 여러 개의 자산(주식, 채권, 파생상품 등)을 분산투자여 포트폴리오를 만들었을 때, 그 포트폴리오가 주는 위험과 기대수익률의 관계에 대해서 고찰해 볼까 합니다.

 

먼저 소개할 것은 아주 오래된 이론이지만 지금도 강력하게 쓰이는 

 

평균 - 분산 포트폴리오 이론

 

입니다.  왜 평균과 분산이 갑툭튀인 걸까요? 내용은 간단한 가정에서 출발합니다. 

 

어느 투자자산 A가  있고 그 투자자산의 수익률 데이터를 생각해 봅시다.

 

○ 투자자산에서 기대할 수 있는 수익률은 A의 수익률 데이터의 기댓값, 즉 평균입니다.

 

○ 반면 이 투자자산 A에 투자했을 때의 위험은 바로 표준편차(또는 분산)가 될 것입니다. 분산이 작은 경우에는 A의 수익률 데이터가 평균 근처에 몰려 있다는 뜻이므로, 안정적인 기대수익률을 예상해 볼 수 있겠죠. 하지만 분산이 큰 경우에는 수익률 분포가 평균에서 멀리 떨어져 분포하게 되므로 수익률이 엄청 크게 나올 수도, 반대로 수익률이 처참할 수도 있는 것이겠죠. 즉 투자의 리스크가 있다는 이야기입니다.

 

이런 개념을 이용하여, 

어떠 자산에 투자할 때 투자리스크는 수익률의 분산(또는 표준편차)

 

로 생각하는 경우가 많습니다.

 

자산에 투자할 때, 투자자들은 가장 위험하지 않은 자산에 투자하여 가장 높은 수익률을 올리고 싶어 합니다. 하지만 이건 꿈같은 이야기겠죠.  높은 수익률을 얻기 위해서는 다소 모험을 즐겨야 합니다. 리스크를 어느 정도 감내할 수 있는 그릇이 되어야 큰 수익을 담을 수 있겠죠. 이른바

 

High Risk, High Return

입니다.

하이 리스크, 하이 리턴

 

얼마나 유명한 말인지 노래로도 있습니다.

HIGH RISK HIGH RETURN 크게 벌은 만큼 다시 갖다 박아 내 밑천 [가사 中]

 

 

그런데 높은 수익을 얻기 위해 위험을 엄청나게 짊어지는 투자자는 없겠죠. 투자자들은 다양한 투자 자산을 비교해 봅니다. 비교를 통해

○ 같은 위험(분산)을 가지지만, 기대 수익률이 더 좋은 자산  

○ 같은 기대수익률 중에서 위험(분산)이 가장 낮은 자산

을 선택하게 됩니다. 시장에 주어진, 내가 투자할 수 있는 자산이 많으면 좋겠지만, 한계가 있을 수 있죠. 그래서 투자자들은 주어진 자산들을 적절히 섞어 분산투자를 생각해 봅니다. 내가 가진 돈으로 이것저것 섞어서 투자를 해 보죠. 이러한 과정을 "포트폴리오를 만든다"라고 합니다.

 

요지는 이렇습니다.

① 시장에 주어진 자산을 이리저리 섞어 봅니다 (포트폴리오 만들기)

② 그 포트폴리오를 만드는 방법에 따라 기대수익률과 위험(분산)을 구해 봅니다.

③ 기대수익률과 위험의 관계를 파악하여 내 마음에 쏙 드는 포트폴리오를 선택!!

 

간단한 경우, 시장에 투자 자산이 두 개인 경우부터 알아봅시다.

 

 

 

두 개 자산의 기대수익률과 리스크

 

두 자산 X1,X2 의 기대수익률을 r1,r2,  수익률의 표준편차를 σ1,σ2라 합시다.

만일 이 두 자산을 적절히 섞어서 투자한다고 합시다. 이른바 포트폴리오를 만드는 거죠.
두 자산이 각각 가중치 w1,w2를 가지고 편의상 
w1+w2=1
이라 합시다. 또 두 자산 모두 매수한 상황이라고 가정합니다. 즉
w1,w20
이죠.

이때, 포트폴리오 
X=w1X1+w2X2
의 기대수익률과 표준편차를 각각 구해봅시다.

 

포트폴리오의 기대수익률

기대수익률은 쉽습니다.

E(X)=E(w1X1+w2X2)=w1E(X1)+w2E(X2)=w1r1+w2r2
입니다. 

 

포트폴리오의 분산


X의 표준편차를 구하기 전, 분산을 먼저 구해보죠.
V(X)=E(X2)(E(X))2=E((w1X1+w2X2)2)(w1E(X1)+w2E(X2))2=w21E(X21)+2w1w2E(X1X2)+w22E(X22)            (w21E(X1)2+2w1w2E(X1)E(X2)+w22E(X2)2)=w21(E(X21)E(X1)2)+w22(E(X22)E(X2)2)+2w1w2(E(X1X2)E(X1)E(X2))=w21V(X1)+w22V(X2)+2w1w2Cov(X1,X2)=w21σ21+w22σ22+2w1w2ρσ1σ2


공분산 Cov(,) 은 여기를 참고하시기 바랍니다. 위 식에서 ρ는 두 자산 X1,X2의 상관계수(correlation)를 뜻하고
ρ=Corr(X1,X2)=Cov(X1,X2)σ1σ2
입니다.

 

식(1)은 아래와 같이 좀 더 멋지게 쓸 수 있습니다.

w=(w1w2) , C=(σ21ρσ1σ2ρσ1σ2σ22)
라 합시다. 즉 C는 공분산 행렬입니다.

그러면 식 (1)은
V(X)=wtCw
처럼 행렬의 곱셈으로 간단히 쓸 수 있습니다.

 

여러 자산의 기대수익률과 리스크


위의 관찰을 확정하여, 만일 투자자산이 n개인 경우는 어떨까요? 자산을 X1,X2,,Xn이라 하고,
각 1in에 대해, Xi의 기대수익률을 ri, 표준편차를 σi라 합시다.

각각의 자산 Xi 에 가중치 wi 씩을 주고, 위의 2 자산 경우처럼
 w1+w2++wn=1  ,  wi0
이라 가정합시다.
이제, 포트폴리오
X=ni=1wiXi=w1X1++wnXn의 기대수익률과 분산을 구해보도록 하죠.

 

포트폴리오의 기대수익률

 

기대수익률은 아래와 같습니다.
E(X)=ni=1wiE(Xi)=ni=1wiri입니다.

 

 

포트폴리오의 분산


분산은 조금 복잡해지는데요. 먼저 다음의 두 식을 구하죠.

E((ni=1wiXi)2)=ni=1w2iE(X2i)+21i<jnwiwjE(XiXj) 이고

E(ni=1wiXi)2=(ni=1wiE(Xi))2=ni=1w2iE(Xi)2+21i<jnwiwjE(Xi)E(Xj)

 

입니다.  따라서
V(X)=E(X2)E(X)2=ni=1w2i(E(X2i)E(Xi)2)+21i<jnwiwj(E(XiXj)E(Xi)E(Xj))=ni=1w2iσ2i+21i<jnwiwjρijσiσj

입니다. 위 식에서 ρij는 자산 Xi,Xj사이의 상관계수이고 수식으로는
ρij=Cov(Xi,Xj)σiσj
입니다.

식(2)도 행렬의 곱의 형태로 멋지게 쓸 수 있습니다.

w=(w1w2wn) , C=(σ21ρ12σ1σ2ρ1nσ1σnρ12σ1σ2σ22ρ2nσ2σnρn1σ1σnρn2σ2σnsigma2n),

즉 w는 가중치 벡터, C는 공분산 행렬이라 하면, 자산 2개 있을 때와 마찬가지로 수식(2)을


V(X)=wtCw
와 같이 쓸 수 있습니다.

 

 

Python Code 

 

두 자산을 섞은 포트폴리오 구현


상관계수 ρ를 갖는 두 자산 X1,X2를 잘 섞어 다양한 포트폴리오를 구현해 보겠습니다.

 

임의의 양수 가중치 w1,w20을 두어(w1+w2=1 가정) 다양한 포트폴리오를 만든 뒤, 이 포트폴리오의 표준편차와 기대수익률을  x축이 표준편차, y축이 기대수익률이 되도록 scattering 해 보죠.

def TwoAsset_Portfolio():
    rate = np.array([0.02, 0.03])   # 두 자산의 수익률: 2%, 3%
    std = np.array([0.05, 0.12])    # 두 자산의 수익률표준편차: 5%, 12% 

    weight = np.linspace(0, 1, 100 + 1)   # 첫번째 기초자산 가중치 : 0~1 100등분
    corr = np.linspace(-1, 1, 10 + 1)     # 두 자산의 상관계수를 -1~1 까지 10등분
    colors = cm.Blues(np.linspace(0.1, 1, len(corr)))  # 각 correlation마다 Blue계열의 색을 쓰기 위한 color map도입

    legend_showed = [0, len(corr) - 1]    # 범례 표시는 corr[0]과 corr[-1] 두 경우만 하기 위해

    for i, (rho, cc) in enumerate(zip(corr, colors)):
        if i in legend_showed:            # 범례 표시
            mylabel = 'corr={:.1f}'.format(rho)
        else:
            mylabel = None                # 범례표시 안함 None

        rate_port = []
        std_port = []
        for w in weight:
            w1 = w            # 자산1 가중치
            w2 = 1 - w        # 자산2 가중치 : w1 + w2=1 이 되게끔

            rate_port.append(w1 * rate[0] + w2 * rate[1])
                              # portfolio의 기대수익률
            std_port.append(np.sqrt(w1 ** 2 * std[0] ** 2 + w2 ** 2 * std[1] ** 2 + 2 * rho * w1 * w2 * std[0] * std[1]))
                              # portfolio의 표준편차
        plt.scatter(std_port, rate_port, color=cc, label=mylabel)
                              # (표준편차, 기대수익률) 을 xy평면에 scattering

    plt.legend()
    plt.xlabel('std')
    plt.ylabel('expectation')
    plt.show()


결과 그림을 보시죠.


 


상관계수가 -1일 때가 제일 왼쪽의 그래프입니다. 완전한 꺾은 선이네요.

 

상관계수가 1일 때는 두 점을 잇는 직선이 됩니다. 두 점이란 바로 (σ1,r1)(σ2,r2) 겠죠.

 

상관계수가 -1에서 1 사이는 왼쪽으로 볼록한 곡선이 됩니다. 표준편차가 커지면(즉 위험이 증가하면) 기대수익률도 커지는 현상도 보이고요. 또한  표준편차를 최소로 하면서 기대수익률을 어느 정도 바라볼 수 있는 

 최소분산 포트폴리오

를 찾을 수도 있습니다. 

 

예컨대, ρ=0.2 인 상황을 봅시다.  최소분산이 어디에서 일어나는지 찾아보기 위해  위의 코드와 아주 비슷한 코드를 하나 새로 작성해 봅시다.

 

def TwoAsset_Portfolio_fixedCorrelation():
    rate = np.array([0.02, 0.03])
    std = np.array([0.05, 0.12])

    weight = np.linspace(0, 1, 100 + 1)
    corr = 0.2

    rate_port = []
    std_port = []
    for w in weight:
        w1 = w
        w2 = 1 - w

        rate_port.append(w1 * rate[0] + w2 * rate[1])
        std_port.append(np.sqrt(w1 ** 2 * std[0] ** 2 + w2 ** 2 * std[1] ** 2 + 2 * corr * w1 * w2 * std[0] * std[1]))

    rate_port = np.array(rate_port)
    std_port = np.array(std_port)
    plt.scatter(std_port, rate_port, color='skyblue', s=20)   # 우선 (표준편차, 기대수익률) scattering

    std_min_x = std_port[std_port == np.min(std_port)]   # 표준편차를 최소로 하는 index 에 해당하는 표준편차 값
    std_min_y = rate_port[std_port == np.min(std_port)]  # 표준편차를 최소로 하는 index 에 해당하는 기대수익률 값

    plt.scatter(std_min_x, std_min_y, color='blue', s=50) # plot dot
    print('w1={:.2f}'.format(weight[std_port == np.min(std_port)][0])) # 표준편차를 최소로 하는 index에 해당하는 w1 가중치
    plt.xlabel('std')
    plt.ylabel('expectation')
    plt.show()

 

결과는 다음과 같습니다.

w1=0.91

즉, w1=0.91,w2=0.09일 때 분산이 최소가 나온다라는 것이죠. 자산 X1에 91%를 투자하고  X2에는 9% 투자할 때 분산이 최소가 된다는 뜻입니다. 바로 최소분산 포트폴리오이죠. 그래프는 아래와 같습니다.

 

파란색 점이 분산이 최소인점이고 가중치가 각각 w1=91%, w2=9% 일때,

 

 

사실 위 점은 수식을 통해서도 찾아낼 수 있습니다.  포트폴리오 X의 분산은

V(X)=w21σ21+w22σ22+2ρw1w2σ1σ2

라 했습니다. w1=w 라 하면 w2=1w이므로 위 분산식을 f(w) 라 하면

f(w)=σ1w2+σ2(1w)2+2ρσ1σ2w(1w)

입니다.

따라서

f(w)=(σ21+σ222ρσ1σ2)w+(ρσ1σ2σ22)

이고

f(w)=σ21+σ222ρσ1σ2입니다.

 

f(w)=(σ1σ2)2+2(1ρ)σ1σ2>0이므로 아래로 볼록 합니다. 따라서 f(w)=0 점이 바로 최솟값이 되겠죠, 즉,

w=ρσ1σ2+σ22σ21+σ222ρσ1σ2

일 때이죠.

 

만일 ρσ2/σ1 , ρσ1/σ2 까지 만족한다면,

 식(4)의 w

0w1

까지 만족합니다. 바로 우리가 찾는 식이죠. 아래와 같이 검산해 볼 수 있습니다.

 

    rate = np.array([0.02, 0.03])
    std = np.array([0.05, 0.12])
    corr = 0.2
    if (corr <= std[0] / std[1]) and (corr <= std[1] / std[0]):
    print('Condition True')

    w = (std[1] ** 2 - corr * std[0] * std[1]) / (std[0] ** 2 + std[1] ** 2 - 2 * corr * std[0] * std[1])
    print('w1={:.4f}'.format(w))

-------------------------------------------------------
Condition True
w1=0.9103

 

 

 

 

세 자산을 섞은 포트폴리오 구현

 

이번에는 세 개의 자산으로 분석합니다.  식(3)을 이용하여 포트폴리오의 분산을 구할 예정입니다.

마찬가지로 세 포트폴리오의 가중치 합이 1이 되게 하여, 포트폴리오의 기대수익률과 분산을 구합니다.

 

위의 예제랑 좀 다른 점은 가중치 합이 1이 되는 세 가중치를 이번에는 난수를 발생시켜 합이 1이 되게 조정해 주는 방법을  택했습니다.

 

def ThreeAsset_Potfolio():
    rate = np.array([0.02, 0.03, 0.04])
    std = np.array([0.01, 0.12, 0.2])
    rho12 = 0.1
    rho13 = 0.2
    rho23 = -0.1
    s12 = std[0] * std[1] * rho12    # 공분산행렬의 (1,2)원소
    s13 = std[0] * std[2] * rho13    # 공분산행렬의 (1,3)원소
    s23 = std[1] * std[2] * rho23    # 공분산행렬의 (2,3)원소

    cov_matrix = np.array([[std[0] ** 2, s12, s13],
                           [s12, std[1] ** 2, s23],
                           [s13, s23, std[2] ** 2]])     # 공분산 행렬

    rate_port = []
    std_port = []

    for i in range(500):
        w = np.random.rand(3)     # 균등난수 3개 w1,w2,w2를 발생하여
        w /= w.sum()              # 그 합인 W= w1+w2+w3으로 나누면 w1/W , w2/W, w3/W 의 합은 1
        rate_result = w @ rate.T  # 기대 수익률은 w1r1 + w2r2 + w3r3 이므로 w와 r의 행렬곱 
        std_result = np.sqrt(w @ cov_matrix @ w.T)   # 분산값 wCw'
        rate_port.append(rate_result)
        std_port.append(std_result)
    rate_port = np.array(rate_port)
    std_port = np.array(std_port)

    plt.style.use('seaborn')      # plot style 지정
    colors = rate_port / std_port

    plt.scatter(std_port, rate_port, c=colors, cmap=cm.autumn) #autumn color map으로 scattering
    plt.xlabel('std')
    plt.ylabel('expectation')

    plt.show()

 

 

 

결과는 아래와 같습니다.  투자자산이 2개일 때와 비슷하게 약간 볼록성이 느껴지는 관계 그래프가 나오네요.

 

 

 

728x90
반응형