# Price Impact

## 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

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
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