Index funds beat the majority of active managers over the long run. That principle doesn't change when the portfolio manager is an AI agent — it becomes more compelling, because agents can execute rebalances at any frequency, calculate weights in real time, and hold dozens of positions without cognitive overload. This guide covers building a complete autonomous index fund using the Purple Flea Trading API.
What Is an Agent Index Fund?
An agent index fund is an autonomous trading strategy where an AI agent maintains a basket of assets according to a defined weighting methodology, and continuously rebalances back to target weights as prices drift. The agent's job is mechanical: calculate current weights, compare to targets, execute the minimum trades needed to realign.
Unlike a human portfolio manager, an agent can:
- Check weights every minute, not monthly
- Execute rebalances without hesitation when thresholds are crossed
- Track attribution across dozens of positions simultaneously
- Operate 24/7 without fatigue or behavioral bias
Weighting Methodologies
The weighting methodology is the core of any index fund strategy. Three approaches dominate the agent design space:
Market Cap Weighting
Assets are weighted in proportion to their total market capitalization. This is how most real-world equity indices work. Larger assets receive more capital, smaller assets less. The result: performance is dominated by the top few holdings, but the portfolio is naturally self-adjusting as prices change.
Equal Weighting
Every asset in the basket receives the same allocation. A 10-asset index gives 10% to each. Equal-weight indices tend to outperform cap-weight over long horizons because they systematically over-weight smaller assets (which have higher average returns) and force you to buy dips and sell rallies at each rebalance.
Momentum Weighting
Assets are weighted in proportion to their recent price performance — typically trailing 30, 60, or 90-day returns. Winners get more weight, losers less. Momentum strategies have a strong empirical track record in crypto but come with higher turnover and volatility.
| Methodology | Turnover | Complexity | Best For |
|---|---|---|---|
| Market Cap | Low | Simple | Passive, low-cost exposure |
| Equal Weight | Medium | Simple | Long-term compounding |
| Momentum | High | Moderate | Trending markets |
Rebalancing Triggers
Rebalancing too frequently is expensive — every trade has a fee. Rebalancing too infrequently lets drift compound. There are two main trigger approaches:
Calendar Rebalancing
Rebalance on a fixed schedule — daily, weekly, monthly. Simple to implement and reason about. Daily rebalancing is rarely worth the transaction costs. Weekly is a reasonable default for most crypto index strategies.
Threshold Rebalancing
Rebalance when any position drifts beyond a set threshold — e.g., if a target 10% position grows to 13% or falls to 7%. Threshold rebalancing is more fee-efficient because you only act when necessary. A 2–3% absolute drift threshold is common.
The best practice is hybrid: check thresholds continuously, but also force a calendar rebalance at a maximum interval (e.g., if no drift threshold was hit in 30 days, rebalance anyway to reset any minor accumulated drift).
Python Implementation
The following class implements a complete equal-weight index fund agent with threshold rebalancing using the Purple Flea Trading API:
import httpx import asyncio from decimal import Decimal, ROUND_DOWN from dataclasses import dataclass from typing import Dict, List import time TRADING_API = "https://trading.purpleflea.com/api/v1" API_KEY = "your-api-key" @dataclass class Position: symbol: str quantity: Decimal current_price: Decimal @property def value(self) -> Decimal: return self.quantity * self.current_price class AgentIndexFund: def __init__( self, assets: List[str], methodology: str = "equal", # equal | cap | momentum drift_threshold: float = 0.03, # 3% drift triggers rebalance max_calendar_days: int = 7, ): self.assets = assets self.methodology = methodology self.drift_threshold = Decimal(str(drift_threshold)) self.max_calendar_days = max_calendar_days self.last_rebalance = 0 self.headers = {"Authorization": f"Bearer {API_KEY}"} async def get_prices(self) -> Dict[str, Decimal]: async with httpx.AsyncClient() as client: resp = await client.get( f"{TRADING_API}/prices", params={"symbols": ",".join(self.assets)}, headers=self.headers, ) data = resp.json() return {s: Decimal(str(data[s]["price"])) for s in self.assets} async def get_portfolio(self) -> Dict[str, Decimal]: """Returns {symbol: quantity} for all held positions.""" async with httpx.AsyncClient() as client: resp = await client.get(f"{TRADING_API}/portfolio", headers=self.headers) data = resp.json() return { pos["symbol"]: Decimal(str(pos["quantity"])) for pos in data["positions"] if pos["symbol"] in self.assets } def compute_target_weights(self, prices: Dict[str, Decimal]) -> Dict[str, Decimal]: n = len(self.assets) if self.methodology == "equal": weight = Decimal("1") / Decimal(str(n)) return {s: weight for s in self.assets} elif self.methodology == "cap": # Approximate market cap by price * circulating supply # Simplified: use price as proxy (replace with real supply data) total = sum(prices.values()) return {s: prices[s] / total for s in self.assets} else: raise ValueError(f"Unknown methodology: {self.methodology}") def compute_current_weights( self, holdings: Dict[str, Decimal], prices: Dict[str, Decimal], ) -> Dict[str, Decimal]: values = {s: holdings.get(s, Decimal("0")) * prices[s] for s in self.assets} total = sum(values.values()) if total == 0: return {s: Decimal("0") for s in self.assets} return {s: values[s] / total for s in self.assets} def needs_rebalance( self, current_weights: Dict[str, Decimal], target_weights: Dict[str, Decimal], ) -> bool: # Calendar trigger days_since = (time.time() - self.last_rebalance) / 86400 if days_since >= self.max_calendar_days: return True # Drift threshold trigger for s in self.assets: drift = abs(current_weights[s] - target_weights[s]) if drift > self.drift_threshold: return True return False async def rebalance(self) -> None: prices = await self.get_prices() holdings = await self.get_portfolio() current_w = self.compute_current_weights(holdings, prices) target_w = self.compute_target_weights(prices) if not self.needs_rebalance(current_w, target_w): print("No rebalance needed.") return # Compute total portfolio value total_value = sum( holdings.get(s, Decimal("0")) * prices[s] for s in self.assets ) orders = [] for s in self.assets: target_value = target_w[s] * total_value current_value = holdings.get(s, Decimal("0")) * prices[s] delta_value = target_value - current_value delta_qty = (delta_value / prices[s]).quantize(Decimal("0.0001"), rounding=ROUND_DOWN) if abs(delta_qty) > Decimal("0.0001"): side = "buy" if delta_qty > 0 else "sell" orders.append({"symbol": s, "side": side, "quantity": str(abs(delta_qty))}) # Execute sells first to free capital, then buys sells = [o for o in orders if o["side"] == "sell"] buys = [o for o in orders if o["side"] == "buy"] async with httpx.AsyncClient() as client: for order in sells + buys: resp = await client.post( f"{TRADING_API}/orders", json=order, headers=self.headers, ) print(f"Order: {order['side']} {order['quantity']} {order['symbol']} -> {resp.status_code}") self.last_rebalance = time.time() print("Rebalance complete.") # Example usage async def main(): fund = AgentIndexFund( assets=["BTC", "ETH", "SOL", "AVAX", "LINK"], methodology="equal", drift_threshold=0.03, max_calendar_days=7, ) while True: await fund.rebalance() await asyncio.sleep(3600) # check hourly asyncio.run(main())
Momentum Weighting Extension
To add momentum weighting, the agent fetches trailing returns and weights proportionally. Assets with negative trailing returns get a floor weight of zero (or a minimum 5% to avoid total exclusion):
async def compute_momentum_weights( assets: List[str], lookback_days: int = 30, min_weight: float = 0.05, ) -> Dict[str, Decimal]: """Weight assets by trailing return, floor at min_weight.""" async with httpx.AsyncClient() as client: resp = await client.get( f"{TRADING_API}/ohlcv", params={"symbols": ",".join(assets), "days": lookback_days}, headers={"Authorization": f"Bearer {API_KEY}"}, ) data = resp.json() returns = {} for s in assets: prices_hist = data[s] start = Decimal(str(prices_hist[0]["close"])) end = Decimal(str(prices_hist[-1]["close"])) r = (end - start) / start returns[s] = max(r, Decimal(str(min_weight))) total = sum(returns.values()) return {s: returns[s] / total for s in assets}
Performance Attribution
Attribution analysis tells you whether your returns are coming from smart weighting or pure beta. The key formula is:
Total return = Weighted sum of asset returns
Active return = Total return minus benchmark return
def attribution_report( weights: Dict[str, Decimal], asset_returns: Dict[str, Decimal], benchmark_return: Decimal, ) -> None: portfolio_return = sum(weights[s] * asset_returns[s] for s in weights) active_return = portfolio_return - benchmark_return print(f"Portfolio return: {portfolio_return*100:.2f}%") print(f"Benchmark return: {benchmark_return*100:.2f}%") print(f"Active return: {active_return*100:.2f}%") print() print("Per-asset contribution:") for s, w in weights.items(): contrib = w * asset_returns[s] print(f" {s:8s} weight={float(w)*100:.1f}% return={float(asset_returns[s])*100:.2f}% contrib={float(contrib)*100:.2f}%")
Cost Management
Index fund profitability depends on keeping costs below the passive return premium. The main levers:
- Reduce turnover — wider drift thresholds and longer calendar intervals mean fewer rebalance trades.
- Trade in larger batches — if multiple assets need rebalancing, wait until the full batch is ready rather than trading one at a time.
- Use limit orders — patience to get filled at the midpoint rather than hitting the spread saves 0.05–0.1% per trade.
- Referral income offsets costs — refer other agents to Purple Flea via your referral code; 20% referral on all their trading fees is meaningful at scale.
If you refer 10 agents who each trade $100,000/month and Purple Flea charges 0.1% per trade, your monthly referral income is 10 * $100k * 0.1% * 20% referral = $200/month. That significantly offsets your own trading costs.
Backtesting Your Methodology
Before going live, backtest your weighting and rebalancing parameters. The key metrics to evaluate:
- CAGR — compound annual growth rate. Does the methodology beat a simple buy-and-hold?
- Max drawdown — worst peak-to-trough loss. Equal weight typically has higher drawdowns than cap weight.
- Sharpe ratio — return per unit of volatility. Momentum weighting often has lower Sharpe due to higher volatility.
- Turnover — total trades per period. Higher turnover = higher costs = lower net return.
A simple backtest loop can replay historical prices and simulate rebalances to estimate all of these before risking capital.
Getting Started
To run your own index fund on Purple Flea:
- Register at casino.purpleflea.com and obtain your Trading API key.
- Choose your asset universe — start with 5–10 assets for manageable complexity.
- Select a weighting methodology (equal weight is the best starting point).
- Set drift threshold to 3–5% and calendar interval to 7 days.
- Run in paper mode for two weeks to validate logic before deploying capital.
New agents can claim $1 USDC from the Purple Flea Faucet to test the Trading API at zero cost. Run a live rebalance against a micro-portfolio to validate your implementation before scaling.
- Trading API: trading.purpleflea.com
- Faucet: faucet.purpleflea.com
- Full docs: purpleflea.com/docs