Most AI agents hold idle crypto between trades. That capital sits dormant, earning nothing. Covered call writing changes that equation: you collect option premium on holdings you were planning to keep anyway, converting static treasury into a yield-generating machine. For agents running systematic strategies, this is one of the most reliable income sources in DeFi — no impermanent loss, no liquidation risk if implemented correctly.
Covered Call Mechanics
A covered call is a two-leg position: you own (or have deposited) the underlying asset, and you sell a call option against it. The buyer of that call pays you an upfront premium. In exchange, you agree to sell your asset at the strike price if the market rises above it by expiry.
Your maximum profit is the premium received plus any appreciation up to the strike. Your maximum loss is the full value of the underlying, same as holding it outright — the sold call does not increase downside exposure. The one cost: if the asset rips far above your strike, you miss the upside above that level. For agents with a bullish-but-not-aggressive view, this tradeoff is favorable.
In traditional finance, covered calls are run weekly or monthly on equities. In crypto, high implied volatility (IV) means premiums are dramatically richer. A BTC 30-day 0.25-delta call might carry 4–6% premium. The same strike in equity markets would pay 0.5–1.2%. Crypto agents have a structural edge here.
Why Crypto IV Makes This Work
Implied volatility in crypto markets consistently runs 60–120% annualized for major assets like BTC and ETH. Altcoins frequently exceed 150%. When you sell an option, you are effectively selling that volatility. If realized volatility comes in below implied — which it does more often than not, because market makers price in a volatility risk premium — you keep the full premium.
The volatility risk premium (VRP) in crypto averages 8–15 percentage points over realized vol on major assets. This is the systematic edge that makes covered call programs profitable over time, independent of directional calls.
For an agent running this weekly: if weekly IV is 90% annualized, the weekly implied move is roughly 90% / sqrt(52) ≈ 12.5%. Selling a 1-standard-deviation OTM call captures the decay on that implied premium even if the asset moves less than 12.5%.
Strike Selection
Strike selection is the single most important parameter. Too far OTM and premium becomes negligible. Too close ATM and you risk assignment on every small rally. The systematic approach:
- Delta 0.20–0.30 (weekly expiry): Collects 0.8–1.5% per week. Assignment probability is 20–30%. Best for agents comfortable rolling frequently.
- Delta 0.25–0.40 (monthly expiry): Collects 3–6% per month. Lower transaction costs. Better for agents with less active monitoring.
- Moneyness 105–115% of spot: Rule-of-thumb for sideways/mildly bullish regimes without a full options chain.
Delta is preferable to raw moneyness because it adjusts for current vol regime. In a 150% IV environment, a 105% strike may actually be near-the-money in probability terms. Delta gives a volatility-adjusted probability of assignment.
| Delta Target | Assignment Prob | Weekly Premium | Monthly Premium |
|---|---|---|---|
| 0.15 | ~15% | 0.4–0.8% | 1.5–3% |
| 0.25 | ~25% | 0.8–1.5% | 3–6% |
| 0.35 | ~35% | 1.5–2.5% | 5–9% |
| 0.40 | ~40% | 2–3.5% | 7–12% |
Protocol Landscape
On-chain covered call infrastructure has matured considerably. Key protocols:
- Lyra Finance: Full AMM-based options on Arbitrum and Optimism. Deep liquidity for BTC and ETH. Programmatic API available.
- Dopex: Option vaults (SSVs) on Arbitrum. Agents can deposit collateral and the vault automatically writes and settles calls.
- Ribbon Finance: Automated weekly call-writing vaults. Simplest entry point — deposit ETH or WBTC, receive weekly yield automatically.
- Friktion (Solana): Volt #01 is a covered call strategy vault. SOL-denominated premiums, weekly settlement.
- ThetaNuts: Multi-chain covered call vaults on ETH, BNB chain, Avalanche. Good for agents wanting diversified exposure.
For agents wanting maximum control (custom strikes, timing, roll logic), Lyra's programmatic interface is the best choice. For set-and-forget with lower engineering overhead, Ribbon or ThetaNuts vaults are preferable.
Roll Mechanics
A "roll" means closing the existing short call and opening a new one, typically at a further expiry or higher strike. Roll decisions follow three scenarios:
- Roll up: Asset has appreciated but not crossed the strike. Close current call (buy to close at a loss relative to premium received), open new call at a higher strike further OTM. Captures more upside while maintaining income.
- Let expire: Asset stays below strike at expiry. Call expires worthless, full premium retained. Simply open a fresh position next cycle.
- Close early: If call has decayed to 20–25% of original premium (e.g., you sold for $100, it's now worth $22), buy to close. You lock in 75–80% of premium early and eliminate assignment risk for the remaining term. Use captured capital to open a new cycle sooner.
The 50% rule is also common: close when premium has decayed by 50% of original value, then reopen. This smooths out income and reduces tail risk from unexpected spikes near expiry.
Python CoveredCallAgent Implementation
import asyncio
import httpx
from datetime import datetime, timedelta
from typing import Optional
PURPLE_FLEA_API = "https://purpleflea.com/api/v1"
LYRA_API = "https://api.lyra.finance/v1"
class CoveredCallAgent:
def __init__(self, api_key: str, wallet_address: str):
self.api_key = api_key
self.wallet = wallet_address
self.headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
self.target_delta = 0.25
self.close_at_pct = 0.25 # close when 25% of premium remains
async def get_spot_price(self, asset: str) -> float:
async with httpx.AsyncClient() as client:
r = await client.get(
f"{PURPLE_FLEA_API}/markets/{asset}-USDC/ticker",
headers=self.headers
)
return float(r.json()["last_price"])
async def find_target_strike(self, asset: str, expiry_days: int) -> dict:
"""Find the strike closest to target delta for given expiry."""
spot = await self.get_spot_price(asset)
async with httpx.AsyncClient() as client:
r = await client.get(
f"{LYRA_API}/instruments",
params={
"asset": asset,
"option_type": "C",
"expiry_days": expiry_days,
}
)
instruments = r.json()["result"]
# Find closest delta to target
best = min(
instruments,
key=lambda x: abs(float(x["greeks"]["delta"]) - self.target_delta)
)
return {
"instrument_name": best["instrument_name"],
"strike": float(best["strike"]),
"delta": float(best["greeks"]["delta"]),
"bid": float(best["best_bid_price"]),
"mark": float(best["mark_price"]),
"expiry": best["expiry_timestamp"],
}
async def write_call(
self,
asset: str,
quantity: float,
expiry_days: int = 7
) -> dict:
"""Write a covered call. Returns order details."""
target = await self.find_target_strike(asset, expiry_days)
spot = await self.get_spot_price(asset)
# Sell at mid between bid and mark for better fill
limit_price = round((target["bid"] + target["mark"]) / 2, 4)
async with httpx.AsyncClient() as client:
r = await client.post(
f"{LYRA_API}/orders",
json={
"instrument_name": target["instrument_name"],
"direction": "sell",
"order_type": "limit",
"amount": quantity,
"limit_price": limit_price,
"wallet": self.wallet,
},
headers=self.headers
)
order = r.json()
premium_usd = limit_price * quantity * spot
premium_pct = (limit_price * quantity) / quantity * 100
print(f"[CoveredCall] WROTE {asset} call")
print(f" Strike: ${target['strike']:,.0f} (delta {target['delta']:.2f})")
print(f" Expiry: {expiry_days}d | Premium: ${premium_usd:.2f} ({premium_pct:.2f}%)")
return order
async def monitor_and_roll(
self,
position: dict,
asset: str,
quantity: float
) -> Optional[dict]:
"""Check if position should be closed early and rolled."""
instrument = position["instrument_name"]
async with httpx.AsyncClient() as client:
r = await client.get(
f"{LYRA_API}/instruments/{instrument}",
headers=self.headers
)
current = r.json()
current_ask = float(current["best_ask_price"])
original_premium = float(position["avg_price"])
# Close early if decayed to 25% of original premium
if current_ask <= original_premium * self.close_at_pct:
print(f"[CoveredCall] Closing early at {current_ask:.4f} "
f"(was {original_premium:.4f}). Rolling now.")
await self._close_position(instrument, quantity)
# Open fresh 7-day call
return await self.write_call(asset, quantity, expiry_days=7)
return None
async def _close_position(self, instrument: str, quantity: float):
async with httpx.AsyncClient() as client:
await client.post(
f"{LYRA_API}/orders",
json={
"instrument_name": instrument,
"direction": "buy",
"order_type": "market",
"amount": quantity,
"wallet": self.wallet,
},
headers=self.headers
)
async def run_weekly_cycle(self, asset: str, quantity: float):
"""Main weekly cycle: write call, monitor daily, roll at expiry."""
print(f"\n=== CoveredCallAgent Weekly Cycle: {asset} ===")
position = await self.write_call(asset, quantity, expiry_days=7)
# Monitor for 7 days
for day in range(7):
await asyncio.sleep(86400) # 24 hours
rolled = await self.monitor_and_roll(position, asset, quantity)
if rolled:
position = rolled
break # Rolled early, new position tracking begins
print(f"[CoveredCall] Cycle complete. Starting next week.")
await self.run_weekly_cycle(asset, quantity)
async def main():
agent = CoveredCallAgent(
api_key="pf_live_your_key_here",
wallet_address="0xYourWalletAddress"
)
# Write covered calls on 1 ETH, weekly cycle
await agent.run_weekly_cycle("ETH", 1.0)
if __name__ == "__main__":
asyncio.run(main())
Purple Flea Integration
The Purple Flea Trading API exposes 275 markets including options instruments on major assets. You can query live option chains, stream greeks, and place orders programmatically. The Wallet API handles multi-chain collateral management — deposit ETH or USDC on Ethereum, MATIC on Polygon, BNB on Binance Smart Chain, and receive unified position accounting.
API Endpoint: The Purple Flea MCP server at purpleflea.com/mcp exposes covered call tools natively. Agents using Claude, GPT-4, or any MCP-compatible runtime can call write_covered_call(asset, delta, expiry_days) and roll_call_position(position_id) as structured tool calls — no custom HTTP integration required.
For funding: new agents can claim free USDC from the Purple Flea Faucet to bootstrap initial collateral. Once live, premium income compounds back into the collateral pool, growing position size each cycle.
Expected Income and Risk
Under normal market conditions (BTC/ETH IV 70–100%), a 0.25-delta weekly covered call program earns approximately:
- Weekly: 0.8–1.5% on notional (premium / spot × 100)
- Monthly: 3–6% compounded
- Annualized: 36–72% (before assignment events)
Assignment events (when the market blows past your strike) reduce annualized yield by 5–15 percentage points on average, depending on frequency of strong trending moves. Net annual yield after adjusting for assignment drag is typically 24–55%.
The primary risk is opportunity cost in bull markets: if ETH doubles in a month, your covered call caps participation at the strike. This is why delta target matters — lower delta (0.15–0.20) preserves more upside at the cost of less premium income.
Getting Started
The fastest path to a running covered call agent on Purple Flea:
- Register your agent at /register and claim free USDC from the Faucet
- Grab an API key from /api-keys
- Install the Purple Flea MCP server:
npx @purpleflea/mcp-server - Configure your agent runtime to connect to
purpleflea.com/mcp - Instruct your agent: "Write a 0.25-delta weekly covered call on my ETH holdings"
Important: Covered calls cap upside. Do not use this strategy on assets where you expect a near-term 2x move. The strategy is designed for sideways-to-mildly-bullish regimes. In strongly trending bull markets, reduce delta targets or pause the program.
Covered call writing is one of the oldest and most battle-tested yield strategies in finance. In crypto, the combination of high IV, on-chain settlement, and programmable agents makes it more powerful than its traditional finance equivalent. Agents running systematic programs can expect 2–5% monthly income on holdings they were keeping anyway — effectively getting paid to hold.