Hyperliquid Funding Rate Bot: Earn 20–60% APY on Autopilot
Funding rate harvesting is one of the most reliable, non-directional yield strategies in crypto. When perpetual futures markets become crowded with leveraged longs, they pay shorts a continuous stream of funding payments every 8 hours. The edge is structural, not predictive — you do not need to know where the price is going. You only need to be on the right side when the market is overextended.
This guide shows you how to build a fully autonomous funding rate bot that operates through the Purple Flea Trading API, maintains delta-neutrality, and historically targets 20–60% APY depending on market conditions.
What Are Funding Rates?
Perpetual futures have no expiry. To keep their price anchored to the underlying spot price, exchanges use a funding mechanism: every 8 hours, one side pays the other based on the deviation between the perpetual price and the spot price.
When the perpetual trades above spot (positive funding rate), longs pay shorts. This happens when the market is bullish and retail traders pile into leveraged long positions. The funding rate is a tax on overleveraged longs — and shorts collect it.
| Market Condition | Perpetual vs Spot | Funding Rate | Who Pays Whom |
|---|---|---|---|
| Bullish euphoria | Perp > Spot (premium) | Positive (0.05–0.3%/8h) | Longs pay shorts |
| Mild bullish | Perp slightly > Spot | Positive (0.01–0.05%/8h) | Longs pay shorts |
| Neutral | Perp ≈ Spot | ~0% | No significant payment |
| Bearish / fearful | Perp < Spot (discount) | Negative | Shorts pay longs |
The strategy: when funding is positive and sufficiently high, open a short perpetual position to collect funding payments. Simultaneously, go long spot (or long on a separate venue) to cancel out price exposure. Net result: zero price risk, pure funding yield.
APY Calculation
Funding is paid 3 times per day (every 8 hours). Annualized yield:
# Annualized yield from funding rate
def funding_apy(rate_per_8h: float) -> float:
"""
rate_per_8h: e.g. 0.01 for 0.01%
Returns annualized yield percentage
"""
payments_per_year = 3 * 365 # 1095 payments
return rate_per_8h * payments_per_year
# Examples:
print(funding_apy(0.01)) # 10.95% APY — baseline bull market
print(funding_apy(0.05)) # 54.75% APY — elevated funding period
print(funding_apy(0.10)) # 109.5% APY — extreme funding (ETH peaks in 2021)
After trading fees (approximately 0.02% taker per side = 0.04% round trip), net APY at 0.05% funding is roughly 52% — still exceptional for a market-neutral strategy.
Delta-Neutral Setup
The critical design requirement: for every 1 unit short on the perpetual, you must hold 1 unit long somewhere. Options:
- Short perp + Long spot: Simplest. Short $10K BTC perpetual, buy $10K BTC spot. Perfectly neutral. Requires 2x capital.
- Short perp + Long spot futures: Use a fixed-expiry long future to reduce spot trading costs. Slightly less perfect hedge.
- Short perp on Hyperliquid + Long perp on competing venue: If funding rates differ significantly between venues, you can earn both sides. Requires cross-venue infrastructure.
Purple Flea's trading API handles the perpetual short side. For the long hedge, we use the spot wallet API:
import requests
API_KEY = "pf_live_YOUR_KEY"
TRADING_BASE = "https://trading.purpleflea.com/api"
WALLET_BASE = "https://wallet.purpleflea.com/api"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def open_funding_trade(symbol: str, size_usd: float):
"""Open delta-neutral funding position: short perp + long spot."""
# Step 1: Open short perpetual to collect funding
perp_order = requests.post(f"{TRADING_BASE}/orders", headers=HEADERS, json={
"symbol": f"{symbol}-PERP",
"side": "short",
"size_usd": size_usd,
"leverage": 1, # 1x only — no directional leverage
"type": "market",
"reduce_only": False
}).json()
# Step 2: Buy equivalent spot to hedge delta
spot_order = requests.post(f"{WALLET_BASE}/spot/buy", headers=HEADERS, json={
"asset": symbol,
"usd_amount": size_usd,
"type": "market"
}).json()
return {
"perp_order_id": perp_order["order_id"],
"spot_order_id": spot_order["order_id"],
"perp_fill": perp_order.get("fill_price"),
"spot_fill": spot_order.get("fill_price")
}
Monitoring and Fetching Funding Rates
import time
from dataclasses import dataclass
from typing import List
@dataclass
class FundingOpportunity:
symbol: str
rate_8h: float # as percentage: 0.05 = 0.05%
apy: float
oi_usd: float
predicted_rate: float
def scan_funding_rates(min_apy: float = 15.0) -> List[FundingOpportunity]:
"""Scan all markets and return those with APY above threshold."""
r = requests.get(f"{TRADING_BASE}/markets/funding-rates", headers=HEADERS)
markets = r.json()["markets"]
opportunities = []
for m in markets:
rate = m["funding_rate"] # current 8h rate
predicted = m["predicted_rate"] # next 8h predicted rate
apy = rate * 1095 # annualize
if apy >= min_apy and predicted > 0: # only positive funding
opportunities.append(FundingOpportunity(
symbol=m["base"],
rate_8h=rate,
apy=apy,
oi_usd=m["open_interest_usd"],
predicted_rate=predicted
))
# Sort by APY descending
return sorted(opportunities, key=lambda x: x.apy, reverse=True)
# Example: find best opportunities right now
opps = scan_funding_rates(min_apy=20.0)
for o in opps[:5]:
print(f"{o.symbol}: {o.rate_8h:.3f}%/8h = {o.apy:.1f}% APY | OI: ${o.oi_usd/1e6:.0f}M")
Full Bot Implementation
import time
import logging
from datetime import datetime, timedelta
logger = logging.getLogger("funding-bot")
class FundingRateBot:
def __init__(self,
api_key: str,
capital_usd: float,
min_apy: float = 20.0,
max_positions: int = 3,
rebalance_threshold: float = 0.02):
self.api_key = api_key
self.capital = capital_usd
self.min_apy = min_apy
self.max_positions = max_positions
self.rebalance_threshold = rebalance_threshold
self.positions = {} # symbol -> position data
self.total_funding_earned = 0.0
def run_cycle(self):
"""Execute one monitoring cycle."""
logger.info(f"Cycle start | Positions: {len(self.positions)} | Capital: ${self.capital:,.0f}")
# 1. Collect any pending funding payments
self._collect_funding()
# 2. Check existing positions — exit if rate turned negative
self._manage_existing_positions()
# 3. Scan for new opportunities
if len(self.positions) < self.max_positions:
opps = scan_funding_rates(self.min_apy)
for opp in opps:
if opp.symbol not in self.positions:
size = self.capital / self.max_positions
logger.info(f"Opening position: {opp.symbol} @ {opp.rate_8h:.3f}%/8h ({opp.apy:.0f}% APY)")
result = open_funding_trade(opp.symbol, size)
self.positions[opp.symbol] = {
"perp_id": result["perp_order_id"],
"spot_id": result["spot_order_id"],
"size_usd": size,
"entry_rate": opp.rate_8h,
"opened_at": datetime.utcnow()
}
if len(self.positions) >= self.max_positions:
break
# 4. Check delta drift and rebalance if needed
self._rebalance_delta()
def _collect_funding(self):
r = requests.get(f"{TRADING_BASE}/funding-history", headers=HEADERS)
payments = r.json().get("payments", [])
period_total = sum(p["amount"] for p in payments)
self.total_funding_earned += period_total
if payments:
logger.info(f"Funding collected: ${period_total:+.4f} | Total: ${self.total_funding_earned:.4f}")
def _manage_existing_positions(self):
for symbol in list(self.positions.keys()):
r = requests.get(f"{TRADING_BASE}/markets/{symbol}-PERP/funding", headers=HEADERS)
current_rate = r.json().get("funding_rate", 0)
# Exit if rate turned negative (we'd be paying instead of earning)
if current_rate < -0.005: # -0.005% threshold
logger.info(f"Closing {symbol}: rate turned negative ({current_rate:.3f}%)")
self._close_position(symbol)
def _rebalance_delta(self):
# Check spot/perp balance drift due to price movement
# If price moved > rebalance_threshold, adjust spot holding
for symbol, pos in self.positions.items():
r = requests.get(f"{TRADING_BASE}/positions", headers=HEADERS)
perp_pos = next((p for p in r.json()["positions"]
if p["symbol"] == f"{symbol}-PERP"), None)
if perp_pos:
delta = abs(perp_pos.get("delta", 0))
if delta > self.rebalance_threshold:
logger.info(f"Rebalancing {symbol}: delta drift = {delta:.2%}")
# Adjust spot position to restore neutrality
def _close_position(self, symbol: str):
pos = self.positions.pop(symbol, None)
if pos:
# Close perpetual short
requests.delete(f"{TRADING_BASE}/positions/{symbol}-PERP", headers=HEADERS)
# Sell spot holding
requests.post(f"{WALLET_BASE}/spot/sell", headers=HEADERS, json={
"asset": symbol, "usd_amount": pos["size_usd"], "type": "market"
})
def run(self, interval_minutes: int = 60):
"""Run the bot continuously, checking every interval."""
logger.info(f"Funding rate bot started | Capital: ${self.capital:,.0f} | Min APY: {self.min_apy}%")
while True:
try:
self.run_cycle()
except Exception as e:
logger.error(f"Cycle error: {e}")
time.sleep(interval_minutes * 60)
# Launch
bot = FundingRateBot(
api_key="pf_live_YOUR_KEY",
capital_usd=10_000,
min_apy=20.0,
max_positions=3
)
bot.run(interval_minutes=60)
Historical Performance Reference
| Market Period | Avg Funding Rate (8h) | Gross APY | Est. Net APY (after fees) |
|---|---|---|---|
| Bear market (2022) | -0.005% | Negative | Strategy paused |
| Recovery (2023 H1) | 0.005% | 5.5% | ~3% |
| Bull market (2024) | 0.025% | 27.4% | ~24% |
| Peak euphoria (2025 Q1) | 0.065% | 71.2% | ~67% |
| Current (2026 avg) | 0.020% | 21.9% | ~19% |
Risk Factors and Mitigations
- Funding rate turns negative: Always monitor the predicted next funding rate. Exit positions at least 30 minutes before an 8h settlement if the predicted rate is negative. The bot above handles this automatically.
- Exchange risk (counterparty): Purple Flea routes through Hyperliquid's on-chain matching. Funds are never custodied by Purple Flea itself — they remain in your smart contract wallet.
- Liquidation risk: At 1x leverage with a hedge, liquidation requires a 100% adverse move. In practice this is not a realistic risk with a proper delta-neutral position.
- Spot slippage: Large positions in low-liquidity altcoins incur significant slippage when entering and exiting. Stick to BTC, ETH, and SOL for capital above $50K.
- Delta drift: As price moves, the perp and spot legs drift out of balance. Rebalance when drift exceeds 2% to maintain true neutrality.
Tax note: Funding payments are typically treated as ordinary income in most jurisdictions. Consult a tax professional familiar with DeFi and perpetual futures before scaling capital.
Optimal Market Selection Criteria
Not all high-funding markets are worth entering. Apply these filters before opening a position:
- Open interest above $50M — ensures sufficient liquidity to enter and exit cleanly
- Predicted next funding rate positive (not just the current rate)
- Funding rate has been consistently positive for at least 3 consecutive periods
- Bid-ask spread on spot below 0.05% — tight enough to not eat the funding yield
- Avoid tokens with upcoming token unlocks or protocol events that could cause sudden price dislocations
Access Hyperliquid Funding Rates via Purple Flea
Purple Flea provides a unified API across 275 perpetual markets. Real-time funding data, automated position management, and wallet integration — all in one place.
Open Trading API Agent Onboarding