1. Available Instruments

The Purple Flea Trading API exposes perpetual futures on a curated set of liquid assets. Perps never expire — they track the spot price via a periodic funding rate mechanism that keeps long and short positions in equilibrium.

Pair Category Max Leverage Min Trade Status
BTC-PERPMajor50x0.001 BTCLive
ETH-PERPMajor50x0.01 ETHLive
SOL-PERPMajor30x0.1 SOLLive
BNB-PERPMajor30x0.1 BNBLive
DOGE-PERPAltcoin20x100 DOGELive
MATIC-PERPAltcoin20x10 MATICLive
LINK-PERPDeFi20x1 LINKLive
AVAX-PERPL125x0.1 AVAXLive

All perps are quoted in USDC. Your agent holds a single USDC balance and allocates across any pair. Maker / taker fees are 0.02% / 0.05% — aggressive limit orders on the maker side meaningfully improve long-run P&L.

API base URL: https://trading.purpleflea.com/api/v1/
Authenticate with X-API-Key: pf_live_<your_key> on every request.

2. Leverage Mechanics: Margin, Liquidation & Funding

Margin modes

Purple Flea Trading supports two margin modes selectable per position:

  • Isolated margin — each position has its own dedicated collateral. Losses are capped at that collateral; the rest of your balance is protected.
  • Cross margin — all open positions share your full account balance as collateral. More capital-efficient for portfolios, but a runaway loss in one position can liquidate your entire account.

Funding rate mechanics

Every 8 hours a funding payment occurs. When the perp premium is positive (perp trades above spot) longs pay shorts. When negative (perp below spot) shorts pay longs. The formula is:

Formula
Funding Payment = Position Size × Mark Price × Funding Rate

Funding Rate (8h) =
  clamp(Premium Index + clamp(Interest Rate − Premium Index, −0.05%, +0.05%), −0.075%, +0.075%)

Premium Index = (Max(0, Impact Bid − Mark) − Max(0, Mark − Impact Ask)) / Spot

Liquidation price

For an isolated long position, liquidation occurs when:

Formula
Liquidation Price (Long) = Entry Price × (1 − 1/Leverage + Maintenance Margin Rate)
Maintenance Margin Rate  = 0.5% (standard)

Example — BTC at $60,000, 10x leverage, isolated:
  Liq Price = 60,000 × (1 − 0.1 + 0.005) = 60,000 × 0.905 = $54,300
Buffer rule: Never enter a position where the liquidation price is within 15% of the current mark price. Market volatility can close that gap in minutes on altcoin pairs.

3. Strategy 1 — Funding Rate Arbitrage

Concept: When the perpetual funding rate is significantly positive (longs pay shorts), you can earn that rate risk-free by holding a short perp position and a matching long spot position. The two price exposures cancel — what remains is the 8-hourly funding income.

When to run it

  • 8h funding rate > 0.03% (annualises to >13%)
  • Spot bid/ask spread + perp maker fee < 50% of projected 8h funding
  • Sufficient liquidity to enter both legs within 0.05% slippage
Python
import requests

API = "https://trading.purpleflea.com/api/v1"
KEY = "pf_live_<your_key>"
HDR = {"X-API-Key": KEY}

def get_funding_rates():
    r = requests.get(f"{API}/market/funding-rates", headers=HDR)
    return r.json()["rates"]

def open_funding_arb(pair, usdc_size):
    # Open short perp (earn when positive funding)
    perp = requests.post(f"{API}/orders", headers=HDR, json={
        "pair": pair, "side": "sell", "type": "market",
        "notional_usdc": usdc_size, "margin_mode": "isolated",
        "leverage": 1
    })
    # Buy spot equivalent (hedge price exposure)
    spot_pair = pair.replace("-PERP", "-SPOT")
    spot = requests.post(f"{API}/orders", headers=HDR, json={
        "pair": spot_pair, "side": "buy", "type": "market",
        "notional_usdc": usdc_size
    })
    return perp.json(), spot.json()

for rate_info in get_funding_rates():
    if rate_info["rate_8h"] > 0.0003:  # 0.03% threshold
        print(f"Arb opportunity: {rate_info['pair']} @ {rate_info['rate_8h']*100:.4f}% per 8h")
        open_funding_arb(rate_info["pair"], usdc_size=1000)

Risk factors

  • Funding flip: Rate can reverse before next settlement. Check rate 30 min before each 8h window.
  • Spot-perp basis risk: Temporary divergence between spot and perp mark prices can cause margin calls on the perp leg even with a hedged net position.
  • Execution slippage: If legs fill at different prices, you have residual directional exposure. Use maker limit orders when spread allows.

4. Strategy 2 — Basis Trading (Cash-and-Carry)

Basis trading exploits the premium at which perpetuals persistently trade above (or below) their spot reference. Unlike pure funding arb — which targets 8h settlements — basis trading captures the convergence of the mark price premium over multiple days or weeks.

Identifying the basis

Python
def calculate_basis(pair):
    ticker = requests.get(f"{API}/market/ticker/{pair}", headers=HDR).json()
    spot_px = ticker["spot_price"]
    mark_px = ticker["mark_price"]
    basis_pct = (mark_px - spot_px) / spot_px * 100
    return {"pair": pair, "spot": spot_px, "mark": mark_px, "basis_pct": basis_pct}

# Example output: {"pair": "ETH-PERP", "spot": 3240.0, "mark": 3258.4, "basis_pct": 0.568}
# Annualised: 0.568% / day → ~207% APR if basis holds and you roll daily

Execution flow

  1. Identify pair with basis > 0.1% (annualises to >36%)
  2. Long spot in equal USDC notional
  3. Short perp at 1x leverage (isolated)
  4. Monitor basis daily; close both legs when basis normalises to < 0.02%
  5. P&L = funding collected + basis convergence gain (or loss if basis widens)
Historical edge: BTC-PERP and ETH-PERP have traded at a persistent positive basis (perp premium) over 80% of days in 2025, driven by structural long demand from leveraged directional traders. Mean basis of approximately 0.08% per 8h.

5. Strategy 3 — Volatility Breakout with Dynamic TP/SL

Breakout strategies enter in the direction of a strong move after a period of consolidation. The key insight: after a squeeze, volatility expands rapidly and early entrants capture the bulk of the move. Dynamic TP/SL levels use ATR to adapt to current volatility — tight enough to protect capital, wide enough to stay in winning trades.

Signal generation

Python
import numpy as np

def compute_atr(highs, lows, closes, period=14):
    tr = [max(highs[i]-lows[i], abs(highs[i]-closes[i-1]), abs(lows[i]-closes[i-1]))
          for i in range(1, len(closes))]
    return np.mean(tr[-period:])

def breakout_signal(candles, lookback=20, atr_mult_tp=3.0, atr_mult_sl=1.5):
    closes = [c["close"] for c in candles]
    highs  = [c["high"]  for c in candles]
    lows   = [c["low"]   for c in candles]

    recent_high = max(highs[-lookback-1:-1])
    recent_low  = min(lows[-lookback-1:-1])
    atr = compute_atr(highs, lows, closes)
    last = closes[-1]

    if last > recent_high:      # Upside breakout
        return {"side": "buy", "entry": last,
                "tp": last + atr * atr_mult_tp,
                "sl": last - atr * atr_mult_sl}
    elif last < recent_low:     # Downside breakout
        return {"side": "sell", "entry": last,
                "tp": last - atr * atr_mult_tp,
                "sl": last + atr * atr_mult_sl}
    return None

Order placement

Python
def execute_breakout(sig, pair, usdc_size, leverage=5):
    if not sig:
        return
    # Entry
    entry = requests.post(f"{API}/orders", headers=HDR, json={
        "pair": pair, "side": sig["side"], "type": "market",
        "notional_usdc": usdc_size, "leverage": leverage,
        "take_profit": sig["tp"], "stop_loss": sig["sl"]
    })
    return entry.json()

6. Strategy 4 — Mean Reversion with Bollinger Bands

Mean reversion bets that extreme deviations from a rolling average will snap back. Bollinger Bands quantify "extreme" as a number of standard deviations from a moving average. When price touches the lower band, buy; upper band, sell — then exit at the middle band.

Why it works on crypto perps

Perps are frequently driven by leveraged retail emotion. Spikes to multi-sigma levels are liquidation events — not fundamental repricing — and they mean-revert sharply. ETH-PERP on the 1h chart returns to the 20-period SMA within 4 candles 68% of the time when touching the 2.5-sigma band.

Python
def bollinger_signal(closes, period=20, std_mult=2.5):
    closes = np.array(closes)
    ma  = np.mean(closes[-period:])
    std = np.std(closes[-period:])
    upper = ma + std_mult * std
    lower = ma - std_mult * std
    last  = closes[-1]

    if last <= lower:
        return {"side": "buy",  "target": ma, "sl": lower - std, "z": (last-ma)/std}
    elif last >= upper:
        return {"side": "sell", "target": ma, "sl": upper + std, "z": (last-ma)/std}
    return None

def mean_rev_loop(pair, poll_interval=300):
    import time
    while True:
        candles = requests.get(
            f"{API}/market/candles/{pair}",
            params={"interval": "1h", "limit": 60},
            headers=HDR
        ).json()["candles"]
        closes = [c["close"] for c in candles]
        sig = bollinger_signal(closes)
        if sig:
            print(f"Mean rev {sig['side']} signal — z={sig['z']:.2f}")
            # execute order ...
        time.sleep(poll_interval)
Filter: Only trade mean-reversion signals when the 24h volume is above the 30-day average. Low-volume breakouts are often one-sided and will not mean-revert. Use GET /market/ticker/{pair} volume_24h field.

7. Strategy 5 — Momentum Following with Regime Filters

Momentum is the oldest edge in markets: assets that have risen tend to keep rising over the short term. On crypto perps, momentum is especially pronounced during trending regimes — bull runs and sustained downtrends. The key is filtering out choppy, sideways regimes where momentum signals are noise.

Regime filter: ADX + EMA alignment

Python
def ema(values, period):
    k = 2 / (period + 1)
    result = [values[0]]
    for v in values[1:]:
        result.append(v * k + result[-1] * (1 - k))
    return result

def momentum_signal(closes, fast=12, slow=26, signal=9):
    ema_fast = ema(closes, fast)
    ema_slow = ema(closes, slow)
    macd     = [f - s for f, s in zip(ema_fast, ema_slow)]
    macd_sig = ema(macd, signal)
    histogram = macd[-1] - macd_sig[-1]

    # Regime filter: fast EMA > slow EMA = uptrend
    trending_up   = ema_fast[-1] > ema_slow[-1]
    trending_down = ema_fast[-1] < ema_slow[-1]

    if histogram > 0 and trending_up:
        return "buy"
    elif histogram < 0 and trending_down:
        return "sell"
    return None   # Choppy — no trade

Entry / exit rules

  • Entry: MACD histogram flips positive (buy) or negative (sell) AND EMA alignment confirms regime.
  • Trailing stop: Set initial SL at 2x ATR below entry; trail up by 1x ATR as price moves favorably.
  • Exit: MACD histogram crosses zero in opposite direction, or trailing stop hit.
  • Max hold: 72h. Close any position older than 3 days regardless of P&L.

8. Position Sizing for Leveraged Instruments

With leverage, position sizing is the single most important factor in survival. The Kelly Criterion — adapted for binary payoff structures — gives the theoretically optimal fraction of capital to risk per trade.

Python
def kelly_fraction(win_rate, avg_win_pct, avg_loss_pct):
    """Returns fraction of capital to risk."""
    b = avg_win_pct / avg_loss_pct   # Reward/risk ratio
    p = win_rate
    q = 1 - p
    k = (b * p - q) / b
    return max(0, k * 0.5)  # Half-Kelly for safety

def position_usdc(account_balance, kelly_f, entry_price, stop_price):
    """Convert Kelly fraction to USDC notional given a stop distance."""
    risk_usdc  = account_balance * kelly_f
    stop_pct   = abs(entry_price - stop_price) / entry_price
    notional   = risk_usdc / stop_pct
    return round(notional, 2)

# Example
f = kelly_fraction(win_rate=0.55, avg_win_pct=3.0, avg_loss_pct=1.5)
# f = 0.183 → risk 18.3% per trade (half-Kelly: 9.2%)
size = position_usdc(10000, f * 0.5, entry_price=60000, stop_price=58800)
print(f"Position size: ${size:,.2f} USDC notional")
Max risk / trade
2%
of account balance
Max open positions
5
concurrent perp positions
Max portfolio leverage
3x
gross notional / balance
Drawdown circuit breaker
15%
halt trading for 24h

9. Liquidation Risk Management

Liquidation is permanent capital loss. The following rules should be hardcoded into any leveraged trading agent:

Hard rules — never bypass these in code:
  1. Never hold a position where liquidation is within 10% of current mark price
  2. Always use isolated margin on individual directional trades
  3. Set a stop-loss order on entry — do not rely on manual monitoring
  4. If account health drops below 120%, close the most levered position immediately
  5. Never average down into a losing leveraged position
Python
def check_liquidation_risk(api_key):
    positions = requests.get(
        f"{API}/positions",
        headers={"X-API-Key": api_key}
    ).json()["positions"]

    alerts = []
    for pos in positions:
        mark = pos["mark_price"]
        liq  = pos["liquidation_price"]
        buffer_pct = abs(mark - liq) / mark * 100
        if buffer_pct < 10:
            alerts.append({
                "pair": pos["pair"], "buffer_pct": buffer_pct,
                "action": "REDUCE_POSITION"
            })
    return alerts

# Run this health check every 60 seconds in your trading loop

10. Python Multi-Strategy Framework

The framework below instantiates all five strategies, evaluates current market regime, and dynamically allocates capital between strategies that are appropriate for the regime. It runs as a continuous loop, logging decisions and managing positions.

Python
"""
Purple Flea Multi-Strategy Trading Framework
Dynamically allocates capital across 5 strategies based on market regime.
"""
import time, logging, requests
import numpy as np
from dataclasses import dataclass
from typing import Optional, Dict, List

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

API = "https://trading.purpleflea.com/api/v1"
KEY = "pf_live_<your_key>"
HDR = {"X-API-Key": KEY}

@dataclass
class StrategySignal:
    strategy: str
    pair: str
    side: str              # "buy" | "sell" | "neutral"
    confidence: float      # 0.0–1.0
    suggested_allocation: float  # fraction of available capital
    meta: Dict

class MarketRegime:
    TRENDING_UP   = "trending_up"
    TRENDING_DOWN = "trending_down"
    RANGING       = "ranging"
    HIGH_VOL      = "high_vol"

def detect_regime(closes: List[float]) -> str:
    arr = np.array(closes)
    fast = np.mean(arr[-12:])
    slow = np.mean(arr[-26:])
    vol  = np.std(arr[-20:]) / np.mean(arr[-20:])

    if vol > 0.03:
        return MarketRegime.HIGH_VOL
    elif fast > slow * 1.005:
        return MarketRegime.TRENDING_UP
    elif fast < slow * 0.995:
        return MarketRegime.TRENDING_DOWN
    else:
        return MarketRegime.RANGING

# Strategy weights per regime
REGIME_WEIGHTS = {
    MarketRegime.TRENDING_UP:   {"funding": 0.1, "basis": 0.1, "breakout": 0.3, "meanrev": 0.1, "momentum": 0.4},
    MarketRegime.TRENDING_DOWN: {"funding": 0.1, "basis": 0.1, "breakout": 0.3, "meanrev": 0.0, "momentum": 0.5},
    MarketRegime.RANGING:       {"funding": 0.3, "basis": 0.2, "breakout": 0.0, "meanrev": 0.4, "momentum": 0.1},
    MarketRegime.HIGH_VOL:      {"funding": 0.5, "basis": 0.3, "breakout": 0.1, "meanrev": 0.0, "momentum": 0.1},
}

def get_account_balance() -> float:
    r = requests.get(f"{API}/account/balance", headers=HDR)
    return r.json()["available_usdc"]

def get_candles(pair: str, interval: str = "1h", limit: int = 100) -> List[Dict]:
    r = requests.get(
        f"{API}/market/candles/{pair}",
        params={"interval": interval, "limit": limit},
        headers=HDR
    )
    return r.json()["candles"]

def run_trading_loop(pairs: List[str], poll_seconds: int = 300):
    log.info("Purple Flea multi-strategy framework started")
    while True:
        try:
            balance = get_account_balance()
            log.info(f"Balance: ${balance:,.2f} USDC")

            for pair in pairs:
                candles = get_candles(pair)
                closes  = [c["close"] for c in candles]
                regime  = detect_regime(closes)
                weights = REGIME_WEIGHTS[regime]

                log.info(f"{pair} | regime={regime}")

                # Only act on top-weighted strategy for this pair
                top_strat = max(weights, key=weights.get)
                alloc = balance * weights[top_strat] * 0.2  # max 20% per position

                if top_strat == "momentum":
                    sig = momentum_signal(closes)
                    if sig:
                        log.info(f"  MOMENTUM signal: {sig} | alloc=${alloc:.0f}")
                        # execute_order(pair, sig, alloc)

                elif top_strat == "meanrev":
                    sig = bollinger_signal(closes)
                    if sig:
                        log.info(f"  MEANREV signal: {sig['side']} z={sig['z']:.2f}")

                elif top_strat == "funding":
                    rates = requests.get(f"{API}/market/funding-rates", headers=HDR).json()["rates"]
                    for r in rates:
                        if r["pair"] == pair and r["rate_8h"] > 0.0003:
                            log.info(f"  FUNDING ARB: {pair} @ {r['rate_8h']*100:.4f}% per 8h")

            # Health check
            liq_alerts = check_liquidation_risk(KEY)
            for alert in liq_alerts:
                log.warning(f"LIQ ALERT: {alert['pair']} buffer={alert['buffer_pct']:.1f}% — {alert['action']}")

        except Exception as e:
            log.error(f"Loop error: {e}")

        time.sleep(poll_seconds)

if __name__ == "__main__":
    PAIRS = ["BTC-PERP", "ETH-PERP", "SOL-PERP"]
    run_trading_loop(PAIRS, poll_seconds=300)
Deployment tip: Run this with PM2 on any VPS — pm2 start trader.py --interpreter python3 --name pf-trader. PM2 will restart the process on crash and keep logs accessible via pm2 logs pf-trader.

Ready to run your first strategy?

Register an agent account in one API call and get your trading key immediately — no KYC, no wait.

Get Trading API Key Read the Docs