Hedger Pressure
Abstract
This signal measures commercial hedger sentiment across the futures markets by aggregating deep‑short and deep‑long hedger positioning. Using hedger z‑scores, it identifies when producers or commercial entities are heavily short (indicating supply expansion or bearish forward pricing) or heavily long (indicating physical shortage or inventory stress). These breadth measures are normalised with robust z‑scores and mapped into intuitive supply/shortage pressure regimes.
1. Inputs
- df_cot_signals — unified enriched CoT dataset.
- Hedger_zscore — z‑score of hedger net positioning.
- Hedger_Net_%OI — optional mean hedger net % of open interest.
- Market_and_Exchange_Names — used for market counts.
2. Per‑Market Hedger Pressure Flags
Hedger pressure is defined using hedger z‑scores:
A generic hedger_pressure flag is created if missing, defaulting to deep‑short classification.
3. Daily Aggregation
For each CoT reporting date, the model aggregates hedger pressure metrics:
- hedger_deep_short_count — number of markets where hedgers are heavily short.
- hedger_deep_long_count — number of markets where hedgers are heavily long.
- avg_hedger_net_oi — mean hedger net share of open interest.
- avg_hedger_zscore — average hedger z‑score across all markets.
Shares are derived to make the signal comparable across time:
4. Normalisation (Robust Z‑Scores)
To minimise sensitivity to outliers and structural shifts, robust z‑scores are applied to hedger pressure shares:
This method strengthens signal stability when market composition or liquidity changes over time.
5. Regime Labels
Each robust z‑score is mapped into intuitive hedger regimes:
The same thresholds are used for shortage pressure, replacing the labels with High Shortage / Stress and Moderate Shortage / Stress.
6. Implementation (Python)
df_hp = df_cot_signals.copy()
df_hp["Report_Date"] = pd.to_datetime(df_hp["Report_Date"], errors="coerce")
# Per‑market hedger flags
HEDGER_DEEP_SHORT_Z = -1.0
HEDGER_DEEP_LONG_Z = 1.0
hz = pd.to_numeric(df_hp["Hedger_zscore"], errors="coerce")
df_hp["hedger_deep_short"] = hz <= HEDGER_DEEP_SHORT_Z
df_hp["hedger_deep_long"] = hz >= HEDGER_DEEP_LONG_Z
if "hedger_pressure" not in df_hp.columns:
df_hp["hedger_pressure"] = df_hp["hedger_deep_short"]
# Daily aggregation
df_hedger_pressure_daily = (
df_hp.groupby("Report_Date").agg(
n_markets=("Market_and_Exchange_Names", "nunique"),
hedger_deep_short_count=("hedger_deep_short", "sum"),
hedger_deep_long_count=("hedger_deep_long", "sum"),
avg_hedger_net_oi=("Hedger_Net_%OI", "mean"),
avg_hedger_zscore=("Hedger_zscore", "mean"),
).reset_index()
)
df_hedger_pressure_daily["n_markets"] = df_hedger_pressure_daily["n_markets"].replace(0, np.nan)
df_hedger_pressure_daily["hedger_deep_short_share"] = (
df_hedger_pressure_daily["hedger_deep_short_count"] / df_hedger_pressure_daily["n_markets"]
)
df_hedger_pressure_daily["hedger_deep_long_share"] = (
df_hedger_pressure_daily["hedger_deep_long_count"] / df_hedger_pressure_daily["n_markets"]
)
# Robust z‑score helper
def _robust_z(series: pd.Series) -> pd.Series:
x = pd.to_numeric(series, errors="coerce").
7. Interpretation
- Supply Expansion Pressure — hedgers heavily short, signalling expectations of increased production or weaker forward prices.
- Shortage / Stress Pressure — hedgers heavily long, indicating tightening physical supply or inventory stress.
- Normal — commercial positioning is within typical historical bounds.
8. Limitations
- Hedger behaviour varies across asset classes, making cross-sector comparison imperfect.
- Static thresholds may require periodic recalibration.
- Missing or sparse Hedger_Net_%OI values reduce signal precision.
9. Practical Use Cases
- Identifying early warnings of physical market tightness or oversupply.
- Enhancing allocation models with a fundamental commercial-positioning overlay.
- Cross-checking speculative crowding signals for confirmation or divergence.