Forex Principles in On-Chain Markets
Traditional foreign exchange (FX) trading involves exploiting price differences between currency pairs across multiple venues: banks, ECNs, and swap markets. Stablecoin markets on decentralized exchanges are structurally identical — and for AI agents, they offer significant advantages over traditional FX:
- 24/7 operation: Unlike FX markets that thin out on weekends and holidays, DeFi never closes. Arbitrage opportunities arise around the clock.
- Transparent order books: Pool state is fully on-chain. There are no hidden institutional orders or dark pool executions — an agent can compute exact prices and profitability before executing.
- Composable execution: Flash loans allow agents to execute round-trip arbitrage without any initial capital outlay, removing the capital efficiency constraint that limits traditional FX arb.
- Programmable settlement: Unlike FX T+2 settlement, on-chain trades settle in seconds. Agents can compound profits continuously rather than waiting days for cash to clear.
FX Arbitrage Fundamentals Applied to Stablecoins
The three classic FX arbitrage strategies translate directly to stablecoin markets:
1. Triangular Arbitrage: In FX, this exploits mispricings between three currency pairs (e.g., USD/EUR, EUR/GBP, GBP/USD). In DeFi: USDC → USDT → DAI → USDC across different pools. If the round-trip converts 1.000 USDC into 1.003 USDC after fees and gas, that 0.3% is pure arbitrage profit.
2. Spatial Arbitrage: The same stablecoin trades at different prices on different exchanges. USDT might be 0.9992 on Uniswap and 0.9998 on Curve — buy low on one, sell high on the other.
3. Statistical Arbitrage (Pairs Trading): Two correlated stablecoins (e.g., USDC and EURC) maintain a known long-run ratio. When the ratio deviates significantly from its mean, the agent takes a position expecting mean reversion. This works especially well for pegged assets with explicit redemption mechanisms that enforce the peg over time.
USDC / USDT / DAI / FRAX Spread Dynamics
The major stablecoins are not interchangeable at par in DeFi markets. Each carries a distinct risk profile, liquidity profile, and market microstructure — and these differences create persistent spreads that disciplined agents can exploit.
Risk Premia by Stablecoin Type
| Stablecoin | Peg Mechanism | Risk Category | Typical Spread vs USDC | Arb Edge |
|---|---|---|---|---|
| USDC | Fiat-backed (Circle) | Lowest | Baseline | Used as reference leg |
| USDT | Fiat-backed (Tether) | Low-Medium | 0–8 bps discount | Persistent discount = free carry |
| DAI | Overcollateralized CDP | Medium | -5 to +15 bps | Spreads widen on high Maker activity |
| FRAX | Fractional-algorithmic | Medium-High | -10 to +20 bps | Largest spread swings = highest alpha |
| LUSD | ETH-backed, 110% CR | Medium | 0 to +100 bps | Redemption mechanism enforces lower bound |
| crvUSD | Curve LLAMMA CDP | Medium | -5 to +10 bps | Tight — but Curve arbitrage fees are near-zero |
| EURC | Euro-backed (Circle) | Low | Tracks EUR/USD, 50–200 bps | FX carry + EUR rate differentials |
Spread Visualization: Typical On-Chain Spreads
Stablecoin Spread Range vs USDC (basis points)
When Spreads Widen
Understanding what causes spread widening is essential for timing entries:
- Regulatory announcements: SEC actions or government commentary on stablecoin issuers can cause USDT or USDC to trade at a discount within minutes
- Reserve transparency events: Tether's quarterly attestations sometimes trigger brief spread widening as market participants update risk assessments
- High borrow demand: When USDT is heavily demanded for leveraged trading, it temporarily trades at a premium to USDC
- Bridge congestion: Cross-chain demand creates localized supply/demand imbalances — USDC might be temporarily cheap on Polygon while expensive on Arbitrum
- Protocol stress: Maker governance decisions, Frax protocol parameter changes, or AAVE market conditions all spill into stablecoin spreads
Cross-Chain Stablecoin Arbitrage
The same stablecoin trades at different prices on different blockchain networks. USDC on Ethereum might trade at $1.0003 while USDC on Polygon trades at $0.9997 — a 6 basis point spread purely due to local supply and demand imbalances.
Mechanics of Cross-Chain Arb
The complete cycle of a cross-chain stablecoin arbitrage trade:
- Detect: Monitor stablecoin prices across target chains (Ethereum, Arbitrum, Optimism, Base, Polygon, Solana)
- Size: Estimate the available arb after bridge fees and gas costs on both sides
- Bridge: Transfer the cheap-chain stablecoin to the expensive-chain via canonical bridge or third-party bridge (Stargate, Across, Hop)
- Sell: Sell on the expensive-chain venue
- Repeat: Hold the proceeds on the target chain for the next opportunity or bridge back
| Bridge Protocol | Fee | Speed | Best For | Arb Viability |
|---|---|---|---|---|
| Across Protocol | 3–8 bps | 1–3 min | USDC, ETH, WBTC | High |
| Stargate (LayerZero) | 6–15 bps | 2–5 min | USDC, USDT, wide chain coverage | Medium |
| Hop Protocol | 5–12 bps | 3–10 min | ETH L1↔L2 stablecoins | Medium |
| Circle CCTP | ~0 (gas only) | 15–20 min | USDC (native cross-chain) | Very High (large) |
| Canonical L2 Bridge | ~0 (gas only) | 7 days (withdraw) | Optimistic rollups | Too slow for arb |
Circle CCTP advantage: Circle's Cross-Chain Transfer Protocol allows USDC to be burned on the source chain and minted on the destination chain natively — no wrapped tokens, no liquidity pools, no counterparty risk. For large USDC arb (>$100K), CCTP often offers the best fee structure despite the 15–20 minute settlement time.
Profitability Threshold Calculation
An agent must clear three cost layers for a cross-chain arb to be profitable:
def compute_breakeven_spread( bridge_fee_bps: float, source_gas_usd: float, dest_gas_usd: float, dex_fee_bps: float, amount_usd: float, price_risk_bps: float = 5, # spread movement risk during bridge time ) -> float: """ Returns the minimum observed spread (in bps) required for a cross-chain stablecoin arb to be profitable after all costs. """ # Convert fixed costs to basis points gas_bps = (source_gas_usd + dest_gas_usd) / amount_usd * 10000 # Total cost in bps total_cost_bps = bridge_fee_bps + gas_bps + dex_fee_bps + price_risk_bps return total_cost_bps # Example: USDC arb Ethereum → Arbitrum via Across breakeven = compute_breakeven_spread( bridge_fee_bps=6, # Across fee source_gas_usd=4.50, # Ethereum send gas dest_gas_usd=0.05, # Arbitrum receive gas dex_fee_bps=1, # Curve 3pool fee amount_usd=50000, # trade size price_risk_bps=4, # 2-min bridge, stablecoin vol ) print(f"Breakeven spread: {breakeven:.1f} bps") # Output: Breakeven spread: 12.0 bps # Minimum observable spread to trade: ~12 bps # Scale sensitivity: how much does size matter? for size in [10_000, 50_000, 200_000, 1_000_000]: be = compute_breakeven_spread(6, 4.50, 0.05, 1, size, 4) print(f" ${size:>10,} → breakeven {be:.1f} bps") # Output: # $ 10,000 → breakeven 57.5 bps # $ 50,000 → breakeven 12.0 bps # $ 200,000 → breakeven 8.3 bps # $ 1,000,000 → breakeven 7.2 bps
The scale sensitivity analysis shows why cross-chain stablecoin arb is primarily a large-capital game on Ethereum mainnet. Smaller agents on L2 chains (where gas is 50–200x cheaper) can run profitable arb at much smaller sizes.
Curve Stable Pools: Mechanics and Edges
Curve Finance is the dominant stablecoin exchange protocol, processing tens of billions of dollars in volume monthly. Understanding Curve's mechanics is essential for any stablecoin arb agent.
The StableSwap Invariant
Curve uses a hybrid AMM invariant that behaves like a constant-sum market maker (x + y = k) near equilibrium and like a constant-product market maker (xy = k) at extreme imbalances. The formula:
A * n^n * ∑x_i + D = A * D * n^n + D^(n+1) / (n^n * ∏x_i)
Where A is the amplification coefficient. A high A (e.g., 200) creates extremely flat pricing near the equilibrium point — this is why Curve offers near-zero slippage for balanced stablecoin swaps. As the pool becomes imbalanced, slippage increases rapidly, signaling an arbitrage opportunity back toward balance.
Identifying Curve Arbitrage Opportunities
Curve arb opportunities arise when a pool's composition deviates significantly from equal weighting. For a 3pool (USDC, USDT, DAI), the balanced state is 1/3 each. When the pool is 45% USDT, 30% USDC, 25% DAI, USDT is cheap (pool wants to get rid of it) and USDC/DAI are expensive.
import httpx import asyncio from dataclasses import dataclass from typing import List, Dict # Curve pool state from their API CURVE_API = "https://api.curve.fi/v1/getPools/ethereum/main" @dataclass class CurvePoolState: pool_address: str name: str coins: List[str] balances_usd: List[float] amplification: int fee_bps: float daily_volume_usd: float @property def total_tvl(self) -> float: return sum(self.balances_usd) @property def weights(self) -> List[float]: total = self.total_tvl if total == 0: return [0.0] * len(self.balances_usd) return [b / total for b in self.balances_usd] def imbalance_score(self) -> float: """ Max deviation of any coin from equal weight. 0 = perfectly balanced, 1 = completely imbalanced. """ n = len(self.coins) equal = 1 / n return max(abs(w - equal) for w in self.weights) def cheap_coins(self, threshold: float = 0.05) -> List[str]: """Coins with weight > equal + threshold (pool wants to sell).""" n = len(self.coins) equal = 1 / n return [ self.coins[i] for i, w in enumerate(self.weights) if w > equal + threshold ] def expensive_coins(self, threshold: float = 0.05) -> List[str]: """Coins with weight < equal - threshold (pool wants to receive).""" n = len(self.coins) equal = 1 / n return [ self.coins[i] for i, w in enumerate(self.weights) if w < equal - threshold ] async def scan_curve_opportunities(min_tvl: float = 1_000_000) -> List[Dict]: """Scan Curve pools for arb opportunities based on pool imbalance.""" async with httpx.AsyncClient() as client: resp = await client.get(CURVE_API, timeout=10) resp.raise_for_status() data = resp.json() opportunities = [] for pool_data in data.get("data", {}).get("poolData", []): try: coins = [c["symbol"] for c in pool_data["coins"]] balances = [float(b) for b in pool_data.get("usdTotal", [])] if not balances or len(balances) != len(coins): continue pool = CurvePoolState( pool_address=pool_data["address"], name=pool_data["name"], coins=coins, balances_usd=balances, amplification=int(pool_data.get("amplificationCoefficient", 100)), fee_bps=float(pool_data.get("fee", 4)), daily_volume_usd=float(pool_data.get("volumeUSD", 0)), ) if pool.total_tvl() < min_tvl: continue imbalance = pool.imbalance_score() if imbalance > 0.05: # > 5% deviation from equal weight opportunities.append({ "pool": pool.name, "address": pool.pool_address, "imbalance": imbalance, "tvl": pool.total_tvl(), "cheap": pool.cheap_coins(), "expensive": pool.expensive_coins(), "fee_bps": pool.fee_bps, }) except (KeyError, ValueError): continue # Sort by imbalance descending opportunities.sort(key=lambda x: x["imbalance"], reverse=True) return opportunities
Depegging Events: Risk and Opportunity
Stablecoin depegs are the highest-variance events in DeFi. A depeg occurs when a stablecoin trades significantly below or above its target price, typically $1.00. For trading agents, depegs represent simultaneous risk (if holding the affected stablecoin) and opportunity (if positioned correctly to arb the recovery or capture the discount).
Historical Depeg Taxonomy
| Event | Stablecoin | Depth | Duration | Recovery Pattern | Agent Strategy |
|---|---|---|---|---|---|
| UST/LUNA collapse (2022) | UST | $0.00 (full) | Permanent | No recovery | Avoid algorithmic with no hard peg |
| USDC banking scare (2023) | USDC | $0.877 | ~3 days | Full recovery | Buy USDC on curve, hold to recovery |
| FRAX algorithmic phase | FRAX | $0.96 | 2–4 weeks | Partial, then new collateral | Short-term arb only |
| DAI peg stress (2022) | DAI | $0.94 | 48 hours | Full via PSM arbitrage | Classic PSM arb |
| stETH depeg (2022) | stETH | $0.94 vs ETH | ~3 months | Full at Merge | Long-horizon arb |
Depeg Response Framework for Agents
Agents need a clear decision tree when a depeg alert fires:
- Classify the depeg type: Is this a liquidity event (temporary, likely recovers) or a solvency event (structural, may not recover)?
- Check the redemption mechanism: Does the stablecoin have a hard redemption path (e.g., USDC at Circle, DAI via Maker PSM)? If yes, arb the discount aggressively up to the redemption cost.
- Estimate recovery time: Liquidity depegs typically recover within 1–72 hours. Solvency depegs may never recover. Agent risk appetite must match the expected holding period.
- Size the position: Never allocate more than 20% of capital to a depeg play. The reward-to-risk is only favorable when the discount exceeds redemption/bridge costs plus a margin of safety.
- Set hard stop-loss: If the depeg deepens beyond your entry point by more than 5%, exit. A deepening depeg is evidence of a structural problem, not a temporary liquidity event.
Critical risk: Never hold a purely algorithmic stablecoin (one without overcollateralization or fiat backing) through a deep depeg. The death spiral mechanic — where protocol tokens are minted to defend the peg, diluting holders and further destroying confidence — can take a stablecoin to zero in hours. The LUNA/UST collapse demonstrated this conclusively in May 2022.
Stablecoin Carry Trade
The traditional FX carry trade borrows in a low-yield currency to invest in a high-yield currency, capturing the interest rate differential. The stablecoin equivalent: borrow low-rate stable assets, deploy into high-rate stable protocols, capture the spread.
The On-Chain Yield Curve
Stablecoin yields vary significantly across protocols and change with market conditions:
| Protocol / Asset | Typical APY Range | Risk | Liquidity |
|---|---|---|---|
| AAVE USDC supply | 2–8% | Low | Instant withdrawal |
| Compound USDT supply | 3–10% | Low | Instant withdrawal |
| Curve 3pool LP | 2–5% + CRV | Medium (IL is low for stables) | Minutes to exit |
| Convex Finance (boosted Curve) | 5–15% | Medium (CVX/CRV price risk) | Minutes to exit |
| Yearn vault (USDC) | 4–12% | Medium (strategy risk) | Instant to hours |
| Perp protocol funding | 10–50%+ (variable) | High (funding flips) | Instant exit |
Carry Trade Implementation
A simple stablecoin carry agent:
- Monitor AAVE/Compound borrow rates for USDC (cost of capital)
- Monitor Yearn/Convex supply rates for USDT (potential yield)
- When spread exceeds gas cost + 2% margin of safety: borrow USDC on AAVE, swap to USDT on Curve, deposit into highest-yield USDT vault
- Monitor continuously — unwind if the spread compresses or borrow rates spike
Key risk — rate volatility: DeFi interest rates can change dramatically within hours. A carry position that yields 6% net can flip negative if borrow rates spike during a high-demand period. Agents must monitor rate changes continuously and have automated unwind triggers — not just entry logic.
Python FXArbitrageAgent
The following is a complete FXArbitrageAgent that orchestrates multi-venue stablecoin monitoring, opportunity detection, and execution through Purple Flea's trading infrastructure.
import asyncio import httpx import logging from dataclasses import dataclass, field from typing import Dict, List, Optional, Tuple from datetime import datetime, timedelta from enum import Enum import time logger = logging.getLogger("FXArbitrageAgent") # Purple Flea infrastructure endpoints PF_TRADING_URL = "https://trading.purpleflea.com/api/v1" PF_WALLET_URL = "https://wallet.purpleflea.com/api/v1" # Stablecoin price feeds (Chainlink aggregators via RPC or price API) PRICE_FEEDS = { "USDC": "https://api.coingecko.com/api/v3/simple/price?ids=usd-coin&vs_currencies=usd", "USDT": "https://api.coingecko.com/api/v3/simple/price?ids=tether&vs_currencies=usd", "DAI": "https://api.coingecko.com/api/v3/simple/price?ids=dai&vs_currencies=usd", "FRAX": "https://api.coingecko.com/api/v3/simple/price?ids=frax&vs_currencies=usd", } COINGECKO_ID_MAP = { "USDC": "usd-coin", "USDT": "tether", "DAI": "dai", "FRAX": "frax", } class ArbType(Enum): SPATIAL = "spatial" # same chain, different venues TRIANGULAR = "triangular" # A→B→C→A CROSS_CHAIN = "cross_chain" # same coin, different chains DEPEG = "depeg" # stablecoin trading at discount @dataclass class StablecoinPrice: symbol: str price: float venue: str chain: str timestamp: float = field(default_factory=time.time) @property def depeg_bps(self) -> float: """Deviation from $1.00 in basis points.""" return (1.0 - self.price) * 10000 @dataclass class ArbOpportunity: arb_type: ArbType buy_venue: str sell_venue: str buy_price: float sell_price: float spread_bps: float input_token: str output_token: str estimated_profit_bps: float max_size_usd: float confidence: float # 0-1 @property def is_viable(self) -> bool: return self.estimated_profit_bps > 5 and self.confidence > 0.7 @dataclass class AgentConfig: api_key: str wallet_id: str max_position_usd: float = 25_000 min_profit_bps: float = 5 # 0.05% minimum net profit depeg_threshold_bps: float = 50 # alert on 0.5% depeg scan_interval_sec: float = 15 max_daily_trades: int = 500 chains: List[str] = field(default_factory=lambda: ["ethereum", "arbitrum", "optimism"]) stablecoins: List[str] = field(default_factory=lambda: ["USDC", "USDT", "DAI", "FRAX"]) class FXArbitrageAgent: """ Autonomous stablecoin FX arbitrage agent for AI-native financial infrastructure. Monitors USDC/USDT/DAI/FRAX prices across multiple venues and chains, detects spatial, triangular, and cross-chain arbitrage opportunities, and executes via Purple Flea's Trading API with automated risk controls. Register and fund via https://faucet.purpleflea.com (free $1 USDC to start). """ def __init__(self, config: AgentConfig): self.config = config self._client: Optional[httpx.AsyncClient] = None self._price_cache: Dict[str, StablecoinPrice] = {} self._trade_count_today: int = 0 self._pnl_today_usd: float = 0.0 self._last_reset: datetime = datetime.utcnow() self._running: bool = False async def _client_get(self) -> httpx.AsyncClient: if self._client is None: self._client = httpx.AsyncClient(timeout=8.0) return self._client async def _fetch_prices(self) -> Dict[str, float]: """Fetch current stablecoin prices from CoinGecko.""" client = await self._client_get() ids = ",".join(COINGECKO_ID_MAP.values()) url = f"https://api.coingecko.com/api/v3/simple/price?ids={ids}&vs_currencies=usd" try: resp = await client.get(url) resp.raise_for_status() data = resp.json() prices = {} for symbol, cg_id in COINGECKO_ID_MAP.items(): if cg_id in data: prices[symbol] = data[cg_id]["usd"] return prices except Exception as e: logger.warning(f"Price fetch failed: {e}") return {} def _compute_fee_bps(self, path_hops: int) -> float: """Estimate all-in fee for a trade path.""" curve_fee_bps = 4 # 0.04% Curve 3pool fee gas_bps = 8 # ~8 bps gas at typical sizes return (curve_fee_bps + gas_bps) * path_hops def _detect_spatial_arb(self, prices: Dict[str, float]) -> List[ArbOpportunity]: """Find pairs trading at spreads exceeding cost of swap.""" opportunities = [] symbols = list(prices.keys()) for i, s1 in enumerate(symbols): for s2 in symbols[i+1:]: p1, p2 = prices[s1], prices[s2] spread_bps = abs(p1 - p2) * 10000 fee_bps = self._compute_fee_bps(1) net_profit_bps = spread_bps - fee_bps if net_profit_bps >= self.config.min_profit_bps: buy_sym = s1 if p1 < p2 else s2 sell_sym = s2 if p1 < p2 else s1 buy_price = min(p1, p2) sell_price = max(p1, p2) # Confidence based on spread magnitude and data freshness confidence = min(1.0, net_profit_bps / 20) opportunities.append(ArbOpportunity( arb_type=ArbType.SPATIAL, buy_venue="Curve", sell_venue="Curve", buy_price=buy_price, sell_price=sell_price, spread_bps=spread_bps, input_token=buy_sym, output_token=sell_sym, estimated_profit_bps=net_profit_bps, max_size_usd=min(self.config.max_position_usd, 100_000), confidence=confidence, )) return opportunities def _detect_depegs(self, prices: Dict[str, float]) -> List[ArbOpportunity]: """Detect stablecoins trading significantly below $1.""" opportunities = [] for symbol, price in prices.items(): depeg_bps = (1.0 - price) * 10000 if depeg_bps > self.config.depeg_threshold_bps: logger.warning(f"DEPEG ALERT: {symbol} = ${price:.6f} ({depeg_bps:.0f} bps off peg)") # Arb: buy cheap stablecoin, redeem or sell once peg recovers net_profit_bps = depeg_bps - self._compute_fee_bps(1) - 20 # extra safety margin if net_profit_bps > 0: opportunities.append(ArbOpportunity( arb_type=ArbType.DEPEG, buy_venue="Curve", sell_venue="Redemption", buy_price=price, sell_price=1.0, spread_bps=depeg_bps, input_token="USDC", output_token=symbol, estimated_profit_bps=net_profit_bps, max_size_usd=min(self.config.max_position_usd * 0.2, 5_000), confidence=0.6 if depeg_bps > 200 else 0.8, )) return opportunities async def _execute_arb(self, opp: ArbOpportunity) -> bool: """Submit arb trade via Purple Flea Trading API.""" client = await self._client_get() size = min(opp.max_size_usd, self.config.max_position_usd) logger.info( f"Executing {opp.arb_type.value} arb: " f"{opp.input_token}→{opp.output_token} at {opp.buy_venue}, " f"est. profit={opp.estimated_profit_bps:.1f}bps, size=${size:,.0f}" ) try: resp = await client.post( f"{PF_TRADING_URL}/swap", headers={"X-API-Key": self.config.api_key}, json={ "from_token": opp.input_token, "to_token": opp.output_token, "amount_usd": size, "wallet_id": self.config.wallet_id, "slippage_bps": int(opp.spread_bps * 0.5), "mev_protection": "flashbots", "label": f"fx_arb_{opp.arb_type.value}", }, ) resp.raise_for_status() result = resp.json() logger.info(f"Trade executed: tx={result.get('tx_hash', 'pending')}") self._trade_count_today += 1 actual_profit = result.get("realized_pnl_usd", 0) self._pnl_today_usd += actual_profit return True except Exception as e: logger.error(f"Trade execution failed: {e}") return False def _reset_daily_stats_if_needed(self) -> None: now = datetime.utcnow() if (now - self._last_reset).days >= 1: logger.info(f"Daily stats: trades={self._trade_count_today}, PnL=${self._pnl_today_usd:.2f}") self._trade_count_today = 0 self._pnl_today_usd = 0 self._last_reset = now async def _scan_cycle(self) -> None: """One full scan-detect-execute cycle.""" self._reset_daily_stats_if_needed() if self._trade_count_today >= self.config.max_daily_trades: logger.warning("Daily trade limit reached, pausing.") return prices = await self._fetch_prices() if not prices: return # Detect all opportunity types opps = self._detect_spatial_arb(prices) opps += self._detect_depegs(prices) # Filter viable opportunities, sort by expected profit viable = [o for o in opps if o.is_viable] viable.sort(key=lambda o: o.estimated_profit_bps, reverse=True) if viable: logger.info(f"Found {len(viable)} viable arb opportunities") # Execute top opportunity only (conservative: one trade per cycle) await self._execute_arb(viable[0]) else: logger.debug(f"No viable arb. Prices: {prices}") async def run(self) -> None: """Main agent loop. Runs indefinitely until stopped.""" logger.info("FXArbitrageAgent starting. Powered by purpleflea.com") self._running = True while self._running: try: await self._scan_cycle() except Exception as e: logger.error(f"Scan cycle error: {e}") await asyncio.sleep(self.config.scan_interval_sec) async def stop(self) -> None: logger.info(f"Agent stopped. Daily PnL: ${self._pnl_today_usd:.2f}") self._running = False if self._client: await self._client.aclose() # Entry point async def main(): logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", ) config = AgentConfig( api_key="YOUR_PURPLE_FLEA_API_KEY", wallet_id="YOUR_WALLET_ID", max_position_usd=10_000, min_profit_bps=8, scan_interval_sec=15, ) agent = FXArbitrageAgent(config) try: await agent.run() except KeyboardInterrupt: await agent.stop() if __name__ == "__main__": asyncio.run(main())
Purple Flea Integration
The FXArbitrageAgent above is designed to work natively with Purple Flea's financial infrastructure stack. Here is how each Purple Flea service plays a role:
- Faucet: New agents claim $1 USDC free. This is your seed capital for testing the FX arbitrage loop end-to-end before committing real funds. No risk, no signup friction.
- Wallet: The agent's USDC and stablecoin balances are managed through Purple Flea Wallet. The wallet API handles signing, nonce management, and multi-chain balance tracking automatically.
- Trading: The
_execute_arbmethod submits orders to the Purple Flea Trading API, which handles route optimization, MEV protection, and execution across Curve, Uniswap, and other venues. - Escrow: For multi-agent FX strategies (e.g., one agent detects the opportunity, another executes), Purple Flea Escrow provides trustless coordination for splitting profits between cooperating agents.
Configuration Recommendations by Strategy
| Strategy | min_profit_bps | max_position_usd | scan_interval_sec | Notes |
|---|---|---|---|---|
| Conservative (new agent) | 15 | 1,000 | 30 | Start here; use faucet seed capital |
| Standard | 8 | 10,000 | 15 | Good balance of frequency and safety |
| Aggressive | 5 | 50,000 | 5 | Requires robust MEV protection and gas monitoring |
| Depeg specialist | 20 (net) | 5,000 | 10 | Depeg events are rare but high yield when they occur |
Start Your FX Arbitrage Agent
Get free USDC from the faucet, connect your wallet, and run the FXArbitrageAgent against live markets. Purple Flea handles the infrastructure — you capture the spread.
Key Takeaways
- Stablecoin FX arbitrage applies classical forex principles to transparent, programmable on-chain markets — with the added advantages of 24/7 operation, atomic execution, and full order book visibility
- USDC/USDT/DAI/FRAX spreads of 2–20 basis points are persistent and systematically exploitable once gas and bridge fees are properly modeled
- Cross-chain arb requires accurate breakeven spread calculation — gas costs on Ethereum mainnet make sub-$50K trades unprofitable on most routes; L2 dramatically lowers this threshold
- Curve's StableSwap invariant creates near-zero slippage near equilibrium and increasing slippage as pools become imbalanced — pool imbalance is a direct signal for arbitrage opportunity
- Depegging events are high-variance plays: only trade depegs with hard redemption mechanisms (USDC, DAI via PSM) — never hold algorithmic stablecoins through a deep depeg
- Stablecoin carry trades work when rate differentials exceed volatility risk — continuous monitoring with automated unwind triggers is essential
- The
FXArbitrageAgentabove integrates cleanly with Purple Flea's full stack: Faucet for seed capital, Wallet for balance management, Trading for optimized execution