Copy Trading Infrastructure: Protocol-Agnostic Copy Trading with Verified Leader Performance
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):
GREENHELIX_API_KEY: API authentication for GreenHelix gateway (read/write access to purchased API tools only)AGENT_SIGNING_KEY: Cryptographic signing key for agent identity (Ed25519 key pair for request signing)
Copy trading is the fastest-growing segment of automated trading, projected to reach $4.2 billion by 2027 according to Allied Market Research. But the current generation of platforms -- eToro, Bybit Copy, NAGA, ZuluTrade -- share a fundamental trust problem that limits their growth and exposes followers to unnecessary risk. Leader performance is self-reported or platform-curated with opaque methodology. Followers have no recourse when leaders lose money beyond closing the copy relationship after the damage is done. Platforms take 20-30% of performance fees while adding no verification, no escrow protection, and no cryptographic proof that stated returns actually occurred. The result is an ecosystem where the most profitable strategy for a leader is not to trade well, but to attract followers, collect fees, and let survivorship bias do the marketing. This guide builds something different: protocol-agnostic copy trading infrastructure where leader performance is cryptographically verified through Ed25519-signed trade records, follower allocations are risk-managed through configurable models, and revenue sharing flows through escrow that releases only when performance criteria are met. The trust layer is GreenHelix. Leaders register as service providers on the marketplace. Followers discover and evaluate them using verified metrics. Performance escrow protects follower capital. Revenue splits are enforced by smart contracts, not gentleman's agreements. The entire system is exchange-agnostic -- the same infrastructure works whether your leaders trade on Binance, Coinbase, Interactive Brokers, or a DEX.
What You'll Learn
- Chapter 1: Copy Trading Architecture
- Chapter 2: CopyTradingLeader Class
- Chapter 3: CopyTradingFollower Class
- Chapter 4: Allocation Models
- Chapter 5: Slippage Handling
- Chapter 6: Performance Escrow
- Chapter 7: Revenue Sharing
- Next Steps
- What's Next
Full Guide
Copy Trading Infrastructure: Protocol-Agnostic Copy Trading with Verified Leader Performance
Copy trading is the fastest-growing segment of automated trading, projected to reach $4.2 billion by 2027 according to Allied Market Research. But the current generation of platforms -- eToro, Bybit Copy, NAGA, ZuluTrade -- share a fundamental trust problem that limits their growth and exposes followers to unnecessary risk. Leader performance is self-reported or platform-curated with opaque methodology. Followers have no recourse when leaders lose money beyond closing the copy relationship after the damage is done. Platforms take 20-30% of performance fees while adding no verification, no escrow protection, and no cryptographic proof that stated returns actually occurred. The result is an ecosystem where the most profitable strategy for a leader is not to trade well, but to attract followers, collect fees, and let survivorship bias do the marketing. This guide builds something different: protocol-agnostic copy trading infrastructure where leader performance is cryptographically verified through Ed25519-signed trade records, follower allocations are risk-managed through configurable models, and revenue sharing flows through escrow that releases only when performance criteria are met. The trust layer is GreenHelix. Leaders register as service providers on the marketplace. Followers discover and evaluate them using verified metrics. Performance escrow protects follower capital. Revenue splits are enforced by smart contracts, not gentleman's agreements. The entire system is exchange-agnostic -- the same infrastructure works whether your leaders trade on Binance, Coinbase, Interactive Brokers, or a DEX.
Table of Contents
- Copy Trading Architecture
- CopyTradingLeader Class
- CopyTradingFollower Class
- Allocation Models
- Slippage Handling
- Performance Escrow
- Revenue Sharing
- What's Next
Chapter 1: Copy Trading Architecture
The Leader-Follower Model with GreenHelix as Trust Layer
Copy trading is conceptually simple: a leader executes trades, and followers mirror those trades in their own accounts. The complexity lies entirely in trust. How does a follower know the leader's track record is real? How does the follower limit their exposure if the leader blows up? How does the leader get paid fairly for generating alpha? And how do both parties resolve disputes without a centralized authority that has perverse incentives?
Traditional platforms solve these problems by becoming the centralized authority. eToro holds both leader and follower funds, controls the performance data, sets the fee structure, and resolves disputes at its discretion. This works until it does not -- platforms can selectively promote leaders who generate revenue, suppress negative performance data, or structure fees that incentivize volume over performance.
The GreenHelix architecture replaces platform trust with cryptographic verification. Leaders submit signed performance metrics that cannot be fabricated. Followers subscribe through performance escrow that protects their capital. Revenue sharing flows through escrow contracts that release only when agreed-upon criteria are met. The platform does not hold funds, does not curate leaders, and does not resolve disputes -- the protocol does.
Architecture Overview
+-------------------+ +---------------------+ +-------------------+
| Copy Leader | | GreenHelix API | | Copy Follower |
| | | | | |
| Execute trades | | | | |
| on exchange | | | | |
| | | | | | |
| Sign trade | | | | |
| record (Ed25519) | | | | |
| | | | | | |
| submit_metrics -------> | Verified Metrics | | |
| publish_event -------> | Event Bus | ----> | Receive signal |
| register_service ------> | Marketplace | ----> | search_services |
| | | | | subscribe |
| | | Performance Escrow | <---- | create_escrow |
| | | | | | | |
| claim_revenue <-------- | release_escrow | | execute trade |
| | | (criteria met) | | on own exchange |
| | | | | | |
| get_reputation <------> | Reputation Engine | <---> | get_reputation |
+-------------------+ +---------------------+ +-------------------+
The data flow works as follows. A leader executes a trade on their exchange of choice -- Binance, Coinbase, Interactive Brokers, a DEX, it does not matter. The leader's bot signs the trade record with its Ed25519 private key and publishes it to the GreenHelix event bus via publish_event. Simultaneously, the leader submits aggregate performance metrics via submit_metrics -- win rate, Sharpe ratio, max drawdown, total return -- that become part of their verifiable reputation. Followers discover leaders through search_services on the marketplace, evaluate them using get_agent_reputation and get_claim_chains, subscribe by creating a performance escrow via create_escrow, and receive trade signals through webhooks registered with register_webhook. When a signal arrives, the follower's bot applies its allocation model, adjusts for risk limits, and executes the corresponding trade on the follower's own exchange account. At the end of each evaluation period, the escrow contract checks whether the leader met the agreed performance criteria. If yes, the leader's revenue share is released. If not, the follower's escrow deposit is returned.
GreenHelix Tools Used
This guide uses the following GreenHelix API tools:
| Tool | Purpose |
|---|---|
register_agent |
Register leader and follower identities with Ed25519 public keys |
register_service |
List a leader's copy trading service on the marketplace |
search_services |
Discover available copy trading leaders |
create_escrow |
Create performance escrow protecting follower deposits |
release_escrow |
Release escrow when performance criteria are met |
submit_metrics |
Submit verified performance metrics for leaders |
get_agent_reputation |
Retrieve a leader's verified reputation score |
get_claim_chains |
Verify the integrity of a leader's performance history |
publish_event |
Broadcast trade signals to followers via the event bus |
register_webhook |
Register follower endpoints to receive trade signals |
create_sla |
Define performance SLA between leader and follower |
check_sla_compliance |
Verify leader meets agreed SLA terms |
Why Protocol-Agnostic Matters
Locking copy trading to a single exchange limits the leader pool and the follower pool. A leader who trades BTC/USDT on Binance Futures should be copyable by a follower on Bybit, OKX, or a self-custodied DEX. The GreenHelix event bus decouples signal generation from signal execution. The leader publishes a normalized trade signal -- symbol, side, size as a percentage of portfolio, entry price, stop loss, take profit -- and each follower's execution engine translates that signal into exchange-specific orders. This is the same architecture used by institutional signal distribution networks like Portware and FlexTrade, scaled down to retail.
Chapter 2: CopyTradingLeader Class
Leader Registration and Service Listing
A copy trading leader is an agent that executes trades on one or more exchanges and broadcasts those trades as signals. Before a leader can attract followers, they must register their identity, list their service on the marketplace, and begin building a verified track record.
Step 1: Generate an Ed25519 Keypair
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
import base64
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
)
PRIVATE_KEY_B64 = base64.b64encode(private_bytes).decode()
PUBLIC_KEY_B64 = base64.b64encode(public_bytes).decode()
Store the private key in a secrets manager. It signs every trade record and performance metric submission -- if it leaks, an attacker can fabricate your track record.
Step 2: Register and List
# Register the leader agent
curl -X POST https://sandbox.greenhelix.net/v1 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "register_agent",
"input": {
"agent_id": "leader-crypto-momentum-01",
"public_key": "'"$PUBLIC_KEY_B64"'",
"name": "Crypto Momentum Alpha"
}
}'
# List the copy trading service on the marketplace
curl -X POST https://sandbox.greenhelix.net/v1 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "register_service",
"input": {
"agent_id": "leader-crypto-momentum-01",
"service_type": "copy_trading",
"name": "Crypto Momentum Alpha -- Copy Trading",
"description": "Momentum-based crypto trading strategy. BTC/ETH/SOL on Binance Futures. 15-minute to 4-hour timeframes. Target Sharpe > 2.0, max drawdown < 15%.",
"pricing": {
"model": "hybrid",
"subscription_monthly_usd": "49.00",
"performance_fee_pct": "15.0"
},
"metadata": {
"strategy_type": "momentum",
"asset_classes": ["crypto"],
"exchanges": ["binance_futures"],
"symbols": ["BTCUSDT", "ETHUSDT", "SOLUSDT"],
"timeframes": ["15m", "1h", "4h"],
"track_record_months": 18,
"verified_sharpe": "2.34",
"verified_max_drawdown_pct": "11.7",
"verified_win_rate_pct": "58.3",
"avg_trades_per_week": 12,
"max_followers": 500
}
}
}'
The max_followers field is critical. Every additional follower increases market impact when the leader's signals are executed simultaneously. A leader trading $100K with 500 followers at $10K each creates $5.1M of correlated order flow. On illiquid pairs, this causes meaningful slippage -- covered in Chapter 5.
The CopyTradingLeader Class
import json
import time
import hashlib
import base64
import uuid
from datetime import datetime, timezone
from typing import Optional
import requests
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey,
)
from cryptography.hazmat.primitives import serialization
class CopyTradingLeader:
"""Copy trading leader that broadcasts verified trade signals."""
def __init__(
self,
api_key: str,
agent_id: str,
private_key_b64: str,
):
self.api_base = "https://api.greenhelix.net/v1"
self.api_key = api_key
self.agent_id = agent_id
self._private_key = Ed25519PrivateKey.from_private_bytes(
base64.b64decode(private_key_b64)
)
self._trades: list[dict] = []
self._session = requests.Session()
self._session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
})
def _execute(self, tool: str, input_data: dict) -> dict:
resp = self._session.post(
f"{self.api_base}/v1",
json={"tool": tool, "input": input_data},
)
resp.raise_for_status()
return resp.json()
def _sign(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 _now_iso(self) -> str:
return datetime.now(timezone.utc).isoformat()
def broadcast_trade_signal(
self,
symbol: str,
side: str,
size_pct: float,
entry_price: float,
stop_loss: Optional[float] = None,
take_profit: Optional[float] = None,
order_type: str = "market",
timeframe: str = "1h",
) -> dict:
"""Broadcast a trade signal to all followers via the event bus."""
signal_id = str(uuid.uuid4())
timestamp = self._now_iso()
payload = {
"signal_id": signal_id,
"leader_id": self.agent_id,
"symbol": symbol,
"side": side,
"size_pct": str(size_pct),
"entry_price": str(entry_price),
"order_type": order_type,
"timeframe": timeframe,
"timestamp": timestamp,
}
if stop_loss is not None:
payload["stop_loss"] = str(stop_loss)
if take_profit is not None:
payload["take_profit"] = str(take_profit)
payload["signature"] = self._sign(payload)
result = self._execute("publish_event", {
"event_type": "copy_trade.signal",
"payload": payload,
})
self._trades.append({
"signal_id": signal_id,
"symbol": symbol,
"side": side,
"size_pct": size_pct,
"entry_price": entry_price,
"stop_loss": stop_loss,
"take_profit": take_profit,
"timestamp": timestamp,
"status": "open",
})
return result
def close_position(
self,
signal_id: str,
exit_price: float,
pnl_pct: float,
) -> dict:
"""Broadcast a position close signal."""
timestamp = self._now_iso()
payload = {
"signal_id": signal_id,
"leader_id": self.agent_id,
"action": "close",
"exit_price": str(exit_price),
"pnl_pct": str(pnl_pct),
"timestamp": timestamp,
}
payload["signature"] = self._sign(payload)
result = self._execute("publish_event", {
"event_type": "copy_trade.close",
"payload": payload,
})
for trade in self._trades:
if trade["signal_id"] == signal_id:
trade["status"] = "closed"
trade["exit_price"] = exit_price
trade["pnl_pct"] = pnl_pct
break
return result
def submit_performance_metrics(self) -> dict:
"""Submit verified performance metrics to build reputation."""
closed_trades = [t for t in self._trades if t["status"] == "closed"]
if not closed_trades:
return {"status": "no_closed_trades"}
wins = [t for t in closed_trades if t["pnl_pct"] > 0]
losses = [t for t in closed_trades if t["pnl_pct"] <= 0]
pnls = [t["pnl_pct"] for t in closed_trades]
total_return = sum(pnls)
win_rate = len(wins) / len(closed_trades) * 100
avg_win = sum(t["pnl_pct"] for t in wins) / len(wins) if wins else 0
avg_loss = sum(t["pnl_pct"] for t in losses) / len(losses) if losses else 0
max_drawdown = self._calculate_max_drawdown(pnls)
sharpe = self._calculate_sharpe(pnls)
metrics = {
"total_trades": len(closed_trades),
"win_rate_pct": str(round(win_rate, 2)),
"total_return_pct": str(round(total_return, 4)),
"avg_win_pct": str(round(avg_win, 4)),
"avg_loss_pct": str(round(avg_loss, 4)),
"max_drawdown_pct": str(round(max_drawdown, 4)),
"sharpe_ratio": str(round(sharpe, 4)),
"last_updated": self._now_iso(),
}
metrics["signature"] = self._sign(metrics)
return self._execute("submit_metrics", {
"agent_id": self.agent_id,
"metrics": metrics,
})
def _calculate_max_drawdown(self, pnls: list[float]) -> float:
cumulative = 0.0
peak = 0.0
max_dd = 0.0
for pnl in pnls:
cumulative += pnl
if cumulative > peak:
peak = cumulative
drawdown = peak - cumulative
if drawdown > max_dd:
max_dd = drawdown
return max_dd
def _calculate_sharpe(self, pnls: list[float]) -> float:
if len(pnls) < 2:
return 0.0
mean = sum(pnls) / len(pnls)
variance = sum((p - mean) ** 2 for p in pnls) / (len(pnls) - 1)
std = variance ** 0.5
if std == 0:
return 0.0
# Annualize assuming ~250 trading days, ~3 trades/day
return (mean / std) * (750 ** 0.5)
def register_service(
self,
name: str,
description: str,
pricing: dict,
metadata: dict,
) -> dict:
"""List the copy trading service on the marketplace."""
return self._execute("register_service", {
"agent_id": self.agent_id,
"service_type": "copy_trading",
"name": name,
"description": description,
"pricing": pricing,
"metadata": metadata,
})
def configure_revenue(
self,
model: str = "hybrid",
subscription_monthly_usd: str = "49.00",
performance_fee_pct: str = "15.0",
high_water_mark: bool = True,
) -> dict:
"""Configure revenue model for the copy trading service."""
return {
"model": model,
"subscription_monthly_usd": subscription_monthly_usd,
"performance_fee_pct": performance_fee_pct,
"high_water_mark": high_water_mark,
}
Revenue Configuration: Fixed Fee vs Percentage vs Hybrid
Leaders choose from three revenue models. Fixed subscription charges a flat monthly fee regardless of performance -- predictable for both parties but does not align leader and follower incentives. Performance fee takes a percentage of profits above a high-water mark -- strongly aligns incentives but creates income volatility for the leader. Hybrid combines a lower monthly subscription with a reduced performance fee -- the subscription covers infrastructure costs while the performance fee rewards alpha. The hybrid model is the industry standard for copy trading services above $25/month.
# Register with hybrid pricing
curl -X POST https://sandbox.greenhelix.net/v1 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "register_service",
"input": {
"agent_id": "leader-crypto-momentum-01",
"service_type": "copy_trading",
"name": "Crypto Momentum Alpha",
"description": "Momentum strategy, BTC/ETH/SOL, Sharpe > 2.0",
"pricing": {
"model": "hybrid",
"subscription_monthly_usd": "49.00",
"performance_fee_pct": "15.0",
"high_water_mark": true,
"billing_cycle": "monthly",
"trial_days": 7
},
"metadata": {
"strategy_type": "momentum",
"min_follower_capital_usd": "1000"
}
}
}'
The high_water_mark flag ensures the leader only earns performance fees on new profits. If a follower's account drops from $10,000 to $8,000, the leader earns no performance fee until the account exceeds $10,000 again. This prevents leaders from earning fees on recovery -- you only pay for net new alpha.
Trade Signal Broadcasting
When the leader executes a trade, the signal is normalized and broadcast to all followers via the GreenHelix event bus. The signal includes the symbol, side, size as a percentage of portfolio (not an absolute amount), and optional stop loss and take profit levels.
import os
leader = CopyTradingLeader(
api_key=os.environ["GREENHELIX_API_KEY"],
agent_id="leader-crypto-momentum-01",
private_key_b64=os.environ["LEADER_PRIVATE_KEY"],
)
# Long BTC with 10% of portfolio, 2% stop loss, 6% take profit
result = leader.broadcast_trade_signal(
symbol="BTCUSDT",
side="buy",
size_pct=10.0,
entry_price=67250.00,
stop_loss=65905.00,
take_profit=71285.00,
order_type="limit",
timeframe="4h",
)
print(f"Signal broadcast: {result}")
# Later, close the position
result = leader.close_position(
signal_id=result["payload"]["signal_id"],
exit_price=71100.00,
pnl_pct=5.72,
)
print(f"Position closed: {result}")
# Submit updated performance metrics
metrics_result = leader.submit_performance_metrics()
print(f"Metrics submitted: {metrics_result}")
The size_pct field is the key abstraction that makes copy trading protocol-agnostic. A leader trading a $500K portfolio who allocates 10% to BTC sends size_pct: 10.0. A follower with a $5K portfolio allocates 10% -- $500 -- to the same trade. The signal describes intent, not execution details. Each follower's execution engine translates that intent into exchange-specific orders appropriate for their account size.
Chapter 3: CopyTradingFollower Class
Discovering and Evaluating Leaders
A follower's first task is finding leaders worth copying. The GreenHelix marketplace exposes leader listings through search_services, and the reputation engine provides verified metrics through get_agent_reputation. The combination lets followers make data-driven decisions rather than relying on platform-curated leaderboards.
# Search for copy trading leaders specializing in crypto momentum
curl -X POST https://sandbox.greenhelix.net/v1 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "search_services",
"input": {
"service_type": "copy_trading",
"query": "crypto momentum",
"filters": {
"min_sharpe": "1.5",
"max_drawdown_pct": "20.0",
"min_track_record_months": 6
},
"sort_by": "sharpe_ratio",
"sort_order": "desc",
"limit": 20
}
}'
# Get verified reputation for a specific leader
curl -X POST https://sandbox.greenhelix.net/v1 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "get_agent_reputation",
"input": {
"agent_id": "leader-crypto-momentum-01"
}
}'
# Verify the leader's performance claim chain
curl -X POST https://sandbox.greenhelix.net/v1 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "get_claim_chains",
"input": {
"agent_id": "leader-crypto-momentum-01",
"claim_type": "performance_metrics"
}
}'
The claim chain is the critical verification step. get_agent_reputation returns aggregate scores, but get_claim_chains returns the Merkle tree of signed performance submissions. A follower can independently verify that each metric submission was signed by the leader's Ed25519 key, that the submissions form an unbroken chain, and that no submissions have been retroactively modified. This is the difference between "the platform says this leader has a 2.34 Sharpe" and "I have cryptographic proof that this leader submitted 18 months of signed performance data that produces a 2.34 Sharpe."
The CopyTradingFollower Class
import json
import time
import base64
import uuid
from datetime import datetime, timezone
from typing import Optional
from dataclasses import dataclass, field
import requests
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey,
Ed25519PublicKey,
)
from cryptography.hazmat.primitives import serialization
@dataclass
class LeaderSubscription:
"""Tracks a follower's subscription to a specific leader."""
leader_id: str
escrow_id: str
max_allocation_pct: float = 20.0
max_drawdown_pct: float = 10.0
max_position_size_pct: float = 5.0
allowed_symbols: list[str] = field(default_factory=list)
active: bool = True
positions: dict = field(default_factory=dict)
cumulative_pnl: float = 0.0
high_water_mark: float = 0.0
class CopyTradingFollower:
"""Copy trading follower that discovers, evaluates, and copies leaders."""
def __init__(
self,
api_key: str,
agent_id: str,
private_key_b64: str,
portfolio_value_usd: float,
):
self.api_base = "https://api.greenhelix.net/v1"
self.api_key = api_key
self.agent_id = agent_id
self.portfolio_value = portfolio_value_usd
self._private_key = Ed25519PrivateKey.from_private_bytes(
base64.b64decode(private_key_b64)
)
self._subscriptions: dict[str, LeaderSubscription] = {}
self._session = requests.Session()
self._session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
})
def _execute(self, tool: str, input_data: dict) -> dict:
resp = self._session.post(
f"{self.api_base}/v1",
json={"tool": tool, "input": input_data},
)
resp.raise_for_status()
return resp.json()
def _sign(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 discover_leaders(
self,
strategy_type: str = "momentum",
min_sharpe: float = 1.5,
max_drawdown: float = 20.0,
min_months: int = 6,
) -> list[dict]:
"""Search for copy trading leaders matching criteria."""
result = self._execute("search_services", {
"service_type": "copy_trading",
"query": strategy_type,
"filters": {
"min_sharpe": str(min_sharpe),
"max_drawdown_pct": str(max_drawdown),
"min_track_record_months": min_months,
},
"sort_by": "sharpe_ratio",
"sort_order": "desc",
"limit": 20,
})
return result.get("services", [])
def evaluate_leader(self, leader_id: str) -> dict:
"""Get verified reputation and performance claim chain for a leader."""
reputation = self._execute("get_agent_reputation", {
"agent_id": leader_id,
})
claims = self._execute("get_claim_chains", {
"agent_id": leader_id,
"claim_type": "performance_metrics",
})
return {
"reputation": reputation,
"claim_chains": claims,
"verified": self._verify_claim_chain(claims),
}
def _verify_claim_chain(self, claims: dict) -> bool:
"""Verify the integrity of a leader's performance claim chain."""
chain = claims.get("chains", [])
if not chain:
return False
# Verify each link is signed and the chain is unbroken
for i, link in enumerate(chain):
if "signature" not in link:
return False
if i > 0 and link.get("previous_hash") != chain[i - 1].get("hash"):
return False
return True
def subscribe(
self,
leader_id: str,
escrow_amount_usd: float,
max_allocation_pct: float = 20.0,
max_drawdown_pct: float = 10.0,
max_position_size_pct: float = 5.0,
allowed_symbols: Optional[list[str]] = None,
evaluation_period_days: int = 30,
performance_criteria: Optional[dict] = None,
) -> dict:
"""Subscribe to a leader with performance escrow protection."""
if performance_criteria is None:
performance_criteria = {
"min_sharpe": "1.0",
"max_drawdown_pct": "20.0",
"min_win_rate_pct": "45.0",
}
escrow_result = self._execute("create_escrow", {
"payer_id": self.agent_id,
"payee_id": leader_id,
"amount": str(escrow_amount_usd),
"currency": "USD",
"conditions": {
"type": "performance_escrow",
"evaluation_period_days": evaluation_period_days,
"criteria": performance_criteria,
"auto_release": True,
},
"description": f"Copy trading subscription: {self.agent_id} -> {leader_id}",
})
escrow_id = escrow_result["escrow_id"]
subscription = LeaderSubscription(
leader_id=leader_id,
escrow_id=escrow_id,
max_allocation_pct=max_allocation_pct,
max_drawdown_pct=max_drawdown_pct,
max_position_size_pct=max_position_size_pct,
allowed_symbols=allowed_symbols or [],
)
self._subscriptions[leader_id] = subscription
# Register webhook to receive trade signals from this leader
self._execute("register_webhook", {
"url": f"https://your-follower-bot.example.com/signals/{leader_id}",
"event_types": ["copy_trade.signal", "copy_trade.close"],
"filters": {"leader_id": leader_id},
"secret": f"webhook-secret-{leader_id}",
})
return escrow_result
def handle_trade_signal(self, signal: dict) -> Optional[dict]:
"""Process an incoming trade signal from a leader."""
leader_id = signal.get("leader_id")
sub = self._subscriptions.get(leader_id)
if not sub or not sub.active:
return None
symbol = signal.get("symbol")
# Check symbol whitelist
if sub.allowed_symbols and symbol not in sub.allowed_symbols:
return {"status": "skipped", "reason": "symbol_not_allowed"}
# Check drawdown limit
if sub.cumulative_pnl < 0 and abs(sub.cumulative_pnl) >= sub.max_drawdown_pct:
sub.active = False
return {"status": "stopped", "reason": "max_drawdown_reached"}
# Check total allocation to this leader
current_allocation = sum(
pos.get("allocated_usd", 0) for pos in sub.positions.values()
)
max_allocation_usd = self.portfolio_value * (sub.max_allocation_pct / 100)
if current_allocation >= max_allocation_usd:
return {"status": "skipped", "reason": "max_allocation_reached"}
# Calculate position size
leader_size_pct = float(signal.get("size_pct", 0))
capped_size_pct = min(leader_size_pct, sub.max_position_size_pct)
position_usd = self.portfolio_value * (capped_size_pct / 100)
# Ensure we do not exceed remaining allocation
remaining = max_allocation_usd - current_allocation
position_usd = min(position_usd, remaining)
if position_usd < 10: # Minimum position size
return {"status": "skipped", "reason": "position_too_small"}
# Execute the trade on the follower's exchange
execution = self._execute_on_exchange(
symbol=symbol,
side=signal.get("side"),
amount_usd=position_usd,
order_type=signal.get("order_type", "market"),
stop_loss=signal.get("stop_loss"),
take_profit=signal.get("take_profit"),
)
signal_id = signal.get("signal_id")
sub.positions[signal_id] = {
"symbol": symbol,
"side": signal.get("side"),
"allocated_usd": position_usd,
"entry_price": execution.get("fill_price"),
"timestamp": signal.get("timestamp"),
}
return execution
def handle_close_signal(self, signal: dict) -> Optional[dict]:
"""Process a position close signal from a leader."""
leader_id = signal.get("leader_id")
signal_id = signal.get("signal_id")
sub = self._subscriptions.get(leader_id)
if not sub or signal_id not in sub.positions:
return None
position = sub.positions[signal_id]
execution = self._close_on_exchange(
symbol=position["symbol"],
side="sell" if position["side"] == "buy" else "buy",
amount_usd=position["allocated_usd"],
)
# Track PnL
pnl_pct = float(signal.get("pnl_pct", 0))
sub.cumulative_pnl += pnl_pct
if sub.cumulative_pnl > sub.high_water_mark:
sub.high_water_mark = sub.cumulative_pnl
del sub.positions[signal_id]
return execution
def _execute_on_exchange(self, **kwargs) -> dict:
"""Execute a trade on the follower's exchange. Override per exchange."""
# Placeholder -- implement per exchange (Binance, Coinbase, etc.)
return {
"status": "filled",
"fill_price": kwargs.get("amount_usd", 0),
"exchange": "binance",
}
def _close_on_exchange(self, **kwargs) -> dict:
"""Close a position on the follower's exchange. Override per exchange."""
return {"status": "closed", "exchange": "binance"}
def unsubscribe(self, leader_id: str) -> dict:
"""Unsubscribe from a leader and close all open positions."""
sub = self._subscriptions.get(leader_id)
if not sub:
return {"status": "not_subscribed"}
# Close all open positions
for signal_id, position in list(sub.positions.items()):
self._close_on_exchange(
symbol=position["symbol"],
side="sell" if position["side"] == "buy" else "buy",
amount_usd=position["allocated_usd"],
)
sub.active = False
sub.positions.clear()
return {"status": "unsubscribed", "leader_id": leader_id}
Risk Limits Per Leader
The LeaderSubscription dataclass encodes four risk constraints that protect the follower:
max_allocation_pct -- The maximum percentage of the follower's portfolio that can be allocated to positions from this leader at any point in time. Default 20%. If a follower subscribes to five leaders at 20% each, their entire portfolio is allocated -- but no single leader can cause more than 20% damage.
max_drawdown_pct -- The cumulative loss threshold that triggers automatic unsubscription. If a leader's signals produce cumulative losses exceeding this threshold, the follower stops copying. Default 10%. This is a circuit breaker that prevents catastrophic losses from a leader who has lost their edge.
max_position_size_pct -- The maximum size of any single position, regardless of what the leader signals. If a leader allocates 25% of their portfolio to a single trade (aggressive), the follower caps it at 5% (conservative). This prevents a single bad trade from causing outsized damage.
allowed_symbols -- An optional whitelist of tradeable symbols. A follower might want to copy a leader's BTC and ETH trades but skip altcoin signals. An empty list means all symbols are allowed.
import os
follower = CopyTradingFollower(
api_key=os.environ["GREENHELIX_API_KEY"],
agent_id="follower-conservative-01",
private_key_b64=os.environ["FOLLOWER_PRIVATE_KEY"],
portfolio_value_usd=25000.00,
)
# Subscribe to the momentum leader with conservative risk limits
escrow = follower.subscribe(
leader_id="leader-crypto-momentum-01",
escrow_amount_usd=500.00,
max_allocation_pct=15.0,
max_drawdown_pct=8.0,
max_position_size_pct=3.0,
allowed_symbols=["BTCUSDT", "ETHUSDT"],
evaluation_period_days=30,
performance_criteria={
"min_sharpe": "1.5",
"max_drawdown_pct": "15.0",
"min_win_rate_pct": "50.0",
},
)
print(f"Subscribed with escrow: {escrow['escrow_id']}")
This follower has a $25,000 portfolio and allocates at most 15% ($3,750) to the momentum leader. No single position exceeds 3% ($750). If cumulative losses reach 8% ($2,000), copying stops automatically. Only BTC and ETH signals are followed -- SOL is filtered out. The $500 escrow deposit is released to the leader only if they maintain a Sharpe above 1.5, drawdown below 15%, and win rate above 50% over 30 days.
Chapter 4: Allocation Models
Why One Size Does Not Fit All
A leader who allocates 15% of a $500K portfolio to a BTC long should not trigger the same $75K allocation from a $50K follower. The follower would be risking 150% of their capital. Even with max_position_size_pct caps, the relations
…(truncated)