"""Multi-Agent Trading Example for OpenClaw. This example demonstrates how multiple agents collaborate to make trading decisions using the decision fusion system. Different agents with different roles provide opinions that are combined into a final trading signal. To run: python examples/multi_agent.py """ import random from typing import List from openclaw.fusion.decision_fusion import ( AgentOpinion, AgentRole, DecisionFusion, FusionConfig, FusionResult, SignalType, ) class SimpleAgent: """A simplified agent for demonstration purposes. In production, each agent would have its own analysis logic and economic tracking. """ def __init__(self, agent_id: str, role: AgentRole, bias: float = 0.0): self.agent_id = agent_id self.role = role self.bias = bias # Positive = bullish, negative = bearish self.skill_level = random.uniform(0.5, 0.9) def analyze(self, symbol: str) -> AgentOpinion: """Generate an opinion about a symbol.""" # Simulate analysis with some randomness base_signal = random.randint(-2, 2) # Apply bias if self.bias > 0.3: base_signal = max(base_signal, 0) # Bullish agents prefer buy/hold elif self.bias < -0.3: base_signal = min(base_signal, 0) # Bearish agents prefer sell/hold # Map to signal type signal_map = { -2: SignalType.STRONG_SELL, -1: SignalType.SELL, 0: SignalType.HOLD, 1: SignalType.BUY, 2: SignalType.STRONG_BUY, } signal = signal_map.get(base_signal, SignalType.HOLD) # Generate reasoning based on role reasoning = self._generate_reasoning(symbol, signal) # Confidence based on skill level and signal clarity confidence = self.skill_level * random.uniform(0.7, 1.0) # Key factors factors = self._generate_factors() return AgentOpinion( agent_id=self.agent_id, role=self.role, signal=signal, confidence=confidence, reasoning=reasoning, factors=factors, ) def _generate_reasoning(self, symbol: str, signal: SignalType) -> str: """Generate reasoning based on role and signal.""" templates = { AgentRole.MARKET_ANALYST: { SignalType.STRONG_BUY: f"{symbol} shows strong bullish momentum with volume surge", SignalType.BUY: f"{symbol} technical indicators suggest upward movement", SignalType.HOLD: f"{symbol} consolidating, wait for clearer direction", SignalType.SELL: f"{symbol} showing weakness in support levels", SignalType.STRONG_SELL: f"{symbol} breakdown below key support with high volume", }, AgentRole.SENTIMENT_ANALYST: { SignalType.STRONG_BUY: f"Extremely positive sentiment for {symbol} across social media", SignalType.BUY: f"Positive news sentiment detected for {symbol}", SignalType.HOLD: f"Mixed sentiment for {symbol}, no clear direction", SignalType.SELL: f"Negative sentiment emerging for {symbol}", SignalType.STRONG_SELL: f"Strong negative sentiment and fear for {symbol}", }, AgentRole.FUNDAMENTAL_ANALYST: { SignalType.STRONG_BUY: f"{symbol} fundamentals exceptionally strong, undervalued", SignalType.BUY: f"{symbol} earnings beat expectations, solid growth", SignalType.HOLD: f"{symbol} fundamentals stable, fairly valued", SignalType.SELL: f"{symbol} showing signs of overvaluation", SignalType.STRONG_SELL: f"{symbol} fundamentals deteriorating rapidly", }, AgentRole.BULL_RESEARCHER: { SignalType.STRONG_BUY: f"Catalyst identified: {symbol} poised for significant upside", SignalType.BUY: f"Bullish thesis intact for {symbol}", SignalType.HOLD: f"Waiting for better entry on {symbol}", SignalType.SELL: f"Temporary setback, but {symbol} long-term bullish", SignalType.STRONG_SELL: f"{symbol} thesis broken, exit position", }, AgentRole.BEAR_RESEARCHER: { SignalType.STRONG_BUY: f"{symbol} short squeeze potential, cover shorts", SignalType.BUY: f"{symbol} oversold bounce likely", SignalType.HOLD: f"{symbol} no clear bearish catalyst yet", SignalType.SELL: f"Bearish pattern forming on {symbol}", SignalType.STRONG_SELL: f"{symbol} significant downside risk identified", }, AgentRole.RISK_MANAGER: { SignalType.STRONG_BUY: f"Low risk environment, can increase {symbol} position", SignalType.BUY: f"Acceptable risk levels for {symbol} trade", SignalType.HOLD: f"Risk elevated, reduce {symbol} exposure", SignalType.SELL: f"High risk detected for {symbol}, scale down", SignalType.STRONG_SELL: f"Critical risk level for {symbol}, exit immediately", }, } role_templates = templates.get(self.role, templates[AgentRole.MARKET_ANALYST]) return role_templates.get(signal, "No clear signal") def _generate_factors(self) -> List[str]: """Generate relevant factors based on role.""" factors_by_role = { AgentRole.MARKET_ANALYST: [ "Moving Average Crossover", "Volume Profile", "Support/Resistance", "MACD Divergence", "RSI Levels" ], AgentRole.SENTIMENT_ANALYST: [ "Social Media Buzz", "News Sentiment", "Analyst Ratings", "Insider Activity", "Options Flow" ], AgentRole.FUNDAMENTAL_ANALYST: [ "P/E Ratio", "Revenue Growth", "Profit Margins", "Debt/Equity", "Free Cash Flow" ], AgentRole.BULL_RESEARCHER: [ "Growth Catalysts", "Market Expansion", "New Products", "Competitive Advantage", "Industry Trends" ], AgentRole.BEAR_RESEARCHER: [ "Valuation Concerns", "Competition Threats", "Regulatory Risks", "Margin Pressure", "Slowing Growth" ], AgentRole.RISK_MANAGER: [ "Volatility Spike", "Correlation Risk", "Liquidity Check", "Position Size Limits", "Stop Loss Levels" ], } factors = factors_by_role.get(self.role, ["General Analysis"]) # Select 2-3 random factors return random.sample(factors, min(3, len(factors))) def create_agent_team() -> List[SimpleAgent]: """Create a team of agents with different roles and biases.""" return [ # Market Analysts - technical focus SimpleAgent("market_01", AgentRole.MARKET_ANALYST, bias=0.1), # Sentiment Analysts - news/social focus SimpleAgent("sentiment_01", AgentRole.SENTIMENT_ANALYST, bias=0.0), # Fundamental Analysts - company fundamentals SimpleAgent("fundamental_01", AgentRole.FUNDAMENTAL_ANALYST, bias=0.2), # Bull Researcher - optimistic view SimpleAgent("bull_01", AgentRole.BULL_RESEARCHER, bias=0.5), # Bear Researcher - cautious view SimpleAgent("bear_01", AgentRole.BEAR_RESEARCHER, bias=-0.3), # Risk Manager - risk focus SimpleAgent("risk_01", AgentRole.RISK_MANAGER, bias=-0.1), ] def print_opinion(opinion: AgentOpinion, index: int) -> None: """Print an agent's opinion in a formatted way.""" print(f"\n [{index}] {opinion.agent_id} ({opinion.role.value})") print(f" Signal: {opinion.signal.name}") print(f" Confidence: {opinion.confidence:.1%}") print(f" Reasoning: {opinion.reasoning}") print(f" Factors: {', '.join(opinion.factors)}") def print_fusion_result(result: FusionResult) -> None: """Print fusion result in a formatted way.""" print("\n" + "-" * 50) print("FUSION RESULT") print("-" * 50) print(f" Symbol: {result.symbol}") print(f" Final Signal: {result.final_signal.name}") print(f" Recommendation: {result.get_recommendation_text()}") print(f" Confidence: {result.final_confidence:.1%}") print(f" Consensus: {result.consensus_level:.1%}") if result.supporting_opinions: print(f"\n Supporting ({len(result.supporting_opinions)} opinions):") for op in result.supporting_opinions[:3]: print(f" - {op.agent_id}: {op.signal.name}") if result.opposing_opinions: print(f"\n Opposing ({len(result.opposing_opinions)} opinions):") for op in result.opposing_opinions[:3]: print(f" - {op.agent_id}: {op.signal.name}") if result.risk_assessment: print(f"\n Risk Assessment: {result.risk_assessment}") if result.execution_plan: plan = result.execution_plan print(f"\n Execution Plan:") print(f" Action: {plan.get('action', 'N/A')}") print(f" Urgency: {plan.get('urgency', 'N/A')}") print(f" Position Size: {plan.get('position_size', 'N/A')}") if plan.get('notes'): print(f" Notes: {'; '.join(plan['notes'])}") def main(): """Run the multi-agent example.""" print("=" * 60) print("OpenClaw Trading - Multi-Agent Decision Fusion") print("=" * 60) # Create agent team print("\n1. Creating agent team...") agents = create_agent_team() for agent in agents: bias_str = "bullish" if agent.bias > 0.2 else "bearish" if agent.bias < -0.2 else "neutral" print(f" - {agent.agent_id}: {agent.role.value} ({bias_str}, skill={agent.skill_level:.0%})") # Create decision fusion engine print("\n2. Initializing decision fusion engine...") config = FusionConfig( confidence_threshold=0.3, consensus_threshold=0.6, enable_risk_override=True, ) fusion = DecisionFusion(config=config) print(f" Confidence threshold: {config.confidence_threshold}") print(f" Risk override enabled: {config.enable_risk_override}") # Analyze multiple symbols symbols = ["AAPL", "TSLA", "NVDA"] for symbol in symbols: print(f"\n{'=' * 60}") print(f"Analyzing {symbol}") print("=" * 60) # Collect opinions print("\n3. Collecting agent opinions...") fusion.start_fusion(symbol) for i, agent in enumerate(agents, 1): opinion = agent.analyze(symbol) fusion.add_opinion(opinion) print_opinion(opinion, i) # Execute fusion print("\n4. Executing decision fusion...") result = fusion.fuse(portfolio_value=100000.0) # Print results print_fusion_result(result) # Summary print("\n" + "=" * 60) print("SUMMARY") print("=" * 60) history = fusion.get_fusion_history() print(f"\nTotal decisions made: {len(history)}") signal_counts = {} for r in history: signal_counts[r.final_signal.name] = signal_counts.get(r.final_signal.name, 0) + 1 print("\nSignal distribution:") for signal, count in sorted(signal_counts.items()): bar = "█" * count print(f" {signal:15} {bar} ({count})") avg_confidence = sum(r.final_confidence for r in history) / len(history) avg_consensus = sum(r.consensus_level for r in history) / len(history) print(f"\nAverage confidence: {avg_confidence:.1%}") print(f"Average consensus: {avg_consensus:.1%}") print("\n" + "=" * 60) print("Multi-agent example complete!") print("=" * 60) if __name__ == "__main__": main()