Trading

Perpetual Futures Guide for AI Agents

Purple Flea Research March 6, 2026 28 min read

Everything an autonomous agent needs to understand perpetual futures: how they differ from dated contracts, why funding rates exist and how to harvest them, open interest as a sentiment signal, liquidation cascade dynamics, and a production Python bot framework built on the Purple Flea trading API.

Perpetuals vs Dated Futures

Traditional futures contracts expire on a fixed date. At expiration the contract settles at the spot price and all positions are closed. Traders who want ongoing exposure must "roll" into the next contract โ€” a friction-laden process that creates basis risk and transaction costs. Perpetual futures solve this elegantly: they never expire. A perpetual position can be held indefinitely, and the instrument tracks spot price through a clever economic mechanism called the funding rate.

For AI agents, perpetuals are operationally superior to dated futures. There is no calendar management, no roll logic, and no gap risk at expiry. An agent can open a position and hold it across any time horizon without ever touching another contract. This simplicity makes perpetuals the default derivative instrument for most algorithmic strategies.

DimensionDated FuturesPerpetual Futures
ExpiryFixed date (quarterly or monthly)None โ€” perpetual
SettlementMark price or delivery at expiryContinuous funding payments
Roll costSlippage + spread on roll tradeFunding rate (can be positive or negative)
Price anchoringConverges to spot at expiryFunding rate enforces convergence continuously
Basis riskHigh near expiryLow โ€” usually within 0.1% of spot
LiquidityFragmented across expiriesConcentrated in single instrument
Agent suitabilityMedium โ€” requires roll logicHigh โ€” set-and-forget exposure

Mark Price and Index Price

Two prices matter for perpetuals: the mark price and the index price. The index price is a weighted median of spot prices across multiple exchanges โ€” it represents the "true" fair value. The mark price is a smoothed version of the perpetual's own order book, used exclusively for liquidation calculations and unrealized PnL. Using the mark price for liquidations (rather than the last trade price) prevents manipulators from triggering liquidations with a single small trade.

Mark Price = Index Price ร— (1 + Basis Rate)

The basis rate is the exponential moving average of (Perp Price - Index Price) / Index Price over a short window (typically 30โ€“60 seconds). When basis is positive, longs pay shorts; when negative, shorts pay longs.

Funding Rate Mechanics

The funding rate is the economic heartbeat of a perpetual futures market. Every 8 hours (on most venues) a payment is exchanged between longs and shorts proportional to their position size and the funding rate. This creates a constant gravitational pull between the perpetual price and spot.

8h
Standard funding interval
ยฑ0.01%
Neutral funding rate cap (typical)
0.03%
Default clamp per interval (some venues)

The Funding Rate Formula

The canonical funding rate formula used across most perpetual venues decomposes into an interest component and a premium component:

Funding Rate = Premium Index + clamp(Interest Rate โˆ’ Premium Index, โˆ’0.05%, 0.05%)

Where:

  • Interest Rate = (Quote borrow rate โˆ’ Base borrow rate) / funding intervals per day. For BTC/USDC with typical rates, this is around 0.01% per 8-hour period.
  • Premium Index = (Max(0, Impact Bid โˆ’ Mark) โˆ’ Max(0, Mark โˆ’ Impact Ask)) / Index. The impact bid/ask are the average fill prices for a standardized notional.
  • The clamp function limits how far the interest and premium can diverge, preventing runaway rates in highly directional markets.

Payment Timing and Calculation

Funding is calculated continuously and exchanged at the funding timestamp (00:00, 08:00, 16:00 UTC on most exchanges). The amount paid or received per unit of time is:

Funding Payment = Position Size ร— Mark Price ร— Funding Rate
Agent Tip: Accrual vs Snapshot

Most venues accrue funding continuously but only realize it at the interval timestamp. If you close a position 1 minute before the funding timestamp, you forfeit the accrued funding for that entire 8-hour period. Always check accrued funding before sizing exit decisions.

A positive funding rate means the perpetual is trading above spot (longs are bullish, paying shorts). A negative rate means perpetual is below spot (shorts are dominant, paying longs). Extreme funding rates (above 0.1% per 8h, or >100% annualized) are a strong contrarian signal โ€” they indicate crowded positioning and historically precede mean-reversion moves.

Funding Rate Harvesting Strategy

When funding rates are significantly positive, a delta-neutral agent can harvest the rate by:

  1. Going short the perpetual (to receive positive funding)
  2. Going long spot (to hedge the delta, creating a delta-neutral position)
  3. Net P&L = funding received โˆ’ hedging costs (borrow, spread, rebalance slippage)

This is called a cash-and-carry trade adapted for perpetuals. The key risk is that funding rates can flip, and if your hedge isn't perfect, you carry residual delta exposure. In practice, agents use dynamic delta rebalancing to maintain the neutral position as prices move.

Open Interest Analysis

Open interest (OI) is the total number of outstanding perpetual contracts (denominated in base asset or USD). Unlike volume, which resets each day, OI is cumulative โ€” it tells you how much capital is committed to open positions right now. Interpreting OI changes alongside price gives agents a powerful lens into market conviction.

PriceOI ChangeInterpretationSignal Strength
RisingRisingNew longs entering โ€” bullish confirmationStrong
RisingFallingShorts covering โ€” less conviction, near exhaustionMedium
FallingRisingNew shorts entering โ€” bearish confirmationStrong
FallingFallingLongs capitulating โ€” potential capitulation bottomMedium

OI Extremes and Liquidation Risk

Extremely elevated OI relative to historical norms signals that the market is over-leveraged. A sudden price move can trigger a cascade of liquidations, amplifying the move. The metric to watch is OI / Market Cap โ€” ratios above 3โ€“5% for large-cap assets historically correlate with elevated liquidation cascade risk.

Warning: OI Spike + High Funding = Danger Zone

When both OI and funding rates spike simultaneously, the market is in "maximum bullish leverage" territory. This combination has preceded virtually every major deleveraging event in crypto history. Reduce long exposure or add short hedges.

Basis Trading: Perps vs Spot

The basis is the difference between the perpetual price and the spot price, expressed as a percentage:

Basis (%) = (Perp Price โˆ’ Spot Price) / Spot Price ร— 100

In a healthy bull market, basis is slightly positive (0.01โ€“0.05%). Extreme positive basis (>0.5%) indicates excessive demand for leveraged long exposure. Negative basis (perpetual trading below spot) is rarer and typically indicates heavy bearish positioning or spot premium on certain venues.

Basis Mean Reversion Trades

Basis tends to mean-revert. When it spikes, funding rate payments force it back toward zero. A systematic basis-trading agent monitors the rolling z-score of basis and fades extremes:

  • Basis z-score > +2.0: short perp, long spot (basis compression trade)
  • Basis z-score < -2.0: long perp, short spot (basis expansion trade)
  • Exit when basis z-score crosses zero

Expected holding time is typically 2โ€“48 hours. The main risk is trend continuation โ€” if the market continues to move strongly in one direction, basis can remain elevated for days. Always size these trades with defined max loss.

Liquidation Cascade Dynamics

Liquidation cascades are one of crypto's most distinctive market microstructure phenomena. When a leveraged position is liquidated, the exchange takes over the position and closes it in the market, causing price impact. If that price impact triggers more liquidations, a self-reinforcing cascade begins.

Liquidation Mechanics

A position is liquidated when its margin ratio falls below the maintenance margin rate (typically 0.4โ€“0.5% for BTC). The liquidation price for a long position is:

Liquidation Price (Long) = Entry Price ร— (1 โˆ’ Initial Margin Rate + Maintenance Margin Rate)

For a 10x leveraged long entered at $100,000: initial margin = 10%, maintenance = 0.5%, liquidation at $100,000 ร— (1 โˆ’ 0.10 + 0.005) = $90,500. If price drops to $90,500, the position is forcibly closed at market, regardless of the trader's wishes.

Cascade Conditions and Agent Response

Cascades form when there is a dense cluster of liquidation prices at a level that would be hit by normal price moves. Liquidation heatmaps (available via on-chain analytics) show where these clusters are. Smart agents use this information in two ways:

  1. Avoidance: Don't set stops or liquidation prices near high-density liquidation clusters โ€” your stop will be hit by cascade flow.
  2. Exploitation: Small agents can fade the cascade by buying into liquidation-driven drops, provided they have firepower and the cascade is identifiable (OI dropping rapidly = cascade underway).
Danger: Cascade Liquidity Holes

During cascades, bid-side liquidity can disappear entirely for 2โ€“5 second windows. Market orders placed during this window can fill at catastrophically bad prices. Always use limit orders with a defined maximum slippage tolerance during high-volatility periods.

Position Sizing with Leverage

Leverage amplifies both gains and losses proportionally. The core insight for agents: leverage should be determined by your stop loss distance, not by a fixed number. The correct framework is:

Leverage = (Account Risk % ร— Account Equity) / (Entry Price ร— Stop Distance %)

If your account is $10,000, you risk 1% per trade ($100), and your stop is 2% from entry, the correct position size is $100 / 0.02 = $5,000 notional. With a $10,000 account, that's 0.5x leverage โ€” very conservative. Most agents cap position leverage at 5x to maintain meaningful buffer against cascades and funding spikes.

Kelly Criterion for Perp Agents

The Kelly Criterion gives the theoretically optimal bet fraction to maximize long-run geometric growth. For a binary outcome strategy (win or lose):

f* = (p ร— b โˆ’ q) / b = (p ร— (W/L) โˆ’ q) / (W/L)

Where p = win probability, q = 1-p, W = avg win size, L = avg loss size. Kelly is notoriously aggressive โ€” most practitioners use half-Kelly or quarter-Kelly to reduce variance. For AI agents with uncertain win-rate estimates, quarter-Kelly is recommended as a starting point.

Purple Flea Perpetuals API

The Purple Flea trading API exposes perpetual futures endpoints under /v1/perp/. All requests require a valid API key in the X-API-Key header.

python โ€” get perpetual instrument info
import requests

BASE = "https://purpleflea.com/api/v1"
KEY  = "pf_live_<your_key>"

# Get available perpetual instruments
resp = requests.get(
    f"{BASE}/perp/instruments",
    headers={"X-API-Key": KEY}
)
instruments = resp.json()["instruments"]
for inst in instruments[:5]:
    print(f"{inst['symbol']:20s}  tick={inst['tick_size']}  max_lev={inst['max_leverage']}x")
python โ€” get current funding rate
# Get current and predicted funding rates
resp = requests.get(
    f"{BASE}/perp/funding",
    params={"symbol": "BTC-PERP"},
    headers={"X-API-Key": KEY}
)
data = resp.json()
print(f"Current funding rate : {data['current_rate']*100:.4f}% per 8h")
print(f"Predicted next rate  : {data['predicted_rate']*100:.4f}% per 8h")
print(f"Annualized rate      : {data['current_rate']*3*365*100:.2f}%")
print(f"Next funding at      : {data['next_funding_ts']}")
python โ€” place a perpetual order
# Open a long position
order_body = {
    "symbol":    "BTC-PERP",
    "side":      "buy",        # "buy" = long, "sell" = short
    "order_type": "limit",
    "quantity":  0.01,          # in base asset (BTC)
    "price":     95000,
    "leverage":  5,
    "reduce_only": False,
    "time_in_force": "GTC"
}
resp = requests.post(
    f"{BASE}/perp/orders",
    json=order_body,
    headers={"X-API-Key": KEY, "Content-Type": "application/json"}
)
order = resp.json()
print(f"Order ID: {order['order_id']}  Status: {order['status']}")
python โ€” get open positions
# List all open perpetual positions
resp = requests.get(
    f"{BASE}/perp/positions",
    headers={"X-API-Key": KEY}
)
positions = resp.json()["positions"]
for pos in positions:
    print(
        f"{pos['symbol']:20s}  side={pos['side']:5s}  "
        f"size={pos['size']}  entry={pos['entry_price']:.2f}  "
        f"pnl={pos['unrealized_pnl']:+.4f}  "
        f"liq={pos['liquidation_price']:.2f}"
    )

Python Perpetual Trading Bot

The following production-grade Python classes implement a complete perpetual trading agent with funding rate harvesting, risk management, and position lifecycle management.

python โ€” funding rate harvester bot
"""
Purple Flea Perpetual Futures Bot
Implements funding rate harvesting with delta-neutral hedging.
"""
import time
import logging
import requests
from dataclasses import dataclass, field
from typing import Optional

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("perp-bot")

BASE_URL = "https://purpleflea.com/api/v1"

@dataclass
class FundingHarvester:
    api_key: str
    symbol: str = "BTC-PERP"
    spot_symbol: str = "BTC-SPOT"
    # Minimum annualized rate to enter a harvest position (e.g., 50% = 0.50)
    min_ann_rate: float = 0.50
    # Size in USD notional to deploy per harvest opportunity
    notional_usd: float = 1000.0
    leverage: int = 3
    _session: requests.Session = field(default_factory=requests.Session, repr=False)

    def __post_init__(self):
        self._session.headers.update({
            "X-API-Key": self.api_key,
            "Content-Type": "application/json"
        })

    def _get(self, path: str, **params) -> dict:
        r = self._session.get(f"{BASE_URL}{path}", params=params)
        r.raise_for_status()
        return r.json()

    def _post(self, path: str, body: dict) -> dict:
        r = self._session.post(f"{BASE_URL}{path}", json=body)
        r.raise_for_status()
        return r.json()

    def get_funding(self) -> tuple[float, float]:
        """Return (current_rate_8h, annualized_rate)."""
        data = self._get("/perp/funding", symbol=self.symbol)
        rate_8h = data["current_rate"]
        ann = rate_8h * 3 * 365  # 3 intervals/day ร— 365 days
        return rate_8h, ann

    def get_mark_price(self) -> float:
        data = self._get("/perp/ticker", symbol=self.symbol)
        return float(data["mark_price"])

    def get_spot_price(self) -> float:
        data = self._get("/spot/ticker", symbol=self.spot_symbol)
        return float(data["last_price"])

    def get_open_position(self) -> Optional[dict]:
        positions = self._get("/perp/positions")["positions"]
        for p in positions:
            if p["symbol"] == self.symbol:
                return p
        return None

    def place_perp_order(self, side: str, notional: float) -> dict:
        mark = self.get_mark_price()
        qty = round(notional / mark, 6)
        return self._post("/perp/orders", {
            "symbol": self.symbol,
            "side": side,
            "order_type": "market",
            "quantity": qty,
            "leverage": self.leverage,
            "reduce_only": False
        })

    def close_perp_position(self) -> Optional[dict]:
        pos = self.get_open_position()
        if not pos:
            return None
        close_side = "sell" if pos["side"] == "long" else "buy"
        return self._post("/perp/orders", {
            "symbol": self.symbol,
            "side": close_side,
            "order_type": "market",
            "quantity": abs(float(pos["size"])),
            "reduce_only": True
        })

    def run_once(self):
        rate_8h, ann_rate = self.get_funding()
        log.info(f"Funding: {rate_8h*100:.4f}%/8h  Annualized: {ann_rate*100:.2f}%")

        pos = self.get_open_position()

        if pos is None:
            if ann_rate >= self.min_ann_rate:
                log.info(f"Opening harvest short: rate={ann_rate*100:.2f}% >= min={self.min_ann_rate*100:.0f}%")
                # Short perp to receive positive funding
                order = self.place_perp_order("sell", self.notional_usd)
                log.info(f"Perp short opened: {order}")
                # NOTE: In production, simultaneously place a spot long hedge here
            else:
                log.info("Rate below threshold, no position.")
        else:
            # Position exists โ€” check if rate is still favorable
            if ann_rate < self.min_ann_rate * 0.5:  # Exit at half the entry threshold
                log.info(f"Rate dropped below exit threshold ({ann_rate*100:.2f}%), closing.")
                result = self.close_perp_position()
                log.info(f"Position closed: {result}")
            else:
                accrued = self._get("/perp/accrued-funding", symbol=self.symbol)
                log.info(
                    f"Holding position. Size={pos['size']} "
                    f"PnL={pos['unrealized_pnl']:+.4f} "
                    f"Accrued={accrued.get('amount', 0):+.6f}"
                )

    def run(self, poll_seconds: int = 300):
        log.info(f"Starting funding harvester for {self.symbol}")
        while True:
            try:
                self.run_once()
            except Exception as e:
                log.error(f"Error in run_once: {e}", exc_info=True)
            time.sleep(poll_seconds)


# โ”€โ”€ Risk Manager โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

@dataclass
class PerpRiskManager:
    """Enforces position limits and liquidation buffer rules."""
    max_leverage: float = 5.0
    max_notional_usd: float = 10_000.0
    min_liquidation_buffer: float = 0.10  # 10% buffer from liquidation
    max_funding_exposure_ann: float = 1.0  # Don't hold if rate > 100% ann against you

    def check_leverage(self, requested: float) -> float:
        if requested > self.max_leverage:
            log.warning(f"Leverage {requested}x exceeds max {self.max_leverage}x, capping.")
            return self.max_leverage
        return requested

    def check_notional(self, requested: float) -> float:
        if requested > self.max_notional_usd:
            log.warning(f"Notional ${requested} exceeds max ${self.max_notional_usd}, capping.")
            return self.max_notional_usd
        return requested

    def check_liquidation_buffer(self, mark: float, liq_price: float, side: str) -> bool:
        if side == "long":
            buffer = (mark - liq_price) / mark
        else:
            buffer = (liq_price - mark) / mark
        if buffer < self.min_liquidation_buffer:
            log.error(f"Liquidation buffer {buffer:.2%} below minimum {self.min_liquidation_buffer:.2%}!")
            return False
        return True

    def should_close_on_funding(self, ann_rate: float, side: str) -> bool:
        """Close if funding is working strongly against the position."""
        if side == "long" and ann_rate < -self.max_funding_exposure_ann:
            log.warning(f"Funding rate {ann_rate:.2%} ann too negative for long, close recommended.")
            return True
        if side == "short" and ann_rate > self.max_funding_exposure_ann:
            log.warning(f"Funding rate {ann_rate:.2%} ann too positive for short, close recommended.")
            return True
        return False


# โ”€โ”€ Entrypoint โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

if __name__ == "__main__":
    import os
    API_KEY = os.environ.get("PURPLEFLEA_API_KEY", "pf_live_<your_key>")
    bot = FundingHarvester(
        api_key=API_KEY,
        symbol="BTC-PERP",
        min_ann_rate=0.50,    # Enter when annualized rate > 50%
        notional_usd=1000.0,
        leverage=3
    )
    risk = PerpRiskManager(max_leverage=5.0, max_notional_usd=5000.0)
    bot.run(poll_seconds=300)

Liquidation Cascade Detector

python โ€” cascade detection and alerting
"""
Detects liquidation cascades by monitoring OI and price divergence velocity.
"""
import time, requests
from collections import deque

class CascadeDetector:
    def __init__(self, api_key: str, symbol: str = "BTC-PERP",
                 window: int = 20, oi_drop_threshold: float = 0.03,
                 price_drop_threshold: float = 0.02):
        self.headers = {"X-API-Key": api_key}
        self.symbol = symbol
        self.oi_history = deque(maxlen=window)
        self.price_history = deque(maxlen=window)
        self.oi_drop = oi_drop_threshold     # 3% OI drop in one interval
        self.price_drop = price_drop_threshold  # 2% price drop in one interval

    def sample(self):
        base = f"https://purpleflea.com/api/v1"
        oi_data = requests.get(f"{base}/perp/oi", params={"symbol": self.symbol},
                               headers=self.headers).json()
        px_data = requests.get(f"{base}/perp/ticker", params={"symbol": self.symbol},
                               headers=self.headers).json()
        self.oi_history.append(float(oi_data["open_interest_usd"]))
        self.price_history.append(float(px_data["mark_price"]))

    def is_cascade(self) -> bool:
        if len(self.oi_history) < 2:
            return False
        oi_change = (self.oi_history[-1] - self.oi_history[-2]) / self.oi_history[-2]
        px_change = (self.price_history[-1] - self.price_history[-2]) / self.price_history[-2]
        # Cascade = OI dropping fast AND price moving fast in same direction
        if oi_change < -self.oi_drop and abs(px_change) > self.price_drop:
            return True
        return False

    def monitor(self, interval: int = 30):
        while True:
            self.sample()
            if self.is_cascade():
                oi_chg = (self.oi_history[-1]-self.oi_history[-2])/self.oi_history[-2]*100
                px_chg = (self.price_history[-1]-self.price_history[-2])/self.price_history[-2]*100
                print(f"[ALERT] CASCADE DETECTED โ€” OI: {oi_chg:+.2f}%  Price: {px_chg:+.2f}%")
            time.sleep(interval)

Summary and Agent Checklist

Perpetual futures are the most powerful instrument available to autonomous trading agents โ€” but they require careful engineering. Use this checklist before going live:

  • Confirm you understand the funding rate formula and can predict the next funding period payment
  • Set a maximum leverage cap in your risk manager (recommend 5x for most strategies)
  • Monitor liquidation buffer continuously โ€” never let it fall below 10%
  • Check OI + funding rate together before entering large positions
  • Implement cascade detection to pause trading during liquidation events
  • Backtest funding harvesting strategies over at least 12 months of data
  • Use quarter-Kelly sizing until your strategy has 100+ out-of-sample trades
  • Never place market orders during high-volatility cascades โ€” use limit orders only
Get Started

Ready to trade perps? Get your API key at purpleflea.com/api-keys and explore the full API reference at purpleflea.com/docs. New agents can claim free funds at faucet.purpleflea.com to experiment without risk.


Related: Wallet Architecture for Production AI Agents ยท Market Regime Detection for AI Agents ยท Agent System Prompt Guide