← Back to All Tutorials

Tutorial 02: HIP-3 Funding Rate Scanner Beginner-Friendly

Table of Contents
  1. What Does This Scanner Do?
  2. Key Concepts
  3. How It Works
  4. Code Walkthrough
  5. Dependencies
  6. Glossary

1. What Does This Scanner Do?

This tool scans all funding rates across Hyperliquid - both regular crypto perpetuals and HIP-3 tokenized assets (oil, gold, stocks). It displays the top 30 highest and top 30 most negative funding rates in formatted tables, filtering out small markets.

Simple Analogy: Imagine a newspaper that lists every rental property in town and shows which landlords are charging the most (high funding = expensive to hold long) and which are paying you to move in (negative funding = they pay you). This scanner does that for crypto trading fees.

The scanner loops every 5 minutes and shows you:

2. Key Concepts

What is a Funding Rate?

In perpetual futures, there's no expiry date. To keep the futures price close to the real price, exchanges use a funding rate - a periodic fee paid between traders.

Why it matters: Extreme funding rates can signal overcrowded trades and potential reversals. They also affect your P&L - high positive funding eats into long profits.

Open Interest (OI)

The total dollar value of all open (unclosed) positions. The scanner filters for MIN_OI_VALUE = $5,000,000 to only show markets with enough liquidity to trade.

Annualized Rate

The funding rate extrapolated to a yearly percentage. If the 8-hour funding rate is 0.01%, the annualized rate would be about 10.95% (0.01% x 3 payments/day x 365 days). This helps you compare funding rates to traditional interest rates.

3. How It Works

1. Fetch Crypto
Perp Funding Rates
1b. Fetch HIP-3
Asset Funding Rates


2. Combine &
Standardize Data


3. Filter by OI
(min $5M)


4. Sort by Rate %
Show Top/Bottom 30


Wait 5 minutes
then repeat

4. Code Walkthrough

1 display_top_bottom() - The main display function

def display_top_bottom(df, label):
    # Step 1: Clean and standardize the dataframe
    df = _standardize_df(df.copy())

    # Step 2: Check we have a Rate % column
    if "Rate %" not in df.columns:
        return

    # Step 3: Sort by rate, highest first
    df = df.dropna(subset=["Rate %"]).sort_values("Rate %", ascending=False)

    # Step 4: Filter out small markets (OI < $5M)
    if "OI Value" in df.columns:
        df = df[df["OI Value"] >= MIN_OI_VALUE]

    # Step 5: Show top 30 highest and top 30 lowest
    top_pos = df.head(30)
    top_neg = df.tail(30).sort_values("Rate %", ascending=True)

Line by line:

2 fetch_crypto_funding() - Get regular crypto rates

This function queries the Hyperliquid API for funding rates on standard crypto perpetuals (BTC, ETH, SOL, etc.). It returns raw data that gets standardized later.

3 fetch_hip3_funding() - Get tokenized asset rates

Same idea, but for HIP-3 markets - these are real-world assets like crude oil (CL), gold, and stocks that trade as perpetual futures on Hyperliquid.

4 scan() - The main loop

def scan():
    while True:
        crypto_df = fetch_crypto_funding()
        hip3_df = fetch_hip3_funding()

        display_top_bottom(crypto_df, "Crypto Perps")
        display_top_bottom(hip3_df, "HIP-3 Assets")

        time.sleep(300)  # Wait 5 minutes

The infinite loop runs the scan every 5 minutes (300 seconds). It fetches both crypto and HIP-3 rates, then displays them.

5. Dependencies

pip install colorama pandas requests python-dotenv

6. Glossary

TermMeaning
Funding RateA periodic fee paid between long and short traders to keep perp prices close to spot
Open Interest (OI)Total value of all outstanding positions in a market
Annualized RateThe funding rate expressed as a yearly percentage
Perpetual (Perp)A futures contract with no expiry date
Spot PriceThe current real price of the asset
LiquidityHow easy it is to buy/sell without moving the price much

7. Full Code: Python to Pseudo-Code Translation

Configuration & Setup

# --- PYTHON ---
BASE_URL = "https://api.moondev.com"
LOOP_INTERVAL_SECONDS = 5 * 60
MIN_OI_VALUE = 5_000_000

# --- PSEUDO-CODE ---
SET BASE_URL to Moon Dev's API address
SET LOOP_INTERVAL_SECONDS to 300 (5 minutes between each scan)
SET MIN_OI_VALUE to $5,000,000 (minimum open interest to show an asset)

fetch_crypto_funding() - Get Regular Crypto Rates

# --- PYTHON ---
def fetch_crypto_funding():
    response = requests.get(f"{BASE_URL}/api/hlp/funding",
                            headers=_auth_headers(), timeout=30)
    response.raise_for_status()
    return response.json()

# --- PSEUDO-CODE ---
FUNCTION fetch_crypto_funding():
    SEND a GET request to Moon Dev API endpoint "/api/hlp/funding"
    INCLUDE our API key in the request headers
    WAIT up to 30 seconds for a response
    IF the request failed: raise an error
    PARSE the response as JSON and RETURN it (a list of funding rates for all crypto perps)

fetch_hip3_funding() - Get HIP-3 Asset Rates

# --- PYTHON ---
def fetch_hip3_funding():
    response = requests.get(f"{BASE_URL}/api/hlp/funding/hip3",
                            headers=_auth_headers(), timeout=30)
    response.raise_for_status()
    return response.json()

# --- PSEUDO-CODE ---
FUNCTION fetch_hip3_funding():
    SEND a GET request to Moon Dev API endpoint "/api/hlp/funding/hip3"
    INCLUDE our API key in the request headers
    WAIT up to 30 seconds for a response
    IF the request failed: raise an error
    PARSE the response as JSON and RETURN it (a list of funding rates for HIP-3 tokenized assets)

_standardize_df() - Normalize Column Names

# --- PYTHON ---
def _standardize_df(df):
    col_map = {}
    for col in df.columns:
        lower = col.lower()
        if "coin" in lower or "symbol" in lower:
            col_map[col] = "Symbol"
        elif "rate_pct" in lower:
            col_map[col] = "Rate %"
        elif "annual" in lower:
            col_map[col] = "Annualized %"
        elif "oi" in lower:
            col_map[col] = "OI Value"
    df = df.rename(columns=col_map)
    for c in ["Rate %", "Annualized %"]:
        if c in df.columns:
            df[c] = pd.to_numeric(df[c], errors="coerce")
    return df

# --- PSEUDO-CODE ---
FUNCTION _standardize_df(dataframe):
    CREATE an empty mapping of old column names to new standard names
    FOR EACH column name in the dataframe:
        CONVERT to lowercase for comparison
        IF the column name contains "coin" or "symbol": map it to "Symbol"
        IF the column name contains "rate_pct": map it to "Rate %"
        IF the column name contains "annual": map it to "Annualized %"
        IF the column name contains "oi": map it to "OI Value"
    RENAME all columns using the mapping
    CONVERT the Rate % and Annualized % columns to numbers
        (any text that can't be converted becomes blank/NaN)
    RETURN the cleaned-up dataframe

display_top_bottom() - Show Highest & Lowest Rates

# --- PYTHON ---
def display_top_bottom(df, label):
    df = _standardize_df(df.copy())
    if "Rate %" not in df.columns:
        return
    df = df.dropna(subset=["Rate %"]).sort_values("Rate %", ascending=False)
    if "OI Value" in df.columns:
        df["OI Value"] = pd.to_numeric(df["OI Value"], errors="coerce")
        df = df[df["OI Value"] >= MIN_OI_VALUE]
    top_pos = df.head(30)
    top_neg = df.tail(30).sort_values("Rate %", ascending=True)
    print(top_pos[display_cols].to_string(index=False))
    print(top_neg[display_cols].to_string(index=False))

# --- PSEUDO-CODE ---
FUNCTION display_top_bottom(dataframe, label):
    CLEAN UP the dataframe: standardize column names, convert types
    IF there's no "Rate %" column: give up and return

    REMOVE any rows that have blank/missing rate values
    SORT the entire dataframe from HIGHEST rate to LOWEST rate

    IF there's an "OI Value" column:
        CONVERT it to numbers
        REMOVE any assets with less than $5 million in open interest
        (This filters out tiny, illiquid markets)

    TAKE the top 30 rows = the 30 highest funding rates
    TAKE the bottom 30 rows and reverse them = the 30 most negative rates

    PRINT a formatted table showing the top 30 highest rates
    PRINT a formatted table showing the top 30 most negative rates

scan() - Run One Complete Scan Cycle

# --- PYTHON ---
def scan():
    crypto_data = fetch_crypto_funding()
    crypto_df = parse_rates_to_df(crypto_data, "crypto")
    hip3_data = fetch_hip3_funding()
    hip3_df = parse_rates_to_df(hip3_data, "hip3")
    for label, df in [("Crypto Perps", crypto_df), ("HIP3 Tokenized", hip3_df)]:
        if df.empty:
            continue
        display_top_bottom(df, label)

if __name__ == "__main__":
    scan()
    while True:
        time.sleep(LOOP_INTERVAL_SECONDS)
        scan()

# --- PSEUDO-CODE ---
FUNCTION scan():
    FETCH all crypto perpetual funding rates from Moon Dev API
    PARSE the raw data into a clean pandas dataframe
    FETCH all HIP-3 tokenized asset funding rates from Moon Dev API
    PARSE the raw data into a clean pandas dataframe

    FOR EACH category ("Crypto Perps" and "HIP3 Tokenized"):
        IF the dataframe is not empty:
            DISPLAY the top 30 highest and top 30 most negative rates

MAIN PROGRAM:
    Run one scan immediately
    THEN loop forever:
        Wait 5 minutes
        Run another scan