Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vishalbelsare/d818d46bbd5f578010e5bf3885de1eed to your computer and use it in GitHub Desktop.
Save vishalbelsare/d818d46bbd5f578010e5bf3885de1eed to your computer and use it in GitHub Desktop.
Computes the high-low spread estimator, an estimate of bid-offer spreads, a measure of liquidity risk. See Corwin & Schultz (2011) for details: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1106193
# high-low spread estimator (hlse)
def hlse(ohlc_df, frequency='daily'):
"""
Computes the high-low spread estimator, an estimate of bid-offer spreads, a measure of liquidity risk.
See Corwin & Schultz (2011) for details: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1106193
Parameters
----------
ohlc_df: DataFrame
DataFrame with DatetimeIndex and Open, High, Low and Close (OHLC) prices from which to compute the high-low spread estimates.
frequency: str, {'daily', 'weekly', 'monthly'}, default 'daily'
daily: daily bid-offer spread estimate.
weekly: weekly bid-offer spread estimate, resampled over a weekly frequency as the mean of daily estimates.
monthly: monthly bid-offer spread estimate, resampled over a monthly frequency as the mean of daily estimates.
Returns
-------
S: Series
Datetimeindex and time series of high-low spread estimates.
"""
# define vars: mid, 2 day high and 2 day low vars
mid, high_2d, low_2d = (ohlc_df.high + ohlc_df.low)/2, ohlc_df.high.rolling(2).max(), ohlc_df.low.rolling(2).min()
# compute adjustment for overnight price moves
ohlc_df['gap_up'], ohlc_df['gap_down'] = ohlc_df.low - ohlc_df.close.shift(1), ohlc_df.high - ohlc_df.close.shift(1)
# adjustment for gap up
ohlc_df['high_adj'], ohlc_df['low_adj'] = np.where(ohlc_df.gap_up > 0, ohlc_df.high - ohlc_df.gap_up, ohlc_df.high), np.where(ohlc_df.gap_up > 0, ohlc_df.low - ohlc_df.gap_up, ohlc_df.low)
# adjustment for gap down
ohlc_df['high_adj'], ohlc_df['low_adj'] = np.where(ohlc_df.gap_down < 0, ohlc_df.high - ohlc_df.gap_down, ohlc_df.high), np.where(ohlc_df.gap_down < 0, ohlc_df.low - ohlc_df.gap_down, ohlc_df.low)
# B beta
B = (np.log(ohlc_df.high_adj/ohlc_df.low_adj))**2 + (np.log(ohlc_df.high_adj.shift(1)/ohlc_df.low_adj.shift(1)))**2
# G gamma
G = (np.log(high_2d/low_2d))**2
# alpha
alpha = ((np.sqrt(2 * B) - np.sqrt(B)) / (3 - 2 * np.sqrt(2))) - (np.sqrt(G/(3 - 2 * np.sqrt(2))))
# replace negative values by 0
alpha = pd.Series(np.where(alpha < 0, 0, alpha), index=alpha.index)
# substitute alpha into equation 14 to get high-low spread estimate S
S = (2 * (np.exp(alpha) - 1)) / (1 + np.exp(alpha))
# resample using daily mean
if frequency == 'weekly':
S = S.resample('W').mean()
if frequency == 'monthly':
S = S.resample('M').mean()
# drop NaNs
S.dropna(inplace=True)
return S
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment