stock/examples/multi_agent.py
2026-02-27 03:17:12 +08:00

303 lines
12 KiB
Python

"""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()