DeFi yield rates are not static. The APY on Aave's USDC market can shift from 4.2% to 9.8% in a single afternoon as large borrowers draw down liquidity. Compound's USDT rate might spike to 12% for 48 hours when on-chain demand surges, then fall back to 3% once the borrowing pressure subsides. Yearn might launch a new vault with a 20% boosted APY for the first week, then normalize as TVL flows in and dilutes the rewards.

A human monitoring this manually checks once a day at best. They miss the 9.8% Aave window. They don't notice the 48-hour Compound spike until it's over. They read about the Yearn vault launch in a newsletter a week after the best rates have already been claimed by early depositors.

An AI agent running the Purple Flea Yield Aggregator API polls every 50+ protocols hourly, computes the optimal allocation across assets and chains, and rotates capital automatically when the spread exceeds the gas cost of moving. It compounds rewards daily. It generates a structured daily report. It never sleeps, never misses a rate spike, and makes no emotional decisions about "waiting to see if rates go higher."

The Yield Farming Problem at Scale

The challenge is not finding high-APY opportunities — they exist constantly somewhere in DeFi. The challenge is the operational overhead of capturing them:

At a portfolio size of $10,000, even a 1% APY improvement over a year is $100 — barely worth the mental overhead for a human. For an agent running 24/7, the marginal cost of each optimization is near zero. This is the core value proposition: agents make the operational overhead disappear.

Supported Protocols

The Purple Flea Yield Aggregator API aggregates rates from the following protocols across Ethereum, Arbitrum, Base, Optimism, Polygon, and Solana:

Aave V3
Compound V3
Yearn Finance
Convex
Curve Finance
Spark Protocol
Morpho Blue
Pendle Finance
Fluid
EulerV2
Kamino
MarginFi

Rates are refreshed every 60 seconds via on-chain reads against each protocol's smart contracts. No reliance on third-party APIs that may go stale — Purple Flea reads rates directly from the chain.

APY Types: What You're Actually Earning

Not all APY figures are equal. Understanding what's included in each number is critical to making accurate rotation decisions.

Base APY (lending rate)

The utilization-driven interest rate paid in the same asset you deposited. If you deposit USDC at 5% base APY, you receive 5% more USDC over a year. This is the most reliable component — it's denominated in stablecoins and is not subject to token price risk.

Reward APY (governance token incentives)

Additional yield paid in protocol governance tokens (COMP, AAVE, CRV, etc.). A "12% APY" on Compound might be 5% base USDC plus 7% in COMP tokens. If COMP drops 30% next month, your realized APY was closer to 7%, not 12%. The Purple Flea API reports base APY and reward APY separately so you can model the token-price-adjusted return.

Boosted APY (veToken systems)

Curve, Convex, and Yearn use vote-escrowed token systems where locking governance tokens boosts your reward multiplier up to 2.5x. Convex abstracts this complexity — depositing to Convex gives you boosted CRV rewards without locking CRV yourself. Pendle Finance allows you to strip the yield component from liquid staking tokens and sell or buy it separately, enabling fixed-rate exposure to otherwise variable yields.

Protocol Asset Base APY Reward APY Total APY
Aave V3 USDC 4.8% 0.3% AAVE 5.1%
Compound V3 USDC 5.2% 1.4% COMP 6.6%
Morpho Blue USDC 6.1% 0% 6.1%
Spark Protocol USDC 5.5% 0.5% SPK 6.0%
Yearn USDC USDC 7.3% 0% 7.3%

Sample data. Actual rates fluctuate continuously — always use live API data for decisions.

Auto-Compounding Math: Why Frequency Matters

Compounding converts simple interest into exponential growth. The difference between compounding annually and compounding daily on an 8% APY position is real money:

Principal $10,000
Nominal APY 8.00%
Simple (annual compound) — year end value $10,800
Monthly compound — year end value $10,830
Daily compound — year end value $10,832.77
Continuous compound (theoretical max) $10,832.87
Bonus from daily vs simple (net of typical gas) +$22.77 / year on $10k

The compounding bonus grows proportionally with principal. At $100k it becomes $227/year. At $1M it becomes $2,277/year from compounding frequency alone — before any rotation benefits. The agent earns this "for free" by simply claiming and re-depositing rewards daily.

The YieldFarmer Agent: Full Implementation

yield_farmer.py
import os, time, logging, requests from datetime import datetime, timezone from dataclasses import dataclass API_KEY = os.environ["PURPLEFLEA_API_KEY"] BASE = "https://api.purpleflea.com" HDR = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") @dataclass class YieldPosition: protocol: str asset: str amount_usd: float current_apy: float deposited_at: float # unix timestamp last_compound: float # unix timestamp class YieldFarmer: # Configuration ROTATION_THRESHOLD_BPS = 50 # rotate if new APY is 50+ bps better COMPOUND_INTERVAL_HOURS = 24 # compound rewards once per day POLL_INTERVAL_SECONDS = 3600 # check rates every hour ASSETS = ["USDC", "USDT", "ETH", "wstETH"] def __init__(self): self.positions: dict[str, YieldPosition] = {} self.total_compound_events = 0 def get_best_apy(self, asset: str) -> dict: """Return the highest-APY protocol for the given asset.""" r = requests.get( f"{BASE}/yield/rates", headers=HDR, params={ "asset": asset, "sort_by": "total_apy", "exclude_reward_tokens": "false", # include governance token rewards "min_tvl_usd": 10_000_000, # only established pools }, timeout=10, ) r.raise_for_status() rates = r.json()["rates"] return rates[0] # highest APY first def rotate_if_better(self, asset: str): """Check if rotating to a higher-APY protocol is worth the gas cost.""" if asset not in self.positions: return pos = self.positions[asset] best = self.get_best_apy(asset) new_apy = best["total_apy_pct"] spread_bps = (new_apy - pos.current_apy) * 100 if spread_bps < self.ROTATION_THRESHOLD_BPS: logging.info("%s: spread=%.1fbps below threshold. No rotation.", asset, spread_bps) return # Estimate gas cost as a fraction of position APY over 30 days gas_estimate_r = requests.get( f"{BASE}/yield/rotation-cost", headers=HDR, params={"from_protocol": pos.protocol, "to_protocol": best["protocol"], "asset": asset, "amount_usd": pos.amount_usd}, timeout=10, ).json() gas_cost_usd = gas_estimate_r["estimated_gas_usd"] # APY gain over 30 days must exceed gas cost apy_gain_30d = pos.amount_usd * (spread_bps / 10_000) * (30 / 365) if apy_gain_30d <= gas_cost_usd: logging.info("%s: rotation gain $%.2f <= gas $%.2f. Holding.", asset, apy_gain_30d, gas_cost_usd) return logging.info("%s: Rotating %s -> %s (spread=%.1fbps gain_30d=$%.2f gas=$%.2f)", asset, pos.protocol, best["protocol"], spread_bps, apy_gain_30d, gas_cost_usd) # Execute rotation r = requests.post( f"{BASE}/yield/rotate", headers=HDR, json={ "from_protocol": pos.protocol, "to_protocol": best["protocol"], "asset": asset, "amount_usd": pos.amount_usd, }, timeout=60, ) r.raise_for_status() pos.protocol = best["protocol"] pos.current_apy = new_apy logging.info("%s: Rotation complete. Now earning %.2f%% APY on %s", asset, new_apy, pos.protocol) def compound_all(self): """Claim and re-deposit pending rewards across all positions.""" for asset, pos in self.positions.items(): age_hours = (time.time() - pos.last_compound) / 3600 if age_hours < self.COMPOUND_INTERVAL_HOURS: continue r = requests.post( f"{BASE}/yield/compound", headers=HDR, json={"protocol": pos.protocol, "asset": asset}, timeout=30, ) r.raise_for_status() result = r.json() rewards_usd = result.get("rewards_claimed_usd", 0) pos.amount_usd += rewards_usd pos.last_compound = time.time() self.total_compound_events += 1 logging.info("Compounded %s on %s: +$%.4f (event #%d)", asset, pos.protocol, rewards_usd, self.total_compound_events) def daily_report(self) -> dict: """Generate a structured daily report of all positions.""" report = { "timestamp": datetime.now(timezone.utc).isoformat(), "total_compound_events": self.total_compound_events, "positions": [], } total_value = 0.0 weighted_apy = 0.0 for asset, pos in self.positions.items(): report["positions"].append({ "asset": asset, "protocol": pos.protocol, "amount_usd": pos.amount_usd, "apy": pos.current_apy, }) total_value += pos.amount_usd weighted_apy += pos.amount_usd * pos.current_apy report["total_value_usd"] = total_value report["weighted_avg_apy"] = weighted_apy / total_value if total_value else 0 logging.info("Daily report: TVL=$%.2f weighted_APY=%.2f%%", total_value, report["weighted_avg_apy"]) return report def run(self): """Main agent loop — runs indefinitely.""" while True: try: # 1. Compound pending rewards self.compound_all() # 2. Check for better rates on each asset for asset in self.ASSETS: self.rotate_if_better(asset) # 3. Daily report self.daily_report() except Exception as e: logging.error("Agent loop error: %s", e, exc_info=True) time.sleep(self.POLL_INTERVAL_SECONDS) if __name__ == "__main__": farmer = YieldFarmer() farmer.run()

Gas Cost Consideration

The rotation threshold of 50 basis points is not arbitrary. It accounts for the amortized gas cost of the rotation transaction spread over 30 days — the minimum horizon over which the rate advantage must persist to be profitable.

The formula the agent uses: apy_gain_30d = position_usd * (spread_bps / 10,000) * (30 / 365)

On a $50,000 USDC position, a 50bps spread produces $50,000 * 0.005 * (30/365) = $20.55 over 30 days. If the gas cost of rotating on Ethereum mainnet is $18, this is barely profitable. On Arbitrum (gas ~$0.20) or Base (gas ~$0.05), the same rotation costs less than $1 and the threshold can be reduced to 10-15 bps, enabling much more aggressive optimization.

Chain selection tip: Deploy yield farming agents on L2s (Arbitrum, Base, Optimism) wherever the protocols support it. The same yield optimization strategy that barely breaks even on mainnet due to gas costs can run 50-100x more frequently on L2, capturing rate movements that mainnet strategies must ignore.

Tax Implications

In most jurisdictions, each reward claim and reinvestment is a taxable event. Claiming $10 of COMP rewards and immediately re-depositing them as USDC generates two taxable events: the COMP income (ordinary income at fair market value when received) and the subsequent COMP-to-USDC swap (capital gains event). Daily compounding on an active position can generate 365+ taxable events per asset per year.

For tax-sensitive jurisdictions:

Tax advice disclaimer: This is not tax advice. Crypto tax law varies by country and is evolving rapidly. Consult a qualified tax professional before deploying an automated yield strategy in a tax-sensitive context.


Start automating your DeFi yield today

Real-time rates from 50+ protocols, gas-aware rotation, auto-compounding, and daily reports — all through a single API key.

View Yield Aggregator API →

Related APIs