Left alone, a portfolio naturally drifts toward its biggest winners. If BTC doubles while ETH stays flat, your original 50/50 allocation becomes 66/34 โ meaning you now have twice the concentration in a single asset that has already had its big run. This is how unrebalanced portfolios silently accumulate concentration risk over time, even without any active decision-making by the agent.
Portfolio rebalancing is the systematic correction of this drift. By periodically selling overweight positions and buying underweight ones, your agent maintains the risk profile it was designed for. This guide covers threshold-based and time-based rebalancing, the math behind drift calculation, and a complete Python implementation using the Purple Flea wallet and trading APIs.
Define your target weights as the desired percentage of total portfolio value held in each asset. At any point in time, the current weight of an asset is simply its current value divided by total portfolio value.
Drift for an asset is the absolute difference between its current weight and its target weight. A portfolio with targets [BTC 50%, ETH 30%, USDC 20%] and current values worth [BTC 65%, ETH 25%, USDC 10%] has drifts of [15%, 5%, 10%]. The maximum drift is 15% โ meaning BTC is significantly overweight.
The rebalance trade for each asset is: trade value = (target weight โ current weight) ร total portfolio value. Negative values mean sell; positive values mean buy. Execute sells first to generate USDC, then use that USDC for the buy side.
Rebalancing on a fixed schedule (e.g., every month) has a flaw: if a market moves 30% on day 2 of the month, you won't correct until day 30. Threshold-based rebalancing triggers whenever any asset drifts beyond a defined tolerance โ commonly 5% absolute or 25% relative.
This approach minimizes unnecessary transaction costs (you don't rebalance when drift is within tolerance) while correcting meaningful imbalances promptly. The 5% threshold is a practical sweet spot: tight enough to maintain your intended allocation, wide enough to avoid constant small trades eating into returns through fees.
import purpleflea import os client = purpleflea.TradingClient(api_key=os.environ["PURPLEFLEA_API_KEY"]) wallet = purpleflea.WalletClient(api_key=os.environ["PURPLEFLEA_API_KEY"]) TARGET_WEIGHTS = { "BTC": 0.50, "ETH": 0.30, "SOL": 0.20, } DRIFT_THRESHOLD = 0.05 # 5% absolute drift triggers rebalance def get_portfolio_state(): # Fetch current balances and prices balances = wallet.get_balances() prices = client.get_prices(symbols=["BTC-USDT", "ETH-USDT", "SOL-USDT"]) holdings = {} total_value = 0.0 for asset, target in TARGET_WEIGHTS.items(): qty = balances.get(asset, {}).get("available", 0.0) price = prices[f"{asset}-USDT"]["last"] value = qty * price holdings[asset] = {"qty": qty, "price": price, "value": value} total_value += value for asset in holdings: holdings[asset]["weight"] = holdings[asset]["value"] / total_value if total_value > 0 else 0 holdings[asset]["drift"] = abs(holdings[asset]["weight"] - TARGET_WEIGHTS[asset]) return holdings, total_value def needs_rebalance(holdings): return any(h["drift"] > DRIFT_THRESHOLD for h in holdings.values()) holdings, total_value = get_portfolio_state() print(f"Portfolio value: ${total_value:,.2f}") for asset, h in holdings.items(): print(f" {asset}: {h['weight']:.1%} (target {TARGET_WEIGHTS[asset]:.1%}, drift {h['drift']:.1%})") if needs_rebalance(holdings): print("Rebalance triggered.") else: print("Portfolio within tolerance. No action needed.")
When drift exceeds the threshold, calculate trade sizes and execute. Always process sells before buys to ensure USDC is available for the buy-side orders.
def execute_rebalance(holdings, total_value): trades = [] for asset, h in holdings.items(): target_value = TARGET_WEIGHTS[asset] * total_value delta_usdt = target_value - h["value"] if abs(delta_usdt) < 10: # skip trades smaller than $10 continue trades.append({ "asset": asset, "symbol": f"{asset}-USDT", "side": "sell" if delta_usdt < 0 else "buy", "usdt_amount": abs(delta_usdt) }) # Execute sells first for trade in sorted(trades, key=lambda t: t["side"], reverse=True): order = client.place_order( symbol=trade["symbol"], side=trade["side"], quote_amount=trade["usdt_amount"], order_type="market" ) print( f" {trade['side'].upper()} {trade['asset']}: " f"${trade['usdt_amount']:.2f} | " f"Fill: ${order['fill_price']:,.2f}" )
Some agents prefer the simplicity of a fixed schedule: rebalance on the first of each month, period. This approach requires less monitoring logic and is easier to reason about in audit logs. The tradeoff is that large interim drifts may persist for weeks before correction.
The best production configuration combines both approaches: check drift every hour, trigger an emergency rebalance if any asset drifts beyond 15%, and always rebalance on the monthly schedule regardless of drift. This provides a safety net for large moves while avoiding over-trading during calm periods.
Advanced agents hold positions across multiple chains simultaneously โ ETH on Ethereum mainnet, SOL on Solana, BTC perpetuals on Hyperliquid. Purple Flea's multi-chain wallet API consolidates balances from all supported chains into a single view, enabling cross-chain drift calculation with the same approach as single-chain rebalancing.
When rebalancing requires moving assets across chains (e.g., selling overweight ETH mainnet to buy underweight SOL), the agent must account for bridge latency (typically 2-15 minutes) and bridge fees. Build this latency into your rebalancing logic by placing the sell order, waiting for confirmation, bridging, then placing the buy order once the bridged funds arrive.
Log every rebalance event and the drift state that triggered it. Over weeks of data, you can visualize drift patterns to optimize your threshold. If you rebalanced 40 times in a month, your threshold is too tight โ raise it. If a position drifted to 30% before triggering, lower it.
| Rebalance Trigger | Avg Monthly Trades | Max Drift Observed | Best For |
|---|---|---|---|
| 2% threshold | 25-40 | 3% | Very tight allocation control |
| 5% threshold | 6-12 | 8% | Most agents (recommended) |
| 10% threshold | 2-4 | 15% | Low-fee environments |
| Monthly schedule | 1 | 20%+ | Minimal complexity agents |
| 5% + Monthly | 6-12 | 8% | Production best practice |
Fee consideration: Each rebalance incurs trading fees. At 0.1% per trade and 3 assets, a full rebalance costs ~0.3% of portfolio value. A monthly rebalance costs 3.6%/year in fees. Threshold-based rebalancing only when drift exceeds 5% typically costs 0.6-1.2%/year โ a significant saving at scale.
Rebalancing is the difference between a portfolio that compounds risk and one that maintains its intended characteristics over market cycles. For agents running long-term accumulation strategies โ DCA, index-style holds, or yield farming โ automated rebalancing is a mandatory component of sound portfolio design.
Explore the complete reference at /agent-portfolio-rebalancing, and see all balance and price endpoints at /crypto-wallet-api and /trading-api.