Fractionally Differentiated Features - jaeaehkim/trading_system_beta GitHub Wiki
Motivation
- Financial Series(์ผ๋ฐ์ ์ธ ์๊ณ์ด๋ก ๋ํ๋๋ ๊ธ์ต ๋ฐ์ดํฐ. ex ๊ฐ๊ฒฉ๋ฐ์ดํฐ)๋ Arbitrage์ ์ํด ๊ธฐ๋ณธ์ ์ธ ์ํ๊ฐ ์๋ฉธ๋์ด ์์ผ๋ฏ๋ก ์ ์ฒ๋ฆฌ ๋์ง ์์ ์ํ์์ Low Signal/Noise๋ฅผ ๋ณด์ธ๋ค๊ณ ์๋ ค์ ธ ์๋ค. Feature๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ฐ๋ฆฌ๋ ๊ฐ์ข
๋ค์ํ ์ฐ์ฐ์๋ฅผ ํตํด์ ์ํ๊ฐ ๋จ์์๋ Series๋ก ๋ณํ์์ผ์ผ ํ๋ค.
- ์ผ๋จ, ํต๊ณํ ์ชฝ์์ Regression Analysis๋ฅผ ํ๊ธฐ ์ํด Series๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ์ฌ Factor(Feature)๋ฅผ ๊ณ์ฐํ๊ธฐ ๋ณด๋ค๋ Differentiation์ ํ๊ณ Fitting ์์
์ ์์ํ๋ค. ์ด๋, Diff๋ ๋จ์ 1,2,3์ฐจ์ ์ ์ ์ฐจ๋ถ์ผ๋ก ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๊ณ , 1์ฐจ ์ฐจ๋ถ๋ง ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ 99%์ด๋ค.
- ๊ฐ๊ฒฉ ์๊ณ์ด์ ๊ฒฝ์ฐ ๋ชจ๋ ๊ฐ์ด ๊ฐ๊ฒฉ ์์ค(Level)์ ๋ํ ๊ธฐ์ต์ด ์กด์ฌํ๊ณ ์ด๋ฅผ ์ ์ ์ฐจ๋ถํ๊ฒ ๋๋ฉด ์ ์์ฑ์ ํ๋ณด๋์ง๋ง ๊ฑฐ์ ๋ชจ๋ ๊ธฐ์ต์ด ์ญ์ ๋๋ฏ๋ก (์ ํํ๋ Return์ ๋์ ๊ธฐ์ต์ผ๋ก๋ ์ด๋ฏธ ๋ง์ ์ํ๊ฐ ์์ง๋๊ณ ์์ด์) ์์ฌ Signal์ ๋ฝ์๋ด๊ธฐ ์ํด์ ๋ณต์กํ ์ฐ์ฐ์๋ฅผ ํ์ฉํ๊ฒ ๋๊ณ ์ด๋ ๊ณผ์ต์ ํ์ ์์ธ์ ์ ๊ณตํ๊ฒ ๋๋ค.
- ์์ ๋ฌธ์ ๋ ์ด๋ค ๋ฐฉ์์ผ๋ก ์ ๊ทผํด๋ ๋จ์์๋ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ์ด๋ ๋๋ฒจ๋กญ ์ํฌ ์ ์๋ ์ฌ์ง๊ฐ ์๋ ๋ถ๋ถ์ '์ ์ ์ฐจ๋ถ'์ด ์๋ '์ค์ ์ฐจ๋ถ'์ ํตํด์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ต๋ํ ์ด๋ ค๋ด๋ ์๋ก์ด Series๋ฅผ ๋ง๋ค์ด ๋ด๊ณ ์ด๋ฅผ ํตํด Feature๋ฅผ ๊ฐ๋ฐํ๋ ๊ฒ์์ ์์ฌ ์ ํธ๋ฅผ ์กฐ๊ธ์ด๋ผ๋ ๋๋ฆด ์ ์๋ค๋ ์ ์ ๋๊ธฐ๊ฐ ๋๋ค.
Dilemma : Stationarity vs Memory
- Memory(๊ธฐ์ต) : Series์ ํ๊ท ์ ์๊ฐ์ ๋ฐ๋ผ ๋ณ๋์ํค๋ ์ด์ Level์ ์ผ์ ๊ธฐ๊ฐ์ ์ ๋ณด์ ๋ํ ์กด์ฌ ์ ๋ฌด. ๋ค ์์ด์ง ์ํ๋ฅผ Stationarity 100%๋ผ๊ณ ๋ณผ ์ ์์.
- Weak Stationaryํ๋ฉด์ ์์ฌ Signal์ด ๋ง์ Series๋ก ๋ณํํ๋๊ฒ ์ค์
- ์ง๋ํ์ต ์๊ณ ๋ฆฌ์ฆ์ ๋๊ฐ Stationarity๊ฐ ํ์ํจ. ์ด์ ๋ ๋ ์ด๋ธ ๋์ง ์์ ์๋ก์ด ๊ด์ธก ๊ฐ(Test or Real Data)์ ๋ ์ด๋ธ ๋ ์์ (Train Data)์ ์งํฉ์ผ๋ก mappingํ ํ์์ฑ์ด ์๊ณ ์ด๋ก๋ถํฐ ์๋ก์ด ๊ด์ธก ๊ฐ์ ๋ ์ด๋ธ์ ์ถ๋ก ํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ, Stationarity๊ฐ ๋๋ฌด ์๋ค๋ฉด ๋ฐ์ฐ์ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์.
- Stationarity๋ ์์ธก๋ ฅ์ ๋ด๋ณดํ์ง ๋ชปํ๊ณ ๊ณ ์ฑ๋ฅ ML ๋ชจ๋ธ์ ์ํ ํ์,๋ถ์ถฉ๋ถ ์กฐ๊ฑด
- Literature Review : (Hosking,1981) > Johansen > Nielsen > MacKinnon > Jensen > Jones > Popiel > Cavaliere > Taylor
- Hosking๋ถํฐ ์ด๋ฏธ ARMIA Process Family๋ฅผ ์ค์ ์ฐจ๋ถ์ด ๊ฐ๋ฅํ๋๋ก ์ผ๋ฐํํ์๊ณ ์ดํ์ Continuous Probablistic Process์ ์ค์ ์ฐจ๋ถ์ ์ฐ์ฐ ์ต์ ํ์ ๊ด๋ จ
The Method
Backshift Operator

| 

- Backshift Operator๋ฅผ ํตํด ๋ณต์กํ๊ฒ ๊ผฌ๋ฆฌ๋ฅผ ๋ฌด๋ ์๊ณ์ด ๊ณ์ฐ์ ๊ฐ๋จํ๊ฒ ํํํ ์ ์๊ณ ์ด ๊ณผ์ ์์ ์ดํญ ๊ณ์ฐ์ด ์ฌ์ฉ๋จ.
Long Memory & Iterative Calculation for Weight


- Backshift๋ฅผ ํตํด์ X_t๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ํํํ ์ ์๊ณ weights๋ฅผ ๋จ์ ๋์ดํ ๊ฒ๊ณผ Iterativeํ๊ฒ ํํํ ์์์ ๋ค์๊ณผ ๊ฐ์ด ์ ๋ฆฌํ ์ ์๋ค.
- ์๋ ์ฝ๋๋ weights๋ฅผ iterativeํ๊ฒ ๊ณ์ฐํ๋ ๊ฒ์ ๋ํ๋
def getWeights(d, size):
# thresh > 0 drops insignificant weights
w = [1.0]
for k in range(1, size):
w_ = -w[-1] / k * (d - k + 1)
w.append(w_)
w = np.array(w[::-1]).reshape(-1, 1)
return w
Implementation
- ์์์ '์ค์ ์ฐจ๋ถ'์ ํ๊ธฐ ์ํด์ ํ์ํ ์ฌ์ ์ง์์ ๋ค๋ค๊ณ ์ค์ ๋ก ๊ตฌํํ๋ 2๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ํด ์๊ฐ
Expanding Window



-

- ์ค์ ์๊ณ์ด์ ์ ํํ๊ธฐ ๋๋ฌธ์ ๊ด์ธก๊ฐ์ด T๊ฐ๊น์ง ์ ํ๋๋ค. ๊ฐ์ค๊ฐ์ w_k๋ 1~T-1๊น์ง 0์ด ์๋ ๊ฐ์ ๊ฐ๋๋ค. ์ด๋ก ์ธํด, ์ด๊ธฐ ํฌ์ธํธ์ ์ต์ข
ํฌ์ธํธ๋ ์๋ก ๋ค๋ฅธ ๊ธฐ์ต๋์ ๊ฐ๊ฒ ๋๋ค. Expanding Window ๊ธฐ๋ฒ์์ ์๋ก ๋ค๋ฅธ ๊ธฐ์ต๋์ ๊ด์ฌํ์ง ์๊ณ ๋จ์ํ ์์ X_t, w๋ฅผ T๊ฐ๊น์ง์ ๊ฒฝ์ฐ๋ก ์ ํํ์ฌ ๊ณ์ฐํ๋ค.
- ๊ฐ ํฌ์ธํธ ๋ง๋ค์ ๊ธฐ์ต๋์ relative weight-loss๋ฅผ ํตํด ์ ๋ํ ํ ์ ์๋ค. Fixed-Width Window Fracdiff์์๋ ์ด๋ฅผ ํ์ฉํ ์ค์ ์ฐจ๋ถ์ ์ฌ์ฉํ๋ค.
def fracDiff(series, d, thres=0.01):
'''
Increasing width window, with treatment of NaNs
Note: For thres=1, nothing is skipped.
Note 2: d can be any positive fractional, not necessarily bounded [0,1]
'''
# 1) Compute weights for the longest series
w = getWeights(d, series.shape[0])
# 2) Determine initial calcs to be skipped based on the weight-loss threshold
w_ = np.cumsum(abs(w))
w_ /= w_[-1]
skip = w_[w_ > thres].shape[0]
# 3) Apply weights to values
df = {}
for name in series.columns:
seriesF, df_ = series[name](/jaeaehkim/trading_system_beta/wiki/name).fillna(method='ffill').dropna(), pd.Series(index=series.index) # bug in the original code
for iloc in range(skip, seriesF.shape[0]):
loc = seriesF.index[iloc]
if not np.isfinite(series.loc[loc, name]):
continue # exclude NAs
a = w[-(iloc + 1):, :].T
b = seriesF.loc[:loc]
df_[loc] = np.dot(a, b)[0, 0]
df[name] = df_.copy(deep=True)
df = pd.concat(df, axis=1)
return df
Fixed-Width Window Fracdiff




- lambda๋ฅผ ์ด์ฉํด์ threshold ์ผ์ ์์ค ์ดํ๋ ๊ฐ์ค๊ฐ์ ์ญ์ ํ์ฌ ๊ฐ์ค๊ฐ์ ๋์ผํ ๋ฒกํฐ(๊ธธ์ด๊ฐ l*๋ก ์ผ์ )๋ฅผ Xt์ ๋ชจ๋ ๊ณ์ฐ์ ์ฌ์ฉํ์ฌ ์ผ๊ด์ฑ์ ๋ถ์ฌํจ.
def getWeights_FFD(d, thres):
w, k = [1.0], 1
while True:
w_ = -w[-1] / k * (d - k + 1)
if abs(w_) < thres:
break
w.append(w_)
k += 1
return np.array(w[::-1]).reshape(-1, 1)
def fracDiff_FFD(series, d, thres=1e-5):
# Constant with window (new solution)
w = getWeights_FFD(d, thres)
width, df = len(w) - 1, {}
for name in series.columns:
seriesF, df_ = series[name](/jaeaehkim/trading_system_beta/wiki/name).fillna(method='ffill').dropna(), pd.Series(index=series.index)
for iloc1 in range(width, seriesF.shape[0]):
loc0, loc1 = seriesF.index[iloc1 - width], seriesF.index[iloc1]
if not np.isfinite(series.loc[loc1, name]):
continue # exclude NAs
df_[loc1] = np.dot(w.T, seriesF.loc[loc0:loc1])[0, 0]
df[name] = df_.copy(deep=True)
df = pd.concat(df, axis=1)
return df
Stationarity with Maximum Memory Preservation
- adfuller test๋ฅผ ํ์ฉํด์ d ๊ฐ์ 0 ~ 1๊น์ง 0.01 ~ 0.1 ๋จ์๋ก ํ
์คํธ ํ์ฌ ์ต์ ์ง์ ์ ์ฐพ์๋ผ ์ ์๋ค.
- ๋๋ถ๋ถ์ ๊ฒฝ์ฐ d=0.5~0.6 ์ ๋๋ก ์ฌ์ฉํ๋๋ฏ.
Application to Quant System
- ๊ธฐ์กด์ feature ๋ง๋ค ๋๋ Event bar ๋ฐ์ดํฐ์ ์ฐ์ฐ์๋ฅผ ๋ํด ๊ณ์ฐํ๋ ๋ฐฉ์์ ์ฌ์ฉํจ
- ๊ฐ๊ฒฉ ์๊ณ์ด, Volume Bar, Event Bar ๊ฐ๊ฐ์ ์ค์ ์ฐจ๋ถ์ ์ ์ฉํ์ฌ feature๋ฅผ ๊ณ์ฐํ๋ค๋ฉด ๋ค๋ฅธ ์ ๋ณด๋ฅผ ๋ฝ์๋ผ ์ ์์ ๊ฒ์ผ๋ก ๋ณด์