CRR模型

Photo by Simon Wilkes on Unsplash

本文重點概要

  • 文章難度:★★★☆☆
  • 使用交易面資料進行選擇權定價
  • 閱讀建議:本文主要將 CRR Model 程式化,公式的推導並不在這次文章的範疇內,建議讀者再閱讀前,先了解 CRR Model 的意涵。

前言

在我們之前的文章 —  Black-Scholes 模型與 Greeks,向各位介紹了如何將 Black-Scholes Model 程式化,然而 Black-Scholes 模型無法推算美式買賣權的理論價格,因此在 Black Scholes 橫空出世的三年後,約翰考克斯、史蒂芬羅斯與馬克史賓斯坦發明了一個相對簡易但更泛用的選擇權定價公式 —  CRR 模型。

CRR 模型利用離散二項式定理,假使未來每個時間點都只會有上漲與下跌兩種情況,並且漲幅跌幅固定。如此一來,未來標的物價格就可以隨時間推進繪製成一張二元樹模型。接著計算每個節點之下,選擇權的內含價值,再將每節點的價值取其現值後,向前推導就可以得出選擇權的理論價值。

編輯環境與模組需求

本文使用 Window 作業系統以及 Jupyter Notebook 作為編輯器。

# Load required package
import math 
import tejapi
import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt 
from scipy.stats import norm
plt.style.use('ggplot')

# log in TEJ API
api_key = 'YOUR_KEY'
tejapi.ApiConfig.api_key = api_key
tejapi.ApiConfig.ignoretz = True

資料庫使用

公司交易面資料庫: 未調整股價(日),資料代碼為(TWN/APRCD)。
衍生性金融商品資料庫: 選擇權日交易狀況,資料代碼為(TWN/AOPTION)。

資料導入

使用台灣加權股價指數(Y9999)未調整收盤價,時間區間為2021/01/31到2023/04/19。並且載入台灣加權指數買權與賣權(TXO202304C15500、TXO202304P15500),該選擇權為歐式買權、開始交易日為1/31,到期日為4/19,履約價格為15500。

# set time zone
gte, lte = '2021-03-16', '2023-04-20'

# Get stock price
stocks = tejapi.get('TWN/APRCD',
                   paginate = True,
                   coid = 'Y9999',
                   mdate = {'gte':gte, 'lte':lte},
                   opts = {
                       'columns':[ 'mdate','close_d']
                   }
                  )

# Get options price
puts = tejapi.get( # puts price
    'TWN/AOPTION',
    paginate = True,
    coid = 'TXO202304P15500',
    mdate = {'gte':gte, 'lte':lte},
    opts = {
        'columns':['mdate', 'coid','settle', 'kk', 'theoremp', 'acls', 'ex_price', 'td1y', 'avolt', 'rtime']
    }
)
calls = tejapi.get( # calls price
    'TWN/AOPTION',
    paginate = True,
    coid = 'TXO202304C15500',
    mdate = {'gte':gte, 'lte':lte},
    opts = {
        'columns':['mdate', 'coid','settle', 'kk', 'theoremp', 'acls', 'ex_price', 'td1y', 'avolt', 'rtime']
    }
)

# set index
stocks = stocks.set_index('mdate')
puts = puts.set_index('mdate')
calls = calls.set_index('mdate')

資料處理

計算大盤之日報酬並且計算移動報酬波動度,以252天也就是一年為窗格迭代下去。

# Calculate stock return and moving volatility
stocks['daily return'] = np.log(stocks['close_d']) - np.log(stocks['close_d'].shift(1))
stocks['moving volatility'] = stocks['daily return'].rolling(252).std()

CRR 模型

如同前言所述,CRR 模型是一個更直觀且更靈活的選擇權定價模型。雖然他不像 Black Scholes 一樣具有封閉解,且因為二元樹結構的關係,在計算上會較 Black Scholes 耗時。然而,CRR 因為會遍歷選擇權存續的所有時間點,因此在針對一些因時而變的選擇權定價上,相較於Black Scholes更有優勢,比如: 美式選擇權、奇異選擇權。

CRR 模型的公式基本上就是針對二元樹每個節點進行求現值的動作,一開始我們可以利用以下公式計算出下一個時間點,股價漲跌的幅度與機率,分別為圖中的u, d, p。

接著可以計算出下個時點上升與下降的股價,並且隨著時間推移形成一個樹狀圖。圖中黑色的線條與數學式為股價的變化,而紅色的線條與數學式則是買權的價值。可以發現我們先算出未來股價的變化(EX: uS0, dS0),再來將股價與履約價格相減取得買權的內含價值(EX: Ct,1, Ct,2),最後將買權內含價值一步一步回推現值,最終可推回今日買權理論價格。

買權價格樹狀圖
買權價格樹狀圖

賣權的話則只需要改變計算內含價值的方法,改動為履約價格扣除股票價格(EX: Pt,0, Pt,1)。

賣權價格樹狀圖
賣權價格樹狀圖

CRR 模型相較於 Black Scholes,可以針對美式買賣權進行訂價。所謂的美式選擇權就是持有選擇權者可以在到期前提前履約,而一般的買賣權則被稱為歐式選擇權。對於持有人來說,只要當下的內含價值大於回推時的現值時,就有履約動機。因此每個節點的選擇權價格會在回推現值與內含價值中取大者,見下圖中螢光色部分。

美式買權樹狀圖
美式買權樹狀圖

美式賣權樹狀圖
美式賣權樹狀圖

了解 CRR 如何計算選擇權價格後,我們直接進入程式化部分。

class crr_model:
    # init fuction
    def __init__(self, s, x, r, t, sigma, N, sigma_daily = True):
        
        t /= 252 
        dt = t/N 
        if sigma_daily:
            sigma *= np.sqrt(252)
        u = np.exp(sigma * math.sqrt(dt))
        d = 1/u
        p = (np.exp(r*dt)-d) / (u-d)
        
        self.s = s
        self.x = x
        self.r = r
        self.t = t
        self.N = N 
        self.dt = dt
        self.u = u
        self.d = d
        self.p = p
        self.sigma = sigma
    
    # european call price
    def eu_call_price(self):
        
        lattice = np.zeros((self.N+1, self.N+1))
        for j in range(self.N+1):
            lattice[self.N, j] = max(0, self.s*(self.u**j)*(self.d**(self.N-j)) - self.x)
        for i in range(self.N-1, -1, -1):
            for j in range(i+1):
                lattice[i, j] = np.exp(-self.r*self.dt)*(self.p*lattice[i+1,j+1] + (1-self.p) * lattice[i+1, j])
    
        return lattice[0,0], lattice
    
    # european put price
    def eu_put_price(self):
        
        lattice = np.zeros((self.N+1, self.N+1))
        for j in range(self.N+1):
            lattice[self.N, j] = max(0, self.x - self.s*(self.u**j)*(self.d**(self.N-j)))
        for i in range(self.N-1, -1, -1):
            for j in range(i+1):
                lattice[i, j] = np.exp(-self.r*self.dt)*(self.p*lattice[i+1,j+1] + (1-self.p) * lattice[i+1, j])
    
        return lattice[0,0], lattice
    
    # american call price
    def am_call_price(self):
        
        lattice = np.zeros((self.N+1, self.N+1))
        for j in range(self.N+1):
            lattice[self.N, j] = max(0, self.s*(self.u**j)*(self.d**(self.N-j)) - self.x)
        for i in range(self.N-1, -1, -1):
            for j in range(i+1):
                lattice[i, j] = max(np.exp(-self.r*self.dt)*(self.p*lattice[i+1,j+1] + (1-self.p) * lattice[i+1, j]),
                                   self.s*(self.u**j)*(self.d**(i-j)) - self.x )
    
        return lattice[0,0], lattice        
    
    # american put price
    def am_put_price(self):

        lattice = np.zeros((self.N+1, self.N+1))
        for j in range(self.N+1):
            lattice[self.N, j] = max(0, self.x - self.s*(self.u**j)*(self.d**(self.N-j)))
        for i in range(self.N-1, -1, -1):
            for j in range(i+1):
                lattice[i, j] = max(
                    np.exp(-self.r*self.dt)*(self.p*lattice[i+1,j+1] + (1-self.p) * lattice[i+1, j]), 
                    self.x - self.s*(self.u**j)*(self.d**(i-j))
                                   )
    
        return lattice[0,0], lattice             

為了重現樹狀結構,我們利用 numpy 的巢狀陣列組成一個(N+1)*(N+1)的矩陣,其中最左上角的元素就是選擇權的理論價格。其中藍色線條左下角事實上就是上述的樹狀圖。

s = 100 # set stock price at time 0
x = 95 # set strike price
r = 0 # set risk-free rate = 0%
t = 252 # set time to maturity at 252 days 
sigma = 0.3 # set annualized volatility at 0.3
N = 4 # set steps at 4

crr = crr_model(s, x, r, t, sigma, N, sigma_daily = False)
call, call_lat = crr.eu_call_price()
call_lat
樹狀圖
樹狀圖

收斂特性

眼尖的讀者可能已經注意到變數(N)的存在,N可以視為將到期期間切分成幾次,比如: 若到期期間為 252 天, N設定為251 ,表示一天會算一次未來價格,樹狀圖也會有252層。也就是我們的樹的層數(N+1)會是由N所決定。問題來了,那N究竟要取多大,才會有更佳的訂價結果。事實上,這並沒也一個特定的N值,但我們可以發現,隨著我們增加N的數量,也就是將時間切得更細碎,計算出來的選擇權價格會趨近於一個定值。因此若電腦效能許可之下,N值可以是多多益善的。

# plot the convergency pattern of crr model

calls_ = []
for n in range(1, 100):
    
    s = 100
    x = 100
    r = 0.011
    t = 52
    sigma = 0.3
    
    crr = crr_model(s, x, r, t, sigma, n, sigma_daily = False)
    call, call_lat = crr.eu_call_price()
    calls_.append(call)

plt.plot(range(1, 100), calls_, color = 'red')
plt.xlabel('Numbers of N')
plt.ylabel('Theoretical call price')
plt.title('Options price convergency')
plt.savefig('Options price convergency')
plt.show()
價格收斂性
價格收斂性

實際案例

最後我們來觀察一下,透過 CRR 模型所得的理論價格與 TEJ 所計算的 Black Scholes 價格以及實際價格進行對比。

我們採用時間為 2023-01-1 到 2023-04-19、履約價格為15500的台指賣權,其中無風險利率採用台灣五年期公債殖利率 — 0.011,Sigma 採用以252天為窗格的台指報酬率標準差,N設定為1000。所得結果如下,可以發現相較於 TEJ 所計算出的 Black Scholes 價格,CRR 價格更接近真實市場價格。 

s = stocks.loc['2023-01-31']['close_d'] # get the stock price at the first dat of options trading
x = 15500 # strike price
r = 0.011 # use 5-year Taiwan government bond ytm
t = 51 # time to maturity
sigma = stocks.loc['2023-01-31']['moving volatility'] # get the return volatility at the first day od options trading
N = 100 # divided time 2 maturity into 10 parts

crr = crr_model(s, x, r, t, sigma, N, sigma_daily = True)
call, call_lat = crr.eu_call_price() # european call price
put, put_lat = crr.eu_put_price() # european put price
call_a, call_lat_a = crr.am_call_price() # american call price
put_a, put_lat_a = crr.am_put_price() # american put price

print('CRR theoretical price: ', put)
print('TEJ Black Scholes price: ', puts.loc['2023-01-31']['theoremp'])
print('Real price: ', puts.loc['2023-01-31']['settle'])
實測結果
實測結果

結論

CRR 模型作為後起之秀,相較於 Black Scholes 提供了更多的靈活性。之後的衍生性商品熱潮中,許多特別的選擇權都可使用 CRR 模型或其延伸模型進行訂價。其簡易的數學計算方法與理論基礎,讓許多對於選擇權投資新手是個入門的好選項。於這篇文章,我們完成了 CRR 模型針對歐式與美式選擇權的訂價程式化。之後我們會提供更多選擇權或衍生性商品相關的知識,歡迎持續關注本平台,此外,也歡迎讀者及投資者們選購 TEJ E Shop中的方案來建構自己的選擇權定價程式。請注意以上訂價公式與選擇權商品僅為示範所用,不代表本台任何投資或標的上的建議。

完整程式碼

延伸閱讀

相關連結

返回總覽頁
Procesing