| name | funding-rate-awareness |
| description | Use before entering or holding any perpetual futures position on HyperLiquid. Funding rate is a perpetuals-exclusive carry cost that has no analogue in spot or traditional futures. Elevated funding directly deducts from trade edge on every 8-hour settlement. This skill covers funding mechanics, carry cost calculation, regime classification, long/short asymmetry, funding-momentum as an independent alpha signal, crowding detection, and integration with position sizing and risk controls. |
| category | agentic |
Funding Rate Awareness
When This Skill Activates
Apply this skill:
- Before entering any perpetual futures long or short position
(funding rate determines the carry cost of the trade)
- When hold time is expected to exceed 2 hours (intra-candle scalps
below 2 hours are funding-neutral in practice; anything held
through a settlement window is not)
- When evaluating an existing position for continuation vs. exit:
if funding has shifted since entry, re-evaluate carry viability
- When using funding rate as an independent alpha signal (extreme
funding ā crowded trade ā mean-reversion opportunity)
- When classifying a post-trade loss to determine whether carry
cost was the primary performance drag (FM-5 from ema-cross-failure-modes)
Funding Rate Mechanics on HyperLiquid
HyperLiquid perpetuals use a continuous funding model that settles
hourly (not the standard 8-hour CEX cycle). Key mechanics:
Funding interval: 1 hour (HyperLiquid native)
Settlement: Continuous accrual, charged/paid hourly
Premium: Funding rate reflects the premium of perp price
over mark price (index-derived)
Long pays short: When funding > 0 (perp premium: bullish positioning)
Short pays long: When funding < 0 (perp discount: bearish positioning)
Rate normalisation: HyperLiquid 1h rate Ć 8 = equivalent 8h CEX rate
Critical: HyperLiquid quotes funding as a 1-hour rate.
All thresholds in this skill use the 1-hour rate natively.
When comparing to CEX data or academic literature (which uses
8-hour rates), divide the 8h rate by 8 to get the 1h equivalent.
def normalise_funding_rate(rate: float, source_interval_hours: float) -> float:
"""Normalise any funding rate to HyperLiquid 1-hour equivalent."""
return rate / source_interval_hours
Funding Rate Regime Classification
def classify_funding_regime(
funding_1h_pct: float,
funding_24h_avg_pct: float,
oi_current: float,
oi_7d_avg: float,
) -> dict:
"""
Classify current funding regime.
Returns regime class, direction pressure, and carry cost assessment.
"""
abs_rate = abs(funding_1h_pct)
oi_ratio = oi_current / oi_7d_avg if oi_7d_avg > 0 else 1.0
crowded_oi = oi_ratio >= 1.40
annualised_pct = funding_1h_pct * 24 * 365
if abs_rate <= 0.005:
regime = "NEUTRAL"
carry_concern = "none"
alpha_signal = "none"
elif abs_rate <= 0.015:
regime = "MILD"
carry_concern = "low"
alpha_signal = "none"
elif abs_rate <= 0.030:
regime = "ELEVATED"
carry_concern = "moderate"
alpha_signal = "watch"
elif abs_rate <= 0.060:
regime = "HIGH"
carry_concern = "high"
alpha_signal = "contrarian_watch" if crowded_oi else "watch"
else:
regime = "EXTREME"
carry_concern = "critical"
alpha_signal = "contrarian_signal"
persistent = (abs(funding_24h_avg_pct) >= 0.020)
direction_pressure = (
"LONG_CROWDED" if funding_1h_pct > 0.020 else
"SHORT_CROWDED" if funding_1h_pct < -0.020 else
"BALANCED"
)
return {
"regime": regime,
"funding_1h_pct": funding_1h_pct,
"funding_24h_avg": funding_24h_avg_pct,
"annualised_pct": round(annualised_pct, 1),
"carry_concern": carry_concern,
"alpha_signal": alpha_signal,
"direction_pressure": direction_pressure,
"crowded_oi": crowded_oi,
"oi_ratio": round(oi_ratio, 2),
"persistent": persistent,
}
Regime Reference Table
| Regime | 1h Rate | 8h Equiv | Annualised | Carry Concern | Action |
|---|
| NEUTRAL | ⤠0.005% | ⤠0.040% | ⤠4.4% | None | No constraint |
| MILD | 0.005ā0.015% | 0.040ā0.120% | 4.4ā13.1% | Low | Monitor |
| ELEVATED | 0.015ā0.030% | 0.120ā0.240% | 13.1ā26.3% | Moderate | Reduce hold time |
| HIGH | 0.030ā0.060% | 0.240ā0.480% | 26.3ā52.6% | High | Block longs; short carry positive |
| EXTREME | > 0.060% | > 0.480% | > 52.6% | Critical | Block all longs; evaluate contrarian short |
Carry Cost Calculation
Quantify the exact funding cost before committing to a position:
def calculate_carry_cost(
position_size_usd: float,
funding_1h_pct: float,
direction: str,
expected_hold_hours: float,
leverage: float = 1.0,
) -> dict:
"""
Calculate total carry cost for a position over its expected hold.
For longs: carry cost is positive (paid) when funding > 0.
For shorts: carry income is positive (received) when funding > 0.
"""
notional = position_size_usd * leverage
settlements = expected_hold_hours
long_rate_per_hour = funding_1h_pct / 100
if direction == "long":
carry_per_hour_usd = notional * long_rate_per_hour
else:
carry_per_hour_usd = -notional * long_rate_per_hour
total_carry_usd = carry_per_hour_usd * settlements
carry_pct_of_pos = (total_carry_usd / position_size_usd) * 100
return {
"direction": direction,
"position_usd": position_size_usd,
"notional_usd": notional,
"funding_1h_pct": funding_1h_pct,
"expected_hold_h": expected_hold_hours,
"carry_per_hour_usd": round(carry_per_hour_usd, 4),
"total_carry_usd": round(total_carry_usd, 4),
"carry_pct_of_pos": round(carry_pct_of_pos, 4),
"carry_is_cost": carry_per_hour_usd > 0,
"carry_is_income": carry_per_hour_usd < 0,
}
Carry Break-Even Calculation
Before entry, compute the minimum price move required just to recover
carry cost ā this is the carry-adjusted break-even:
def carry_adjusted_breakeven(
entry_price: float,
funding_1h_pct: float,
direction: str,
expected_hold_hours: float,
leverage: float = 1.0,
) -> dict:
"""
Minimum price move to recover carry cost at expected hold duration.
If breakeven move > realistic ATR-based target, the trade lacks edge.
"""
carry_decimal = (funding_1h_pct / 100) * expected_hold_hours
if direction == "long":
breakeven_move_pct = carry_decimal * leverage
breakeven_price = entry_price * (1 + breakeven_move_pct)
else:
breakeven_move_pct = -carry_decimal * leverage
breakeven_price = entry_price * (1 + breakeven_move_pct)
return {
"entry_price": entry_price,
"carry_breakeven_price": round(breakeven_price, 4),
"breakeven_move_pct": round(breakeven_move_pct * 100, 4),
"hold_hours": expected_hold_hours,
}
Long/Short Asymmetry in Funding
Funding creates a structural asymmetry between long and short entries
that must be evaluated independently for each direction:
LONG_FUNDING_BLOCK_THRESHOLD = 0.030
LONG_FUNDING_CAUTION_THRESHOLD = 0.015
SHORT_FUNDING_INCOME_FLOOR = 0.020
SHORT_FUNDING_INCOME_ENHANCED = 0.050
def evaluate_funding_for_direction(
funding_1h_pct: float,
direction: str,
expected_hold_hours: float,
) -> dict:
"""
Evaluate whether funding rate is compatible with the proposed direction.
Returns permitted flag, sizing adjustment, and carry income/cost assessment.
"""
if direction == "long":
if funding_1h_pct >= LONG_FUNDING_BLOCK_THRESHOLD:
return {
"permitted": False,
"sizing_adj": 0.0,
"carry_type": "COST",
"reason": f"Funding {funding_1h_pct:.3f}% >= block threshold "
f"{LONG_FUNDING_BLOCK_THRESHOLD:.3f}%. Long carry cost "
f"too high. Expected carry over {expected_hold_hours}h: "
f"{funding_1h_pct * expected_hold_hours:.3f}% of notional.",
}
elif funding_1h_pct >= LONG_FUNDING_CAUTION_THRESHOLD:
reduction_factor = 1.0 - (
(funding_1h_pct - LONG_FUNDING_CAUTION_THRESHOLD) /
(LONG_FUNDING_BLOCK_THRESHOLD - LONG_FUNDING_CAUTION_THRESHOLD)
) * 0.5
return {
"permitted": True,
"sizing_adj": round(reduction_factor, 2),
"carry_type": "COST_CAUTION",
"reason": f"Funding {funding_1h_pct:.3f}% in caution zone. "
f"Reduce long size to {reduction_factor*100:.0f}% of normal.",
}
else:
return {
"permitted": True,
"sizing_adj": 1.0,
"carry_type": "NEUTRAL_OR_INCOME",
"reason": f"Funding {funding_1h_pct:.3f}% below caution threshold. "
"Long carry acceptable.",
}
else:
if funding_1h_pct >= SHORT_FUNDING_INCOME_ENHANCED:
return {
"permitted": True,
"sizing_adj": 1.10,
"carry_type": "INCOME_ENHANCED",
"reason": f"Funding {funding_1h_pct:.3f}% >= {SHORT_FUNDING_INCOME_ENHANCED:.3f}%. "
"Short receives enhanced carry income. Edge structurally improved.",
}
elif funding_1h_pct >= SHORT_FUNDING_INCOME_FLOOR:
return {
"permitted": True,
"sizing_adj": 1.0,
"carry_type": "INCOME",
"reason": f"Funding {funding_1h_pct:.3f}% above income floor. "
"Short receives positive carry income.",
}
elif funding_1h_pct < -0.030:
return {
"permitted": False,
"sizing_adj": 0.0,
"carry_type": "REVERSE_COST",
"reason": f"Funding {funding_1h_pct:.3f}% strongly negative. "
"Short pays carry (long-favoured funding). Block short.",
}
else:
return {
"permitted": True,
"sizing_adj": 1.0,
"carry_type": "NEUTRAL",
"reason": "Funding neutral for short direction.",
}
Funding as an Alpha Signal (Contrarian)
Extreme funding rates indicate extreme positioning crowding. When the
crowd is heavily one-sided, the trade against the crowd ā the
funding mean-reversion short (when funding is extreme positive)
or funding mean-reversion long (when funding is extreme negative)
ā has structural carry income on top of the contrarian price thesis.
CONTRARIAN_FUNDING_THRESHOLD = 0.050
CONTRARIAN_OI_ELEVATION_FACTOR = 1.40
CONTRARIAN_PERSISTENCE_HOURS = 12
def evaluate_funding_contrarian_signal(
funding_1h_pct: float,
funding_24h_avg_pct: float,
oi_current: float,
oi_7d_avg: float,
hours_above_threshold: float,
cascade_score: int,
regime_adx: float,
) -> dict:
"""
Evaluate whether extreme funding constitutes an actionable contrarian signal.
Requires: extreme rate + elevated OI + persistence + no active cascade.
"""
rate_extreme = abs(funding_1h_pct) >= CONTRARIAN_FUNDING_THRESHOLD
oi_elevated = (oi_current / oi_7d_avg) >= CONTRARIAN_OI_ELEVATION_FACTOR
persistent = hours_above_threshold >= CONTRARIAN_PERSISTENCE_HOURS
no_cascade = cascade_score < 4
ranging_regime = regime_adx < 25.0
all_conditions = rate_extreme and oi_elevated and persistent and no_cascade
signal_type = (
"CONTRARIAN_SHORT" if funding_1h_pct > 0 else
"CONTRARIAN_LONG"
) if all_conditions else None
return {
"contrarian_signal": signal_type is not None,
"signal_type": signal_type,
"rate_extreme": rate_extreme,
"oi_elevated": oi_elevated,
"persistent": persistent,
"no_cascade": no_cascade,
"ranging_regime": ranging_regime,
"regime_note": (
"Trending regime: contrarian signal has lower edge vs ranging"
if not ranging_regime and all_conditions else None
),
"reason": (
f"Contrarian {signal_type} signal: funding={funding_1h_pct:.3f}%, "
f"OI ratio={oi_current/oi_7d_avg:.2f}x, "
f"persistent={hours_above_threshold:.0f}h"
if signal_type else
"; ".join(filter(None, [
f"rate {funding_1h_pct:.3f}% not extreme" if not rate_extreme else None,
f"OI ratio {oi_current/oi_7d_avg:.2f}x < 1.40" if not oi_elevated else None,
f"only {hours_above_threshold:.0f}h elevated (< 12h)" if not persistent else None,
f"cascade score {cascade_score} >= 4" if not no_cascade else None,
]))
),
}
Why Contrarian Funding Trades Work
- Carry income: The contrarian side receives funding on every
settlement ā shorting extreme positive funding earns 0.050%+/h
while waiting for the mean-reversion
- Crowding risk: Extreme long positioning means the pool of
new long buyers is exhausted; any catalyst triggers a cascade
of stops and liquidations (amplified by FM-6 from EMA skill)
- Persistence requirement: A single spike to extreme funding
may resolve within hours. Only persistent crowding (12h+)
reflects structural rather than transient positioning
Warning: Contrarian funding signals are not trend-fade signals.
The contrarian position is sized conservatively (max 0.15 Kelly)
and held with a tight ATR stop. It is a carry income + crowding
unwind play, not a price prediction.
Funding Monitor: Real-Time Position Management
For open positions, funding must be monitored continuously:
def monitor_open_position_funding(
entry_funding_1h_pct: float,
current_funding_1h_pct: float,
direction: str,
hold_hours_elapsed: float,
total_carry_paid_pct: float,
unrealised_pnl_pct: float,
) -> dict:
"""
Assess whether an open position should be exited based on
funding rate changes since entry.
"""
funding_worsened = (
direction == "long" and current_funding_1h_pct > entry_funding_1h_pct + 0.010
or
direction == "short" and current_funding_1h_pct < entry_funding_1h_pct - 0.010
)
carry_eroding = (
total_carry_paid_pct > 0 and
unrealised_pnl_pct > 0 and
total_carry_paid_pct > unrealised_pnl_pct * 0.50
)
funding_now_blocked = (
direction == "long" and current_funding_1h_pct >= LONG_FUNDING_BLOCK_THRESHOLD
)
action = (
"EXIT_IMMEDIATELY" if funding_now_blocked and unrealised_pnl_pct < 0.005 else
"CONSIDER_EXIT" if (funding_worsened or carry_eroding) else
"HOLD"
)
return {
"action": action,
"funding_worsened": funding_worsened,
"carry_eroding": carry_eroding,
"funding_now_blocked": funding_now_blocked,
"total_carry_paid_pct": total_carry_paid_pct,
"unrealised_pnl_pct": unrealised_pnl_pct,
"reason": (
f"Funding shifted from {entry_funding_1h_pct:.3f}% to "
f"{current_funding_1h_pct:.3f}% since entry. "
f"Carry paid {total_carry_paid_pct:.3f}%, "
f"unrealised PnL {unrealised_pnl_pct:.3f}%."
),
}
Pre-Entry Funding Gate (Master Function)
def funding_pre_entry_gate(
funding_1h_pct: float,
funding_24h_avg_pct: float,
oi_current: float,
oi_7d_avg: float,
direction: str,
expected_hold_hours: float,
entry_price: float,
position_size_usd: float,
leverage: float,
cascade_score: int,
) -> dict:
"""
Single gate function. Returns entry_permitted, sizing_adjustment,
carry_cost_usd, and carry_breakeven_price.
All must be checked before any position entry.
"""
regime = classify_funding_regime(
funding_1h_pct, funding_24h_avg_pct, oi_current, oi_7d_avg
)
direction_eval = evaluate_funding_for_direction(
funding_1h_pct, direction, expected_hold_hours
)
carry = calculate_carry_cost(
position_size_usd, funding_1h_pct, direction,
expected_hold_hours, leverage
)
breakeven = carry_adjusted_breakeven(
entry_price, funding_1h_pct, direction, expected_hold_hours, leverage
)
entry_permitted = direction_eval["permitted"]
return {
"entry_permitted": entry_permitted,
"funding_regime": regime["regime"],
"direction_eval": direction_eval,
"sizing_adjustment": direction_eval["sizing_adj"],
"carry_cost_usd": carry["total_carry_usd"],
"carry_pct_of_pos": carry["carry_pct_of_pos"],
"breakeven_price": breakeven["carry_breakeven_price"],
"breakeven_move_pct": breakeven["breakeven_move_pct"],
"direction_pressure": regime["direction_pressure"],
"crowded_oi": regime["crowded_oi"],
"contrarian_eligible": regime["alpha_signal"] in ("contrarian_watch", "contrarian_signal"),
"reason": direction_eval["reason"],
}
Failure Modes: Funding-Specific Losses
FFM-1: Carry Accumulation (Hold-Time Blindness)
Description: A valid directional trade is held well beyond its
expected hold time as the trader waits for a larger profit target.
Funding accrues continuously, converting a profitable trade into a
breakeven or loss even as the price prediction is eventually
correct.
Example: Long BTC-PERP at 0.025% funding, held 24h while
waiting for a 1% move. Carry cost: 0.025% Ć 24 = 0.60% of notional.
A 0.5% unrealised profit becomes a 0.1% loss net of carry.
Prevention: Set expected_hold_hours conservatively at entry.
Monitor via monitor_open_position_funding() on a timer. Exit
if carry_eroding = True before the target is reached.
FFM-2: Funding Spike at Entry
Description: Funding rate spikes immediately after entry (common
during a volatile breakout that creates rapid long crowding). The
trade was entered with acceptable funding but the rate moved to the
block threshold within 1-2 hours.
Prevention: monitor_open_position_funding() must run on every
hourly settlement. If funding_now_blocked = True and the trade is
not yet meaningfully profitable, treat as an EXIT_IMMEDIATELY signal.
FFM-3: Negative Funding Trap for Shorts
Description: A short position is entered in a market where
funding is negative (shorts pay, longs receive). The directional
trade may be correct, but carry is working against the short side.
Losses from both carry and adverse price movement compound.
Prevention: evaluate_funding_for_direction() returns permitted: False
when funding_1h_pct < -0.030. Never short into persistently
negative funding without a very high-conviction, fast-moving thesis
with stop-loss tight enough that carry is negligible.
FFM-4: Contrarian Position Pre-Cascade
Description: A contrarian funding short is entered on an
extreme funding signal, but the extreme funding is driven by a
positioning buildup that precedes a cascade rather than a
normal crowding unwind. Price spikes higher before the
cascade occurs, stopping out the contrarian short.
Prevention: cascade_score gate in evaluate_funding_contrarian_signal():
block contrarian entries when cascade_score ā„ 4. Contrarian
sizing cap of 0.15 Kelly prevents a stop-out from being catastrophic.
Worked Example ā Pre-Entry Gate on ETH-PERP Long
Asset: ETH-PERP, 1H timeframe
Signal: RSI oversold level reversal (from rsi-reversal-regime-dependency)
Direction: Long
Timestamp: 2026-04-07T14:00Z
Funding inputs:
funding_1h_pct: 0.026%
funding_24h_avg: 0.022%
oi_current: $2.8B
oi_7d_avg: $2.1B
cascade_score: 2
Regime classification:
abs_rate=0.026% ā ELEVATED
oi_ratio = 2.8B / 2.1B = 1.33 (below 1.40 crowded threshold)
persistent = 24h avg 0.022% >= 0.020 ā True
direction_pressure: LONG_CROWDED (0.026% > 0.020%)
alpha_signal: watch
Direction evaluation (long):
funding 0.026% >= CAUTION=0.015, < BLOCK=0.030
reduction_factor = 1.0 - ((0.026-0.015)/(0.030-0.015)) * 0.5
= 1.0 - (0.011/0.015) * 0.5
= 1.0 - 0.367 = 0.633
sizing_adj: 0.63 (reduce to 63% of normal size)
permitted: True (COST_CAUTION)
Carry cost (example $10,000 position, 2Ć leverage, 6h hold):
notional: $20,000
carry/hour: $20,000 Ć 0.026/100 = $5.20/h
total 6h carry: $31.20 (0.312% of $10,000 position)
Break-even price:
entry: $3,150
carry move needed: 0.026% Ć 6h Ć 2 leverage = 0.312%
break-even: $3,150 Ć 1.00312 = $3,159.83
Decision:
entry_permitted: True (with reduced size)
sizing_adjustment: 0.63
carry_cost: $31.20 over 6h
breakeven: $3,159.83 (requires 0.31% move just to recover carry)
Coordinator check (with RSI skill):
RSI reversal signal valid: True (ADX < 20, ranging regime)
Funding gate: permitted with 0.63 sizing
Final position: 63% of normal RSI reversal size
TP must exceed $3,159.83 before valid risk/reward
Integration with Other Skills
ema-cross-failure-modes (strategy/): FM-5 (funding drain on
EMA cross longs) is prevented by running funding_pre_entry_gate()
before every EMA long entry. The EMA cross pre-entry filter calls
the funding gate as one of its six sub-checks. Share
funding_1h_pct and oi_current data computed once per cycle.
rsi-reversal-regime-dependency (strategy/): RFM-4 (funding
bleed on range longs) uses evaluate_funding_for_direction().
funding_ok in evaluate_rsi_level_signal() maps to
permitted = True from this gate. RSI range longs must not
be taken when direction_pressure = LONG_CROWDED.
high-funding-carry-avoidance (regime-detection/): That skill
provides a binary block signal for extreme carry cases; this
skill provides the full graduated response (block/caution/size
reduction/income). Use the regime-detection skill for fast
filtering; use this skill for precise sizing calculation.
liquidation-cascade-risk (regime-detection/): cascade_score
is used in evaluate_funding_contrarian_signal() to prevent
entering contrarian trades ahead of a cascade-driven short squeeze.
Cascades and extreme funding co-occur frequently ā always check
both simultaneously.
kelly-position-sizing-perps (risk/): The sizing_adjustment
from evaluate_funding_for_direction() is applied as a
multiplicative cap on the Kelly fraction. Kelly output Ć
funding_sizing_adj = final position fraction.
drawdown-kill-switch-trigger (risk/): Extreme funding
regimes (EXTREME class, funding > 0.060%) elevate the system's
overall risk level and should lower the drawdown threshold
for kill-switch activation during the elevated period.
Audit JSONL Schema
{
"event": "funding_pre_entry_gate",
"timestamp_utc": "2026-04-07T14:00:00Z",
"asset": "ETH",
"direction": "long",
"funding_1h_pct": 0.026,
"funding_24h_avg_pct": 0.022,
"funding_regime": "ELEVATED",
"oi_ratio": 1.33,
"crowded_oi": false,
"direction_pressure": "LONG_CROWDED",
"entry_permitted": true,
"sizing_adjustment": 0.63,
"carry_cost_usd": 31.20,
"carry_pct_of_pos": 0.312,
"breakeven_price": 3159.83,
"breakeven_move_pct": 0.312,
"cascade_score": 2,
"contrarian_eligible": false,
"reason": "Funding 0.026% in caution zone. Reduce long size to 63% of normal."
}
Quick Decision Tree
Any perpetual position entry considered:
ā
āāā 1. Run funding_pre_entry_gate() with current data
ā āāā entry_permitted = False ā BLOCK. No entry.
ā āāā entry_permitted = True
ā āāā sizing_adjustment < 1.0 ā reduce size proportionally
ā āāā sizing_adjustment > 1.0 ā short carry income (max 1.10)
ā
āāā 2. Carry cost check:
ā carry_pct_of_pos > 0.50% for expected hold ā reconsider hold time
ā breakeven_move_pct > 0.5 Ć ATR(expected_hold_h) ā edge likely insufficient
ā
āāā 3. Contrarian check (if not entering directional):
ā contrarian_eligible = True ā run evaluate_funding_contrarian_signal()
ā All 4 conditions met ā contrarian signal valid, size at 0.15 Kelly max
ā
āāā 4. Position open ā hourly monitor:
ā monitor_open_position_funding() on every settlement
ā action = EXIT_IMMEDIATELY ā close immediately
ā action = CONSIDER_EXIT ā evaluate vs. price target proximity
ā
āāā 5. On close (if carry was material):
Log FFM class if carry was primary drag (total_carry_paid > 30% of gross PnL loss)
Update rolling funding_regime frequency for the asset