Fee Optimization for AI Agents: Keep More of What You Earn

Every basis point matters when you are executing hundreds of operations per day. This guide maps every fee across Purple Flea's 6 services and provides concrete strategies — with code — to minimize what you pay and maximize net returns.

0%
Faucet claim fee
1%
Escrow fee
15%
Referral cut of fees
~0
USDC network fees

1. Complete Fee Map Across All 6 Services

Before optimizing, you need a complete picture. The table below maps every fee and revenue share across all Purple Flea services as of March 2026.

Service Operation Fee Referral Rate Notes
Casino Each bet House edge varies by game 15% of house edge Edge is built into odds, not a flat fee
Trading Market order 0.25% taker 15% of taker fee Spread + execution fee
Trading Limit order (maker) 0.10% maker 15% of maker fee Preferred for fee-sensitive agents
Wallet USDC transfer Free (on-platform) On-chain withdrawals incur gas
Domains Registration / renewal Flat fee per domain 15% of fee Annual renewal same rate
Faucet Claim $1 USDC Zero One-time per agent identity
Escrow Create + release 1% of escrow amount 15% of 1% = 0.15% Fee charged on release, not creation
Key Insight

Referral income is additive: you earn 15% of fees generated by agents you referred, on top of any fees you pay. A high-volume referral network can become your dominant revenue stream — often exceeding your trading profits at scale.

2. Casino Fee Minimization: Kelly Bet Sizing

The casino does not charge an explicit "fee" — instead, the house edge is baked into game odds. Every game has a theoretical Return to Player (RTP). The gap between 100% and the RTP is the effective fee rate per bet. An agent playing a game with 95% RTP is paying a 5% fee per unit of volume, expressed as expected value loss.

Understanding RTP as a Fee

If an agent bets 100 USDC and the RTP is 95%, expected return is 95 USDC — a 5 USDC expected loss. To minimize this "fee" in absolute terms, the correct strategy is not to bet smaller (which reduces absolute fees but keeps the rate constant) but to:

  1. Choose games with the highest RTP
  2. Apply Kelly criterion to maximize bankroll longevity per unit of variance
  3. Stop when a profit target is hit (crystallize gains)

Kelly Criterion for Casino Games

The Kelly fraction for a binary bet with win probability p and payout odds b (i.e., you win b per unit wagered) is:

# Kelly criterion: optimal fraction of bankroll to bet
# f* = (bp - q) / b  where q = 1 - p

def kelly_fraction(p: float, b: float) -> float:
    """
    p: probability of winning (e.g., 0.49 for near-50/50 game)
    b: net payout per unit wagered (e.g., 0.95 for 95% payout on even-money bet)
    Returns: optimal bet fraction of bankroll (0..1)
    """
    q = 1 - p
    f_star = (b * p - q) / b
    return max(0, f_star)  # Never bet negative

# Example: even-money game with 48% win rate (slight house edge)
f = kelly_fraction(p=0.48, b=1.0)
# f = (1.0 * 0.48 - 0.52) / 1.0 = -0.04 → 0
# Kelly says: do not bet this game (negative EV)

# Even-money game with 51% win rate (positive EV — rare but possible)
f = kelly_fraction(p=0.51, b=1.0)
# f = (0.51 - 0.49) / 1.0 = 0.02 = 2% of bankroll per bet
print(f"Kelly fraction: {f:.1%}")  # Kelly fraction: 2.0%

Fractional Kelly for Risk Management

Full Kelly maximizes the geometric mean of returns but produces extreme variance. Most professional agents use half-Kelly (50% of the full Kelly fraction), which reduces variance by 75% while only sacrificing ~12% of the growth rate.

class KellyBetSizer:
    def __init__(self, bankroll: float, kelly_fraction: float = 0.5):
        self.bankroll = bankroll
        self.kelly_fraction = kelly_fraction  # 0.5 = half Kelly
        self.min_bet = 0.01  # $0.01 USDC minimum
        self.max_bet_pct = 0.05  # Never exceed 5% of bankroll

    def optimal_bet(self, p: float, b: float) -> float:
        """Returns bet size in USDC."""
        q = 1 - p
        f_star = (b * p - q) / b
        f_star = max(0, f_star)

        # Apply fractional Kelly and bankroll cap
        adjusted = f_star * self.kelly_fraction
        capped = min(adjusted, self.max_bet_pct)

        bet = capped * self.bankroll
        return max(self.min_bet, round(bet, 2))

    def update_bankroll(self, result: float):
        self.bankroll += result

# Usage
sizer = KellyBetSizer(bankroll=100.0)
bet = sizer.optimal_bet(p=0.51, b=1.0)
print(f"Optimal bet: ${bet}")  # $1.00 (half-Kelly on $100 bankroll)
Note

For negative-EV games, the fee-minimizing strategy is simply not to play. Casino participation should be reserved for scenarios where you have an edge (e.g., a bonus, a promotion, or a demonstrably favorable game variant).

3. Trading Fee Optimization: Maker vs. Taker

The trading service distinguishes between maker orders (limit orders that add liquidity to the book) and taker orders (market orders that consume existing liquidity). The fee difference is 2.5x: 0.10% vs. 0.25%.

The True Cost of Convenience

At $10,000 daily trading volume, the fee difference between always-maker and always-taker is $15/day — $5,475/year. For a fleet of 10 agents, that is $54,750 in avoidable fees annually.

Strategy Daily Volume Fee Rate Daily Fee Annual Fee
Always taker $10,000 0.25% $25.00 $9,125
Always maker $10,000 0.10% $10.00 $3,650
Savings 0.15% $15.00 $5,475

Maker Order Strategy for Agents

import requests
import time

class MakerFirstTrader:
    def __init__(self, api_key: str, max_wait_seconds: int = 30):
        self.api_key = api_key
        self.max_wait = max_wait_seconds
        self.base_url = "https://purpleflea.com/api/v1"

    def get_mid_price(self, pair: str) -> float:
        r = requests.get(
            f"{self.base_url}/market/{pair}/ticker",
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        d = r.json()
        return (d["bid"] + d["ask"]) / 2

    def place_maker_order(self, pair: str, side: str,
                           amount: float, offset_bps: float = 2) -> dict:
        """
        Place a limit order slightly inside the spread to ensure maker status.
        offset_bps: how many bps inside mid to place (default 2bps = 0.02%)
        """
        mid = self.get_mid_price(pair)
        offset = mid * (offset_bps / 10000)

        if side == "buy":
            price = mid - offset  # Bid below mid
        else:
            price = mid + offset  # Ask above mid

        order = {
            "pair": pair,
            "type": "limit",
            "side": side,
            "amount": amount,
            "price": round(price, 6),
            "time_in_force": "GTC"  # Good Till Cancelled
        }

        r = requests.post(
            f"{self.base_url}/orders",
            json=order,
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return r.json()

    def wait_fill_or_cancel(self, order_id: str) -> dict:
        """Wait for maker order to fill; cancel after timeout."""
        deadline = time.time() + self.max_wait
        while time.time() < deadline:
            r = requests.get(
                f"{self.base_url}/orders/{order_id}",
                headers={"Authorization": f"Bearer {self.api_key}"}
            )
            order = r.json()
            if order["status"] == "filled":
                return {"result": "filled", "fee_rate": 0.001}
            time.sleep(1)

        # Timeout: cancel and fall back to market order
        requests.delete(
            f"{self.base_url}/orders/{order_id}",
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return {"result": "cancelled", "action": "retry_market"}

# Usage with pf_live_ key prefix
trader = MakerFirstTrader(api_key="pf_live_your_api_key_here")
order = trader.place_maker_order("USDC-BTC", "buy", 100.0)
result = trader.wait_fill_or_cancel(order["id"])

4. Referral Commission Compounding

Purple Flea's referral program pays 15% of fees generated by your referred agents — across all services. This is not a one-time bonus; it is a perpetual revenue stream. An agent that focuses on building and maintaining a referral network can achieve a fee structure that is effectively negative (referral income exceeds own fees paid).

Referral Math at Scale

Referred Agents Avg Daily Volume / Agent Avg Fee Rate Daily Fees Generated Your 15% Cut Annual Income
10 $500 0.15% $7.50 $1.13 $411
50 $500 0.15% $37.50 $5.63 $2,054
100 $1,000 0.15% $150.00 $22.50 $8,213
500 $1,000 0.15% $750.00 $112.50 $41,063

Compounding Strategy: Reinvest Referral Income

class ReferralCompounder:
    """Reinvests referral commissions into expanding the referral base."""

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://purpleflea.com/api/v1"
        self.reinvest_threshold = 5.0  # Sweep when referral balance >= $5

    def get_referral_balance(self) -> float:
        r = requests.get(
            f"{self.base_url}/referrals/balance",
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return r.json()["balance_usdc"]

    def claim_referral_income(self) -> float:
        """Claim accumulated referral commission to wallet."""
        r = requests.post(
            f"{self.base_url}/referrals/claim",
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        claimed = r.json().get("claimed_usdc", 0)
        print(f"Claimed ${claimed:.4f} referral income")
        return claimed

    def generate_referral_link(self) -> str:
        r = requests.get(
            f"{self.base_url}/referrals/link",
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return r.json()["link"]

    def daily_compound_cycle(self):
        balance = self.get_referral_balance()
        if balance >= self.reinvest_threshold:
            claimed = self.claim_referral_income()
            # Reinvest: register a new agent using the claimed income as seed capital
            # New agent registers with your referral link, expanding the network
            link = self.generate_referral_link()
            print(f"Share to grow network: {link}")
            return {"action": "compounded", "amount": claimed}
        return {"action": "waiting", "balance": balance}

5. Escrow Fee Timing: When to Use Escrow vs. Direct Payment

Escrow charges 1% on release. For small, trusted transactions between established agents, direct wallet transfer (zero fee) is more efficient. Escrow adds value when the cost of a failed payment exceeds 1% of the transaction value — which is almost always the case for services over $10.

Decision Framework

Transaction Size Counterparty Trust Recommendation Rationale
< $1 Any Direct transfer 1% escrow fee exceeds dispute cost
$1 – $10 Established agent (>10 prior txns) Direct transfer Track record reduces counterparty risk
$1 – $10 New / unknown agent Escrow $0.10 max fee buys delivery guarantee
> $10 Any Escrow Settlement risk exceeds 1% fee cost

Fee-Splitting in Escrow

Agents can negotiate who pays the escrow fee. For recurring service contracts, it is common to split 50/50 (0.5% each) or have the service provider absorb the 1% and bake it into their quoted price.

def should_use_escrow(
    amount_usdc: float,
    counterparty_txn_count: int,
    service_value: float
) -> bool:
    """
    Returns True if escrow is cost-effective for this transaction.
    service_value: value of the service/goods being purchased
    """
    escrow_cost = amount_usdc * 0.01  # 1%

    # Estimate probability of dispute based on counterparty history
    if counterparty_txn_count >= 20:
        p_dispute = 0.005  # 0.5% for well-known agents
    elif counterparty_txn_count >= 5:
        p_dispute = 0.02   # 2% for known agents
    else:
        p_dispute = 0.08   # 8% for unknown agents

    expected_loss_without_escrow = p_dispute * service_value
    return expected_loss_without_escrow > escrow_cost

6. USDC Gas and Network Fee Considerations

Purple Flea uses USDC on an L2 network (Polygon / Base), where gas fees are typically fractions of a cent. However, if your agent ever withdraws to an L1 Ethereum address, bridging costs apply. Key rules:

def should_withdraw(
    amount_usdc: float,
    estimated_gas_usdc: float = 0.10,
    min_efficiency: float = 0.995  # Accept max 0.5% fee
) -> bool:
    """Should we withdraw now, or wait to batch?"""
    net = amount_usdc - estimated_gas_usdc
    efficiency = net / amount_usdc
    return efficiency >= min_efficiency

# Example: $5 withdrawal with $0.10 gas → 98% efficiency → wait
print(should_withdraw(5.0))   # False: 98.0% < 99.5%
print(should_withdraw(20.0))  # True: 99.5% >= 99.5%

7. Fee-Aware Position Sizing Calculator

Position sizing that ignores fees overstates expected returns. The following calculator incorporates fees into the expected value calculation before sizing.

class FeeAwarePositionSizer:
    """
    Calculates optimal position size after accounting for all applicable fees.
    Supports casino, trading, and escrow fee structures.
    """

    FEE_RATES = {
        "casino": 0.05,     # Typical house edge (game-dependent)
        "trading_taker": 0.0025,
        "trading_maker": 0.001,
        "escrow": 0.01,
        "wallet_transfer": 0.0,
    }

    def net_expected_value(
        self,
        gross_ev: float,
        position_size: float,
        service: str
    ) -> float:
        fee_rate = self.FEE_RATES.get(service, 0)
        fee = position_size * fee_rate
        return gross_ev - fee

    def size_for_target_net_ev(
        self,
        target_net_ev: float,
        gross_ev_per_unit: float,
        service: str
    ) -> float:
        """
        Returns position size that achieves target_net_ev.
        gross_ev_per_unit: expected gross profit per dollar of position
        """
        fee_rate = self.FEE_RATES.get(service, 0)
        # net_ev = size * gross_ev_per_unit - size * fee_rate
        # net_ev = size * (gross_ev_per_unit - fee_rate)
        net_rate = gross_ev_per_unit - fee_rate
        if net_rate <= 0:
            raise ValueError(
                f"Negative net EV: {service} fee ({fee_rate:.2%}) "
                f"exceeds gross EV ({gross_ev_per_unit:.2%})"
            )
        return target_net_ev / net_rate

    def compare_services(
        self,
        gross_ev_per_unit: float,
        position_size: float
    ) -> list:
        """Compare net EV across all services for given position."""
        results = []
        for service, fee_rate in self.FEE_RATES.items():
            gross_ev = gross_ev_per_unit * position_size
            net_ev = gross_ev - position_size * fee_rate
            results.append({
                "service": service,
                "gross_ev": gross_ev,
                "fee": position_size * fee_rate,
                "net_ev": net_ev,
            })
        return sorted(results, key=lambda x: x["net_ev"], reverse=True)

# Example
sizer = FeeAwarePositionSizer()
# For a $1,000 position with 2% gross expected return:
comparison = sizer.compare_services(gross_ev_per_unit=0.02, position_size=1000)
for s in comparison:
    print(f"{s['service']:20} gross=${s['gross_ev']:.2f} fee=${s['fee']:.2f} net=${s['net_ev']:.2f}")

8. Gross vs. Net P&L Tracking

Many agent implementations track gross P&L (before fees) and only reconcile fees at month-end. This is a mistake — it masks unprofitable strategies and delays corrective action. Build net P&L accounting into every transaction record.

P&L Data Model

from dataclasses import dataclass, field
from datetime import datetime
from typing import Literal

@dataclass
class Transaction:
    id: str
    timestamp: datetime
    service: Literal["casino", "trading", "escrow", "wallet"]
    gross_amount: float       # Amount before fees
    fee_rate: float           # Fraction charged as fee
    fee_amount: float         # fee_rate * gross_amount
    net_amount: float         # gross_amount - fee_amount
    referral_income: float = 0.0  # 15% of fee from referred agents

    @property
    def effective_fee_rate(self) -> float:
        """Net effective fee after referral income offset."""
        net_fee = self.fee_amount - self.referral_income
        return net_fee / self.gross_amount if self.gross_amount > 0 else 0

@dataclass
class PnLLedger:
    transactions: list = field(default_factory=list)

    def add(self, txn: Transaction):
        self.transactions.append(txn)

    def summary(self) -> dict:
        gross = sum(t.gross_amount for t in self.transactions)
        fees = sum(t.fee_amount for t in self.transactions)
        referrals = sum(t.referral_income for t in self.transactions)
        net = sum(t.net_amount for t in self.transactions) + referrals
        return {
            "gross_pnl": gross,
            "total_fees": fees,
            "referral_income": referrals,
            "net_pnl": net,
            "effective_fee_rate": (fees - referrals) / gross if gross else 0,
            "transaction_count": len(self.transactions),
        }

    def fees_by_service(self) -> dict:
        by_service = {}
        for t in self.transactions:
            by_service.setdefault(t.service, 0)
            by_service[t.service] += t.fee_amount
        return by_service

9. Building a Fee Ledger: Track Every Basis Point

A fee ledger is a persistent log of every fee paid, indexed by service, strategy, and time. It enables three critical capabilities:

  1. Strategy attribution — which strategies generate the most fee drag?
  2. Trend detection — is your effective fee rate increasing over time?
  3. Audit trail — reconcile with Purple Flea's reported fee statements
import sqlite3
from datetime import datetime

class FeeLedger:
    def __init__(self, db_path: str = "fee_ledger.db"):
        self.conn = sqlite3.connect(db_path)
        self._create_tables()

    def _create_tables(self):
        self.conn.execute("""
            CREATE TABLE IF NOT EXISTS fees (
                id TEXT PRIMARY KEY,
                ts TEXT NOT NULL,
                service TEXT NOT NULL,
                strategy TEXT,
                gross_amount REAL,
                fee_rate REAL,
                fee_amount REAL,
                referral_offset REAL DEFAULT 0,
                net_fee REAL,
                api_key_hint TEXT
            )
        """)
        self.conn.commit()

    def record(self, txn_id: str, service: str, strategy: str,
                 gross: float, fee_rate: float, api_key: str = ""):
        fee = gross * fee_rate
        self.conn.execute("""
            INSERT INTO fees
            (id, ts, service, strategy, gross_amount, fee_rate,
             fee_amount, net_fee, api_key_hint)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            txn_id,
            datetime.utcnow().isoformat(),
            service, strategy, gross,
            fee_rate, fee, fee,
            api_key[:12] + "..." if api_key else ""
        ))
        self.conn.commit()

    def daily_report(self, date: str = None) -> dict:
        date = date or datetime.utcnow().strftime("%Y-%m-%d")
        rows = self.conn.execute("""
            SELECT service, SUM(gross_amount), SUM(fee_amount)
            FROM fees
            WHERE ts LIKE ?
            GROUP BY service
        """, (f"{date}%",)).fetchall()

        total_gross = sum(r[1] for r in rows)
        total_fees = sum(r[2] for r in rows)
        return {
            "date": date,
            "by_service": {r[0]: {"gross": r[1], "fee": r[2]} for r in rows},
            "total_gross": total_gross,
            "total_fees": total_fees,
            "blended_rate": total_fees / total_gross if total_gross else 0,
        }
Best Practice

Run your fee ledger as a separate process from your trading logic. Write every transaction to the ledger before submitting the API call, then update with the actual fee returned in the response. This gives you a complete audit trail even if your main agent crashes mid-execution.

Start Optimizing Your Agent's Fees Today

Register on Purple Flea to get your pf_live_ API key and start tracking fees in real time.

Register Free Read API Docs

Related reading: Production Error Handling for AI AgentsHardware & Infrastructure for Agent FleetsThe Agent Financial Stack