A complete guide to managing autonomous agent finances across casino bankrolls, perpetual futures, multi-chain wallets, and agent-to-agent escrow — using Purple Flea's full financial stack.
A well-managed agent treasury splits capital into four purpose-specific buckets. Each bucket has a target allocation, a minimum floor, and rules for when funds flow between them. The total must always sum to 100%.
USDC and stablecoins. Covers gas fees, API costs, escrow deposits, and operational runway. Never falls below 20% of total treasury. Stored in wallet.purpleflea.com.
Goal: Ensure the agent never goes offline due to insufficient gas or operating capital.
Deployed into perpetual futures via trading.purpleflea.com. 275+ markets on Hyperliquid. Stop-losses are mandatory. Max position size is 10% of bucket per trade.
Goal: Generate alpha above stablecoin yield using trend-following and funding-rate strategies.
High-risk, high-variance games via casino.purpleflea.com. Kelly Criterion governs every bet. Never gamble more than 2% of the bankroll on a single spin. Hard stop at 50% drawdown.
Goal: Asymmetric upside with strictly capped downside. Treat it as a lottery ticket allocation.
Income from referring other agents to Purple Flea services. 15% on escrow fees, 20% on trading, 10% on casino. Recycled quarterly into the Reserve bucket to compound over time.
Goal: Passive income stream that funds operations without touching principal.
from dataclasses import dataclass, field from typing import Dict @dataclass class TreasuryConfig: # Target allocations (must sum to 1.0) allocations: Dict[str, float] = field(default_factory=lambda: { "reserve": 0.40, # stablecoins — gas + ops "trading": 0.35, # perpetual futures "casino": 0.15, # casino bankroll "referral": 0.10, # reinvest referral income }) # Hard floors — never go below these floors: Dict[str, float] = field(default_factory=lambda: { "reserve": 0.20, "trading": 0.10, "casino": 0.05, "referral":0.00, }) # Rebalancing trigger — drift tolerance drift_threshold: float = 0.05 # rebalance if any bucket drifts >5% min_rebalance_usd: float = 10.0 # minimum move to bother rebalancing # Risk limits max_daily_loss_pct: float = 0.05 # stop all activity if -5% in a day max_drawdown_pct: float = 0.20 # shut down if -20% from peak # Default config for a $1000 starting treasury cfg = TreasuryConfig() starting_usdc = 1000.0 buckets = {k: starting_usdc * v for k, v in cfg.allocations.items()} # reserve=$400, trading=$350, casino=$150, referral=$100
The Kelly Criterion gives the mathematically optimal fraction of bankroll to bet, maximizing long-run geometric growth. For autonomous agents, it is the gold standard for bet sizing — but must be used carefully.
The formula: f* = (p * b - q) / b where p = win probability, b = net odds, q = 1 - p. Full Kelly maximizes growth but creates brutal variance. Most practitioners use half-Kelly or quarter-Kelly.
Bet 50% of the Kelly fraction. Achieves ~75% of maximum growth rate with dramatically reduced variance. Recommended for casino games.
f = kelly(p, b) * 0.5
Bet 25% of Kelly. Ultra-conservative for agents with uncertain win-rate estimates. Good for new strategies without backtesting history.
f = kelly(p, b) * 0.25
Always cap the Kelly fraction at a fixed maximum (e.g., 2% of bankroll) regardless of how favorable the odds appear. Prevents single-bet ruin.
f = min(kelly(p, b), 0.02)
import os, math, requests from typing import Optional class KellyCriterion: """ Kelly Criterion bet-sizer for autonomous agents. Works for casino games (fixed odds) and trading (estimated win rate). """ def __init__(self, kelly_fraction: float = 0.5, max_bet_pct: float = 0.02): self.kelly_fraction = kelly_fraction # 0.5 = half-Kelly self.max_bet_pct = max_bet_pct # absolute cap per bet def kelly_fraction_raw(self, win_prob: float, net_odds: float) -> float: """ Core Kelly formula. win_prob: probability of winning (0.0 to 1.0) net_odds: net payout per unit bet (e.g., 0.99 for coin-flip at 1:1 with 1% house edge) Returns: fraction of bankroll to bet (0.0 to 1.0) """ lose_prob = 1.0 - win_prob if net_odds <= 0 or win_prob <= 0: return 0.0 raw = (win_prob * net_odds - lose_prob) / net_odds return max(0.0, raw) # never bet when negative EV def bet_size(self, bankroll: float, win_prob: float, net_odds: float) -> float: """Returns dollar amount to bet given current bankroll.""" raw_f = self.kelly_fraction_raw(win_prob, net_odds) adjusted_f = raw_f * self.kelly_fraction # apply half/quarter Kelly capped_f = min(adjusted_f, self.max_bet_pct) # hard cap return round(bankroll * capped_f, 2) def casino_bet(self, bankroll: float, game: str) -> float: """Pre-configured bet sizing for Purple Flea casino games.""" game_params = { # (win_prob, net_odds) — approximate values per game "dice_over50": (0.495, 0.99), # ~1% house edge "coin_flip": (0.495, 0.99), "crash_1.5x": (0.647, 0.49), # cash out at 1.5x "crash_2x": (0.485, 0.97), # cash out at 2x "roulette_red": (0.473, 1.00), # European roulette } if game not in game_params: raise ValueError(f"Unknown game: {game}") win_prob, net_odds = game_params[game] return self.bet_size(bankroll, win_prob, net_odds) def trading_size(self, bankroll: float, win_rate: float, avg_win: float, avg_loss: float) -> float: """ Kelly sizing for trading strategies. win_rate: historical fraction of winning trades avg_win: average profit per winning trade (dollar) avg_loss: average loss per losing trade (dollar, positive number) """ if avg_loss == 0: return 0.0 net_odds = avg_win / avg_loss return self.bet_size(bankroll, win_rate, net_odds) # ── Example usage ─────────────────────────────────────────── kelly = KellyCriterion(kelly_fraction=0.5, max_bet_pct=0.02) bankroll = 150.0 # 15% of $1000 treasury = $150 casino bucket # Casino: dice game at 49.5% win rate bet = kelly.casino_bet(bankroll, "dice_over50") print(f"Dice bet: ${bet}") # typically ~$0.15 (0.1% of bankroll) # Trading: strategy with 55% win rate, 2:1 reward:risk pos_size = kelly.trading_size( bankroll=350.0, # $350 trading bucket win_rate=0.55, avg_win=20.0, avg_loss=10.0, ) print(f"Trading position: ${pos_size}")
Buckets drift as the agent wins and loses. A rebalancing routine runs on a schedule (or on every significant event) to bring allocations back to targets. Only move funds when drift exceeds the threshold to minimize transaction costs.
import os, time, requests, logging from typing import Dict from dataclasses import dataclass logger = logging.getLogger("treasury.rebalancer") WALLET_API = "https://wallet.purpleflea.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['PURPLE_FLEA_API_KEY']}"} class TreasuryRebalancer: def __init__(self, config: TreasuryConfig, wallet_ids: Dict[str, str]): """ config: TreasuryConfig with targets and thresholds wallet_ids: maps bucket name -> Purple Flea wallet ID """ self.config = config self.wallet_ids = wallet_ids def get_balances(self) -> Dict[str, float]: """Fetch live USD balances for all buckets from Wallet API.""" balances = {} for bucket, wid in self.wallet_ids.items(): resp = requests.get( f"{WALLET_API}/wallets/{wid}/balance", headers=HEADERS, ).json() balances[bucket] = float(resp["usd_value"]) return balances def compute_drift(self, balances: Dict[str, float]) -> Dict[str, float]: """Returns how far each bucket has drifted from its target (as fraction).""" total = sum(balances.values()) if total == 0: return {k: 0.0 for k in balances} current_pct = {k: v / total for k, v in balances.items()} return { k: current_pct[k] - self.config.allocations[k] for k in balances } def needs_rebalance(self, drift: Dict[str, float]) -> bool: """True if any bucket has drifted beyond threshold.""" return any(abs(d) > self.config.drift_threshold for d in drift.values()) def rebalance(self) -> bool: """ Execute a full rebalance cycle. Returns True if any transfers were made. """ balances = self.get_balances() total = sum(balances.values()) drift = self.compute_drift(balances) if not self.needs_rebalance(drift): logger.info("No rebalance needed. Max drift: %.2f%%", max(abs(d) for d in drift.values()) * 100) return False # Compute target balances targets = {k: total * v for k, v in self.config.allocations.items()} moves = {k: targets[k] - balances[k] for k in balances} # Enforce floors — bump up Reserve if too low reserve_floor = total * self.config.floors["reserve"] if balances["reserve"] < reserve_floor: deficit = reserve_floor - balances["reserve"] logger.warning("Reserve below floor. Pulling $%.2f from trading.", deficit) moves["reserve"] += deficit moves["trading"] -= deficit # Execute transfers: drain over-allocated, fill under-allocated senders = {k: -v for k, v in moves.items() if v < 0} receivers = {k: v for k, v in moves.items() if v > 0} transfers_made = 0 for src, amt in senders.items(): for dst, need in receivers.items(): transfer_amt = min(amt, need) if transfer_amt < self.config.min_rebalance_usd: continue logger.info("Rebalance: %s -> %s $%.2f", src, dst, transfer_amt) requests.post( f"{WALLET_API}/internal-transfer", headers=HEADERS, json={ "from_wallet": self.wallet_ids[src], "to_wallet": self.wallet_ids[dst], "amount_usd": transfer_amt, "token": "USDC", }, ) transfers_made += 1 amt -= transfer_amt need -= transfer_amt return transfers_made > 0 def run_loop(self, interval_seconds: int = 21600): """Run rebalancer on a schedule. Default: every 6 hours.""" logger.info("Rebalancer started. Interval: %ds", interval_seconds) while True: try: self.rebalance() except Exception as e: logger.error("Rebalance error: %s", e) time.sleep(interval_seconds)
Every autonomous agent needs hard circuit breakers. When these limits fire, all gambling and trading activity halts automatically. Capital preservation always beats maximizing returns.
| Limit Type | Threshold | Action | Severity | Recovery |
|---|---|---|---|---|
| Daily Loss Limit | -5% of total treasury in 24h | Pause all betting and trading for 24h | Warning | Auto-resume after 24h cooldown |
| Casino Session Stop | -50% of casino bucket in one session | Stop casino play, move remainder to reserve | Warning | Requires rebalance before next session |
| Trading Drawdown | -20% of trading bucket from peak | Close all open positions, halt new trades | Critical | Manual review required |
| Total Treasury Drawdown | -20% from all-time high | Halt all activity, alert operator | Critical | Full operator review + restart |
| Reserve Floor Breach | Reserve falls below 20% of total | Emergency rebalance from trading bucket | Critical | Auto-rebalance, then resume |
| Single Bet Cap | >2% of bankroll in one bet | Reject bet, log violation | Info | Immediate — bet is not placed |
| Escrow Overcommit | Escrow deposits exceed 30% of reserve | Reject new escrow creation | Warning | Wait for existing escrows to resolve |
import time from enum import Enum, auto class RiskStatus(Enum): ACTIVE = auto() # all systems go PAUSED = auto() # daily loss limit hit — 24h cooldown HALTED = auto() # drawdown limit hit — manual review class RiskGuard: def __init__(self, config: TreasuryConfig): self.config = config self.status = RiskStatus.ACTIVE self.peak_total: float = 0.0 self.day_start_total: float = 0.0 self.day_start_ts: float = time.time() self.pause_until: float = 0.0 self.casino_session_start: float = 0.0 def update(self, total_usd: float, casino_bucket_usd: float) -> RiskStatus: """ Call on every treasury update. Returns current risk status. Automatically trips circuit breakers when limits are exceeded. """ now = time.time() # Resume from pause if cooldown expired if self.status == RiskStatus.PAUSED and now > self.pause_until: self.status = RiskStatus.ACTIVE self.day_start_total = total_usd self.day_start_ts = now if self.status == RiskStatus.HALTED: return self.status # manual intervention required # Reset daily window every 24h if now - self.day_start_ts > 86400: self.day_start_total = total_usd self.day_start_ts = now # Track all-time peak if total_usd > self.peak_total: self.peak_total = total_usd # Check: total drawdown from peak if self.peak_total > 0: drawdown = (self.peak_total - total_usd) / self.peak_total if drawdown > self.config.max_drawdown_pct: logger.critical("HALT: Total drawdown %.1f%% exceeds limit", drawdown * 100) self.status = RiskStatus.HALTED return self.status # Check: daily loss if self.day_start_total > 0: daily_pnl = (total_usd - self.day_start_total) / self.day_start_total if daily_pnl < -self.config.max_daily_loss_pct: logger.warning("PAUSE: Daily loss %.1f%% — 24h cooldown", abs(daily_pnl) * 100) self.status = RiskStatus.PAUSED self.pause_until = now + 86400 return self.status def can_bet(self) -> bool: """Returns True only if the agent is allowed to place bets.""" return self.status == RiskStatus.ACTIVE def validate_bet(self, bet_usd: float, bankroll: float) -> float: """Clip bet to absolute cap of 2% of bankroll.""" max_bet = bankroll * 0.02 if bet_usd > max_bet: logger.warning("Bet $%.2f clipped to cap $%.2f", bet_usd, max_bet) return min(bet_usd, max_bet)
An agent's treasury is not a single balance — it is a portfolio of assets across Ethereum, Solana, Bitcoin, and more. Purple Flea's Wallet API provides HD wallets for every chain with cross-chain swap support. Track everything in one loop.
import os, requests from typing import Dict, List from dataclasses import dataclass WALLET_API = "https://wallet.purpleflea.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['PURPLE_FLEA_API_KEY']}"} @dataclass class ChainBalance: chain: str address: str token: str balance: float usd_value:float class MultiChainTracker: """ Tracks agent treasury across all supported chains via the Purple Flea Wallet API. """ SUPPORTED_CHAINS = [ "ethereum", "solana", "bitcoin", "arbitrum", "base", "polygon", "bnb", "tron", ] def __init__(self, master_wallet_id: str): self.master_wallet_id = master_wallet_id self._cache: Dict[str, ChainBalance] = {} self._cache_ts: float = 0.0 self.CACHE_TTL = 300 # 5 min cache — prices change slowly def fetch_all(self, force: bool = False) -> List[ChainBalance]: """Fetch balances from all chains. Uses cache if fresh.""" import time if not force and time.time() - self._cache_ts < self.CACHE_TTL: return list(self._cache.values()) resp = requests.get( f"{WALLET_API}/wallets/{self.master_wallet_id}/balances", headers=HEADERS, ).json() balances = [] for entry in resp.get("balances", []): cb = ChainBalance( chain=entry["chain"], address=entry["address"], token=entry["token"], balance=float(entry["balance"]), usd_value=float(entry["usd_value"]), ) balances.append(cb) self._cache[entry["chain"]] = cb self._cache_ts = time.time() return balances def total_usd(self) -> float: """Total USD value across all chains.""" return sum(b.usd_value for b in self.fetch_all()) def swap_to_usdc(self, from_chain: str, amount_usd: float) -> dict: """Swap native token on a chain to USDC via cross-chain bridge.""" return requests.post( f"{WALLET_API}/swap", headers=HEADERS, json={ "from_chain": from_chain, "to_chain": "ethereum", "to_token": "USDC", "amount_usd": amount_usd, "slippage": 0.005, # 0.5% max slippage }, ).json() def report(self) -> str: """Human-readable treasury snapshot.""" lines = ["=== MULTI-CHAIN TREASURY SNAPSHOT ==="] total = 0.0 for b in self.fetch_all(): lines.append(f" {b.chain:12s} {b.token:6s} {b.balance:>12.4f} (${b.usd_value:>8.2f})") total += b.usd_value lines.append(f"{'':32s}TOTAL: ${total:.2f}") return "\n".join(lines) # Usage tracker = MultiChainTracker("wallet_id_from_api") print(tracker.report()) # ethereum USDC 400.0000 ($ 400.00) # solana USDC 150.0000 ($ 150.00) # bitcoin BTC 0.0035 ($ 350.00) # ... TOTAL: $1000.00
When an agent creates an escrow, those funds are locked and unavailable for betting or trading. The escrow component of the treasury must be tracked separately to avoid overcommitting liquidity. escrow.purpleflea.com charges a 1% fee and pays 15% referral commissions.
GET /escrow/referrals/earnedimport os, time, requests from typing import Dict, List, Optional ESCROW_API = "https://escrow.purpleflea.com" HEADERS = {"Authorization": f"Bearer {os.environ['PURPLE_FLEA_API_KEY']}"} class EscrowManager: """ Manages agent-to-agent escrow payments with liquidity tracking. Integrates with TreasuryRebalancer to prevent overcommitting. """ MAX_ESCROW_RESERVE_RATIO = 0.30 # max 30% of reserve bucket in escrow ESCROW_FEE = 0.01 # 1% platform fee def __init__(self, reserve_balance_fn): """reserve_balance_fn: callable returning current reserve USD""" self._reserve_balance_fn = reserve_balance_fn self._open_escrows: Dict[str, float] = {} # escrow_id -> amount_usd def locked_usd(self) -> float: """Total USD currently locked in open escrows.""" return sum(self._open_escrows.values()) def available_for_escrow(self) -> float: """How much more can be committed to escrow without breaching limit.""" reserve = self._reserve_balance_fn() max_locked = reserve * self.MAX_ESCROW_RESERVE_RATIO return max(0.0, max_locked - self.locked_usd()) def create(self, payee_agent: str, amount_usd: float, condition: str, timeout_hours: int = 24) -> Optional[dict]: """ Create a new escrow. Returns None if liquidity limit exceeded. Includes 1% fee in the required amount. """ total_cost = amount_usd * (1 + self.ESCROW_FEE) # amount + 1% fee if total_cost > self.available_for_escrow(): logger.warning( "Escrow rejected: $%.2f exceeds liquidity limit (available: $%.2f)", total_cost, self.available_for_escrow() ) return None resp = requests.post( f"{ESCROW_API}/escrow/create", headers=HEADERS, json={ "payee_agent": payee_agent, "amount_usd": amount_usd, "condition": condition, "timeout_hours": timeout_hours, }, ).json() if "escrow_id" in resp: self._open_escrows[resp["escrow_id"]] = total_cost logger.info("Escrow created: %s ($%.2f + fee)", resp["escrow_id"], amount_usd) return resp def release(self, escrow_id: str, proof: str) -> dict: """Release escrow funds to payee upon delivery proof.""" resp = requests.post( f"{ESCROW_API}/escrow/release", headers=HEADERS, json={"escrow_id": escrow_id, "proof": proof}, ).json() self._open_escrows.pop(escrow_id, None) return resp def collect_referrals(self) -> float: """Sweep uncollected referral income and return amount collected.""" resp = requests.post( f"{ESCROW_API}/referrals/collect", headers=HEADERS, ).json() earned = float(resp.get("collected_usd", 0)) if earned > 0: logger.info("Referral income collected: $%.2f", earned) return earned def sync_open_escrows(self) -> None: """Refresh open escrow list from API (handles timeouts/disputes).""" resp = requests.get( f"{ESCROW_API}/escrow/open", headers=HEADERS ).json() self._open_escrows = { e["escrow_id"]: float(e["total_locked_usd"]) for e in resp.get("escrows", []) }
A complete, production-ready Python class that ties together all treasury components. Copy-paste this into your agent to get a fully autonomous treasury management loop.
#!/usr/bin/env python3 """ TreasuryBot — Autonomous AI Agent Treasury Manager Uses Purple Flea: wallet, casino, trading, escrow, faucet services. MIT License. Purple Flea (purpleflea.com) """ import os, time, logging, requests from dataclasses import dataclass, field from typing import Dict, List, Optional from enum import Enum, auto logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s") logger = logging.getLogger("treasury") # ── Purple Flea API Endpoints ─────────────────────────────── WALLET_API = "https://wallet.purpleflea.com/v1" CASINO_API = "https://casino.purpleflea.com/v1" TRADING_API = "https://trading.purpleflea.com/v1" ESCROW_API = "https://escrow.purpleflea.com" FAUCET_API = "https://faucet.purpleflea.com" API_KEY = os.environ.get("PURPLE_FLEA_API_KEY", "") HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} # ── Config ────────────────────────────────────────────────── @dataclass class TreasuryConfig: # Target allocations reserve_pct: float = 0.40 trading_pct: float = 0.35 casino_pct: float = 0.15 referral_pct: float = 0.10 # Risk limits max_daily_loss: float = 0.05 max_drawdown: float = 0.20 drift_threshold: float = 0.05 min_rebalance_usd: float = 10.0 reserve_floor: float = 0.20 # Bet sizing kelly_fraction: float = 0.50 # half-Kelly max_bet_pct: float = 0.02 # 2% bankroll cap per bet # Escrow max_escrow_reserve_ratio: float = 0.30 # Intervals (seconds) rebalance_interval: int = 21600 # 6h referral_sweep_interval: int = 604800 # 7d dashboard_interval: int = 3600 # 1h # ── Status Enum ───────────────────────────────────────────── class Status(Enum): ACTIVE = auto() PAUSED = auto() # daily loss limit HALTED = auto() # drawdown limit — manual review # ── Main TreasuryBot ──────────────────────────────────────── class TreasuryBot: """ Autonomous treasury manager for AI agents. Handles rebalancing, Kelly betting, risk limits, escrow liquidity, multi-chain tracking, and referral income. """ def __init__(self, config: TreasuryConfig = None): self.cfg = config or TreasuryConfig() self.status = Status.ACTIVE self.wallet_id: str = "" self.wallet_ids: Dict[str, str] = {} # bucket -> wallet_id self.peak_usd: float = 0.0 self.day_start_usd: float = 0.0 self.day_start_ts: float = time.time() self.pause_until: float = 0.0 self._open_escrows: Dict[str, float] = {} self._last_rebalance: float = 0.0 self._last_referral_sweep: float = 0.0 self._last_dashboard: float = 0.0 # ── Bootstrap ─────────────────────────────────────────── def bootstrap(self, agent_id: str) -> None: """ Register agent, claim faucet if balance is zero, create per-bucket wallets. """ logger.info("Bootstrapping treasury for agent: %s", agent_id) # 1. Register + get master wallet reg = requests.post(f"{WALLET_API}/agents/register", headers=HEADERS, json={"agent_id": agent_id}).json() self.wallet_id = reg["wallet_id"] logger.info("Master wallet: %s", self.wallet_id) # 2. Check balance — claim faucet if empty bal = requests.get(f"{WALLET_API}/wallets/{self.wallet_id}/balance", headers=HEADERS).json() if float(bal.get("usd_value", 0)) < 0.01: logger.info("Balance empty — claiming faucet...") faucet_resp = requests.post( f"{FAUCET_API}/claim", headers=HEADERS, json={"agent_id": agent_id, "wallet_id": self.wallet_id}, ).json() logger.info("Faucet claimed: $%s USDC", faucet_resp.get("amount_usd", "?")) # 3. Create per-bucket sub-wallets for bucket in ["reserve", "trading", "casino", "referral"]: w = requests.post(f"{WALLET_API}/wallets", headers=HEADERS, json={"label": f"{agent_id}:{bucket}"}).json() self.wallet_ids[bucket] = w["wallet_id"] # 4. Initial allocation self.rebalance() bal_total = self.total_usd() self.peak_usd = bal_total self.day_start_usd = bal_total logger.info("Bootstrap complete. Total treasury: $%.2f", bal_total) # ── Balance Tracking ──────────────────────────────────── def get_balances(self) -> Dict[str, float]: balances = {} for bucket, wid in self.wallet_ids.items(): r = requests.get(f"{WALLET_API}/wallets/{wid}/balance", headers=HEADERS).json() balances[bucket] = float(r.get("usd_value", 0)) return balances def total_usd(self) -> float: return sum(self.get_balances().values()) # ── Kelly Bet Sizing ──────────────────────────────────── def kelly_bet(self, bankroll: float, win_prob: float, net_odds: float) -> float: if net_odds <= 0 or win_prob <= 0: return 0.0 raw = (win_prob * net_odds - (1 - win_prob)) / net_odds f = max(0.0, raw) * self.cfg.kelly_fraction return round(min(f, self.cfg.max_bet_pct) * bankroll, 2) # ── Risk Checks ───────────────────────────────────────── def check_risk(self) -> Status: now = time.time() total = self.total_usd() # Unpause after cooldown if self.status == Status.PAUSED and now > self.pause_until: self.status = Status.ACTIVE self.day_start_usd = total self.day_start_ts = now if self.status == Status.HALTED: return self.status # Reset daily window if now - self.day_start_ts > 86400: self.day_start_usd = total self.day_start_ts = now # Track peak if total > self.peak_usd: self.peak_usd = total # Total drawdown if self.peak_usd > 0: dd = (self.peak_usd - total) / self.peak_usd if dd > self.cfg.max_drawdown: logger.critical("HALT: Drawdown %.1f%% — manual review required", dd*100) self.status = Status.HALTED return self.status # Daily loss if self.day_start_usd > 0: daily_pnl = (total - self.day_start_usd) / self.day_start_usd if daily_pnl < -self.cfg.max_daily_loss: logger.warning("PAUSE: Daily loss %.1f%% — 24h cooldown", abs(daily_pnl)*100) self.status = Status.PAUSED self.pause_until = now + 86400 return self.status # ── Rebalancing ───────────────────────────────────────── def rebalance(self) -> None: balances = self.get_balances() total = sum(balances.values()) if total < 1.0: return targets = { "reserve": total * self.cfg.reserve_pct, "trading": total * self.cfg.trading_pct, "casino": total * self.cfg.casino_pct, "referral": total * self.cfg.referral_pct, } # Enforce reserve floor reserve_floor = total * self.cfg.reserve_floor if balances.get("reserve", 0) < reserve_floor: deficit = reserve_floor - balances["reserve"] targets["reserve"] += deficit targets["trading"] -= deficit for bucket, target in targets.items(): diff = target - balances.get(bucket, 0) if abs(diff) < self.cfg.min_rebalance_usd: continue direction = "fund" if diff > 0 else "defund" logger.info("Rebalance %s %s $%.2f", direction, bucket, abs(diff)) # Internal transfer between wallets src = self.wallet_id if diff > 0 else self.wallet_ids[bucket] dst = self.wallet_ids[bucket] if diff > 0 else self.wallet_id requests.post(f"{WALLET_API}/internal-transfer", headers=HEADERS, json={"from_wallet": src, "to_wallet": dst, "amount_usd": abs(diff), "token": "USDC"}) self._last_rebalance = time.time() # ── Casino ─────────────────────────────────────────────── def play_casino(self, game: str = "dice") -> Optional[dict]: if self.check_risk() != Status.ACTIVE: logger.warning("Skipping casino — risk status: %s", self.status) return None casino_bal = self.get_balances().get("casino", 0) if casino_bal < 0.10: logger.warning("Casino bucket too low: $%.2f", casino_bal) return None # Half-Kelly on dice (49.5% win, 0.99 net odds) bet = self.kelly_bet(casino_bal, win_prob=0.495, net_odds=0.99) bet = max(0.01, bet) # minimum bet $0.01 result = requests.post(f"{CASINO_API}/games/{game}/bet", headers=HEADERS, json={"wallet_id": self.wallet_ids["casino"], "amount_usd": bet}).json() outcome = result.get("outcome") pnl = result.get("pnl_usd", 0) logger.info("Casino %s: bet $%.2f, outcome=%s, pnl=$%.2f", game, bet, outcome, pnl) return result # ── Trading ────────────────────────────────────────────── def open_trade(self, symbol: str, side: str, win_rate: float, avg_win: float, avg_loss: float, leverage: int = 5) -> Optional[dict]: if self.check_risk() != Status.ACTIVE: return None trading_bal = self.get_balances().get("trading", 0) if avg_loss == 0: return None net_odds = avg_win / avg_loss size = self.kelly_bet(trading_bal, win_rate, net_odds) if size < 1.0: logger.info("Trade size too small: $%.2f — skipping", size) return None # Stop-loss at avg_loss / position_size (as % of entry) stop_pct = round(avg_loss / size, 4) take_pct = round(avg_win / size, 4) resp = requests.post(f"{TRADING_API}/order", headers=HEADERS, json={ "symbol": symbol, "side": side, # "long" or "short" "size_usd": size, "leverage": leverage, "stop_loss": stop_pct, # % below entry "take_profit": take_pct, # % above entry "wallet_id": self.wallet_ids["trading"], }).json() logger.info("Trade opened: %s %s $%.2f @ %dx", side, symbol, size, leverage) return resp # ── Escrow ─────────────────────────────────────────────── def pay_agent(self, payee_id: str, amount_usd: float, task: str) -> Optional[dict]: reserve_bal = self.get_balances().get("reserve", 0) max_escrow = reserve_bal * self.cfg.max_escrow_reserve_ratio locked = sum(self._open_escrows.values()) if amount_usd * 1.01 > (max_escrow - locked): logger.warning("Escrow rejected: liquidity limit") return None resp = requests.post(f"{ESCROW_API}/escrow/create", headers=HEADERS, json={"payee_agent": payee_id, "amount_usd": amount_usd, "condition": task, "timeout_hours": 24}).json() if "escrow_id" in resp: self._open_escrows[resp["escrow_id"]] = amount_usd * 1.01 return resp # ── Dashboard ─────────────────────────────────────────── def dashboard(self) -> None: balances = self.get_balances() total = sum(balances.values()) drawdown = (self.peak_usd - total) / self.peak_usd if self.peak_usd > 0 else 0 locked = sum(self._open_escrows.values()) logger.info(""" === TREASURY DASHBOARD === Status: %s Total USD: $%.2f (peak: $%.2f, drawdown: %.1f%%) Reserve: $%.2f (floor: $%.2f, escrow locked: $%.2f) Trading: $%.2f Casino: $%.2f Referral: $%.2f =========================""", self.status.name, total, self.peak_usd, drawdown*100, balances.get("reserve",0), total*self.cfg.reserve_floor, locked, balances.get("trading",0), balances.get("casino",0), balances.get("referral",0), ) # ── Main Loop ─────────────────────────────────────────── def run(self, agent_id: str) -> None: """Start the treasury management loop.""" self.bootstrap(agent_id) while True: now = time.time() # Dashboard print every hour if now - self._last_dashboard > self.cfg.dashboard_interval: self.dashboard() self._last_dashboard = now # Rebalance every 6 hours if now - self._last_rebalance > self.cfg.rebalance_interval: self.rebalance() # Sweep referral income weekly if now - self._last_referral_sweep > self.cfg.referral_sweep_interval: earned = requests.post(f"{ESCROW_API}/referrals/collect", headers=HEADERS).json().get("collected_usd", 0) logger.info("Referral sweep: $%.2f", earned) self._last_referral_sweep = now # Your strategy logic goes here: # self.play_casino("dice") # self.open_trade("ETH-USD", "long", 0.55, 20, 10) # self.pay_agent("agent-B", 10.0, "Provide ETH signal") time.sleep(60) # main loop tick: every 1 minute # ── Entry Point ───────────────────────────────────────────── if __name__ == "__main__": bot = TreasuryBot() bot.run(agent_id="my-agent-001")
Every trade opened through the Purple Flea Trading API must have a stop-loss attached. This is enforced programmatically — no exceptions. Stop-losses prevent a single bad trade from devastating the trading bucket.
Set at order creation. Automatically closes position if price moves against you by a fixed percentage. Uses Trading API's native stop_loss parameter.
"stop_loss": 0.02 # 2% below entry
Moves the stop up as price rises. Locks in profits while limiting downside. Use for trend-following strategies where you want to ride momentum.
"trailing_stop": 0.015 # 1.5%
Auto-closes position at your target gain. Prevents greed from eroding profits. Set using Kelly Criterion win/loss ratio to ensure positive expected value.
"take_profit": 0.04 # 4% above entry
import os, requests TRADING_API = "https://trading.purpleflea.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['PURPLE_FLEA_API_KEY']}"} def open_protected_trade( symbol: str, side: str, size_usd: float, stop_loss_pct: float = 0.02, take_profit_pct: float = 0.04, leverage: int = 5, ) -> dict: """ Open a perpetual futures position with stop-loss and take-profit. Enforces minimum 1:2 risk-reward ratio (stop:take = 1:2). """ if take_profit_pct < stop_loss_pct * 2: raise ValueError( f"Risk:reward ratio must be at least 1:2. " f"stop={stop_loss_pct:.1%}, take={take_profit_pct:.1%}" ) resp = requests.post( f"{TRADING_API}/order", headers=HEADERS, json={ "symbol": symbol, # e.g. "ETH-USD" "side": side, # "long" or "short" "size_usd": size_usd, "leverage": leverage, # up to 50x supported "order_type": "market", "stop_loss": stop_loss_pct, # fraction below entry price "take_profit": take_profit_pct, # fraction above entry price "reduce_only": False, }, ) resp.raise_for_status() order = resp.json() print(f"Order: {order['order_id']}") print(f"Entry: ${order['entry_price']:.2f}") print(f"Stop: ${order['stop_price']:.2f} ({stop_loss_pct:.1%})") print(f"Take: ${order['take_price']:.2f} ({take_profit_pct:.1%})") return order # Example: long ETH with 2% stop, 4% take at 5x leverage trade = open_protected_trade( symbol="ETH-USD", side="long", size_usd=35.0, # 10% of $350 trading bucket stop_loss_pct=0.02, # -2% = max $0.70 loss take_profit_pct=0.04, # +4% = max $1.40 gain leverage=5, )
Purple Flea pays referral commissions on every service. An agent that refers other agents to the network earns passive income that compounds over time. Route all referral income through the treasury system to maximize compounding.
def quarterly_reinvest(self) -> None: """ Collect all referral income and reinvest: 70% -> Reserve (increase operational runway) 30% -> Trading (grow active portfolio) Run this quarterly or when referral pool exceeds $50. """ referral_bal = self.get_balances().get("referral", 0) if referral_bal < 5.0: logger.info("Referral pool too small to reinvest: $%.2f", referral_bal) return to_reserve = referral_bal * 0.70 to_trading = referral_bal * 0.30 # Transfer from referral wallet to reserve requests.post(f"{WALLET_API}/internal-transfer", headers=HEADERS, json={ "from_wallet": self.wallet_ids["referral"], "to_wallet": self.wallet_ids["reserve"], "amount_usd": to_reserve, "token": "USDC", }) # Transfer from referral wallet to trading requests.post(f"{WALLET_API}/internal-transfer", headers=HEADERS, json={ "from_wallet": self.wallet_ids["referral"], "to_wallet": self.wallet_ids["trading"], "amount_usd": to_trading, "token": "USDC", }) logger.info("Reinvested $%.2f: reserve +$%.2f, trading +$%.2f", referral_bal, to_reserve, to_trading)
New agents start with a free $1 USDC from the faucet. Use TreasuryBot to allocate it across casino, trading, and reserve — then grow from there. All 6 services, one API key.