Corwin-Schultz Spread

Beckers, Parkinson volatility extimator

Roll Model에서 지적된 단점 중 하나는 관찰된 가격 계열인 {pt}\{p_t\}가 close price에만 종속된다는 점이었다. Beckers는 고가-저가에 근거한 변동성 추정량이 종가만을 사용한 변동성 추정량보다 더 정확하다는 것을 보였다. Parkinson은 Geometric Brownian Motion(GBM)을 따르는 연속 시계열 가격에 대해 다음을 유도하였다.

E[1Tt=1T(log[HtLt])2]=k1σHL2E\left[ \frac{1}{T}\sum_{t=1}^T \left( \log\left[ \frac{H_t}{L_t}\right] \right)^2 \right] = k_1 \sigma^2_{HL}
E[1Tt=1T(log[HtLt])]=k2σHLE\left[ \frac{1}{T}\sum_{t=1}^T \left( \log\left[ \frac{H_t}{L_t}\right] \right) \right] = k_2 \sigma_{HL}

여기서 k1=4log(2)k_1 = 4\log(2), k2=8πk_2 = \sqrt{\frac{8}{\pi}}이다. 이를 통해 변동성 σHL\sigma_{HL}은 관측된 high-low price를 기초로 하여 안정적으로 추정할 수 있다.

Corwin, Schultz spread estimator

Corwin, Schultz(2012)는 Beckers(1983)의 연구를 바탕으로 high-low price로부터 bis-ask spread 추정량을 제안하였다. 그 추정량은 두 가지 원칙에 기반을 두고 있다.

  1. high price는 거의 항상 ask price에 매치되고, low price는 대부분 bid price에 매치된다는 것이다. 이를 통해 high-low price의 비율이 bid-ask spread와 변동성을 반영한다.
  2. 변동성으로부터 비롯된 high-low price ratio의 구성 요소는 두 관측값 사이에 경과한 시간에 비례해 증가한다.

Corwin, Schultz는 bid-ask spread를 가격의 퍼센티지로 다음과 같이 계산할 수 있다는 것을 보였다.

St=2(eαt1)1+eαtS_t = \frac{2(e^{\alpha_t} - 1)}{1+e^{\alpha_t}}

여기서

αt=2βtβt322γt322\alpha_t = \frac{\sqrt{2 \beta_t} - \sqrt{\beta_t}}{3 - 2\sqrt{2}} - \sqrt{ \frac{\gamma_t}{3 - 2\sqrt{2}} }
βt=E[j=01[log(HtjLtj)]2]\beta_t = E \left[ \sum_{j=0}^1 \left[ \log \left( \frac{H_{t-j}}{L_{t-j}} \right)\right]^2 \right]
γt=[log(Ht1,tLt1,t)]2\gamma_t = \left[ \log \left( \frac{H_{t-1, t}}{L_{t-1, t}} \right)\right]^2

python code

class CorwinSchultz :
    def __init__(self, high : pd.Series, low : pd.Series) -> None:
        self.high = high
        self.low = low
        
    def beta(self, window : int) -> pd.Series:
        ret = np.log(self.high / self.low)
        high_low_ret = ret ** 2
        beta = high_low_ret.rolling(window=2).sum()
        beta = beta.rolling(window=window).mean()
        return beta
        
    def gamma(self) -> pd.Series:
        high_max = self.high.rolling(window = 2).max()
        low_min = self.low.rolling(window = 2).min()
        gamma = np.log(high_max / low_min) ** 2
        return gamma
        
    def alpha(self, window : int) -> pd.Series:
        den = 3 - 2 * 2 ** .5
        alpha = (2 ** .5 - 1) * (self.beta(window = window) ** .5) / den
        alpha -= (self.gamma() / den) ** .5
        alpha[alpha < 0] = 0
        return alpha
        
    def corwin_schultz_estimator(self, window : int = 20) -> pd.Series :
        alpha_ = self.alpha(window = window)
        spread = 2 * (np.exp(alpha_) - 1) / (1 + np.exp(alpha_))
        start_time = pd.Series(self.high.index[0:spread.shape[0]], index=spread.index)
        spread = pd.concat([spread, start_time], axis=1)
        spread.columns = ['Spread', 'Start_Time']
        return spread.Spread
        
    def becker_parkinson_vol(self, window: int = 20) -> pd.Series:
        Beta = self.beta(window = window)
        Gamma = self.gamma()
        k2 = (8 / np.pi) ** 0.5
        den = 3 - 2 * 2 ** .5
        sigma = (2 ** -0.5 - 1) * Beta ** 0.5 / (k2 * den)
        sigma += (Gamma / (k2 ** 2 * den)) ** 0.5
        sigma[sigma < 0] = 0
        return sigma
profile
자택경비원 1일차

0개의 댓글

관련 채용 정보