Skip to content

Kyle's Lambda

API

function
kyle_lambda(prices, volumes)

Kyle's Lambda

A measure of market impact cost from Kyle (1985), which can be interpreted as the cost of demanding a certain amount of liquidity over a given time period.

It is also used as a measure of market liquidity and can be estimated by the volume required to move the price of a security by one dollar. Sometimes referred to as Kyles lambda, this measure is an inverse proxy of liquidity, with higher values of lambda implying lower liquidity and market depth. The authors estimate this measure on a daily basis by using all transactions during normal trading hours on each day.

Given the sequence of

  • intraday returns [R_{i,1}, R_{i,2}, ..., R_{i,T}],
  • prices [p_{i,1}, p_{i,2}, ..., p_{i,T}], and
  • volumes [v_{i,1}, v_{i,2}, ..., v_{i,T}]

for security i during a specific day, the following regression is estimated:

R_{i,t} = \alpha_i + \lambda_i \text{Sgn}(t) \ln(v_{i,t}\times p_{i,t}) + \varepsilon_{i,t}

where \text{Sgn}(t) is -1 or + 1 depending on the direction of the trade, i.e., “buy” or “sell”, as determined according to the following rule:

  • if R_{i,t} is positive, the value +1 is assigned to that transaction (to indicate net buying),
  • if R_{i,t} is negative, the value −1 is assigned to that transaction (to indicate net selling).

Any interval with zero return receives the same sign as that of the most recent transaction with a non-zero return (using returns from the prior day, if necessary).

Parameters
  • prices (np.ndarray) (n_securities, n_periods) array of security prices
  • volumes (np.ndarray) (n_securities, n_periods) array of security volumes
Returns (np.ndarray)

Array of Kyle's Lambda estimates for the securities

Note

The prices data is used to calculate the asset returns, which is 1 less than the number of prices. As such, the volumes data of the first period is not used in the calculation.

Examples
>>> import numpy as np
>>> from frds.measures import kyle_lambda

3 assets daily volume for 6 days

>>> volumes = np.array(
...     [[100, 180, 900, 970, 430, 110], [200, 250, 400, 590, 260, 600], [300, 700, 220, 110, 290, 310]]
... )

Their daily prices

>>> prices = np.array(
...     [[44, 39, 36, 28, 23, 18], [82, 81, 79, 40, 26, 13], [55, 67, 13, 72, 10, 65]]
... )

Calculate their respective Kyle's Lambda estimates.

>>> kyle_lambda(prices, volumes)
array([-0.02198189, -0.1951004 ,  0.22752204])

References

Additional Note

Alternatively, following Hasbrouck (2009) and Goyenko, Holden, Trzcinka (2009), Kyle's Lambda for a given stock i and day t, is calculated as the slope coefficient \lambda_{i,t} in the regression:

R_{i,t,n}= \delta_{i,t} + \lambda_{i,t} S_{i,t,n}+\varepsilon_{i,t,n}

where for the nth five-minute period on date t and stock i, R_{i,t,n} is the stock return and S_{i,t,n} is the sum of the signed square-root dollar volume (V), that is,

S_{i,t,n}=\sum_k{\text{Sgn}}(V_{i,t,n,k}) \sqrt{V_{i,t,n,k}}

Example code below:

# KylesLambda.py
import numpy as np

name = 'KylesLambda'
description = """
A measure of market impact cost from Kyle (1985), 
which can be interpreted as the cost of demanding a certain amount of liquidity over a given time period.
Result is Lambda*1E6.
"""
vars_needed = ['Price', 'Volume', 'Direction']


def estimate(data):
    price = data['Price'].to_numpy()
    volume = data['Volume'].to_numpy()
    direction = data['Direction'].to_numpy()
    sqrt_dollar_volume = np.sqrt(np.multiply(price, volume))
    signed_sqrt_dollar_volume = np.abs(
        np.multiply(direction, sqrt_dollar_volume))
    # Find the total signed sqrt dollar volume and return per 5 min.
    timestamps = np.array(data.index, dtype='datetime64')
    last_ts, last_price = timestamps[0], price[0]
    bracket_ssdv = 0
    bracket = last_ts + np.timedelta64(5, 'm')
    rets, ssdvs, = [], []
    for idx, ts in enumerate(timestamps):
        if ts <= bracket:
            bracket_ssdv += signed_sqrt_dollar_volume[idx]
        else:
            ret = np.log(price[idx-1]/last_price)
            if not np.isnan(ret) and not np.isnan(bracket_ssdv):
                rets.append(ret)
                ssdvs.append(bracket_ssdv)
            # Reset bracket
            bracket = ts + np.timedelta64(5, 'm')
            last_price = price[idx]
            bracket_ssdv = signed_sqrt_dollar_volume[idx]
    # Perform regression.
    x = np.vstack([np.ones(len(ssdvs)), np.array(ssdvs)]).T
    try:
        coef, _, _, _ = np.linalg.lstsq(x, np.array(rets), rcond=None)
    except np.linalg.LinAlgError:
        return None
    else:
        return None if np.isnan(coef[1]) else coef[1]*1E6

Source code | Bug report | Sponsor me


Last update: July 26, 2021
Back to top