Run Bar

대규모 거래자들은 order book을 전부 휩쓸어 가거나 소위 물타기(iceberg) 주문, 혹은 분할 주문을 하는 방법 등으로 거래를 실행하는데 이는 sequence {bt}t=1,,T\{b_t\}_{t=1,\dots,T}안에 거래 흔적을 남긴다. 이러한 이유로 전체 거래량 안에서의 매수 시퀀스를 조사해 보는 것이 유용하며, 이 매수 시퀀스가 기대에서 벗어날 경우에 표본 추출을 한다

시장상황을 하나 가정해 보자. 기업 A의 1분기 실적 발표 이전에 내부 정보의 유출로 실적의 개선 혹은 부진이라는 정보를 가진 증권 시장 참여자가 뉴스 보도 이전에 거래를 하려고 한다. 이때, 전자의 경우는 추가 매수 주문을 넣을 것이고, 후자의 경우 매도 주문을 넣을 것이다. 이러한 정보 기반 거래자의 참여자가 적절한 수준으로 많을 때, order book에서는 기업 A의 거래량이 증가할 것이다. imbalance bar는 매도와 매수의 방향과 관게 없이 거래량 자체가 기대값을 벗어날 경우에 샘플링을 한다. run bar는 여기에서 더 나아가, 틱이 매수인지(bt=1)(b_t = 1) 혹은 매도인지(bt=1)(b_t = -1)까지 고려하여, 매수 시퀀스가 기대값에서 벗어났을 경우에 샘플링을 한다는 아이디어다. 이 경우, 어느 방향에서 정보 기반 거래자가 주문을 요청하는지 추적이 가능하다는 점에서 장점을 가지고 있다.

Tick Run Bar

현재 run의 길이는 다음과 같이 정의할 수 있다

θT=max{tbt=1Tbttbt=1Tbt}\theta_T = \max \left\{ \sum_{t|b_t = 1}^T b_t - \sum_{t|b_t = -1}^T b_t \right\}

다음으로, 바의 시작 지점에서의 기대값 θT\theta_T를 계산한다

E0[θT]=E0[T]max(P[bt=1],1P[bt=1])E_0[\theta_T] = E_0[T]\max(P[b_t = 1], 1 - P[b_t = 1])

경험적으로 E0[T]E_0[T]는 이전 바들의 window = TT인 지수 가중 이동 평균(EWMA)으로 계산할 수 있고, P[bt=1]P[b_t = 1]은 이전 바들의 매수 tick 비율의 지수 가중 이동 평균으로 계산할 수 있다.

셋째, Tick run bar를 다음 조건을 만족하는 tick의 TT^*연접 부분 집합으로 정의한다.

T=arg maxT{θTE0[T]max(P[bt=1],1P[bt=1])}T^{*} = \argmax_T \left\{ \theta_T \geq E_0[T] \max \left( P[b_t = 1], 1-P[b_t = 1] \right) \right\}

여기서 run의 기대 틱 횟수는 max(P[bt=1],1P[bt=1])\max \left( P[b_t = 1], 1-P[b_t = 1]\right)으로 추정된다. θT\theta_T가 기대값보다 더 많은 런을 보여문다면, 작은 TT가 조건을 만족할 것이다.

이런식으로 정의하면 각 side별 틱 개수를 저장할 수 있는데, 이는 시퀀스의 길이를 측정하는 것보다 더 유용하다. 아래는 tick run bar를 정의하는 하나의 파이썬 함수 코드이다.

def tick_run_bars(file_path_or_df: Union[str, Iterable[str], pd.DataFrame],
                  num_prev_bars: int,
                  expected_imbalance_window: int = 10000,
                  exp_num_ticks_init: int = 20000,
                  batch_size: int = 2e7,
                  analyse_thresholds: bool = False,
                  verbose: bool = True):
                       
    bars = RunBars(metric='tick_run', num_prev_bars=num_prev_bars,
                   expected_imbalance_window=expected_imbalance_window,
                   exp_num_ticks_init=exp_num_ticks_init,
                   batch_size=batch_size, analyse_thresholds=analyse_thresholds)
    run_bars = bars.batch_run(file_path_or_df=file_path_or_df, verbose=verbose)

    return run_bars, pd.DataFrame(bars.bars_thresholds)

아래 예시는 동일한 데이터셋에 대하여 기대 틱의 값 300, EWMA 계산을 위한 look back기간을 300으로 지정한 tick run bar sampling의 결과이다.

Volume Run Bar / Dollar Run Bar

volume run bar, dollar run bar는 앞서 언급한 tick run bar의 개념을 확장한 것이다. tick run bar에서 각 방향별 틱의 개수가 기대를 벗어날 때마다 샘플링을 한다면, VRB와 DRB는 각각 거래량과 달러 가치가 기대치를 벗어날 때마다 샘플링을 하는 것이다. 틱 규칙에 대한 관행적 명칭에 따라 바의 최종 관측값 인덱스인 TT를 결정해야 한다.

우선, 런에 관련된 거래량 혹은 달러 가치는 다음과 같이 정의할 수 있다.

θT=max{tbt=1Tbtνttbt=1Tbtνt}\theta_T = \max \left\{ \sum_{t|b_t = 1}^T b_t \nu_t - \sum_{t|b_t = -1}^T b_t \nu_t \right\}

여기서 νt\nu_t는 바의 타입에 따라서 거래량이 될 수도 있고 달러 가치가 될 수도 있다. 다음으로, 바의 시작 지점에서 기대값 θT\theta_T를 계산한다.

E0[θT]=E0[T]max{P(bt=1)E0(νtbt=1),(1P(bt=1))E0(νtbt=1)}E_0[\theta_T] = E_0[T]\max\left\{ P(b_t = 1)E_0(\nu_t|b_t = 1), (1 - P(b_t = 1))E_0(\nu_t|b_t=-1) \right\}

사실 E0[T]E_0[T]는 이전 바들로부터 TT값의 지수 가중 이동 평균으로 계산할 수 있고, P(bt=1)P(b_t = 1)은 이전 바들의 매수 틱 비율의 지수 가중 이동 평균으로 계산할 수 있다. 또한, E0(νtbt=1)E_0(\nu_t|b_t = 1)은 이전 매수 거래량 혹은 달러 가치 바들의 EWMA값으로, E0(νtbt=1)E_0(\nu_t|b_t = -1)은 이전 매도 거래량 혹은 달러 가치 바들의 EWMA값으로 추정할 수 있다.

마지막으로, VRB혹은 DRB를 다음 조건을 만족하는 틱의 TT^*연접 부분 집합으로 정의한다.

T=arg minT{θTE0[T]max(P[bt=1]E0[νtbt=1],(1P[bt=1])E0[νtbt=1])}T^{*} = \argmin_{T} \left\{ \theta_T \geq E_0[T]\max\left( P[b_t = 1]E_0[\nu_t|b_t = 1], (1 - P[b_t = 1])E_0[\nu_t|b_t = -1] \right) \right\}

여기서 런의 기대 거래량 혹은 달러 가치는 max(P[bt=1]E0[νtbt=1],(1P[bt=1])E0[νtbt=1])\max\left(P[b_t = 1]E_0[\nu_t|b_t = 1], (1 - P[b_t = 1])E_0[\nu_t|b_t = -1]\right)으로 추정된다. θT\theta_T이 기대값보다 많은 런을 보이거나, 런으로부터의 거래량이 기대값보다 크다면 작은 TT가 이 조건을 만족할 것이다.

다음은 python을 이용해 VRB와 DRB를 구현하는 코드 예제이다.

def volume_run_bars(file_path_or_df: Union[str, Iterable[str], pd.DataFrame],
                    num_prev_bars: int,
                    expected_imbalance_window: int = 10000,
                    exp_num_ticks_init: int = 20000,
                    batch_size: int = 2e7,
                    analyse_thresholds: bool = False,
                    verbose: bool = True):
    bars = RunBars(metric='volume_run', num_prev_bars=num_prev_bars,
                   expected_imbalance_window=expected_imbalance_window,
                   exp_num_ticks_init=exp_num_ticks_init,
                   batch_size=batch_size, analyse_thresholds=analyse_thresholds)
    run_bars = bars.batch_run(file_path_or_df=file_path_or_df, verbose=verbose)

    return run_bars, pd.DataFrame(bars.bars_thresholds)
    
def dollar_run_bars(file_path_or_df: Union[str, Iterable[str], pd.DataFrame],
                    num_prev_bars: int,
                    expected_imbalance_window: int = 10000,
                    exp_num_ticks_init: int = 20000,
                    batch_size: int = 2e7,
                    analyse_thresholds: bool = False,
                    verbose: bool = True):
    bars = RunBars(metric='dollar_run', num_prev_bars=num_prev_bars,
                   expected_imbalance_window=expected_imbalance_window,
                   exp_num_ticks_init=exp_num_ticks_init,
                   batch_size=batch_size, analyse_thresholds=analyse_thresholds)
    run_bars = bars.batch_run(file_path_or_df=file_path_or_df, verbose=verbose)

    return run_bars, pd.DataFrame(bars.bars_thresholds)

다음은 각 표본추출법에 대한 샘플링 결과이다. 두 경우 모두 기대 틱을 100단위로 지정하였으며, EWMA 계산을 위한 look back 기간을 300으로 지정하였다.

profile
자택경비원 1일차

0개의 댓글

관련 채용 정보