ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬으로 금리파생상품(조기상환권, 수의상환권, Put Option, Call Option) 모델 만들기(fsolve로 Black-Derman-Toy 모델 구현)(Part 1)
    파이썬 2020. 10. 22. 16:50

    6개월만에 쓰는 글인 것 같습니다. 4월 22일자 글(파이썬으로 목표값 찾기, https://pythoncpa.tistory.com/6?category=806912)에 우연한 분께서 fsolve라고 하는 목표값 찾기 함수가 있다고 가르침을 주셔서, 또 구글과 유튜브를 뒤져서 허접한 모델을 만드는데 성공했습니다. 그런게 있는 줄도 몰랐는데 이 자리를 빌어서 댓글을 남겨주신 우연히 님께 감사드립니다.

     

    일단, BDT 모형(Black-Derman-Toy model, en.wikipedia.org/wiki/Black%E2%80%93Derman%E2%80%93Toy_model)은 금리변동을 이항모형으로 추정하여, 특정 채권에 부여된 콜옵션 또는 풋옵션 등의 가치를 계산하는 모형입니다. 모델링 과정에서 어려운 부분은 Calibration(금리 보정)이라는 과정인데, 시장에서 관측된 이자율로 계산한 채권의 현재가치와 선도금리 이항트리로 계산한 채권의 현재가치가 일치하도록 매기간 단기선도이자율에 보정금리를 반영하는 절차입니다. 이 과정에서 목표값 찾기 기능이 필요하여, 엑셀로 구현시에는 목표값 찾기 기능을 활용하고, 파이썬으로 구현시에는 fsolve로 구현이 가능한 것 같습니다. 파이썬은 라이브러리가 방대한 언어이기 때문에 fsolve 이외에 다른 함수도 있을 수 있으나, 제가 알고있는 목표값 찾는 함수는 fsolve 밖에 없기 때문에 fsolve로 구현하였습니다. 목표값 찾는 함수를 직접 만들려고 시도했던 것에 비해서 장족의 발전입니다.

     

    아래 이미지 파일들은 주피터 노트북에서 캡쳐한 파일입니다. 파일을 통째로 올리고 싶으나 제 주된 밥벌이 중 하나가 파생상품 평가라서 그렇게 용감할 수 없는 점에 대해 양해의 말씀을 올립니다.

     

    [1] 일단 판다스, 넘파이, 매쓰 모듈을 임포트합니다.

     

    [2] 모형에 쓰일 현물이자율을 정의합니다. 원래는 시장에서 관측된 YTM에서 Spot Rate을 도출해야 하는데 그러면 시작도 하기 전에 지치게 되므로 바로 Spot Rate을 각각 5%, 6%, 7%로 지정하였습니다. 현물이자율은 단기선도이자율과 다르게 현재시점부터 만기시점까지 기하평균으로 적용되는 이자율입니다. 즉 s2가 6%라는 의미는 0에서 2 시점까지 매년 6%가 적용된다는 의미입니다. 단기선도이자율이 매 단위기간마다 정의되는 것과 차이가 있습니다.

     

    [3] f1은 0에서 1시점까지의 단기선도이자율이므로 당연히 s1과 동일합니다. f1에 s1과 같은 값을 입력합니다. f1은 약간 혼란을 줄 수 있어서 0f1 또는 f(0,1) 등으로 표현할까 했는데, 숫자로 시작하는 변수는 파이썬 문법 때문에 사용할 수 없고, 두번째거는 복잡해서 함수형태라서 그냥 f1, f2, f3 이렇게 표현했습니다.

     

    [4] f2를 단기선도이자율 정의에 맞게 계산한 것입니다. (1+s2)^2 = (1+f1)*(1+f2) 등식이 성립하도록 f2를 구했습니다.

    [5] 만기 2년짜리 제로쿠폰채권을 현물이자율로 계산한 값과 단기선도이자율로 계산한 값이 동일한 것인지 검증한 것입니다. 가끔 소수점 16번째 자리에서 1이 차이가 나는 경우가 있습니다. 파이썬 종특인 것으로 이해하고 있습니다.

     

    [6], [7] 위와 마찬가지로 f3를 구하고 검증하는 코드입니다.

     

    [8] 만기가 1년, 2년, 3년이고 액면이 1원인 제로쿠폰채권의 가치를 구한 것입니다. 현물이자율로 구하건 단기선도이자율로 구하건 동일한 결과가 나와야 할 것입니다. 이표채를 예로들면 복잡해질 것 같아서 무이표채를 예로 들었으며, 액면을 1원으로 한 이유도 동일합니다.

    [9] 그냥 보기 좋게 표로 정리한 것입니다. 데이터프레임의 이름을 market_data로 한 것은 현물이자율, 선도이자율, 현재가치 등이 시장에서 관찰된 YTM으로 계산된 값임을 가정하였기 때문이기도 하며, 아래에서 선물이자율 이항트리에서 계산할 Calibration 과정을 거친 data와 의미상 대비시킬 의도도 있습니다.

     

    [10] 평가대상채권에 적용할 변동성 V를 10%로 가정하고, 상승계수 u, 하락계수 d를 계산한 것입니다.

     

    [11] 선도이자율 이항트리를 만들기 위해서 3기간의 0으로 채워진 트리를 먼저 만들어 줍니다.

    [12] f1, V, u, d에 따라 3기간의 선도이자율 트리를 만들어 줍니다. for 반복문보다 while 반복문으로 만드니 훨씬 깔끔해 보입니다. 앞에 글들을 보시면 이 단순한 코드 대신 얼마나 복잡한 코드를 썻는지 확인하실 수 있습니다. 역시 사람은 배워야 합니다.

     

    [13] 선도이자율 이항트리의 이자율을 활용하여 계산한 현재가치를 pvb1, pvb2, pvb3로 정의하였습니다. 시장에서 관측된 값으로 계산한 현재가치인 pv1, pv2, pv3와 구분하기 위함이며, binomial tree의 앞자인 b를 따서 pvb라고 이름을 만들었습니다.

     

    [14] pvb1과 pv1은 당연히 같습니다.

     

    [15] pvb2를 계산합니다. 코드를 풀어 설명하자면 f_tree.loc[1, 2]는 f_tree의 1행 2열에 있는 값을 의미하므로 금리가 1회 상승한 경우의 금리입니다. 따라서 a는 금리가 f1에서 1회 상승한 경우 만기 2년인 제로쿠폰채권의 시점 1에서의 현재가치입니다. 마찬가지로 b는 금리가 f1에서 1회 하락한 경우 만기 2년인 제로쿠폰채권의 시점 1에서의 현재가치입니다. 만기 2년 채권의 시점 1의 현재가치 a와 b에 대해서 각각 확률 50%를 고려하고 f1으로 1기간을 더 할인해 주면 현재 시점의 pvb2를 구할 수 있습니다. BDT 모형에서 금리의 상승확률과 하락확률은 각각 50%로 봅니다. 이게 왜 50% 인지는 제가 논의하는 영역 밖의 일이므로, 더 이상 궁금해하지 않습니다. Cox Ross Rubinstein 논문은 원문을 찾아 읽어봤는데 놀랍게도 읽기 전과 읽은 후에 저의 이해도에 큰 차이가 없었습니다. 찾는데도 시간 엄청 오래 걸리고 건너 뛰면서 읽는데도 시간이 굉장히 오래 걸렸습니다. 모델에 대한 이론적인 이해는 강진홍 회계사님의 공정가치평가 책으로 만족합니다.

     

    [16] 안타깝게도 pvb2와 pv2는 일치하지 않습니다. 선도이자율 트리의 금리와 확률을 고려하여 계산한 현재가치와 시장에서 관측된 현재가치가 다르다는 것입니다. 재무관리이론들은 대체로 시장이 답인 것으로 귀결이 됩니다. 따라서 이것도 결론은 시장이 답이므로, f1, V, u, d로 계산한 단기선도이자율 이항트리에서 해당 기간의 선도이자율에 보정금리를 가산하는 방식으로 해결합니다. 여기서부터가 복잡합니다.

     

    [17] f(x)라는 함수를 정의하는데, 이 함수는 pv2와 pvb2의 차이를 구하는 함수입니다. pvb2 계산시 산식이 들어가 있습니다.

     

    [18] fsolve 함수를 임포트하고, f(x)를 0으로 만드는 x를 구하는 코드입니다. x는 0.01986847 이렇게 계산되었습니다. 보이기는 소수점 8자리 숫자로 보이지만, 엑셀로 다운받아서 보면 소수점 16자리 숫자임을 확인할 수 있습니다. f(x)를 단순화 시키는 데 시간이 오래 걸렸는데 캡쳐해놓고 보니까 초딩도 할 수 있는 것처럼 보이는군요. 시점 2에 적용할 보정금리가 0.01986847이라는 의미이며, 아래와 같이 선도이자율 이항트리의 각 위치에 동일한 값을 더해줍니다.

     

    [19] 시점 2의 각 노드에 있는 단기선도이자율에 보정금리 x를 더해서 최초에 f1, V, u, d 만으로 계산한 선도이자율 이항트리를 보정해줍니다. 이 작업을 Calibration 이라고 합니다. 매 시점마다 동일한 작업을 수행해 주어야 합니다.

    [20] ,[21] 변경된 선도이자율 이항트리로 pvb2를 재계산해서 pv2와 비교합니다. 여전히 False로 나오기는 하지만 두 값의 차이는 1/10^16 입니다. 여기를 True로 나오게 만들고 싶어서 금리를 변경해 보았는데, 여기가 True가 나오면 다른 곳에서 False가 나오고 어떨 때는 선도이자율과 현물이자율 검증에서 False가 나오고 해서 그냥 그대로 두었습니다. 여튼 매우 근접한 값이 나옵니다.

     

    [22] pvb3을 구합니다. pvb2에서 1기간만 늘어난 것입니다. 기간이 길어지면 당연히 반복문을 써야 합니다만, 본 모델은 기간이 짧아서 수작업을 한번 더 했습니다. 만기가 3년인 액면 1원의 제로쿠폰채권이 시점2에서 각각 경우(uu, ud, dd 또는 상승상승, 상승하락, 하락하락)에 따라 a, b, c의 현재가치를 가지게 되며, 시점1에서는 각각 d와 e의 현재가치를 가지고 현재시점에서는 시점1의 가치를 50%의 확률로 가중하여 f1으로 할인하면 됩니다.

    [23] 예상했던데로 pvb3와 pv3는 차이가 납니다.

     

    [24] pvb3과 pv3의 차이를 구하는 함수를 만들었습니다.

    [25] f(x)를 0으로 만드는 x를 구합니다.

    [26] x를 시점3의 선도이자율에 각각 더해줍니다. 변경된 이자율 트리도 출력해봅니다.

     

    [27] 보정된 선도이자율 이항트리에 근거하여 pvb3를 구합니다.

    [28] pvb3와 pv3를 비교하였더니 이번에는 깔끔하게 True가 떴습니다. 끝이 아름답습니다.

     

    3기간의 단기선도이자율 이항트리를 만드는 것으로 이번 글은 마칠까 합니다. 다음 글에는 위에서 구한 선도이자율 이항트리를 가지고 옵션가치를 구하는 코드를 올려보겠습니다. 글을 늦게 올리게 될 수도 있으므로 미리 간략히 말씀을 드리자면, 위에서 구한 선도이자율 이항트리의 각 금리는 해당 시점(시점 1, 2, 3)과 경우(u, d, uu, ud, dd 등)에 대응되는 채권 가치가 계산될 것인데, 해당 채권에 put option이 부여된 경우 해당 시점의 채권가치가 put option 행사시 가치보다 작다면 put option이 행사될 것이고, put option 행사되는 경우를 고려한 채권의 현재가치는 그렇지 않은 경우보다 가치가 클 것이며, 그 가치의 차이가 put option의 가치가 될 것입니다.

     

    긴 글 읽어 주셔서 감사합니다.

    댓글

Designed by Tistory.