AmihudIlliquidity#
Description#
The Amihud (2002) illiquidity ratio measures how much the price moves per unit
of trading volume (notional). At each bar it computes |return| / notional,
then takes a trailing-window mean over window_size observations. A large
value indicates an illiquid, high-impact regime: a small trade moves the price
substantially. A small value indicates a liquid market where large volume is
absorbed with little price effect.
AmihudIlliquidity(window_size, start_policy)(return_, notional) returns
RollingMean(window_size, start_policy)(|return_| / notional).
The ratio is elementwise: if either return_ or notional is NaN at a
given bar, the ratio for that bar is NaN and RollingMean skips it
(inheriting nan_policy: ignore from the C++ engine).
A common pipeline is:
Compute bar returns with
LogReturnorReturn.Compute
notionalas price times volume for the same bar.Feed both to
AmihudIlliquidityto obtain a rolling illiquidity estimate.
Parameters:
window_size(int, >= 2): size of the trailing window.start_policy(str, default"strict"): controls warmup behavior."strict"emitsNaNuntilwindow_sizeobservations have been seen."expanding"uses however many observations are available."zero"fills the warmup period with zero.
Return value: the Amihud illiquidity estimate at each time step. NaN
during warmup under "strict", and whenever notional is zero or missing.
Compared to RollingKyleLambda (which requires signed order-flow data),
AmihudIlliquidity needs only a price return and a traded volume, making it
cheap to compute from standard OHLCV bars without trade-level data.
Reference: Amihud, Y. (2002). "Illiquidity and stock returns: cross-section and time-series effects." Journal of Financial Markets, 5(1), 31-56.
Examples#
Usage plot#
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from screamer import AmihudIlliquidity
rng = np.random.default_rng(8)
n = 300
ret = rng.standard_normal(n) * 0.01
notional = np.abs(rng.standard_normal(n)) + 1.0
notional[130:200] *= 0.25 # a thin, illiquid patch
amihud = AmihudIlliquidity(30)(ret, notional)
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, row_heights=[0.5, 0.5],
vertical_spacing=0.08)
fig.add_trace(go.Scatter(y=notional, name='notional', line=dict(color='steelblue')),
row=1, col=1)
fig.add_trace(go.Scatter(y=amihud, name='Amihud illiquidity',
line=dict(color='crimson')), row=2, col=1)
fig.update_layout(title='AmihudIlliquidity: price move per dollar traded',
yaxis=dict(title='notional'), yaxis2=dict(title='illiquidity'),
margin=dict(l=20, r=20, t=60, b=20), legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1))
fig.show()