Price Impact

A simple adverse selection measure based on spreads.

Definition

The 5-min price impact is the permanent component of the effective spread. It measures the gross losses to the liquidity demanders due to adverse selection (Glosten and Harris (1988)).

For a given stock $i$ and day $t$, the 5-min price impact of the $k$th trade is defined as:

$$ pimpact_{i,t,k}=2q_{i,t,k} \left( \ln(M_{i,t,k+5})-\ln(M_{i,t,k}) \right) $$

where $M_{i,t,k+5}$ is the midpoint of the consolidated BBO prevailing five minutes after the $k$th trade, $M_{i,t,k}$ is the midpoint of the consolidated BBO prevailing at the time of the $k$th trade, and $q_{i,t,k}$ is the buy-sell indicator (+1 for buys, –1 for sells). Aggregating over day $t$, a stock’s price impact $pimpact_{i,t}$ is the dollar-volume-weighted average of the price impact $pimpact_{i,t,k}$ computed over all trades on day $t$.

Source Code

MIT MIT

This example Python code is not optimized for speed and serves only demonstration purpose. It may contain errors.

# PriceImpact.py
import numpy as np

name = 'PriceImpact'
description = """
The 5-min price impact is the permanent component of the effective spread. 
It measures the gross losses to the liquidity demanders due to adverse selection (Glosten and Harris (1988)).
"""
vars_needed = ['Price', 'Volume', 'Mid Point', 'Direction']


def estimate(data):
    log_midpt = np.log(data['Mid Point'].to_numpy())
    timestamps = np.array(data.index, dtype='datetime64')
    # Find the Quote Mid Point 5 min later than each trade.
    matched_log_midpt = []
    last_ts = timestamps[0]
    for idx, ts1 in enumerate(timestamps):
        for i, ts2 in enumerate(timestamps[idx:]):
            if ts2 - ts1 >= np.timedelta64(5, 'm'):
                matched_log_midpt.append(log_midpt[idx+i])
                break
    matched = len(matched_log_midpt)
    pimpact = 2 * data['Direction'].to_numpy()[:matched] * \
        (matched_log_midpt-log_midpt[:matched])
    # Daily price impact is the dollar-volume-weighted average
    # of the price impact computed over all trades in the day.
    price = data['Price'].to_numpy()
    volume = data['Volume'].to_numpy()
    dolloar_volume = np.multiply(volume, price)[:matched]
    pimpact = np.sum(np.multiply(pimpact, dolloar_volume) /
                     np.sum(dolloar_volume))
    return None if np.isnan(pimpact) else pimpact