Connect Microsoft AutoGen v0.4 multi-agent conversations to Purple Flea's financial infrastructure. Let your agent teams analyze, deliberate, and execute โ with real funds.
In AutoGen v0.4, tools are registered as function schemas and the agent runtime automatically resolves which agent handles each tool call. This makes it straightforward to expose Purple Flea API calls as native AutoGen tools that any agent in a group chat can invoke.
import asyncio, os from autogen_agentchat.agents import AssistantAgent, UserProxyAgent from autogen_ext.models import OpenAIChatCompletionClient import httpx # Purple Flea API key โ use environment variable, never hardcode PF_API_KEY = os.environ["PURPLE_FLEA_API_KEY"] # pf_live_... PF_BASE = "https://purpleflea.com/api/v1" async def purpleflea_get_balance() -> dict: """Get current agent wallet balance from Purple Flea""" async with httpx.AsyncClient() as c: r = await c.get( f"{PF_BASE}/wallet/balance", headers={"Authorization": f"Bearer {PF_API_KEY}"} ) return r.json() async def purpleflea_trade(symbol: str, side: str, amount: float) -> dict: """Place a trade on Purple Flea trading service""" async with httpx.AsyncClient() as c: r = await c.post( f"{PF_BASE}/trade/order", headers={"Authorization": f"Bearer {PF_API_KEY}"}, json={"symbol": symbol, "side": side, "amount": amount, "mode": "paper"} ) return r.json() # Build AutoGen agent with Purple Flea tools model_client = OpenAIChatCompletionClient(model="gpt-4o-mini") assistant = AssistantAgent( name="purple_flea_trader", model_client=model_client, tools=[purpleflea_get_balance, purpleflea_trade], system_message="""You are a financial trading agent on Purple Flea. Always check balance before placing trades. Never risk more than 5% of balance on a single trade.""" ) proxy = UserProxyAgent(name="user", human_input_mode="NEVER") async def main(): result = await proxy.initiate_chat( assistant, message="Check my balance and place a paper trade: buy 0.01 BTC if balance > $100" ) print(result.summary) asyncio.run(main())
Claim $1 USDC from the faucet after registering โ no deposit required. Your AutoGen agent can start trading immediately with zero risk of spending real funds until you're ready.
Reads market data, identifies signals, proposes trades with rationale. Cannot execute.
Reviews analyst proposals, checks position limits, approves or rejects. Has veto power.
Only executes after risk approval. Has Purple Flea API access. Cannot self-initiate.
Optional human-in-the-loop. Intercepts large transactions for manual approval.
from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.teams import RoundRobinGroupChat from autogen_agentchat.conditions import TextMentionTermination analyst = AssistantAgent( name="analyst", model_client=model_client, system_message="""You are a market analyst. Analyze market conditions and propose specific trades. Always include: symbol, direction, amount, and rationale. End proposals with 'PROPOSAL READY' when complete.""" ) risk_manager = AssistantAgent( name="risk_manager", model_client=model_client, system_message="""You are a risk manager. Review proposals from the analyst. Check: (1) position size <= 5% of balance, (2) no correlated positions, (3) stop-loss specified. Reply 'APPROVED' or 'REJECTED: [reason]'.""" ) executor = AssistantAgent( name="executor", model_client=model_client, tools=[purpleflea_trade, purpleflea_get_balance], system_message="""You are a trade executor. ONLY execute trades after the risk_manager has said 'APPROVED'. Call purpleflea_trade() with approved parameters. Report execution result. Never initiate trades independently.""" ) termination = TextMentionTermination("EXECUTED") team = RoundRobinGroupChat( participants=[analyst, risk_manager, executor], termination_condition=termination ) async def run_team(market_brief: str): result = await team.run(task=market_brief) return result
from typing import Literal import httpx, os _BASE = "https://purpleflea.com/api/v1" _HEADERS = lambda: {"Authorization": f"Bearer {os.environ['PURPLE_FLEA_API_KEY']}"} async def purpleflea_bet( game: Literal["dice", "coinflip", "roulette"], amount: float, prediction: str ) -> dict: """ Place a bet on the Purple Flea casino. Args: game: Which casino game to bet on (dice, coinflip, roulette) amount: USDC amount to bet (min 0.01) prediction: Your prediction (e.g. "heads", "over_50", "red") Returns: dict with keys: outcome (win/loss), payout, new_balance """ async with httpx.AsyncClient() as c: r = await c.post( f"{_BASE}/casino/bet", headers=_HEADERS(), json={"game": game, "amount": amount, "prediction": prediction} ) return r.json() async def purpleflea_escrow( action: Literal["create", "release", "dispute"], counterparty_agent_id: str, amount: float, condition: str = "", escrow_id: str = "" ) -> dict: """ Create or manage a trustless escrow between agents. Args: action: create, release, or dispute the escrow counterparty_agent_id: Agent ID of the other party amount: USDC amount to escrow (1% fee applies) condition: Human-readable release condition (for create) escrow_id: Existing escrow ID (for release/dispute) Returns: dict with keys: escrow_id, status, fee_paid, net_amount """ async with httpx.AsyncClient() as c: r = await c.post( f"{_BASE}/escrow/{action}", headers=_HEADERS(), json={ "counterparty": counterparty_agent_id, "amount": amount, "condition": condition, "escrow_id": escrow_id, } ) return r.json()
from autogen_agentchat.teams import SelectorGroupChat from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination from autogen_core.models import SystemMessage # Macro analyst: reads news/macro data, forms a view macro_analyst = AssistantAgent( name="macro_analyst", model_client=model_client, system_message="Evaluate macro economic signals. Provide bullish/bearish stance with 1-3 supporting data points." ) # Technical analyst: reads price action technical_analyst = AssistantAgent( name="technical_analyst", model_client=model_client, system_message="Evaluate technical price patterns. Provide entry levels, targets, and stop-loss levels." ) # Risk officer: must approve before executor fires risk_officer = AssistantAgent( name="risk_officer", model_client=model_client, system_message="""Synthesize analyst inputs. Only say 'TRADE APPROVED: [params]' if both analysts agree AND position size is within 3% of balance. Otherwise say 'TRADE REJECTED: [reason]'.""" ) executor = AssistantAgent( name="executor", model_client=model_client, tools=[purpleflea_trade, purpleflea_get_balance, purpleflea_escrow], system_message="Execute ONLY after 'TRADE APPROVED' from risk_officer. Report result as 'EXECUTED'." ) # SelectorGroupChat: LLM decides who speaks next termination = ( TextMentionTermination("EXECUTED") | TextMentionTermination("TRADE REJECTED") | MaxMessageTermination(12) ) team = SelectorGroupChat( participants=[macro_analyst, technical_analyst, risk_officer, executor], model_client=model_client, termination_condition=termination, selector_prompt="""You are a trading desk coordinator. Select the next speaker: macro_analyst โ technical_analyst โ risk_officer โ executor. Only select executor after risk_officer has approved.""" )
A single agent can hallucinate conviction. Multi-agent deliberation forces each perspective to be articulated and challenged. The risk officer pattern ensures no trade executes without explicit approval from a designated gatekeeper โ an architectural check rather than a prompt instruction.
UserProxyAgent handles this natively.from autogen_agentchat.agents import UserProxyAgent # Approve automatically for small amounts, require human for large def approval_policy(message: str) -> bool: """Return True to execute, False to pause for human""" import re # Extract amount from message like "TRADE APPROVED: BTC buy 500 USDC" match = re.search(r'(\d+(?:\.\d+)?)\s+USDC', message) if match: amount = float(match.group(1)) return amount < 100 # Auto-approve below $100 return False # Require human for ambiguous cases approval_proxy = UserProxyAgent( name="compliance_proxy", human_input_mode="ALWAYS", # Will pause and wait for stdin is_termination_msg=lambda msg: approval_policy(msg.get("content", "")), max_consecutive_auto_reply=1, code_execution_config=False ) # For production: replace human_input_mode with a Slack/webhook callback # so approvals come from your team's notification channel
import hashlib, json from functools import wraps from datetime import datetime, timedelta # Simple in-memory cache for agent decisions _cache: dict = {} def cache_decision(ttl_seconds: int = 300): """Cache an agent tool result for repeated market conditions""" def decorator(fn): @wraps(fn) async def wrapper(*args, **kwargs): key = hashlib.md5( json.dumps({"fn": fn.__name__, "args": args, "kwargs": kwargs}, sort_keys=True).encode() ).hexdigest() if key in _cache: result, expiry = _cache[key] if datetime.now() < expiry: return result # Cache hit: no LLM call result = await fn(*args, **kwargs) _cache[key] = (result, datetime.now() + timedelta(seconds=ttl_seconds)) return result return wrapper return decorator # Cache balance checks for 60s โ balance doesn't change that fast @cache_decision(ttl_seconds=60) async def purpleflea_get_balance() -> dict: async with httpx.AsyncClient() as c: r = await c.get(f"{_BASE}/wallet/balance", headers=_HEADERS()) return r.json() # Never cache order placement โ every trade must be a live API call
gpt-4o-mini handle analyst deliberation. Only use gpt-4o for the final risk officer decision. 10x cost reduction on most runs.Register takes 30 seconds. Claim $1 USDC from the faucet and your AutoGen team can start trading immediately. 6 financial services, one API key.
pf_live_ ยท No credit card required