ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 영구포트폴리오 직장인에게 최적화하기 (3)
    재테크 2021. 1. 24. 22:31

    이번 글은 지난 글에 이어서 직장인에 맞는 적금식 영구 포트폴리오의 운용과 조금이라도 나은 수익률을 위한 운용 전략을 시뮬레이션을 통하여 찾아보고 그 전략을 공유하는 글이다. 전략 2는 자산 가격의 변동과 수익 상황에 따라 분할 매수/매도를 하는 전략을 선택하여 지난 15년간의 데이터를 기준으로 수익률은 높이고 MDD는 낮추는 일석이조의 효과를 거두었다. 하지만 역시 과거 데이터에 과적합(overfitting) 되어 신뢰성이 떨어진다는 한계점이 있다. 15년의 데이터라고 하지만 관측한 데이터의 수가 약 189개 밖에 안되며 (월 별 데이터이기 때문에) 흔히 MDD가 발생하는 지점이 자산 가격의 폭락이 이루어졌던 2019년 4월이 아닌 것도 이상하다. 나는 시뮬레이션을 통한 각 자산의 운용 전략이 가격 변동 추세에 조금이라도 더 잘 대응하는 방법에 대한 인사이트를 얻었다는 것에 의의를 두고 좀 더 일반화된 전략을 적용해보고 분석하기로 했다.

     

    원래 영구 포트폴리오는 자산 가격의 변동성에 의해 발생한 자산 금액 비중의 차이를 다시 조절하면서 (rebalancing) 자산들을 저가에 사고 고가에 팔아 안정적인 수익률을 일으킨다. 하지만 rebalancing 과정에서 자산을 팔았을 때 발생한 수익은 그대로 세금으로 내게 된다. 따라서 나는 적금식으로 매달 추가되는 돈을 저가 매수에만 써서 수익 실현을 최소한으로 하여 rebalancing 효과를 누리는 전략을 실험해보기로 했다.

     

    전략 3. 가격 변동에 의해 줄어든 비중의 자산을 사기

    각 자산별 총평가액은 매월 가격 변동에 의하여 그 비중이 바뀐다. 이 전략은 매월 변동된 자산의 가치가 떨어진 것부터 가장 높은 자산 가치에 해당하는 가격에 맞게 투자 금액을 분배한다.

    자산 (원) 현금 주식 채권 투자 금액
    현재 가치 1,000,000 1,200,000 800,000 1,100,000 800,000
    채권 매수 1,000,000 1,200,000 1,200,000 1,100,000 400,000
    현금 매수 1,200,000 1,200,000 1,200,000 1,100,000 200,000
    금 매수 1,200,000 1,200,000 1,200,000 1,200,000 100,000
    균등 분배 1,225,000 1,225,000 1,225,000 1,225,000 0

    예를 들어, 각 자산별 현재 가치가 위의 1행처럼 분포되어있다고 하고 새 투자 금액이 80만 원이 추가되었다고 할 때 가격 하락에 의하여 가장 가치가 떨어져 있는 채권, 현금, 금 순서로 최대 가치인 주식의 금액에 맞게 투자금액을 투자한다. 그리고 투자 금액이 남는다면 투자 금액을 모든 자산에 분배하고 투자한 자산으로 새로 매수를 한다. 그리고 가격이 맞지 않아 남은 가격은 이월돼서 다음 달 투자에 사용된다.

    자산 (원) 현금 주식 채권 투자 금액
    현재 가치 1,000,000 1,200,000 200,000 1,100,000 800,000
    채권 매수 1,000,000 1,200,000 1,000,000 1,100,000 0

    만약 위의 상황처럼 채권의 가격이 너무 떨어져서 투자 금액을 모두 투자하더라도 가격이 균등하게 맞춰지지 않는다면 그 달에는 더 이상 거래를 진행하지 않는다.

     

    백테스트 결과

    전략 3의 전략 1과의 비교

    결과는 놀랍게도 전략 1에 소폭 밀리는 2억 4705만원의 총 평가 가치로 계산되었다. 최대 손실 (MDD) 값은 2009년 4월 1일 기준으로 9.0%로 전략 1보다 더 안정적인 구성인 결과를 냈지만 총수익금액이 절대적으로 낮은 것은 이전 전략들에 비해 너무 매력적이지 않게 다가왔다. 원인을 분석해봤더니 이전 전략들은 현금에 투자하는 비용을 매월 20만 원으로 고정했지만 이 전략은 평균 281,000원 정도의 금액이 현금 투자에 쓰였다. 즉, 장기적인 관점에서 상대적으로 투자 자산의 가치 상승에 비해 현금의 복리 수익이 따라가지 못하기 때문에 현금에 많이 투자하는 것이 손해라는 뜻이다.

     

    이를 보정하기 위하여 두 가지 변형 전략을 실험해보았다.

    3-1. 현금은 매달 20%만큼 투자, 그 외 투자 금액으로 나머지 자산 (주식, 채권, 금)에 전략 3을 적용하기

    3-2. 현금을 제외해버리고 나머지 자산들만으로 전략 3을 적용하기

     

    전략 3-1, 3-2 적용 후 전략 1과 다시 비교

    전략 3-1은 총 2억 5115만원의 평가액으로 전략 1처럼 무조건 매수하는 전략보다는 성과가 소폭 앞섰고 MDD는 9.3%로 전략 전략 1의 10.9%보다는 확실히 앞섰다. 일단 rebalancing을 하는 것이 장기적인 안정성과 성장률 모든 측면에서 무조건 균등하게 사는 것보다는 좋은 성과를 낸다는 것을 검증했다.

     

    전략 3-2는 다른 전략들보다 더 높은 평가액인 2억 7620만 원이 나왔다. 현금의 가치 하락이 2008년 이후에 양적 완화를 적용하고나서부터 가속화되었다는 점을 감안했을 때 예상된 결과이다.  MDD 값이 12.5%로 모든 전략을 통틀어서 최대로 나왔고 고점 대비 최대 손실 후 전 고점을 회복하는데 걸리는 시간의 차이가 다른 전략에 비해 오래 걸리는 것은 사실이다. 하지만 약 2500만 원의 수익률 차이를 보고 나니 개인적으로는 현금 비중을 25%보다는 줄여야겠다는 생각이 들었다.

    전략 전략 1 전략 3-1 전략 3-2
    MDD 10.9% 9.3% 12.5%
    전 고점 회복에 걸린 기간 8개월 6개월 9개월

     

    구현

    이전 전략에서 구현했던 util 함수를 여전히 이용했고 거래 수수료는 여전히 0.3%를 적용하였다.

    from utils import (
        load_stock_prices, save_results, to_kr_prices, get_dates, get_mdd
    )
    
    
    # 월별 데이터 전처리
    dates = get_dates()
    dollars = load_stock_prices('USD_KRW')
    stocks = to_kr_prices(load_stock_prices('SPY'), dollars)
    bonds = to_kr_prices(load_stock_prices('TLT'), dollars)
    golds = to_kr_prices(load_stock_prices('IAU'), dollars)
    
    
    # 현금을 똑같이 rebalancing에 사용하는 전략 3의 기본 버전
    def simulate_with_cash():
        volumes = [0] * 3
        balances = [0] * 4
        deposit = 0
        results = []
        cash_inputs = []
        for curr_prices in zip(stocks, bonds, golds):
            deposit += 800000
            for i in range(3):
                balances[i] = curr_prices[i] * volumes[i]
            balances[3] = int(balances[3] * 1.00165)
            max_balance = max(balances)
            cash_input = 0
            # 자산 평가액에 따라 정렬하여 투자금액을 분배
            for index, balance in sorted(list(enumerate(balances)),
                                         key=lambda x: x[1])[:-1]:
                need_balance = max_balance - balance
                if index == 3:
                    add_balance = min(need_balance, deposit)
                    balances[3] += add_balance
                    deposit -= add_balance
                    cash_input += add_balance
                else:
                    add_balance = min(need_balance, deposit)
                    add_volume = add_balance // (curr_prices[index] * 1.003)
                    balances[index] += add_volume * curr_prices[index]
                    volumes[index] += add_volume
                    deposit -= int(add_volume * curr_prices[index] * 1.003)
    
            # 남은 투자금액을 각 자산별로 균등하게 재분배
            remain_division = deposit // 4
            for i in range(3):
                add_volume = remain_division // (curr_prices[i] * 1.003)
                volumes[i] += add_volume
                balances[i] += add_volume * curr_prices[i]
                deposit -= int(add_volume * curr_prices[i] * 1.003)
    
            balances[3] += remain_division
            cash_input += remain_division
            deposit -= remain_division
            cash_inputs.append(cash_input)
            results.append(sum(balances) + deposit)
        return results
    
    
    # 전략 3-1: 현금을 매월 20만원씩 투자하는 것으로 고정하고 나머지 자산을 rebalancing하는 전략
    def simulate_with_fixed_cash():
        volumes = [0] * 3
        balances = [0] * 3
        deposit = 0
        cash = 0
        results = []
        for curr_prices in zip(stocks, bonds, golds):
            deposit += 600000
            cash = int(cash * 1.00165)
            cash += 200000
            for i in range(3):
                balances[i] = curr_prices[i] * volumes[i]
            max_balance = max(balances)
            for index, balance in sorted(list(enumerate(balances)),
                                         key=lambda x: x[1])[:-1]:
                need_balance = max_balance - balance
                add_balance = min(need_balance, deposit)
                add_volume = add_balance // (curr_prices[index] * 1.003)
                balances[index] += add_volume * curr_prices[index]
                volumes[index] += add_volume
                deposit -= int(add_volume * curr_prices[index] * 1.003)
    
            remain_division = deposit // 3
            for i in range(3):
                add_volume = remain_division // (curr_prices[i] * 1.003)
                volumes[i] += add_volume
                balances[i] += add_volume * curr_prices[i]
                deposit -= int(add_volume * curr_prices[i] * 1.003)
    
            results.append(sum(balances) + deposit + cash)
        return results
    
    
    # 전략 3-2: 현금을 투자하지 않고 나머지 자산만으로 rebalancing하는 전략
    def simulate_without_cash():
        volumes = [0] * 3
        balances = [0] * 3
        deposit = 0
        results = []
        for curr_prices in zip(stocks, bonds, golds):
            deposit += 800000
            for i in range(3):
                balances[i] = curr_prices[i] * volumes[i]
            max_balance = max(balances)
            for index, balance in sorted(list(enumerate(balances)),
                                         key=lambda x: x[1])[:-1]:
                need_balance = max_balance - balance
                add_balance = min(need_balance, deposit)
                add_volume = add_balance // (curr_prices[index] * 1.003)
                balances[index] += add_volume * curr_prices[index]
                volumes[index] += add_volume
                deposit -= int(add_volume * curr_prices[index] * 1.003)
    
            remain_division = deposit // 3
            for i in range(3):
                add_volume = remain_division // (curr_prices[i] * 1.003)
                volumes[i] += add_volume
                balances[i] += add_volume * curr_prices[i]
                deposit -= int(add_volume * curr_prices[i] * 1.003)
    
            results.append(sum(balances) + deposit)
        return results
    
    
    # results = simulate_with_cash()
    # results = simulate_with_fixed_cash()
    results = simulate_without_cash()
    mdd, mdd_date = get_mdd(get_dates(), results)
    save_results(map(lambda x: [int(x)], results), columns=['총 평가액'])
    

     

    결론

    지금까지 적금식으로 투자금액을 늘리려는 직장인이 영구 포트폴리오를 도입할 때 어떻게하면 안정성을 덜 떨어뜨리면서 수익률을 높일 수 있을지를 여러 가지 전략으로 알아봤다. 결론적으로 영구 포트폴리오는 충분히 매력적이나 원래 방법인 현금 25% 비율은 조금 낮춰서 리벨런싱을 하면서 운용하는 것(전략 3-1, 3-2 사이 어딘가)이 매력적이라고 생각한다.

     

    하지만 미래는 과거와 똑같지 않기 때문에 똑같은 자산으로 아주 똑같은 전략을 도입하는 것이 정답은 아니라고 생각하며 상관관계가 낮은 자산에 분산 투자하고 리벨런싱을 통하여 수익률을 늘리는 개념 정도만 이해하고 투자에 참고하면 좋을 것 같다. 나와 같이 재테크에 관심이 있는 개발자 혹은 코딩을 할 줄 아는 사람이라면 공유한 코드를 통하여 여러 가지 다양한 실험을 해보면서 많은 인사이트를 얻었으면 좋겠다.

    댓글

Designed by Tistory.