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-PERP | Major | 50x | 0.001 BTC | Live |
ETH-PERP | Major | 50x | 0.01 ETH | Live |
SOL-PERP | Major | 30x | 0.1 SOL | Live |
BNB-PERP | Major | 30x | 0.1 BNB | Live |
DOGE-PERP | Altcoin | 20x | 100 DOGE | Live |
MATIC-PERP | Altcoin | 20x | 10 MATIC | Live |
LINK-PERP | DeFi | 20x | 1 LINK | Live |
AVAX-PERP | L1 | 25x | 0.1 AVAX | Live |
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.
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:
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:
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
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
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
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
- Identify pair with basis > 0.1% (annualises to >36%)
- Long spot in equal USDC notional
- Short perp at 1x leverage (isolated)
- Monitor basis daily; close both legs when basis normalises to < 0.02%
- P&L = funding collected + basis convergence gain (or loss if basis widens)
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
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
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.
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)
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
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.
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")
9. Liquidation Risk Management
Liquidation is permanent capital loss. The following rules should be hardcoded into any leveraged trading agent:
- Never hold a position where liquidation is within 10% of current mark price
- Always use isolated margin on individual directional trades
- Set a stop-loss order on entry — do not rely on manual monitoring
- If account health drops below 120%, close the most levered position immediately
- Never average down into a losing leveraged position
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.
""" 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)
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