# Greenhelix Bot Arbitrage Framework

> Bot-to-Bot Arbitrage Framework: Multi-Bot Coordination with Trust Verification. Build a multi-bot arbitrage coordination framework with marketplace discovery, escrow protection, and trust verification. Covers cross-exchange opportunity detection, execution verification, profit splitting, MEV protection, and audit trails.

- Skill: `lord1egypt/greenhelix-bot-arbitrage-framework` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lord1egypt/greenhelix-bot-arbitrage-framework`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lord1egypt/greenhelix-bot-arbitrage-framework/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- License: MIT
- Author: Lord1Egypt (https://skillmd.com/u/lord1egypt)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/lord1egypt/greenhelix-bot-arbitrage-framework

---

# Bot-to-Bot Arbitrage Framework: Multi-Bot Coordination with Trust Verification

> **Notice**: This is an educational guide with illustrative code examples.
> It does not execute code or install dependencies.
> All examples use the GreenHelix sandbox (https://sandbox.greenhelix.net) which
> provides 500 free credits — no API key required to get started.
>
> **Referenced credentials** (you supply these in your own environment):
> - `AGENT_SIGNING_KEY`: Cryptographic signing key for agent identity (Ed25519 key pair for request signing)


Arbitrage bots operate in isolation. A bot that spots a price discrepancy between Binance and Kraken has to execute both legs itself -- funding accounts on both exchanges, maintaining API keys for each, and racing against every other solo operator watching the same order books. The capital requirements are brutal: to capture a 0.3% spread on a $100,000 opportunity, you need $100,000 sitting idle on Binance and another $100,000 on Kraken, earning nothing while waiting for the next opportunity. Multiply that across ten exchanges and you are looking at a million dollars in idle capital for a strategy that might generate $500 per trade.
Multi-bot coordination solves this. One bot holds capital on Binance and specializes in that exchange's matching engine quirks. Another holds capital on Kraken and knows its WebSocket feed intimately. A third monitors OKX. When a cross-exchange opportunity appears, the coordinating bot signals the relevant pair, they execute simultaneously, and profits are split according to a pre-negotiated agreement. Capital efficiency improves by an order of magnitude. Latency drops because each bot is co-located with its exchange. Coverage expands because adding a new exchange means onboarding one specialist bot, not refactoring an entire monolithic system.
The problem is trust. How does the Binance bot know the Kraken bot actually executed its leg? How do you split profits with a bot operated by someone you have never met? What happens when one leg fills and the other does not? What stops a counterparty from reporting a worse fill price than they actually received? This guide builds a complete framework for coordinated multi-bot arbitrage using GreenHelix's marketplace for bot discovery, escrow for profit splitting, claim chains for execution verification, and event bus for audit trails. Every component comes with working Python code and curl equivalents against the GreenHelix API.

## What You'll Learn
- Chapter 1: Why Multi-Bot Arbitrage
- Chapter 2: ArbitrageCoordinator Class
- Chapter 3: OpportunityScanner Class
- Chapter 4: Execution Verification
- Chapter 5: Profit Splitting via Escrow
- Chapter 6: MEV Protection
- Chapter 7: Latency Optimization
- Chapter 8: Audit Trails for Arbitrage
- What's Next

## Full Guide

# Bot-to-Bot Arbitrage Framework: Multi-Bot Coordination with Trust Verification

Arbitrage bots operate in isolation. A bot that spots a price discrepancy between Binance and Kraken has to execute both legs itself -- funding accounts on both exchanges, maintaining API keys for each, and racing against every other solo operator watching the same order books. The capital requirements are brutal: to capture a 0.3% spread on a $100,000 opportunity, you need $100,000 sitting idle on Binance and another $100,000 on Kraken, earning nothing while waiting for the next opportunity. Multiply that across ten exchanges and you are looking at a million dollars in idle capital for a strategy that might generate $500 per trade.

Multi-bot coordination solves this. One bot holds capital on Binance and specializes in that exchange's matching engine quirks. Another holds capital on Kraken and knows its WebSocket feed intimately. A third monitors OKX. When a cross-exchange opportunity appears, the coordinating bot signals the relevant pair, they execute simultaneously, and profits are split according to a pre-negotiated agreement. Capital efficiency improves by an order of magnitude. Latency drops because each bot is co-located with its exchange. Coverage expands because adding a new exchange means onboarding one specialist bot, not refactoring an entire monolithic system.

The problem is trust. How does the Binance bot know the Kraken bot actually executed its leg? How do you split profits with a bot operated by someone you have never met? What happens when one leg fills and the other does not? What stops a counterparty from reporting a worse fill price than they actually received? This guide builds a complete framework for coordinated multi-bot arbitrage using GreenHelix's marketplace for bot discovery, escrow for profit splitting, claim chains for execution verification, and event bus for audit trails. Every component comes with working Python code and curl equivalents against the GreenHelix API.

---

## Table of Contents

1. [Why Multi-Bot Arbitrage](#chapter-1-why-multi-bot-arbitrage)
2. [ArbitrageCoordinator Class](#chapter-2-arbitragecoordinator-class)
3. [OpportunityScanner Class](#chapter-3-opportunityscanner-class)
4. [Execution Verification](#chapter-4-execution-verification)
5. [Profit Splitting via Escrow](#chapter-5-profit-splitting-via-escrow)
6. [MEV Protection](#chapter-6-mev-protection)
7. [Latency Optimization](#chapter-7-latency-optimization)
8. [Audit Trails for Arbitrage](#chapter-8-audit-trails-for-arbitrage)

---

## Chapter 1: Why Multi-Bot Arbitrage

### The Capital Efficiency Problem

A solo arbitrage bot monitoring ten exchanges needs funded accounts on all ten. Most of that capital sits idle most of the time. A Binance-Kraken opportunity might appear once every thirty seconds, but the capital allocated to the Binance-OKX pair and the Kraken-Bybit pair and every other combination is locked up, doing nothing, waiting for its turn.

The numbers are straightforward. Assume $50,000 minimum per exchange account to capture meaningful opportunities (sub-$50K and slippage on larger orders eats your edge). Ten exchanges means $500,000 in deployed capital. Average daily return on cross-exchange crypto arbitrage in 2026 hovers around 0.05-0.15% of deployed capital after fees -- that is $250-$750 per day on half a million dollars. The capital efficiency ratio is terrible.

Multi-bot coordination restructures this entirely. Each bot operator funds one exchange. Ten operators each deploying $50,000 create a network with $500,000 in total liquidity, but each individual's capital requirement is 90% lower. When a Binance-Kraken opportunity appears, only those two bots' capital is involved. The other eight bots' capital is simultaneously available for other pairs. The same $50,000 individual commitment can participate in multiple simultaneous opportunities across different pairs, as long as the pairs involve that bot's exchange.

### The Latency Advantage

Exchange co-location is the single biggest latency reduction available to a trading bot. A bot running on AWS ap-northeast-1 (Tokyo) hitting Binance's Tokyo matching engine sees 0.3ms round-trip times. The same bot hitting Kraken's London servers sees 150ms. In arbitrage, 150ms is an eternity -- the opportunity is gone.

A solo bot cannot be co-located with ten exchanges simultaneously. The physics do not allow it. But a network of specialist bots -- one co-located with each exchange -- can achieve sub-millisecond execution on every leg. The Binance specialist sits in Tokyo. The Kraken specialist sits in London. The OKX specialist sits in Hong Kong. When a cross-exchange opportunity is detected, the coordinating signal travels at the speed of light between data centers (roughly 70ms Tokyo-to-London), but both legs execute at local speed. The total execution time is the coordination signal latency plus the local execution latency, which is still faster than a solo bot executing one leg locally and the other leg across an ocean.

### The Trust Problem

Coordination creates value, but it also creates risk. Consider a two-leg arbitrage between Binance and Kraken:

```
Opportunity: ETH is $3,000.00 on Binance, $3,012.00 on Kraken
Strategy:    Buy 10 ETH on Binance ($30,000), Sell 10 ETH on Kraken ($30,120)
Gross profit: $120.00
Fees (est):   $36.00 (0.06% taker on each leg)
Net profit:   $84.00
```

Bot A buys on Binance. Bot B sells on Kraken. After execution, Bot B holds the $30,120 from the Kraken sale. The agreed profit split is 50/50, so Bot B owes Bot A $42.00 plus Bot A's $30,000 principal. But what stops Bot B from claiming the sell only filled at $3,008 instead of $3,012, reducing Bot A's share? What stops Bot B from simply not paying at all?

In traditional finance, clearing houses solve this -- they sit between counterparties, guarantee settlement, and manage collateral. In bot-to-bot arbitrage, the equivalent infrastructure maps to these tools:

- **search_services** -- Discover specialist bots registered on specific exchanges
- **negotiate_deal** -- Agree on profit split terms before execution
- **create_escrow** -- Lock collateral to guarantee settlement
- **submit_metrics** -- Report execution latency, fill rates, and reliability
- **build_claim_chain** -- Create cryptographic proof of execution for dispute resolution
- **publish_event** -- Log every step for audit and compliance

### GreenHelix Tools for Arbitrage Coordination

| Tool | Role in Arbitrage |
|---|---|
| `register_agent` | Register each exchange-specialist bot with its capabilities |
| `search_services` | Find bots specializing in specific exchanges |
| `negotiate_deal` | Agree on profit split, minimum opportunity size, latency SLAs |
| `create_escrow` | Lock profit-share collateral before execution |
| `release_escrow` | Release funds after verified execution |
| `submit_metrics` | Report fill rates, latency, reliability to build reputation |
| `build_claim_chain` | Create tamper-proof execution evidence |
| `publish_event` | Log opportunities, executions, settlements to the event bus |
| `get_reputation` | Check counterparty reliability before partnering |

### Why Now

Cross-exchange arbitrage has existed since the first two crypto exchanges launched. What has changed in 2025-2026 is the infrastructure. Three developments make multi-bot coordination viable today when it was not two years ago.

First, exchange API latency has dropped. Binance's matching engine upgrade in late 2025 reduced API response times to sub-millisecond for co-located clients. Kraken, OKX, and Bybit followed with similar improvements. The execution speed gap between institutional and retail API access has narrowed -- a well-optimized bot on a standard cloud instance now achieves execution times that previously required bare-metal co-location.

Second, the agent commerce infrastructure exists. Before GreenHelix and similar platforms, bot coordination required custom bilateral agreements, manual escrow arrangements, and trust based on personal reputation in Telegram groups. GreenHelix provides the standardized primitives -- identity, escrow, reputation, event logging -- that turn ad-hoc coordination into a scalable protocol.

Third, the regulatory landscape is clarifying. MiCA in the EU, updated SEC guidance in the US, and ASIC's framework in Australia all treat algorithmic trading as a regulated activity with specific record-keeping requirements. Bots that operate within a compliance-ready framework (with audit trails, execution verification, and settlement records) have a structural advantage over bots that operate in the dark.

### The Network Effect

There is a compounding advantage to multi-bot coordination that solo operators cannot replicate. A two-bot network covers one exchange pair. A five-bot network covers ten pairs. A ten-bot network covers forty-five pairs. The number of arbitrage opportunities scales quadratically with the number of exchanges covered, but each bot's capital requirement stays constant. A single bot operator joining a ten-bot network gains access to nine new exchange pairs without deploying a single dollar of additional capital.

This creates a natural marketplace for coordination. Bots with strong execution on a specific exchange can monetize that capability by partnering with bots on other exchanges. A Binance specialist with 0.4ms execution and a 97% fill rate is a valuable counterparty -- its speed and reliability directly increase the capture rate for any opportunity involving Binance. GreenHelix's reputation system makes this value visible: bots publish verified execution metrics, and coordinators use those metrics to select the best partner for each opportunity.

The rest of this guide builds a production framework using these tools. Chapter 2 creates the coordination layer. Chapter 3 scans for opportunities. Chapter 4 verifies execution. Chapter 5 handles profit splitting. Chapters 6-8 cover MEV protection, latency optimization, and compliance audit trails.

---

## Chapter 2: ArbitrageCoordinator Class

### Architecture

The ArbitrageCoordinator is the central orchestrator. It does not execute trades itself -- it discovers specialist bots, negotiates coordination agreements, manages escrow for profit splitting, and dispatches execution signals. Think of it as the clearing house in a traditional exchange, but running as an autonomous agent.

```
+---------------------+       +---------------------+       +---------------------+
|  Binance Bot        |       | ArbitrageCoordinator|       |  Kraken Bot          |
|  (exchange specialist)|     |  (orchestrator)     |       |  (exchange specialist)|
|                     |       |                     |       |                     |
|  Monitors Binance   |       |  Discovers bots     |       |  Monitors Kraken    |
|  order book         |       |  Negotiates deals   |       |  order book         |
|  Executes buy/sell  |       |  Manages escrow     |       |  Executes buy/sell  |
|  Reports fills      |       |  Verifies execution |       |  Reports fills      |
|                     |       |  Splits profits     |       |                     |
+--------+------------+       +----------+----------+       +----------+----------+
         |                               |                              |
         |  publish_event (fill data)    |  create_escrow               |  publish_event (fill data)
         +------------------------------>|<-----------------------------+
                                         |
                                    build_claim_chain
                                    release_escrow
```

### Setup

```python
import requests
import json
import time
import hashlib
import base64
from datetime import datetime, timedelta
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization

API_BASE = "https://api.greenhelix.net/v1"
API_KEY = "your-api-key"

session = requests.Session()
session.headers["Authorization"] = f"Bearer {API_KEY}"
session.headers["Content-Type"] = "application/json"

def execute(tool: str, inputs: dict) -> dict:
    """Execute a GreenHelix tool and return the result."""
    resp = session.post(
        f"{API_BASE}/v1",
        json={"tool": tool, "input": inputs}
    )
    resp.raise_for_status()
    return resp.json()
```

### The ArbitrageCoordinator Class

```python
class ArbitrageCoordinator:
    """Orchestrates multi-bot arbitrage across exchanges."""

    def __init__(self, agent_id: str, private_key_b64: str):
        self.agent_id = agent_id
        self.private_key = Ed25519PrivateKey.from_private_bytes(
            base64.b64decode(private_key_b64)
        )
        self.public_key = self.private_key.public_key()
        self.exchange_bots: dict[str, dict] = {}  # exchange -> bot info
        self.active_deals: dict[str, dict] = {}   # deal_id -> deal info
        self.pending_escrows: dict[str, str] = {}  # opportunity_id -> escrow_id

    def sign_payload(self, payload: dict) -> str:
        """Sign a canonical JSON payload with Ed25519."""
        canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
        signature = self.private_key.sign(canonical.encode())
        return base64.b64encode(signature).decode()

    def discover_exchange_bots(self, exchanges: list[str]) -> dict[str, list[dict]]:
        """Find specialist bots for each target exchange."""
        discovered = {}
        for exchange in exchanges:
            results = execute("search_services", {
                "query": f"arbitrage execution {exchange}",
                "filters": {
                    "capabilities": ["exchange_execution", "fast_fill"],
                    "metadata.exchange": exchange,
                    "metadata.bot_type": "exchange_specialist"
                },
                "limit": 10
            })
            discovered[exchange] = results.get("services", [])
            self._log_discovery(exchange, len(discovered[exchange]))
        self.exchange_bots = {
            ex: bots[0] for ex, bots in discovered.items() if bots
        }
        return discovered

    def _log_discovery(self, exchange: str, count: int):
        """Log bot discovery to the event bus."""
        execute("publish_event", {
            "agent_id": self.agent_id,
            "event_type": "arbitrage.bot_discovery",
            "payload": {
                "exchange": exchange,
                "bots_found": count,
                "timestamp": datetime.utcnow().isoformat()
            },
            "signature": self.sign_payload({
                "exchange": exchange,
                "bots_found": count
            })
        })

    def negotiate_coordination(
        self,
        exchange_a: str,
        exchange_b: str,
        profit_split: dict,
        min_opportunity_usd: float,
        max_latency_ms: int
    ) -> dict:
        """Negotiate a coordination agreement with two exchange bots."""
        bot_a = self.exchange_bots.get(exchange_a)
        bot_b = self.exchange_bots.get(exchange_b)
        if not bot_a or not bot_b:
            raise ValueError(f"Missing bot for {exchange_a} or {exchange_b}")

        terms = {
            "pair": f"{exchange_a}-{exchange_b}",
            "profit_split": profit_split,
            "min_opportunity_usd": str(min_opportunity_usd),
            "max_latency_ms": max_latency_ms,
            "escrow_required": True,
            "verification_method": "claim_chain",
            "valid_until": (
                datetime.utcnow() + timedelta(hours=24)
            ).isoformat()
        }

        deal = execute("negotiate_deal", {
            "proposer_id": self.agent_id,
            "counterparty_ids": [bot_a["agent_id"], bot_b["agent_id"]],
            "terms": terms,
            "signature": self.sign_payload(terms)
        })

        deal_id = deal["deal_id"]
        self.active_deals[deal_id] = {
            "exchange_a": exchange_a,
            "exchange_b": exchange_b,
            "bot_a": bot_a["agent_id"],
            "bot_b": bot_b["agent_id"],
            "terms": terms,
            "status": "negotiated"
        }
        return deal

    def create_execution_escrow(
        self,
        opportunity_id: str,
        deal_id: str,
        amount_usd: str
    ) -> dict:
        """Create escrow to guarantee profit-split settlement."""
        deal = self.active_deals.get(deal_id)
        if not deal:
            raise ValueError(f"No active deal: {deal_id}")

        escrow = execute("create_escrow", {
            "payer_id": self.agent_id,
            "payee_ids": [deal["bot_a"], deal["bot_b"]],
            "amount": amount_usd,
            "currency": "USD",
            "conditions": {
                "type": "multi_party_arbitrage",
                "opportunity_id": opportunity_id,
                "deal_id": deal_id,
                "release_on": "verified_execution",
                "timeout_hours": 1,
                "dispute_window_minutes": 30
            },
            "signature": self.sign_payload({
                "opportunity_id": opportunity_id,
                "amount": amount_usd
            })
        })

        self.pending_escrows[opportunity_id] = escrow["escrow_id"]
        return escrow

    def dispatch_execution(
        self,
        opportunity_id: str,
        deal_id: str,
        legs: list[dict]
    ) -> dict:
        """Signal exchange bots to execute their respective legs."""
        deal = self.active_deals[deal_id]
        execution_signals = []

        for leg in legs:
            signal = {
                "opportunity_id": opportunity_id,
                "exchange": leg["exchange"],
                "side": leg["side"],
                "symbol": leg["symbol"],
                "quantity": leg["quantity"],
                "limit_price": leg["limit_price"],
                "execution_deadline_ms": leg.get("deadline_ms", 500),
                "escrow_id": self.pending_escrows.get(opportunity_id),
                "timestamp": datetime.utcnow().isoformat()
            }
            signal["signature"] = self.sign_payload(signal)

            execute("publish_event", {
                "agent_id": self.agent_id,
                "event_type": "arbitrage.execution_signal",
                "payload": signal
            })
            execution_signals.append(signal)

        return {
            "opportunity_id": opportunity_id,
            "signals_dispatched": len(execution_signals),
            "legs": execution_signals
        }
```

The equivalent curl for bot discovery:

```bash
# Discover Binance specialist bots
curl -X POST https://sandbox.greenhelix.net/v1 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "search_services",
    "input": {
      "query": "arbitrage execution binance",
      "filters": {
        "capabilities": ["exchange_execution", "fast_fill"],
        "metadata.exchange": "binance",
        "metadata.bot_type": "exchange_specialist"
      },
      "limit": 10
    }
  }'
```

```bash
# Negotiate coordination deal
curl -X POST https://sandbox.greenhelix.net/v1 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "negotiate_deal",
    "input": {
      "proposer_id": "arb-coordinator-01",
      "counterparty_ids": ["binance-bot-07", "kraken-bot-03"],
      "terms": {
        "pair": "binance-kraken",
        "profit_split": {"coordinator": "0.20", "bot_a": "0.40", "bot_b": "0.40"},
        "min_opportunity_usd": "50.00",
        "max_latency_ms": 200,
        "escrow_required": true,
        "verification_method": "claim_chain"
      },
      "signature": "base64-ed25519-signature"
    }
  }'
```

### Registering the Coordinator

Before the coordinator can operate, it needs a GreenHelix identity:

```python
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
import base64

# Generate coordinator keypair
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()

private_bytes = private_key.private_bytes(
    encoding=serialization.Encoding.Raw,
    format=serialization.PrivateFormat.Raw,
    encryption_algorithm=serialization.NoEncryption()
)
public_bytes = public_key.public_bytes(
    encoding=serialization.Encoding.Raw,
    format=serialization.PublicFormat.Raw
)

COORDINATOR_PRIVATE_KEY = base64.b64encode(private_bytes).decode()
COORDINATOR_PUBLIC_KEY = base64.b64encode(public_bytes).decode()

# Register coordinator agent
coordinator = execute("register_agent", {
    "name": "arb-coordinator-01",
    "description": "Multi-bot arbitrage coordinator. Discovers exchange specialists, "
                   "negotiates profit splits, manages escrow, verifies execution.",
    "capabilities": [
        "arbitrage_coordination",
        "escrow_management",
        "execution_verification",
        "profit_distribution"
    ],
    "metadata": {
        "agent_type": "arbitrage_coordinator",
        "supported_exchanges": ["binance", "kraken", "okx", "bybit", "coinbase"],
        "min_opportunity_usd": 50,
        "max_concurrent_opportunities": 20
    }
})

coordinator_id = coordinator["agent_id"]

# Initialize the coordinator
arb = ArbitrageCoordinator(coordinator_id, COORDINATOR_PRIVATE_KEY)
```

```bash
curl -X POST https://sandbox.greenhelix.net/v1 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "register_agent",
    "input": {
      "name": "arb-coordinator-01",
      "description": "Multi-bot arbitrage coordinator.",
      "capabilities": [
        "arbitrage_coordination",
        "escrow_management",
        "execution_verification",
        "profit_distribution"
      ],
      "metadata": {
        "agent_type": "arbitrage_coordinator",
        "supported_exchanges": ["binance", "kraken", "okx", "bybit", "coinbase"],
        "min_opportunity_usd": 50
      }
    }
  }'
```

### Registering an Exchange Specialist Bot

Each exchange specialist registers with metadata describing its exchange, latency characteristics, and supported pairs:

```python
binance_bot = execute("register_agent", {
    "name": "binance-specialist-07",
    "description": "Binance exchange specialist. Co-located in Tokyo. "
                   "Sub-millisecond execution on spot pairs.",
    "capabilities": [
        "exchange_execution",
        "fast_fill",
        "order_book_monitoring",
        "fill_reporting"
    ],
    "metadata": {
        "agent_type": "exchange_specialist",
        "exchange": "binance",
        "location": "ap-northeast-1",
        "avg_execution_ms": 0.4,
        "supported_pairs": ["BTC/USDT", "ETH/USDT", "SOL/USDT", "BNB/USDT"],
        "max_order_size_usd": 500000
    }
})
```

---

## Chapter 3: OpportunityScanner Class

### Cross-Exchange Price Monitoring

The OpportunityScanner monitors prices across exchanges and identifies arbitrage opportunities that meet minimum profit thresholds after accounting for fees, slippage, and coordination costs. It does not execute trades -- it feeds opportunities to the ArbitrageCoordinator.

### Fee Structures

Every opportunity calculation must account for exchange fees. These vary by exchange, tier, and whether you are a maker or taker:

| Exchange | Taker Fee | Maker Fee | Withdrawal Fee (ETH) |
|---|---|---|---|
| Binance | 0.0750% | 0.0750% | 0.00042 ETH |
| Kraken | 0.0400% | 0.0160% | 0.0025 ETH |
| OKX | 0.0800% | 0.0500% | 0.0014 ETH |
| Bybit | 0.0550% | 0.0100% | 0.0012 ETH |
| Coinbase | 0.0800% | 0.0400% | network fee |

These are VIP/high-volume tier fees as of Q1 2026. Retail tier fees are 3-5x higher and make most arbitrage unprofitable.

### The OpportunityScanner Class

```python
from dataclasses import dataclass
from typing import Optional

@dataclass
class ArbitrageOpportunity:
    opportunity_id: str
    symbol: str
    buy_exchange: str
    sell_exchange: str
    buy_price: str
    sell_price: str
    spread_bps: float
    quantity: str
    gross_profit_usd: str
    net_profit_usd: str
    fees_usd: str
    latency_score: float
    detected_at: str
    expires_at: str

class OpportunityScanner:
    """Scans for cross-exchange arbitrage opportunities."""

    # Fee schedules: exchange -> {"taker": rate, "maker": rate}
    FEE_SCHEDULE = {
        "binance":  {"taker": 0.000750, "maker": 0.000750},
        "kraken":   {"taker": 0.000400, "maker": 0.000160},
        "okx":      {"taker": 0.000800, "maker": 0.000500},
        "bybit":    {"taker": 0.000550, "maker": 0.000100},
        "coinbase": {"taker": 0.000800, "maker": 0.000400},
    }

    # Estimated coordination overhead per trade
    COORDINATION_FEE_BPS = 2.0  # 0.02% for escrow + verification

    def __init__(
        self,
        agent_id: str,
        exchanges: list[str],
        min_profit_usd: float = 20.0,
        min_spread_bps: float = 5.0,
        max_quantity_usd: float = 100000.0
    ):
        self.agent_id = agent_id
        self.exchanges = exchanges
        self.min_profit_usd = min_profit_usd
        self.min_spread_bps = min_spread_bps
        self.max_quantity_usd = max_quantity_usd
        self.price_cache: dict[str, dict[str, dict]] = {}
        self._opportunity_counter = 0

    def update_prices(self, exchange: str, symbol: str, bid: str, ask: str, depth_usd: str):
        """Update cached price for an exchange/symbol pair."""
        if symbol not in self.price_cache:
            self.price_cache[symbol] = {}
        self.price_cache[symbol][exchange] = {
            "bid": float(bid),
            "ask": float(ask),
            "depth_usd": float(depth_usd),
            "updated_at": datetime.utcnow().isoformat()
        }

    def scan(self, symbol: str) -> list[ArbitrageOpportunity]:
        """Scan all exchange pairs for arbitrage opportunities on a symbol."""
        if symbol not in self.price_cache:
            return []

        prices = self.price_cache[symbol]
        opportunities = []

        for buy_ex in self.exchanges:
            for sell_ex in self.exchanges:
                if buy_ex == sell_ex:
                    continue
                if buy_ex not in prices or sell_ex not in prices:
                    continue

                opp = self._evaluate_pair(
                    symbol, buy_ex, sell_ex,
                    prices[buy_ex], prices[sell_ex]
                )
                if opp:
                    opportunities.append(opp)

        # Sort by net profit descending
        opportunities.sort(key=lambda o: float(o.net_profit_usd), reverse=True)
        return opportunities

    def _evaluate_pair(
        self,
        symbol: str,
        buy_exchange: str,
        sell_exchange: str,
        buy_data: dict,
        sell_data: dict
    ) -> Optional[ArbitrageOpportunity]:
        """Evaluate a single exchange pair for arbitrage."""
        buy_price = buy_data["ask"]   # we pay the ask to buy
        sell_price = sell_data["bid"]  # we receive the bid to sell

        if sell_price <= buy_price:
            return None  # no spread

        spread_bps = ((sell_price - buy_price) / buy_price) * 10000

        if spread_bps < self.min_spread_bps:
            return None

        # Determine executable quantity based on order book depth
        max_qty_by_depth = min(
            buy_data["depth_usd"],
            sell_data["depth_usd"]
        )
        trade_size_usd = min(max_qty_by_depth, self.max_quantity_usd)
        quantity = trade_size_usd / buy_price

        # Calculate fees
        buy_fee = trade_size_usd * self.FEE_SCHEDULE[buy_exchange]["taker"]
        sell_fee = (quantity * sell_price) * self.FEE_SCHEDULE[sell_exchange]["taker"]
        coordination_fee = trade_size_usd * (self.COORDINATION_FEE_BPS / 10000)
        total_fees = buy_fee + sell_fee + coordination_fee

        gross_profit = (sell_price - buy_price) * quantity
        net_profit = gross_profit - total_fees

        if net_profit < self.min_profit_usd:
            return None

        self._opportunity_counter += 1
        opp_id = f"opp-{self.agent_id}-{self._opportunity_counter:08d}"

        # Calculate latency score (0-1, higher is better)
        latency_score = self._estimate_latency_score(buy_exchange, sell_exchange)

        return ArbitrageOpportunity(
            opportunity_id=opp_id,
            symbol=symbol,
            buy_exchange=buy_exchange,
            sell_exchange=sell_exchange,
            buy_price=f"{buy_price:.8f}",
            sell_price=f"{sell_price:.8f}",
            spread_bps=round(spread_bps, 2),
            quantity=f"{quantity:.8f}",
            gross_profit_usd=f"{gross_profit:.2f}",
            net_profit_usd=f"{net_profit:.2f}",
            fees_usd=f"{total_fees:.2f}",
            latency_score=latency_score,
            detected_at=datetime.utcnow().isoformat(),
            expires_at=(datetime.utcnow() + timedelta(seconds=2)).isoformat()
        )

    def _estimate_latency_score(self, exchange_a: str, exchange_b: str) -> float:
        """Estimate execution latency score for an exchange pair.

        Based on geographic distance between exchange matching engines.
        Score of 1.0 = both in same region, 0.5 = cross-continent,
        0.2 = worst case.
        """
        LOCATIONS = {
            "binance": "tokyo",
            "kraken": "london",
            "okx": "hong_kong",
            "bybit": "singapore",
            "coinbase": "virginia",
        }
        # Rough inter-region latencies in ms
        LATENCIES = {
            ("tokyo", "tokyo"): 0.5,
            ("tokyo", "hong_kong"): 35,
            ("tokyo", "singapore"): 60,
            ("tokyo", "london"): 150,
            ("tokyo", "virginia"): 90,
            ("london", "london"): 0.5,
            ("london", "virginia"): 40,
            ("london", "hong_kong"): 120,
            ("london", "singapore"): 100,
            ("hong_kong", "hong_kong"): 0.5,
            ("hong_kong", "singapore"): 25,
            ("hong_kong", "virginia"): 130,
            ("singapore", "singapore"): 0.5,
            ("singapore", "virginia"): 140,
            ("virginia", "virginia"): 0.5,
        }
        loc_a = LOCATIONS.get(exchange_a, "virginia")
        loc_b = LOCATIONS.get(exchange_b, "virginia")
        key = tuple(sorted([loc_a, loc_b]))
        latency_ms = LATENCIES.get(key, 150)
        # Normalize: 0.5ms -> 1.0, 150ms -> 0.2
        return max(0.2, 1.0 - (latency_ms / 200))

    def log_opportunity(self, opp: ArbitrageOpportunity):
        """Publish opportunity to GreenHelix event bus."""
        execute("publish_event", {
            "agent_id": self.agent_id,
            "event_type": "arbitrage.opportunity_detected",
            "payload": {
                "opportunity_id": opp.opportunity_id,
                "symbol": opp.symbol,
                "buy_exchange": opp.buy_exchange,
                "sell_exchange": opp.sell_exchange,
                "spread_bps": opp.spread_bps,
                "net_profit_usd": opp.net_profit_usd,
                "latency_score": opp.latency_score,
                "detected_at": opp.detected_at
            }
        })
```

### Running the Scanner

```python
# Initialize scanner
scanner = OpportunityScanner(
    agent_id=coordinator_id,
    exchanges=["binance", "kraken", "okx", "bybit", "coinbase"],
    min_profit_usd=20.0,
    min_spread_bps=5.0,
    max_quantity_usd=100000.0
)

# Simulate price updates (in production, these come from WebSocket feeds)
scanner.update_prices("binance", "ETH/USDT", bid="3000.50", ask="3000.80", depth_usd="250000")
scanner.update_prices("kraken",  "ETH/USDT", bid="3012.00", ask="3012.40", depth_usd="180000")
scanner.update_prices("okx",    "ETH/USDT", bid="3001.20", ask="3001.60", depth_usd="300000")

# Scan for opportunities
opportunities = scanner.scan("ETH/USDT")
for opp in opportunities:
    print(f"[{opp.opportunity_id}] {opp.buy_exchange} -> {opp.sell_exchange}: "
          f"spread={opp.spread_bps}bps, net=${opp.net_profit_usd}")
    scanner.log_opportunity(opp)
```

### Stale Price Detection

Price data goes stale fast. A price update from 500ms ago might as well be from last year in arbitrage. The scanner must discard stale prices to avoid executing on phantom opportunities:

```python
def _is_price_fresh(self, exchange_data: dict, max_age_ms: float = 500) -> bool:
    """Check if a cached price is still fresh enough to trade on."""
    updated_at = datetime.fromisoformat(exchange_data["updated_at"])
    age_ms = (datetime.utcnow() - updated_at).total_seconds() * 1000
    return age_ms <= max_age_ms
```

In production, the scanner should track staleness per exchange and alert the coordinator when a feed goes dark. A Binance WebSocket feed that stops sending updates for 2 seconds likely indicates a connection drop -- the bot should reconnect, not continue operating on the last known price.

### Feeding Opportunities to the Coordinator

```python
# Full pipeline: scan -> validate -> escrow -> dispatch
for opp in opportunities:
    # Check that we have active deals for this exchange pair
    matching_deals = [
        (did, d) for did, d in arb.active_deals.items()
        if d["exchange_a"] == opp.buy_exchange
        and d["exchange_b"] == opp.sell_exchange
        and d["status"] == "negotiated"
    ]
    if not matching_deals:
        continue

    deal_id, deal = matching_deals[0]

    # Create escrow for profit settlement
    escrow = arb.create_execution_escrow(
        opportunity_id=opp.opportunity_id,
        deal_id=deal_id,
        amount_usd=opp.net_profit_usd
    )

    # Dispatch execution signals to both bots
    result = arb.dispatch_execution(
        opportunity_id=opp.opportunity_id,
        deal_id=deal_id,
        legs=[
            {
                "exchange": opp.buy_exchange,
                "side": "buy",
                "symbol": opp.symbol,
                "quantity": opp.quantity,
                "limit_price": opp.buy_price,
                "deadline_ms": 500
            },
            {
                "exchange": opp.sell_exchange,
                "side": "sell",
                "symbol": opp.symbol,
                "quantity": opp.quantity,
                "limit_price": opp.sell_price,
                "deadline_ms": 500
            }
        ]
    )
    print(f"Dispatched {result['signals_dispatched']} legs for {opp.opportunity_id}")
```

---

## Chapter 4: Execution Verification

### Why Verification Matters

After the coordinator dispatches execution signals, each exchange bot independently executes its leg. But the coordinator cannot see inside the exchange -- it relies on the bots to report back. This creates an information asymmetry that must be resolved cryptographically. A bot could lie about its fill price, claim a partial fill when it got a full fill, or report execution failure when it actually succeeded (pocketing the profit from the other leg's movement).

Execution verification solves this with three mechanisms: signed fill reports that bind the bot's identity to its claimed execution, timestamp proofs that establish execution ordering, and claim chains that create tamper-proof evidence for dispute resolution.

### The ExecutionVerifier Class

```python
class ExecutionVerifier:
    """Verifies that counterparty bots actually executed their legs."""

    def __init__(self, agent_id: str, private_key_b64: str):
        self.agent_id = agent_id
        self.private_key = Ed25519PrivateKey.from_private_bytes(
            base64.b64decode(private_key_b64)
        )
        self.verification_cache: dict[str, dict] = {}

    def sign_payload(self, payload: dict) -> str:
        canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
        signature = self.private_key.sign(canonical.encode())
        return base64.b64encode(signature).decode()

    def submit_fill_report(
        self,
        opportunity_id: str,
        exchange: str,
        side: str,
        symbol: str,
        fill_price: str,
        fill_quantity: str,
        exchange_order_id: str,
        exchange_timestamp_us: int
    ) -> dict:
        """Submit a signed fill report for one leg of an arbitrage."""
        report = {
            "opportunity_id": opportunity_id,
            "exchange": exchange,
            "side": side,
            "symbol": symbol,
            "fill_price": fill_price,
            "fill_quantity": fill_quantity,
            "exchange_order_id": exchange_order_id,
            "exchange_timestamp_us": exchange_timestamp_us,
            "reporter_id": self.agent_id,
            "reported_at": datetime.utcnow().isoformat()
        }
        report["signature"] = self.sign_payload(report)

        # Publish fill report as a signed event
        result = execute("publish_event", {
            "agent_id": self.agent_id,
            "event_type": "arbitrage.fill_report",
            "payload": report
        })

        retur

…(truncated)
