The Five Options Greeks
Options Greeks are partial derivatives of an option's price with respect to various market parameters. They form the mathematical backbone of every professional options desk and — increasingly — every autonomous trading agent operating in crypto markets. Unlike spot positions where P&L is straightforward, options expose agents to multiple simultaneous risk dimensions that require continuous monitoring and rebalancing.
For an AI agent running 24/7 across dozens of markets, Greeks are not just academic curiosities — they are the primary control signals. An agent that ignores delta will drift directional without knowing it. One that ignores gamma will be blindsided by convexity at expiration. Theta eats premiums silently overnight. Vega explodes on earnings-equivalent events in crypto. This guide gives agents the tools to handle all five.
Rate of change of option price per $1 move in the underlying. Range: −1 to +1.
Rate of change of delta per $1 move. Highest for ATM options near expiration.
Daily time decay in option premium. Negative for buyers, positive for sellers.
Sensitivity to implied volatility. A 1% IV move changes option price by vega.
Sensitivity to interest/funding rates. Measurable in crypto via perpetual funding.
Delta (Δ) — Directional Exposure
Delta is the most fundamental Greek. It answers: if the underlying moves $1, how much does my option position change in value? A call option has positive delta (0 to +1); a put has negative delta (−1 to 0). An at-the-money (ATM) option has delta ≈ ±0.50. Deep in-the-money options approach ±1.00; far out-of-the-money options approach 0.
For AI agents, delta translates directly to equivalent spot/perp exposure. A position
with +200 delta on BTC-USD acts like holding 200 USD worth of BTC. Delta aggregates
across all legs, giving the agent its net directional bet at any moment. The Black-Scholes
formula computes call delta as N(d1), where d1 = (ln(S/K) + 0.5σ²T) / (σ√T).
# Black-Scholes greeks: core implementation
import math
from scipy.stats import norm
def d1(S, K, T, r, sigma):
return (math.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * math.sqrt(T))
def d2(S, K, T, r, sigma):
return d1(S, K, T, r, sigma) - sigma * math.sqrt(T)
def call_delta(S, K, T, r, sigma):
return norm.cdf(d1(S, K, T, r, sigma))
def put_delta(S, K, T, r, sigma):
return norm.cdf(d1(S, K, T, r, sigma)) - 1
# Example: BTC ATM call, 7 days to expiry, 80% IV
S, K, T, r, sigma = 65000, 65000, 7/365, 0.0, 0.80
print(f"Call delta: {call_delta(S, K, T, r, sigma):.4f}") # ~0.5000
print(f"Put delta: {put_delta(S, K, T, r, sigma):.4f}") # ~-0.5000
In crypto markets, agents typically use perpetual funding rates as a proxy for
r. On Purple Flea's 275-market perp exchange, funding updates every 8 hours
and can swing significantly, making rho-awareness more material than in traditional equities.
Gamma (Γ) — Convexity and Acceleration
Gamma measures how fast delta changes. It is the second derivative of option price with respect to the underlying. High gamma means delta shifts rapidly with price moves — which is both an opportunity (gamma scalping) and a risk (rapid P&L swings near expiry). Gamma is always positive for both calls and puts when long, always negative when short.
ATM short-dated options carry the highest gamma. This is why agents running short-gamma
books (selling straddles, iron condors) face outsized danger in the final 24–48 hours
before expiration. The formula: Γ = N'(d1) / (S × σ × √T).
def gamma(S, K, T, r, sigma):
d1_val = d1(S, K, T, r, sigma)
return norm.pdf(d1_val) / (S * sigma * math.sqrt(T))
# Gamma explodes near expiry — critical for short-gamma agents to monitor
for days in [30, 7, 1, 0.25]:
T = days / 365
g = gamma(65000, 65000, T, 0.0, 0.80)
print(f"{days:5.2f}d to expiry → gamma = {g:.8f}")
# Output shows gamma scaling ~5x from 7d to 1d, ~15x from 7d to 6h
Theta (Θ) — Time Decay
Theta is the daily erosion of option premium assuming all else constant. Long options have negative theta (they lose value over time). Short options have positive theta (premium sellers benefit from time passing). In crypto markets that never close, theta accrues continuously — there is no weekend reprieve. An agent selling weekly BTC straddles collects theta 24/7, which is both the appeal and the trap.
def call_theta(S, K, T, r, sigma):
d1_val = d1(S, K, T, r, sigma)
d2_val = d2(S, K, T, r, sigma)
term1 = -(S * norm.pdf(d1_val) * sigma) / (2 * math.sqrt(T))
term2 = -r * K * math.exp(-r * T) * norm.cdf(d2_val)
return (term1 + term2) / 365 # convert to daily theta
def put_theta(S, K, T, r, sigma):
d1_val = d1(S, K, T, r, sigma)
d2_val = d2(S, K, T, r, sigma)
term1 = -(S * norm.pdf(d1_val) * sigma) / (2 * math.sqrt(T))
term2 = +r * K * math.exp(-r * T) * norm.cdf(-d2_val)
return (term1 + term2) / 365
# ATM 7-day call at 80% IV: daily theta per contract
theta_daily = call_theta(65000, 65000, 7/365, 0.0, 0.80)
print(f"Daily theta: ${theta_daily:.2f}") # approximately -$350 per contract
Vega (ν) — Volatility Sensitivity
Vega measures how much an option's price changes for a 1% change in implied volatility. Vega is positive for both calls and puts when long. It is highest for longer-dated, ATM options. In crypto, where IV can swing from 50% to 200% in a single day, vega is often the dominant risk factor — dwarfing delta on event-driven moves like ETF approvals or exchange hacks.
def vega(S, K, T, r, sigma):
d1_val = d1(S, K, T, r, sigma)
return S * norm.pdf(d1_val) * math.sqrt(T) / 100 # per 1% IV move
# Longer-dated options have significantly more vega exposure
for days in [7, 30, 90]:
T = days / 365
v = vega(65000, 65000, T, 0.0, 0.80)
print(f"{days:3d}d vega = ${v:.2f} per 1% IV move")
# 7d: ~$62 | 30d: ~$128 | 90d: ~$221
Rho (ρ) — Rate Sensitivity
Rho measures sensitivity to interest rates (or in crypto, perpetual funding rates).
For short-dated options it is typically the least important Greek, but on perpetuals
where funding can reach ±0.1% per 8 hours (annualized ±109%), rho-equivalent
exposures become material for large deep-ITM positions. Agents should substitute
annualized perpetual funding for r in the Black-Scholes formula.
def call_rho(S, K, T, r, sigma):
d2_val = d2(S, K, T, r, sigma)
return K * T * math.exp(-r * T) * norm.cdf(d2_val) / 100
def put_rho(S, K, T, r, sigma):
d2_val = d2(S, K, T, r, sigma)
return -K * T * math.exp(-r * T) * norm.cdf(-d2_val) / 100
# Crypto: annualize perpetual 8h funding as interest rate proxy
funding_8h = 0.0005 # 0.05% per 8h — positive funding environment
annualized_r = funding_8h * 3 * 365 # ~54.75% annualized
rho_val = call_rho(65000, 65000, 30/365, annualized_r, 0.80)
print(f"Call rho (crypto-adjusted): ${rho_val:.4f}")
How AI Agents Use Greeks to Manage Options Risk
A human trader might glance at their greek dashboard once an hour. An AI agent running on Purple Flea's infrastructure checks Greeks every few seconds and acts within milliseconds. The workflow is a continuous loop:
- Fetch positions — retrieve all open options legs and perpetual hedges.
- Compute portfolio Greeks — sum deltas, gammas, thetas, vegas across all legs.
- Compare to limits — check each Greek against configured thresholds.
- Generate hedge orders — compute the perp size needed to neutralize out-of-bounds Greeks.
- Execute and confirm — place orders via the Purple Flea REST/WebSocket API, await fills.
- Log and sleep — record state, sleep for the configured interval (e.g., 30 seconds).
This loop runs independently of the strategy layer. The strategy decides what positions to hold; the Greek monitor decides how to hedge them. Separating these concerns is critical for agent reliability — a bug in one should not cascade to the other.
With 275 perpetual markets and up to 50x leverage, agents can hedge delta exposures in virtually any crypto market without needing to find a matching options liquidity pool. The perp becomes the universal hedging tool across the entire Greek management stack.
Delta-Neutral Hedging with Perpetual Swaps
Delta-neutral hedging is the practice of offsetting directional exposure so that small moves in the underlying do not affect portfolio value. The goal is to isolate pure volatility, time decay, or spread P&L — whatever edge the agent is actually trying to capture — without being exposed to random directional drift.
The Hedge Calculation
Given a portfolio delta of +ΔP, the agent needs to short ΔP units of the underlying perpetual to reach zero net delta. In practice, agents maintain a tolerance band (e.g., ±0.05 delta) to avoid constant small rebalances that erode profits through fees.
import requests
import time
from dataclasses import dataclass
from typing import List
BASE_URL = "https://api.purpleflea.com/v1"
API_KEY = "pf_live_your_key_here"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
@dataclass
class OptionLeg:
symbol: str
strike: float
expiry_days: float
option_type: str # 'call' or 'put'
size: float # positive = long, negative = short
iv: float # implied volatility (decimal, e.g. 0.80)
class DeltaHedger:
def __init__(self, symbol: str, tolerance: float = 0.05):
self.symbol = symbol # e.g. "BTC-USD"
self.tolerance = tolerance # delta tolerance band before rebalancing
def get_spot_price(self) -> float:
r = requests.get(f"{BASE_URL}/markets/{self.symbol}/ticker", headers=HEADERS)
return r.json()["mark_price"]
def portfolio_delta(self, legs: List[OptionLeg], S: float) -> float:
total_delta = 0.0
for leg in legs:
T = leg.expiry_days / 365
if leg.option_type == "call":
d = call_delta(S, leg.strike, T, 0.0, leg.iv)
else:
d = put_delta(S, leg.strike, T, 0.0, leg.iv)
total_delta += d * leg.size
return total_delta
def get_perp_position(self) -> float:
r = requests.get(
f"{BASE_URL}/positions/{self.symbol}-PERP",
headers=HEADERS
)
data = r.json()
return data.get("size", 0.0) # positive=long, negative=short (base units)
def place_hedge_order(self, delta_to_hedge: float, S: float):
size_in_base = delta_to_hedge / S
side = "sell" if size_in_base > 0 else "buy"
abs_size = abs(size_in_base)
payload = {
"symbol": f"{self.symbol}-PERP",
"side": side, "size": f"{abs_size:.6f}",
"type": "market", "reduce_only": False
}
r = requests.post(f"{BASE_URL}/orders", json=payload, headers=HEADERS)
print(f"[HEDGE] {side} {abs_size:.4f} {self.symbol}-PERP | HTTP {r.status_code}")
return r.json()
def run_loop(self, legs: List[OptionLeg], interval: int = 30):
print(f"[HEDGER] Starting delta-neutral loop for {self.symbol}")
while True:
S = self.get_spot_price()
port_delta = self.portfolio_delta(legs, S)
perp_pos = self.get_perp_position()
perp_delta_usd = perp_pos * S
net_delta = port_delta + perp_delta_usd
print(f"[HEDGER] S={S:.0f} | options_D={port_delta:.3f} | perp_D={perp_delta_usd:.3f} | net={net_delta:.3f}")
if abs(net_delta) > self.tolerance * S:
self.place_hedge_order(net_delta, S)
time.sleep(interval)
Rebalancing Costs vs. Frequency
Every hedge order incurs trading fees. On Purple Flea, maker/taker fees are competitive, but frequent small rebalances will erode theta gains. Use a bandwidth hedge: only rebalance when delta drifts beyond ±N% of position size. Tune N based on IV level.
| IV Level | Recommended Band | Rebalance Frequency | Fee Impact |
|---|---|---|---|
| Low (<40%) | ±0.05 delta | Every 2–4 hours | Low |
| Medium (40–80%) | ±0.10 delta | Every 30–60 min | Medium |
| High (80–150%) | ±0.15 delta | Every 10–20 min | Elevated |
| Extreme (>150%) | ±0.20 delta | Every 5 min max | Critical — cap order size |
Gamma Scalping Algorithms
Gamma scalping is the strategy of buying long options (positive gamma) and continuously rebalancing delta to lock in profits from realized volatility moves. When the underlying moves up, delta increases (because you're long gamma); you sell the perp. When the underlying moves down, delta decreases; you buy the perp. Each round-trip captures the realized move as P&L.
The P&L of a gamma scalp is approximately: P&L ≈ 0.5 × Γ × (ΔS)² − Θ × Δt. You profit if realized volatility exceeds implied volatility. You lose if the market sits still and theta bleeds you dry.
class GammaScalper:
"""
Long ATM straddle + continuous delta rebalancing.
Profits when realized vol > implied vol.
Rebalances on price movement, not fixed intervals.
"""
def __init__(self, symbol, strike, expiry_days, iv, contracts):
self.symbol = symbol
self.K = strike
self.T0 = expiry_days / 365
self.iv = iv
self.contracts = contracts
self.S_prev = None
self.hedge_pnl = 0.0
self.num_rebalances = 0
def gamma_pnl_estimate(self, S_now, S_prev, T):
G = gamma(S_now, self.K, T, 0.0, self.iv)
dS = S_now - S_prev
return 0.5 * G * (dS ** 2) * self.contracts
def straddle_delta(self, S, T):
cd = call_delta(S, self.K, T, 0.0, self.iv)
pd = put_delta(S, self.K, T, 0.0, self.iv)
return (cd + pd) * self.contracts # near-zero for ATM straddle
def capture_threshold(self, S, T, fee_usd=20) -> bool:
# Only rebalance if expected gamma capture exceeds round-trip fee
G = gamma(S, self.K, T, 0.0, self.iv)
expected = 0.5 * G * (S * 0.003) ** 2 # 0.3% move estimate
return expected > fee_usd
def run(self, hedger: DeltaHedger, duration_hours=24):
import datetime
end = datetime.datetime.utcnow() + datetime.timedelta(hours=duration_hours)
elapsed = 0
while datetime.datetime.utcnow() < end:
S = hedger.get_spot_price()
T = max(self.T0 - elapsed/365, 0.001)
if self.S_prev is not None:
g_pnl = self.gamma_pnl_estimate(S, self.S_prev, T)
t_cost = call_theta(S, self.K, T, 0.0, self.iv) * self.contracts * (30/86400)
net = g_pnl + t_cost
self.hedge_pnl += net
print(f"S={S:.0f} | gammaP={g_pnl:.2f} | thetaCost={t_cost:.2f} | net={net:.2f} | total={self.hedge_pnl:.2f}")
straddle_d = self.straddle_delta(S, T)
perp_pos = hedger.get_perp_position()
net_delta = straddle_d + perp_pos * S
if abs(net_delta) > 0.08 * S and self.capture_threshold(S, T):
hedger.place_hedge_order(net_delta, S)
self.num_rebalances += 1
self.S_prev = S
elapsed += 30 / 86400
time.sleep(30)
print(f"Done: {self.num_rebalances} rebalances, PnL=${self.hedge_pnl:.2f}")
Gamma scalping requires realized volatility to consistently exceed implied vol paid at entry. In crypto, this often holds — but during low-vol consolidation periods typical of bear-market bases, agents can bleed theta for weeks before a catalytic move arrives. Always monitor the IV/RV spread before initiating a gamma-long position.
Theta Decay Exploitation (Selling Premium)
The inverse of gamma scalping is theta farming: selling options to collect time decay. The agent is short gamma (net negative), which means it suffers on large moves, but earns steady theta income when the market stays range-bound. This is the approach behind iron condors, covered strangles, and calendar spreads.
The critical metric is the theta-to-vega ratio. An agent selling weekly BTC straddles earns theta rapidly, but carries vega risk. Monitoring this ratio tells the agent whether it is being adequately compensated for its volatility exposure.
class ThetaFarmer:
"""
Sells weekly ATM straddles when IV is elevated.
Collects theta; closes at 70% time elapsed to avoid gamma risk.
"""
IV_ENTRY_MIN = 0.60 # only sell premium when IV > 60%
THETA_VEGA_MIN = 0.12 # minimum theta/vega ratio for entry
MAX_GAMMA_RISK = 2000 # max USD loss on a 2-sigma daily move
def __init__(self, symbol, budget_usd):
self.symbol = symbol
self.budget = budget_usd
def evaluate_entry(self, S, iv, days) -> dict:
T = days / 365
if iv < self.IV_ENTRY_MIN:
return {"enter": False, "reason": "IV below minimum"}
th = abs(call_theta(S, S, T, 0.0, iv))
ve = vega(S, S, T, 0.0, iv)
tv_ratio = th / ve if ve > 0 else 0
if tv_ratio < self.THETA_VEGA_MIN:
return {"enter": False, "reason": f"theta/vega {tv_ratio:.3f} too low"}
sigma_1d = iv / math.sqrt(365)
two_sigma = 2 * sigma_1d * S
G = gamma(S, S, T, 0.0, iv)
gamma_loss_1c = 0.5 * G * two_sigma ** 2
max_contracts = int(self.MAX_GAMMA_RISK / gamma_loss_1c) if gamma_loss_1c > 0 else 10
weekly_theta = th * 7 * max_contracts
return {
"enter": True, "contracts": max_contracts,
"weekly_theta_usd": weekly_theta,
"theta_vega_ratio": tv_ratio,
"gamma_2sigma_risk": gamma_loss_1c * max_contracts
}
def exit_rule(self, entry_iv, current_iv, days_elapsed, days_total) -> str:
if current_iv > entry_iv * 1.30:
return "EXIT_VEGA_SPIKE" # IV spiked 30% — cut vega risk
if days_elapsed / days_total > 0.70:
return "EXIT_GAMMA_RISK" # final 30% of life = gamma danger zone
return "HOLD"
The Theta Decay Curve
Theta does not decay linearly. It accelerates as expiration approaches. For weekly options, roughly 50% of total theta is collected in the final two days. This means agents selling weekly options should plan their exit around 70% of the expiration window — capturing rich late-week theta while avoiding the gamma danger zone near expiry.
Vega Trading — Volatility Arbitrage
Vega trading (vol arb) involves positions based on the spread between implied volatility (what the market prices) and realized volatility (what actually happened). If BTC 30-day IV is 90% but realized vol over the past 30 days was 60%, IV is "rich" — a signal to sell premium. The reverse signals buying cheap vol.
import numpy as np
from collections import deque
class VegaArbAgent:
"""
Monitors the IV - RV spread and signals long/short vol when statistically extreme.
RV is computed from Purple Flea OHLCV data (hourly candles).
"""
def __init__(self, symbol, lookback_days=30, z_threshold=1.5):
self.symbol = symbol
self.lookback = lookback_days
self.z_threshold = z_threshold
self.spread_history = deque(maxlen=lookback_days)
def fetch_hourly_closes(self, n=720) -> list:
r = requests.get(
f"{BASE_URL}/candles/{self.symbol}-PERP",
params={"interval": "1h", "limit": n},
headers=HEADERS
)
return [c["close"] for c in r.json()["candles"]]
def realized_vol(self, prices: list) -> float:
log_ret = np.diff(np.log(prices))
daily_vol = np.std(log_ret) * np.sqrt(24) # hourly → daily
return daily_vol * np.sqrt(365) # daily → annualized
def get_atm_iv(self, expiry="7d") -> float:
r = requests.get(
f"{BASE_URL}/options/{self.symbol}/atm_iv",
params={"expiry": expiry}, headers=HEADERS
)
return r.json()["iv"]
def vol_signal(self) -> dict:
prices = self.fetch_hourly_closes()
rv = self.realized_vol(prices)
iv = self.get_atm_iv()
spread = iv - rv
self.spread_history.append(spread)
if len(self.spread_history) < 5:
return {"signal": "INSUFFICIENT_DATA"}
mu = np.mean(self.spread_history)
sigma = np.std(self.spread_history)
z = (spread - mu) / sigma if sigma > 0 else 0
signal = ("SELL_VOL" if z > self.z_threshold else
"BUY_VOL" if z < -self.z_threshold else "NEUTRAL")
return {"iv": iv, "rv": rv, "spread": spread, "z": z, "signal": signal}
def run(self, interval=3600): # check hourly
while True:
sig = self.vol_signal()
print(f"[VEGA-ARB] IV={sig.get('iv', 0):.1%} RV={sig.get('rv', 0):.1%} "
f"spread={sig.get('spread', 0):.1%} z={sig.get('z', 0):.2f} → {sig['signal']}")
time.sleep(interval)
Crypto volatility is highly regime-dependent. In trending bull markets, realized vol exceeds IV more frequently (momentum creates outsized moves). In ranging markets, IV typically trades rich. Agents should maintain a rolling 30-day IV/RV spread tracker and weight their premium-selling vs. gamma-buying bias by regime.
Full Python Agent: Greeks Monitor
The following is a production-ready Greek tracking agent that continuously monitors a multi-leg options portfolio, computes all five Greeks, checks against configured limits, and auto-hedges when thresholds are breached. Designed to run as a standalone process under PM2 or systemd.
"""
Purple Flea — Greeks Monitor Agent
Tracks delta, gamma, theta, vega for a multi-leg options portfolio.
Auto-hedges via the Purple Flea perpetual API when limits are breached.
"""
import math, time, logging
import requests
from scipy.stats import norm
from dataclasses import dataclass
from typing import List
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
log = logging.getLogger("greeks-monitor")
BASE_URL = "https://api.purpleflea.com/v1"
API_KEY = "pf_live_your_key_here"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
@dataclass
class Greeks:
delta: float = 0.0
gamma: float = 0.0
theta: float = 0.0
vega: float = 0.0
rho: float = 0.0
def __add__(self, other):
return Greeks(self.delta+other.delta, self.gamma+other.gamma,
self.theta+other.theta, self.vega+other.vega, self.rho+other.rho)
def __repr__(self):
return f"D={self.delta:+.4f} G={self.gamma:.6f} Th={self.theta:+.2f}/d V={self.vega:.2f}/1% R={self.rho:.4f}"
@dataclass
class GreekLimits:
max_delta: float = 0.20 # net delta before auto-hedge
min_theta: float = -500 # max daily theta bleed (USD)
max_vega: float = 2000 # max vega per 1% IV move (USD)
@dataclass
class OptionPosition:
strike: float
expiry_days: float
option_type: str # 'call' or 'put'
size: float # positive=long, negative=short
iv: float
def compute_greeks(S, K, T, iv, size, otype) -> Greeks:
if T <= 0: return Greeks()
d1_v = (math.log(S/K) + 0.5*iv**2*T) / (iv*math.sqrt(T))
d2_v = d1_v - iv*math.sqrt(T)
Npd1 = norm.pdf(d1_v); Ncd1 = norm.cdf(d1_v); Ncd2 = norm.cdf(d2_v)
delta_v = Ncd1 if otype == "call" else Ncd1 - 1
gamma_v = Npd1 / (S * iv * math.sqrt(T))
theta_v = (-(S * Npd1 * iv) / (2 * math.sqrt(T))) / 365
vega_v = S * Npd1 * math.sqrt(T) / 100
rho_v = K * T * (Ncd2 if otype == "call" else (Ncd2-1)) / 100
return Greeks(delta_v*size, gamma_v*size, theta_v*size, vega_v*size, rho_v*size)
class GreeksMonitor:
def __init__(self, positions: List[OptionPosition], limits: GreekLimits):
self.positions = positions
self.limits = limits
self.hedge_count = 0
def fetch_price(self, symbol="BTC-USD") -> float:
r = requests.get(f"{BASE_URL}/markets/{symbol}/ticker", headers=HEADERS, timeout=5)
return r.json()["mark_price"]
def portfolio_greeks(self, S: float) -> Greeks:
total = Greeks()
for p in self.positions:
total = total + compute_greeks(S, p.strike, p.expiry_days/365, p.iv, p.size, p.option_type)
return total
def hedge_delta(self, g: Greeks, S: float):
size = abs(g.delta) / S
side = "buy" if g.delta < 0 else "sell"
payload = {"symbol": "BTC-USD-PERP", "side": side, "size": f"{size:.6f}", "type": "market"}
r = requests.post(f"{BASE_URL}/orders", json=payload, headers=HEADERS)
log.info(f"DELTA_HEDGE: {side} {size:.4f} BTC-PERP → {r.status_code}")
self.hedge_count += 1
def run(self, interval=60):
log.info(f"Greeks Monitor: {len(self.positions)} positions")
while True:
try:
S = self.fetch_price()
g = self.portfolio_greeks(S)
log.info(f"S={S:.0f} | {g}")
if abs(g.delta) > self.limits.max_delta: self.hedge_delta(g, S)
if g.theta < self.limits.min_theta: log.warning(f"THETA ALERT: {g.theta:.2f}")
if abs(g.vega) > self.limits.max_vega: log.warning(f"VEGA ALERT: {g.vega:.2f}")
except Exception as e:
log.error(f"Loop error: {e}")
time.sleep(interval)
if __name__ == "__main__":
positions = [
OptionPosition(65000, 7, "call", +5, 0.80), # long 5 ATM calls
OptionPosition(65000, 7, "put", +5, 0.80), # long 5 ATM puts (straddle)
OptionPosition(70000, 7, "call", -3, 0.72), # short 3 OTM calls (wing)
]
limits = GreekLimits(max_delta=0.15, max_vega=1500, min_theta=-400)
monitor = GreeksMonitor(positions, limits)
monitor.run(interval=30)
Greek Exposure Limits and Auto-Hedging Triggers
Defining Greek limits is both a science and an art. Too tight and the agent churns fees constantly. Too loose and a single event wipes the portfolio. The following framework provides a starting point for a $50,000 options portfolio on BTC:
| Greek | Soft Limit (Alert) | Hard Limit (Auto-Hedge) | Hedge Action |
|---|---|---|---|
| Delta | ±0.10 | ±0.20 | Market order perp to neutralize |
| Gamma | Short > 0.0005 | Short > 0.001 | Buy ATM options to reduce short gamma |
| Theta | < −$300/day | < −$500/day | Roll long-dated options or reduce position |
| Vega | > $1,500/1% | > $2,500/1% | Sell OTM options to reduce net vega |
| Rho | Monitor only | N/A | Adjust funding hedge if extreme |
Cascading Hedge Priority
Apply hedges in priority order: delta first (cheapest, most liquid), then gamma (requires buying options), then vega (sell OTM options). Never hedge gamma and vega simultaneously in opposite directions — this creates internal conflicts that amplify rather than reduce risk. The agent should solve: minimize hedge cost subject to bringing all Greeks within limits simultaneously.
Every Greek monitor must implement an emergency halt: if portfolio delta exceeds ±0.50 or vega exceeds $5,000 per 1% move, immediately flatten all positions (market orders) and alert operators. In crypto, extreme moves during low-liquidity windows can create exponential Greek exposures faster than a 30-second polling loop can respond.
Multi-Leg Strategies: Straddles, Iron Condors, Butterflies
Multi-leg options strategies are combinations of calls and puts at different strikes and/or expiries, each designed to target a specific Greek profile. Understanding the aggregate Greek signature of each strategy tells an agent what it is actually betting on.
Long Straddle
Buy ATM call + ATM put at the same strike and expiry. Profits from large moves in either direction.
Short Strangle
Sell OTM call + OTM put. Profits if price stays between strikes through expiry.
Iron Condor
Sell OTM call spread + OTM put spread. Defined risk, defined reward theta strategy.
Long Butterfly
Buy 1 ITM call, sell 2 ATM calls, buy 1 OTM call. Profits near the center strike at expiry.
Calendar Spread
Sell near-dated ATM option, buy far-dated ATM option. Captures theta differential and IV term structure.
Risk Reversal
Buy OTM call, sell OTM put (or reverse). Directional bet with reduced premium cost.
def iron_condor_greeks(S, K_pl, K_ps, K_cs, K_cl, T, iv, size=1) -> Greeks:
"""
Iron condor:
+1 put at K_pl (lower wing — long)
-1 put at K_ps (upper put short — income)
-1 call at K_cs (lower call short — income)
+1 call at K_cl (upper wing — long)
"""
legs = [
("put", K_pl, +size), ("put", K_ps, -size),
("call", K_cs, -size), ("call", K_cl, +size),
]
total = Greeks()
for otype, K, qty in legs:
total = total + compute_greeks(S, K, T, iv, qty, otype)
return total
def butterfly_greeks(S, K_low, K_mid, K_high, T, iv, size=1) -> Greeks:
"""Long call butterfly: +1 ITM, -2 ATM, +1 OTM"""
legs = [
("call", K_low, +size),
("call", K_mid, -2*size),
("call", K_high, +size),
]
total = Greeks()
for otype, K, qty in legs:
total = total + compute_greeks(S, K, T, iv, qty, otype)
return total
# Example: BTC Iron Condor at 65k, $3k wide wings
S = 65000
condor = iron_condor_greeks(S, 59000, 62000, 68000, 71000, 7/365, 0.75, size=2)
print(f"Iron Condor: {condor}")
# Expected: delta ~0, negative gamma, positive theta, negative vega
fly = butterfly_greeks(S, 62000, 65000, 68000, 7/365, 0.75, size=3)
print(f"Butterfly: {fly}")
Backtesting Greeks Strategies
Backtesting a Greeks-based strategy requires historical options data (or simulation from historical spot prices and IV surfaces), realistic transaction costs, and proper fill assumptions. The following framework simulates weekly straddle-selling over historical BTC data fetched from Purple Flea's OHLCV endpoint.
import pandas as pd
import numpy as np
def fetch_daily_closes(symbol, days=365) -> pd.Series:
r = requests.get(
f"{BASE_URL}/candles/{symbol}-PERP",
params={"interval": "1d", "limit": days},
headers=HEADERS
)
df = pd.DataFrame(r.json()["candles"])
df["ts"] = pd.to_datetime(df["timestamp"], unit="ms")
return df.set_index("ts")["close"].astype(float)
def proxy_iv(prices: pd.Series, window=30) -> pd.Series:
log_ret = np.log(prices / prices.shift(1))
rv = log_ret.rolling(window).std() * np.sqrt(365)
return rv * 1.15 # IV typically trades ~15% above RV in crypto
def bs_straddle_price(S, K, T, iv):
"""Call + put at same strike (straddle mid price)"""
d1_v = (math.log(S/K) + 0.5*iv**2*T) / (iv*math.sqrt(T))
d2_v = d1_v - iv*math.sqrt(T)
call = S*norm.cdf(d1_v) - K*norm.cdf(d2_v)
put = call - S + K
return call + put
def backtest_weekly_straddle_sell(symbol="BTC-USD", fee_rate=0.0005):
prices = fetch_daily_closes(symbol, days=365)
ivs = proxy_iv(prices)
results = []
idx = prices.index
for i in range(35, len(idx)-7, 7):
S_entry = prices.iloc[i]
S_exit = prices.iloc[i+5]
iv = ivs.iloc[i]
if pd.isna(iv) or iv < 0.40: continue
premium_in = bs_straddle_price(S_entry, S_entry, 7/365, iv)
premium_out = bs_straddle_price(S_exit, S_entry, 2/365, iv*1.05)
raw = premium_in - premium_out
fees = (premium_in + premium_out) * fee_rate * 2
results.append({
"date": idx[i], "S_entry": S_entry, "S_exit": S_exit,
"iv": iv, "pnl": raw - fees, "win": raw > fees
})
df = pd.DataFrame(results)
df["cumulative"] = df["pnl"].cumsum()
sharpe = df["pnl"].mean() / df["pnl"].std() * np.sqrt(52)
print(f"Weeks tested: {len(df)}")
print(f"Win rate: {df['win'].mean():.1%}")
print(f"Avg weekly PnL: ${df['pnl'].mean():.2f}")
print(f"Cumulative PnL: ${df['cumulative'].iloc[-1]:.2f}")
print(f"Sharpe ratio: {sharpe:.2f}")
return df
Key Backtesting Lessons
- IV premium bias: Historically, BTC implied vol has exceeded realized vol approximately 60–65% of the time, providing a structural edge for premium sellers.
- Event clustering: Losses cluster around macro events (FOMC, ETF approvals, exchange incidents). A regime filter that pauses premium selling during high-uncertainty windows significantly improves drawdown profiles.
- Fee compounding: At 0.05% per side on Purple Flea, aggressive rebalancing can consume 3–4% of portfolio in fees per week. Calibrate bandwidth carefully.
- Dynamic Greeks: Always re-compute Greeks at each simulation time step, not just at entry. Delta on a 7-day option changes dramatically from Monday to Friday.
- Slippage: For large positions in smaller markets, model 0.1–0.5% slippage on market orders. Low-liquidity windows can gap against you significantly.
Purple Flea Trading API — Integration Guide
Purple Flea provides the perpetual infrastructure that underpins all the hedging strategies in this guide. With 275 perpetual markets, up to 50x leverage, and a real-time REST plus WebSocket API, it is purpose-built for automated Greek hedging agents.
Perpetual swaps are the ideal instrument for options Greeks because they have no expiry, no contango, and near-zero basis in liquid markets. An agent can hold a short perp indefinitely to neutralize long-delta options exposure without rolling costs. Register at purpleflea.com/register to get your API key and start hedging.
Quick Start: Register and Place a Hedge Order
import requests
# Step 1: Register your agent (one-time setup)
r = requests.post("https://api.purpleflea.com/v1/agents/register", json={
"name": "greeks-monitor-v1",
"type": "options-hedger",
"strategy": "delta-neutral"
})
api_key = r.json()["api_key"]
HEADERS = {"Authorization": f"Bearer {api_key}"}
# Step 2: Browse available markets (275 perpetuals)
markets = requests.get("https://api.purpleflea.com/v1/markets", headers=HEADERS).json()
btc = next(m for m in markets if m["symbol"] == "BTC-USD-PERP")
print(f"BTC-PERP mark price: ${btc['mark_price']:,.2f}")
print(f"Max leverage: {btc['max_leverage']}x")
# Step 3: Place a delta hedge order
order = requests.post("https://api.purpleflea.com/v1/orders", headers=HEADERS, json={
"symbol": "BTC-USD-PERP", "side": "sell",
"size": "0.1", "type": "market"
}).json()
print(f"Order: {order['order_id']} | status: {order['status']}")
# Step 4: Monitor positions
positions = requests.get("https://api.purpleflea.com/v1/positions", headers=HEADERS).json()
for p in positions.get("positions", []):
print(f"{p['symbol']}: size={p['size']} entry={p['entry_price']} unrealizedPnL=${p['unrealized_pnl']:.2f}")
WebSocket for Sub-Second Greek Monitoring
import asyncio, websockets, json
async def realtime_greek_monitor(api_key, monitor):
"""
Subscribe to live price ticks via WebSocket.
Re-compute and check Greeks on every price update.
Significantly faster than polling — essential for gamma scalping agents.
"""
uri = "wss://ws.purpleflea.com/v1/markets/BTC-USD-PERP/ticker"
extra = {"Authorization": f"Bearer {api_key}"}
async with websockets.connect(uri, extra_headers=extra) as ws:
await ws.send(json.dumps({"op": "subscribe", "channel": "ticker"}))
async for raw in ws:
tick = json.loads(raw)
S = tick.get("mark_price")
if not S: continue
g = monitor.portfolio_greeks(S)
if abs(g.delta) > 0.20:
print(f"[WS] DELTA BREACH: {g.delta:+.4f} @ S={S:.0f} — hedging")
monitor.hedge_delta(g, S)
asyncio.run(realtime_greek_monitor("pf_live_your_key_here", monitor))
Start with a free account registration to receive your API key. Review the full endpoint reference in the Trading API docs. New agents can claim a small starting balance from the Agent Faucet to test strategies at zero risk before deploying capital.
Summary: Greek Management Principles for AI Agents
Options Greeks are the language that converts raw options positions into quantified, actionable risk signals. Mastering Greek computation and automated hedging gives an AI agent a decisive edge in any options strategy:
- Delta — Always know your directional exposure; hedge with perps when it drifts beyond tolerance.
- Gamma — Buy gamma (long straddles) when realized vol exceeds IV; sell gamma (iron condors) when IV is rich.
- Theta — Time decay favors short-option agents; close at 70% of expiry to avoid gamma danger.
- Vega — The dominant risk in crypto; track IV/RV spread continuously and avoid large net vega around major events.
- Rho — Monitor perpetual funding rates as a crypto-native rho proxy; relevant for large deep-ITM positions.
With Purple Flea's 275 perpetual markets providing the hedging backbone, AI agents can implement institutional-grade Greek management at a fraction of traditional infrastructure cost — running autonomously, 24/7, across the full crypto options universe.